mirror of
https://github.com/NixOS/nix
synced 2025-06-25 23:11:16 +02:00
{libutil,libstore}: Factor out chmodIfNeeded
Using std::filesystem::path directly because we need .c_str() anyway to interact with chmod. Path/string views don't have to be null-terminated.
This commit is contained in:
parent
c99edc840c
commit
82f337de10
4 changed files with 57 additions and 4 deletions
|
@ -136,13 +136,10 @@ LocalStore::LocalStore(
|
||||||
for (auto & perUserDir : {profilesDir + "/per-user", gcRootsDir + "/per-user"}) {
|
for (auto & perUserDir : {profilesDir + "/per-user", gcRootsDir + "/per-user"}) {
|
||||||
createDirs(perUserDir);
|
createDirs(perUserDir);
|
||||||
if (!readOnly) {
|
if (!readOnly) {
|
||||||
auto st = lstat(perUserDir);
|
|
||||||
|
|
||||||
// Skip chmod call if the directory already has the correct permissions (0755).
|
// Skip chmod call if the directory already has the correct permissions (0755).
|
||||||
// This is to avoid failing when the executing user lacks permissions to change the directory's permissions
|
// This is to avoid failing when the executing user lacks permissions to change the directory's permissions
|
||||||
// even if it would be no-op.
|
// even if it would be no-op.
|
||||||
if ((st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO)) != 0755 && chmod(perUserDir.c_str(), 0755) == -1)
|
chmodIfNeeded(perUserDir, 0755, S_IRWXU | S_IRWXG | S_IRWXO);
|
||||||
throw SysError("could not set permissions on '%s' to 755", perUserDir);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -275,4 +275,30 @@ TEST(makeParentCanonical, root)
|
||||||
{
|
{
|
||||||
ASSERT_EQ(makeParentCanonical("/"), "/");
|
ASSERT_EQ(makeParentCanonical("/"), "/");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ----------------------------------------------------------------------------
|
||||||
|
* chmodIfNeeded
|
||||||
|
* --------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
TEST(chmodIfNeeded, works)
|
||||||
|
{
|
||||||
|
auto [autoClose_, tmpFile] = nix::createTempFile();
|
||||||
|
auto deleteTmpFile = AutoDelete(tmpFile);
|
||||||
|
|
||||||
|
auto modes = std::vector<mode_t>{0755, 0644, 0422, 0600, 0777};
|
||||||
|
for (mode_t oldMode : modes) {
|
||||||
|
for (mode_t newMode : modes) {
|
||||||
|
chmod(tmpFile.c_str(), oldMode);
|
||||||
|
bool permissionsChanged = false;
|
||||||
|
ASSERT_NO_THROW(permissionsChanged = chmodIfNeeded(tmpFile, newMode));
|
||||||
|
ASSERT_EQ(permissionsChanged, oldMode != newMode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(chmodIfNeeded, nonexistent)
|
||||||
|
{
|
||||||
|
ASSERT_THROW(chmodIfNeeded("/schnitzel/darmstadt/pommes", 0755), SysError);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -776,4 +776,18 @@ std::filesystem::path makeParentCanonical(const std::filesystem::path & rawPath)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool chmodIfNeeded(const fs::path & path, mode_t mode, mode_t mask)
|
||||||
|
{
|
||||||
|
auto pathString = path.string();
|
||||||
|
auto prevMode = lstat(pathString).st_mode;
|
||||||
|
|
||||||
|
if (((prevMode ^ mode) & mask) == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (chmod(pathString.c_str(), mode) != 0)
|
||||||
|
throw SysError("could not set permissions on '%s' to %o", pathString, mode);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace nix
|
} // namespace nix
|
||||||
|
|
|
@ -366,4 +366,20 @@ typedef std::function<bool(const Path & path)> PathFilter;
|
||||||
|
|
||||||
extern PathFilter defaultPathFilter;
|
extern PathFilter defaultPathFilter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Change permissions of a file only if necessary.
|
||||||
|
*
|
||||||
|
* @details
|
||||||
|
* Skip chmod call if the directory already has the requested permissions.
|
||||||
|
* This is to avoid failing when the executing user lacks permissions to change the
|
||||||
|
* directory's permissions even if it would be no-op.
|
||||||
|
*
|
||||||
|
* @param path Path to the file to change the permissions for.
|
||||||
|
* @param mode New file mode.
|
||||||
|
* @param mask Used for checking if the file already has requested permissions.
|
||||||
|
*
|
||||||
|
* @return true if permissions changed, false otherwise.
|
||||||
|
*/
|
||||||
|
bool chmodIfNeeded(const std::filesystem::path & path, mode_t mode, mode_t mask = S_IRWXU | S_IRWXG | S_IRWXO);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue