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
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 {
, 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)
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);
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)
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");
}
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)
}
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)