Make regular dir subsessiond from a template. 80/324680/2
authorMichal Bloch <m.bloch@samsung.com>
Thu, 22 May 2025 21:31:30 +0000 (23:31 +0200)
committerMichal Bloch <m.bloch@samsung.com>
Wed, 28 May 2025 15:37:40 +0000 (17:37 +0200)
Change-Id: I57d4ced4f6aa3c76abc3346b24250ae95fac8753
Signed-off-by: Michal Bloch <m.bloch@samsung.com>
src/service/src/dir_backend_regular_dir.cpp
src/service/src/fs_helpers.cpp
src/service/src/fs_helpers.hpp
src/service/src/main_context.hpp

index baa9bc68ce55cb30c561c63383685c685aeed854..538c52495444d915954cdc515787d2f14cbe4642 100644 (file)
@@ -55,7 +55,16 @@ void DirBackendAddRegularDir::AddSubsessionFinalize (const fs::path& tmpdir_path
 
 bool DirBackendAddRegularDir::AddSubsessionPrepareFromTemplate (const std::string_view subsession_name, const fs::path& main_path, int uid, int gid) const
 {
-       return false; // not supported yet
+       const auto template_path = main_path / TemplateName();
+       const auto subsession_path = main_path / subsession_name;
+
+       /* Consume the template; this finishes much faster than copying.
+        * We need to recreate the template, but we do that later, AFTER
+        * the "add was successful" D-Bus response, so that clients can
+        * start using the copy much faster than otherwise. */
+       fs::rename(template_path, subsession_path);
+
+       return true;
 }
 
 void DirBackendAddRegularDir::AddSubsessionCleanupFailure (const fs::path& tmpdir_path, const fs::path& subsession_path) const
index b6d0890d6729fe0ec19c5ff73702a52fa242c358..8bc7c7d56b87c4d30c2e3ecf4e7049d0b0f840a0 100644 (file)
@@ -130,7 +130,7 @@ static Directory_Class get_directory_type(std::string_view path)
        return Directory_Class::Users;
 }
 
-void add_user_subsession(const int session_uid, const std::string_view subsession_id, const DirBackendAdd &backend)
+bool add_user_subsession(const int session_uid, const std::string_view subsession_id, const DirBackendAdd &backend)
 {
        fs::path main_path;
        try {
@@ -150,13 +150,14 @@ void add_user_subsession(const int session_uid, const std::string_view subsessio
                        , OS::get_gid_from_name(system_share_group)
                );
                if (added_via_template)
-                       return;
+                       return true;
        }
        catch (const std::exception &ex) {
                LOGE("Exception while creating subsession from template [session_uid=%d subsession_id=%s]: %s", session_uid, subsession_id.data(), ex.what());
        }
 
        add_user_subsession_inner(main_path, session_uid, subsession_id, backend, false);
+       return false;
 }
 
 void add_user_subsession_inner(const fs::path &main_path, const int session_uid, const std::string_view subsession_id, const DirBackendAdd &backend, bool force)
index 366d97ac9e2440800ae06a32387e6626f3de2a9e..d59776a5edfce32539b270a04a0be857da7ab411 100644 (file)
@@ -12,7 +12,7 @@ std::filesystem::path get_main_dir_by_user_id(const int uid);
 std::filesystem::path get_last_subsession_path_by_user_id(const int uid);
 void create_main_subdirectory(const int session_uid, const fs::path& main_dir);
 bool subsession_exists(const int session_uid, const std::string_view subsession_id);
-void add_user_subsession(const int session_uid, const std::string_view subsession_id, const DirBackendAdd& backend);
+bool add_user_subsession(const int session_uid, const std::string_view subsession_id, const DirBackendAdd& backend);
 void add_user_subsession_inner(const std::filesystem::path &main_path, const int session_uid, const std::string_view subsession_id, const DirBackendAdd& backend, bool force);
 void remove_user_subsession(const int session_uid, const std::string_view subsession_id);
 bool switch_user_subsession(const int session_uid, const std::string_view prev_subsession, const std::string_view next_subsession);
index 9fc05648f597b524d5646ed33fc0dd80d58719ae..25f13be78179394f8938e8f9e88c9b0be6ee393a 100644 (file)
@@ -188,19 +188,21 @@ struct sessiond_context {
                return false;
        }
 
-       void do_add_user(int session_uid, const std::string& subsession_id, const DirBackendAdd& backend)
+       bool do_add_user(int session_uid, const std::string& subsession_id, const DirBackendAdd& backend)
        {
                GError *err = nullptr;
                if (!g_dbus_connection_emit_signal(connection, nullptr, bus_object.data(), bus_iface.data(), "AddUserStarted",
                                vals_to_g_variant(session_uid, subsession_id), &err))
                        g_error_throw(err, "Failed to emit a signal: ");
 
-               add_user_subsession(session_uid, subsession_id, backend);
+               const bool consumed_template = add_user_subsession(session_uid, subsession_id, backend);
 
                wait_add.try_emplace(session_uid, session_uid, connection, "AddUserCompleted");
                wait_add.at(session_uid).on_start(subsession_id, { });
 
                plugin.OnSubsessionAdded(session_uid, subsession_id);
+
+               return consumed_template;
        }
 
        void do_remove_user(int session_uid, const std::string& subsession_id)
@@ -263,8 +265,11 @@ struct sessiond_context {
                        return;
                }
 
+               const DirBackendAddRegularDir backend;
+
+               bool consumed_template;
                try {
-                       do_add_user(session_uid, subsession_id, DirBackendAddRegularDir {});
+                       consumed_template = do_add_user(session_uid, subsession_id, backend);
                } catch (const std::exception &ex) {
                        g_dbus_method_invocation_return_dbus_error(invocation,
                                get_dbus_error_mapping(SUBSESSION_ERROR_IO_ERROR), "Failed to add subsession");
@@ -272,6 +277,17 @@ struct sessiond_context {
                }
 
                g_dbus_method_invocation_return_value(invocation, nullptr);
+
+               /* Note, this is done after the invocation return. This is so
+                * that clients can use the new subsession ASAP, while restoring
+                * the template can be done independently.
+                *
+                * TODO: It would be nice to do this multi-threadedly (so that
+                * sessiond could also handle unrelated calls for other subsessions)
+                * but this would require a lot of care since so far, everything
+                * is single-threaded so far. */
+               if (consumed_template)
+                       add_user_subsession_inner(get_main_dir_by_user_id(session_uid), session_uid, backend.TemplateName(), backend, true);
        }
 
        void on_add_user_fixed_size(GDBusMethodInvocation *invocation, std::string_view sender, GVariant *parameters)
@@ -301,6 +317,9 @@ struct sessiond_context {
                }
 
                g_dbus_method_invocation_return_value(invocation, nullptr);
+
+               /* Fixed-size templates aren't consumed, so unlike the regular
+                * dir backend there is nothing to do here. */
        }
 
        void on_remove_user(GDBusMethodInvocation *invocation, std::string_view sender, GVariant *parameters)