+ "` file/directory");
}
-static void change_permissions(std::string_view path, mode_t mode)
-{
- if (chmod(path.data(), mode) == -1)
- throw std::system_error(errno, std::system_category(),
- "Couldn't set owner/group permissions of the `"s
- + path.data()
- + "` file/directory");
-}
-
enum class Directory_Class {
App_Name, /* `[SUBSESSION_DIR]/apps_rw/[APP_NAME]` only */
System_Share, /* `[SUBSESSION_DIR]/apps_rw/[APP_NAME]/cache` and below
return type == Directory_Class::App_Name;
}
-static void set_ownership_and_perms(std::string_view src_path, std::string_view dest_path, const mode_t mode,
+static void set_ownership_and_perms(std::string_view src_path, std::string_view dest_path, fs::perms permissions,
const int session_uid, const int gid, bool copy_perms_from_skel)
{
- struct stat info;
- int ret = lstat(src_path.data(), &info);
-
- if (ret)
- throw std::system_error(errno, std::system_category(),
- "Couldn't stat `"s
- + src_path.data()
- + "` file/directory");
-
+ const auto info = fs::symlink_status (src_path);
change_owner_and_group(dest_path, session_uid, gid);
- /* Symlinks don't have permissions, and we
- * don't want to change the underlying file's. */
- if (!S_ISLNK(info.st_mode))
- change_permissions(dest_path, copy_perms_from_skel ? info.st_mode : mode);
+ if (copy_perms_from_skel)
+ permissions = info.permissions();
+
+ /* Symlinks themselves don't have permissions, and we don't want to
+ * change the underlying file's. I'm not sure why we check the source's
+ * symlink status, not the destination's, but in theory they should be
+ * the same so we save a stat() call (and I am too afraid to change
+ * legacy behaviour). If using the destination's state, we could skip
+ * the check and use the `fs::perm_options::nofollow` flag, but when I
+ * tried it (early Tizen 10, 2025-01), it threw "operation not supported". */
+ if (!is_symlink(info))
+ fs::permissions(dest_path, permissions);
}
static std::string get_smack_label(std::string_view src_path, smack_label_type type)
);
int users_gid = get_gid_from_name("users");
- static constexpr mode_t users_mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
- static constexpr mode_t system_share_mode = S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH | S_ISGID;
- static constexpr mode_t apps_rw_dir_mode = S_IRWXU | S_IRGRP | S_IXGRP;
+
+ using enum fs::perms;
+ static constexpr fs::perms users_perms = owner_all
+ | group_read | group_exec
+ | others_read | others_exec;
+
+ static constexpr fs::perms system_share_perms = owner_all
+ | group_all
+ | others_read | others_exec
+ | set_gid;
+
+ static constexpr fs::perms apps_rw_dir_perms = owner_all
+ | group_read | group_exec;
for (auto const& entry : fs::recursive_directory_iterator(source_dir)) {
std::string s_path = entry.path();
std::string d_path = apps_rw_dir + "/" + tmp_path.data();
int gid;
- mode_t mode;
+ fs::perms permissions;
Directory_Class dir_type = get_directory_type(tmp_path);
switch (dir_type) {
case Directory_Class::System_Share:
- mode = system_share_mode;
+ permissions = system_share_perms;
gid = system_share_gid;
break;
case Directory_Class::Users:
case Directory_Class::App_Name:
- mode = users_mode; // N.B. won't be used for the first level subdirectory anyway
+ permissions = users_perms; // N.B. won't be used for the first level subdirectory anyway
gid = users_gid;
break;
}
- set_ownership_and_perms(s_path, d_path, mode, session_uid, gid, should_copy_perms_from_skel(dir_type));
+ set_ownership_and_perms(s_path, d_path, permissions, session_uid, gid, should_copy_perms_from_skel(dir_type));
copy_smack_attributes(s_path, d_path);
}
// Last but not least - the `apps_rw` directory itself
change_owner_and_group(apps_rw_dir, session_uid, system_share_gid);
- change_permissions(apps_rw_dir, apps_rw_dir_mode);
+ fs::permissions(apps_rw_dir, apps_rw_dir_perms);
copy_smack_attributes(source_dir, apps_rw_dir);
// Copy + rename so that the replacement is atomic