Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 45 additions & 4 deletions src/auxiliary/Filesystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,46 @@ std::vector<std::string> list_directory(std::string const &path)
return ret;
}

#ifndef _WIN32
// Need to manually preserve sticky bit and setgid on Unix systems
namespace
{
std::string get_parent(std::string const &path)
{
std::string parent = path;
size_t pos = parent.find_last_of(directory_separator);
if (pos != std::string::npos)
{
parent = parent.substr(0, pos);
if (parent.empty())
parent = "/";
}
else
{
parent.clear();
}
return parent;
}

mode_t get_permissions(std::string const &path)
{
std::string parent = get_parent(path);
if (parent.empty() || !directory_exists(parent))
{
return 0;
}

struct stat s;
if (stat(parent.c_str(), &s) != 0)
{
return 0;
}

return s.st_mode & 07777;
}
} // namespace
#endif

bool create_directories(std::string const &path)
{
if (directory_exists(path))
Expand All @@ -106,10 +146,11 @@ bool create_directories(std::string const &path)
return CreateDirectory(p.c_str(), nullptr);
};
#else
mode_t mask = umask(0);
umask(mask);
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we retrieve the umask just to apply it manually without any modifications? That's what the system does implicitly anyway?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is that supposed to make the function thread-safe against modification of the umask on other threads? If yes, this does not work due to the double call to umask(), also it is irrelevant for MPI-parallel deletion.

Copy link
Copy Markdown
Member

@ax3l ax3l Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. Let's make sure that if someone creates dirs and files with openPMD, it behaves the same as a terminal mkdir and touch with respect to umask and other inherited properties.

It's possible the current implementation is overly verbose and forgets setgid/sticky bits

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Discussed yesterday: Our current implementation probably assumes that the umask is overwritten by the mode_t mode parameter of mkdir(), but that is not the case:

       The  argument mode specifies the mode for the new directory (see inode(7)).  It is modified by the process's umask in the usual way: in the absence
       of a default ACL, the mode of the created directory is (mode & ~umask & 0777).  Whether other mode bits are honored for the created  directory  de-
       pends on the operating system.  For Linux, see VERSIONS below.

Hence, our manual umask handling (1) is unnecessary and (2) is not thread safe due to temporarily manipulating the umask.

auto mk = [mask](std::string const &p) -> bool {
return (0 == mkdir(p.c_str(), 0777 & ~mask));
auto mk = [](std::string const &p) -> bool {
// preserve sticky and setgid from parent
mode_t parentPerms =
get_permissions(get_parent(p)) & (S_ISVTX | S_ISGID);
return (0 == mkdir(p.c_str(), 0777 | parentPerms));
};
#endif
std::istringstream ss(path);
Expand Down
Loading