Using std::filesystem::perms you can get the permissions set on a file. I want to check if I have access to read and write to a file. Using this method works if I am the owner of the file. If I am not the owner of the file (for example root owns it), then the perms returned isn't that useful for the task at hand without knowing the owner.
https://stackoverflow.com/a/7328340 explains how to get the file owner and the current user on Linux systems which can be used in conjunction with std::filesystem::perms for a solution on Linux that is not POSIX compliant.
Is there a way to check if the current user current user can read or write to a file in a POSIX compliant way? Can this be done using only the C++ std lib? What about with Boost?
https://stackoverflow.com/a/10682224 suggests that ownership can not be detected using boost. https://stackoverflow.com/a/59899055 suggests that interpreting the file permissions isn't always that meaningful, but I just want to know if I can read from the file before I attempt opening it.
POSIX rights consist of triads: an example -rw-rw-r--
User rights could be obtained under UNIX by command "id User". For example:
uid=1000(User) gid=1000(User) groups=1000(User),4(adm),7(lp),24(cdrom),27(sudo),30(dip)
User has user id (uid) and belongs to several groups. Ability to read a file is based of uid and groups data. Reading could be done by a process and it also has uid/guid parameters
There are many types of files, let's talk about simplest case about a regular file and not symlink. We need to check tree triads
Checking what the selected user can read file is simple:
// Set here proper info about user
uid_t userId = getuid();
gid_t groupId = getgid();
std::string path = "myfile";
std::filesystem::path filePath(path);
auto status = std::filesystem::status(filePath);
struct stat fileStat;
stat(filePath.c_str(), &fileStat);
if (fileStat.st_uid == userId) {
// User is the same as the owner of the file
if ((status.permissions() & std::filesystem::perms::owner_read) !=
std::filesystem::perms::none) {
return true; // User could read file based on first triple
}
}
Checking rights to read file as others is even simplier:
if ((status.permissions() & std::filesystem::perms::others_read) !=
std::filesystem::perms::none) {
return true; // User could read file based on third triple
}
Group processing is complicated, because we must check all groups user belongs to:
// Get user name
struct passwd *pw = getpwuid(userId);
std::string username = pw->pw_name;
// Get groups list
std::vector<gid_t> groups;
int ngroups = 0;
uint result = getgrouplist(username.c_str(), groupId, nullptr, &ngroups);
groups.resize(ngroups);
result = getgrouplist(username.c_str(), groupId, groups.data(), &ngroups);
// Check all groups
for (uint i = 0; i < ngroups; ++i) {
if (groups[i] == fileStat.st_gid) {
// User belongs to a group that is equal to file group
if ((status.permissions() & std::filesystem::perms::group_read)!=
std::filesystem::perms::none) {
return true; // User could read file based on groups rights
}
}
}
This solution should work on Linux and BSD systems, but it isn't POSIX compatible
There are also ACL and RBAC file permissions, they weren't checked. Those permissions aren't standard