Specify the umask and IPC socket permission as strings. (#2984)
* Support specifying the umask as a string representing an octal number. * Save the umask as a string representing an octal number. * Support specifying the IPC socket permission as a string representing an octal number. * Save the IPC socket permission as a string representing an octal number. * Add a `base` parameter to `tr_parseNum()` for specifying the radix.
This commit is contained in:
parent
7c2477dddf
commit
d8c5c65725
|
@ -55,7 +55,7 @@ Here is a sample of the three basic types: respectively Boolean, Number and Stri
|
|||
* **rename-partial-files:** Boolean (default = true) Postfix partially downloaded files with ".part".
|
||||
* **start-added-torrents:** Boolean (default = true) Start torrents as soon as they are added.
|
||||
* **trash-original-torrent-files:** Boolean (default = false) Delete torrents added from the watch directory.
|
||||
* **umask:** Number (default = 18) Sets transmission's file mode creation mask. See [the umask(2) manpage](https://developer.apple.com/documentation/Darwin/Reference/ManPages/man2/umask.2.html) for more information. Users who want their saved torrents to be world-writable may want to set this value to 0. Bear in mind that the JSON markup language only accepts numbers in base 10, so the standard umask(2) octal notation "022" is written in settings.json as 18.
|
||||
* **umask:** String (default = "022") Sets Transmission's file mode creation mask. See [the umask(2) manpage](https://developer.apple.com/documentation/Darwin/Reference/ManPages/man2/umask.2.html) for more information. Users who want their saved torrents to be world-writable may want to set this value to "0".
|
||||
* **watch-dir:** String
|
||||
* **watch-dir-enabled:** Boolean (default = false) Watch a directory for torrent files and add them to transmission.
|
||||
_Note: When **watch-dir-enabled** is true, only the transmission-daemon, transmission-gtk, and transmission-qt applications will monitor **watch-dir** for new .torrent files and automatically load them._
|
||||
|
|
|
@ -1084,8 +1084,20 @@ tr_rpc_server::tr_rpc_server(tr_session* session_in, tr_variant* settings)
|
|||
}
|
||||
|
||||
key = TR_KEY_rpc_socket_mode;
|
||||
bool is_missing_rpc_socket_mode_key = true;
|
||||
|
||||
if (!tr_variantDictFindInt(settings, key, &i))
|
||||
if (tr_variantDictFindStrView(settings, key, &sv))
|
||||
{
|
||||
/* Read the socket permission as a string representing an octal number. */
|
||||
is_missing_rpc_socket_mode_key = false;
|
||||
i = tr_parseNum<int>(sv, 8).value_or(tr_rpc_server::DefaultRpcSocketMode);
|
||||
}
|
||||
else if (tr_variantDictFindInt(settings, key, &i))
|
||||
{
|
||||
/* Or as a base 10 integer to remain compatible with the old settings format. */
|
||||
is_missing_rpc_socket_mode_key = false;
|
||||
}
|
||||
if (is_missing_rpc_socket_mode_key)
|
||||
{
|
||||
missing_settings_key(key);
|
||||
}
|
||||
|
|
|
@ -79,6 +79,7 @@ static auto constexpr DefaultPrefetchEnabled = bool{ false };
|
|||
static auto constexpr DefaultCacheSizeMB = int{ 4 };
|
||||
static auto constexpr DefaultPrefetchEnabled = bool{ true };
|
||||
#endif
|
||||
static auto constexpr DefaultUmask = int{ 022 };
|
||||
static auto constexpr SaveIntervalSecs = int{ 360 };
|
||||
|
||||
static void bandwidthGroupRead(tr_session* session, std::string_view config_dir);
|
||||
|
@ -371,7 +372,7 @@ void tr_sessionGetDefaultSettings(tr_variant* d)
|
|||
tr_variantDictAddBool(d, TR_KEY_rpc_host_whitelist_enabled, true);
|
||||
tr_variantDictAddInt(d, TR_KEY_rpc_port, TR_DEFAULT_RPC_PORT);
|
||||
tr_variantDictAddStrView(d, TR_KEY_rpc_url, TR_DEFAULT_RPC_URL_STR);
|
||||
tr_variantDictAddInt(d, TR_KEY_rpc_socket_mode, tr_rpc_server::DefaultRpcSocketMode);
|
||||
tr_variantDictAddStr(d, TR_KEY_rpc_socket_mode, fmt::format("{:#o}", tr_rpc_server::DefaultRpcSocketMode));
|
||||
tr_variantDictAddBool(d, TR_KEY_scrape_paused_torrents_enabled, true);
|
||||
tr_variantDictAddStrView(d, TR_KEY_script_torrent_added_filename, "");
|
||||
tr_variantDictAddBool(d, TR_KEY_script_torrent_added_enabled, false);
|
||||
|
@ -390,7 +391,7 @@ void tr_sessionGetDefaultSettings(tr_variant* d)
|
|||
tr_variantDictAddInt(d, TR_KEY_alt_speed_time_day, TR_SCHED_ALL);
|
||||
tr_variantDictAddInt(d, TR_KEY_speed_limit_up, 100);
|
||||
tr_variantDictAddBool(d, TR_KEY_speed_limit_up_enabled, false);
|
||||
tr_variantDictAddInt(d, TR_KEY_umask, 022);
|
||||
tr_variantDictAddStr(d, TR_KEY_umask, fmt::format("{:#o}", DefaultUmask));
|
||||
tr_variantDictAddInt(d, TR_KEY_upload_slots_per_torrent, 14);
|
||||
tr_variantDictAddStrView(d, TR_KEY_bind_address_ipv4, TR_DEFAULT_BIND_ADDRESS_IPV4);
|
||||
tr_variantDictAddStrView(d, TR_KEY_bind_address_ipv6, TR_DEFAULT_BIND_ADDRESS_IPV6);
|
||||
|
@ -446,7 +447,7 @@ void tr_sessionGetSettings(tr_session const* s, tr_variant* d)
|
|||
tr_variantDictAddBool(d, TR_KEY_rpc_enabled, tr_sessionIsRPCEnabled(s));
|
||||
tr_variantDictAddStr(d, TR_KEY_rpc_password, tr_sessionGetRPCPassword(s));
|
||||
tr_variantDictAddInt(d, TR_KEY_rpc_port, tr_sessionGetRPCPort(s));
|
||||
tr_variantDictAddInt(d, TR_KEY_rpc_socket_mode, s->rpc_server_->socketMode());
|
||||
tr_variantDictAddStr(d, TR_KEY_rpc_socket_mode, fmt::format("{:#o}", s->rpc_server_->socket_mode_));
|
||||
tr_variantDictAddStr(d, TR_KEY_rpc_url, tr_sessionGetRPCUrl(s));
|
||||
tr_variantDictAddStr(d, TR_KEY_rpc_username, tr_sessionGetRPCUsername(s));
|
||||
tr_variantDictAddStr(d, TR_KEY_rpc_whitelist, tr_sessionGetRPCWhitelist(s));
|
||||
|
@ -463,7 +464,7 @@ void tr_sessionGetSettings(tr_session const* s, tr_variant* d)
|
|||
tr_variantDictAddInt(d, TR_KEY_alt_speed_time_day, tr_sessionGetAltSpeedDay(s));
|
||||
tr_variantDictAddInt(d, TR_KEY_speed_limit_up, tr_sessionGetSpeedLimit_KBps(s, TR_UP));
|
||||
tr_variantDictAddBool(d, TR_KEY_speed_limit_up_enabled, tr_sessionIsSpeedLimited(s, TR_UP));
|
||||
tr_variantDictAddInt(d, TR_KEY_umask, s->umask);
|
||||
tr_variantDictAddStr(d, TR_KEY_umask, fmt::format("{:#o}", s->umask));
|
||||
tr_variantDictAddInt(d, TR_KEY_upload_slots_per_torrent, s->uploadSlotsPerTorrent);
|
||||
tr_variantDictAddStr(d, TR_KEY_bind_address_ipv4, tr_address_to_string(&s->bind_ipv4->addr));
|
||||
tr_variantDictAddStr(d, TR_KEY_bind_address_ipv6, tr_address_to_string(&s->bind_ipv6->addr));
|
||||
|
@ -796,8 +797,15 @@ static void sessionSetImpl(struct init_data* const data)
|
|||
|
||||
#ifndef _WIN32
|
||||
|
||||
if (tr_variantDictFindInt(settings, TR_KEY_umask, &i))
|
||||
if (tr_variantDictFindStrView(settings, TR_KEY_umask, &sv))
|
||||
{
|
||||
/* Read a umask as a string representing an octal number. */
|
||||
session->umask = tr_parseNum<mode_t>(sv, 8).value_or(DefaultUmask);
|
||||
umask(session->umask);
|
||||
}
|
||||
else if (tr_variantDictFindInt(settings, TR_KEY_umask, &i))
|
||||
{
|
||||
/* Or as a base 10 integer to remain compatible with the old settings format. */
|
||||
session->umask = (mode_t)i;
|
||||
umask(session->umask);
|
||||
}
|
||||
|
|
|
@ -117,16 +117,21 @@ void tr_wait_msec(long int delay_milliseconds);
|
|||
|
||||
#if defined(__GNUC__) && !__has_include(<charconv>)
|
||||
|
||||
#include <iomanip> // std::setbase
|
||||
#include <sstream>
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] std::optional<T> tr_parseNum(std::string_view& sv)
|
||||
[[nodiscard]] std::optional<T> tr_parseNum(std::string_view& sv, int base = 10)
|
||||
{
|
||||
auto val = T{};
|
||||
auto const str = std::string(std::data(sv), std::min(std::size(sv), size_t{ 64 }));
|
||||
auto sstream = std::stringstream{ str };
|
||||
auto const oldpos = sstream.tellg();
|
||||
sstream >> val;
|
||||
/* The base parameter only works for bases 8, 10 and 16.
|
||||
All other bases will be converted to 0 which activates the
|
||||
prefix based parsing and therefore decimal in our usual cases.
|
||||
This differs from the from_chars solution below. */
|
||||
sstream >> std::setbase(base) >> val;
|
||||
auto const newpos = sstream.tellg();
|
||||
if ((newpos == oldpos) || (sstream.fail() && !sstream.eof()))
|
||||
{
|
||||
|
@ -141,12 +146,15 @@ template<typename T>
|
|||
#include <charconv> // std::from_chars()
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] std::optional<T> tr_parseNum(std::string_view& sv)
|
||||
[[nodiscard]] std::optional<T> tr_parseNum(std::string_view& sv, int base = 10)
|
||||
{
|
||||
auto val = T{};
|
||||
auto const* const begin_ch = std::data(sv);
|
||||
auto const* const end_ch = begin_ch + std::size(sv);
|
||||
auto const result = std::from_chars(begin_ch, end_ch, val);
|
||||
/* The base parameter works for any base from 2 to 36 (inclusive).
|
||||
This is different from the behaviour of the stringstream
|
||||
based solution above. */
|
||||
auto const result = std::from_chars(begin_ch, end_ch, val, base);
|
||||
if (result.ec != std::errc{})
|
||||
{
|
||||
return std::nullopt;
|
||||
|
|
Loading…
Reference in New Issue