# undef HAVE_STRUCT_STAT_ST_CTIM
# undef HAVE_STRUCT_STAT_ST_MTIM
#endif
+
+#ifdef _WIN32
+# ifdef _MSC_VER
+typedef unsigned __int32 mode_t;
+typedef int pid_t;
+# endif
+#endif // _WIN32
[[config_umask]] *umask* (*CCACHE_UMASK*)::
- This option specifies the umask for files and directories in the cache
- directory. This is mostly useful when you wish to share your cache with
- other users.
+ This option (an octal integer) specifies the umask for files and directories
+ in the cache directory. This is mostly useful when you wish to share your
+ cache with other users.
== Cache size management
#include "exceptions.hpp"
#include "fmtmacros.hpp"
+#include <util/string_utils.hpp>
+
#include "third_party/fmt/core.h"
// System headers
return result;
}
-uint32_t
-parse_umask(const std::string& value)
-{
- if (value.empty()) {
- return std::numeric_limits<uint32_t>::max();
- }
-
- size_t end;
- uint32_t result = std::stoul(value, &end, 8);
- if (end != value.size()) {
- throw Error("not an octal integer: \"{}\"", value);
- }
- return result;
-}
-
std::string
-format_umask(uint32_t umask)
+format_umask(nonstd::optional<mode_t> umask)
{
- if (umask == std::numeric_limits<uint32_t>::max()) {
- return {};
+ if (umask) {
+ return FMT("{:03o}", *umask);
} else {
- return FMT("{:03o}", umask);
+ return {};
}
}
break;
case ConfigItem::umask:
- m_umask = parse_umask(value);
+ if (!value.empty()) {
+ const auto umask = util::parse_umask(value);
+ if (!umask) {
+ throw Error(umask.error());
+ }
+ m_umask = *umask;
+ }
break;
}
bool stats() const;
const std::string& stats_log() const;
const std::string& temporary_dir() const;
- uint32_t umask() const;
+ nonstd::optional<mode_t> umask() const;
void set_base_dir(const std::string& value);
void set_cache_dir(const std::string& value);
bool m_stats = true;
std::string m_stats_log;
std::string m_temporary_dir;
- uint32_t m_umask = std::numeric_limits<uint32_t>::max(); // Don't set umask
+ nonstd::optional<mode_t> m_umask;
bool m_temporary_dir_configured_explicitly = false;
return m_temporary_dir;
}
-inline uint32_t
+inline nonstd::optional<mode_t>
Config::umask() const
{
return m_umask;
// initial configuration file. The intention is that all files and directories
// in the cache directory should be affected by the configured umask and that
// no other files and directories should.
- if (config.umask() != std::numeric_limits<uint32_t>::max()) {
- original_umask = umask(config.umask());
+ if (config.umask()) {
+ original_umask = umask(*config.umask());
}
}
-// Copyright (C) 2020 Joel Rosdahl and other contributors
+// Copyright (C) 2020-2021 Joel Rosdahl and other contributors
//
// See doc/AUTHORS.adoc for a complete list of contributors.
//
nonstd::optional<mode_t> m_saved_umask;
};
-UmaskScope::UmaskScope(nonstd::optional<mode_t> new_umask)
+inline UmaskScope::UmaskScope(nonstd::optional<mode_t> new_umask)
{
#ifndef _WIN32
if (new_umask) {
#endif
}
-UmaskScope::~UmaskScope()
+inline UmaskScope::~UmaskScope()
{
#ifndef _WIN32
if (m_saved_umask) {
bool fall_back_to_original_compiler = false;
Args saved_orig_args;
- nonstd::optional<mode_t> original_umask;
+ nonstd::optional<uint32_t> original_umask;
std::string saved_temp_dir;
{
# error _WIN32_WINNT is undefined
# endif
-# ifdef _MSC_VER
-typedef int mode_t;
-typedef int pid_t;
-# endif
-
# ifndef __MINGW32__
typedef int64_t ssize_t;
# endif
#include "string_utils.hpp"
#include <FormatNonstdStringView.hpp>
+#include <Util.hpp>
#include <fmtmacros.hpp>
// System headers
namespace util {
+nonstd::expected<mode_t, std::string>
+parse_umask(const std::string& value)
+{
+ try {
+ return Util::parse_unsigned(value, 0, 0777, "umask", 8);
+ } catch (const Error& e) {
+ return nonstd::make_unexpected(e.what());
+ }
+}
+
nonstd::expected<std::string, std::string>
percent_decode(nonstd::string_view string)
{
#include <third_party/nonstd/string_view.hpp>
// System headers
+#include <string>
#include <utility>
// End of system headers
namespace util {
+// Parse `value` (an octal integer).
+nonstd::expected<mode_t, std::string> parse_umask(const std::string& value);
+
// Percent-decode[1] `string`.
//
// [1]: https://en.wikipedia.org/wiki/Percent-encoding
CHECK(config.sloppiness() == 0);
CHECK(config.stats());
CHECK(config.temporary_dir().empty()); // Set later
- CHECK(config.umask() == std::numeric_limits<uint32_t>::max());
+ CHECK(config.umask() == nonstd::nullopt);
}
TEST_CASE("Config::update_from_file")
| SLOPPY_IVFSOVERLAY));
CHECK_FALSE(config.stats());
CHECK(config.temporary_dir() == FMT("{}_foo", user));
- CHECK(config.umask() == 0777);
+ CHECK(config.umask() == 0777u);
}
TEST_CASE("Config::update_from_file, error handling")
{
Util::write_file("ccache.conf", "umask = ");
CHECK(config.update_from_file("ccache.conf"));
- CHECK(config.umask() == std::numeric_limits<uint32_t>::max());
+ CHECK(config.umask() == nonstd::nullopt);
}
SUBCASE("invalid size")
return left.first == right.first && left.second == right.second;
}
+TEST_CASE("util::parse_umask")
+{
+ CHECK(util::parse_umask("1") == 01u);
+ CHECK(util::parse_umask("002") == 2u);
+ CHECK(util::parse_umask("777") == 0777u);
+ CHECK(util::parse_umask("0777") == 0777u);
+
+ CHECK(util::parse_umask("").error()
+ == "invalid unsigned octal integer: \"\"");
+ CHECK(util::parse_umask(" ").error()
+ == "invalid unsigned octal integer: \"\"");
+ CHECK(util::parse_umask("088").error()
+ == "invalid unsigned octal integer: \"088\"");
+}
+
TEST_CASE("util::percent_decode")
{
CHECK(util::percent_decode("") == "");