Use std::fs for stat and mode 69/318569/5
authorMichal Bloch <m.bloch@samsung.com>
Thu, 30 Jan 2025 16:31:54 +0000 (17:31 +0100)
committerMichal Bloch <m.bloch@samsung.com>
Tue, 4 Feb 2025 11:51:09 +0000 (12:51 +0100)
Change-Id: I31fca9acc678734276400311b65a5b2412ccc6ab

src/service/src/fs_helpers.cpp

index 7780d8550fcceee7c5459351dc8839ef13fe6b74..8486be4a890e03035c7e8c220bacbeea2b541509 100644 (file)
@@ -78,15 +78,6 @@ static void change_owner_and_group(std::string_view path, const int session_uid,
                        + "` 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
@@ -100,24 +91,24 @@ static inline bool should_copy_perms_from_skel(Directory_Class type) {
        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)
@@ -338,9 +329,19 @@ void add_user_subsession(const int session_uid, const std::string_view subsessio
                );
 
                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();
@@ -351,27 +352,27 @@ void add_user_subsession(const int session_uid, const std::string_view subsessio
                        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