#include <filesystem>
+namespace fs = std::filesystem;
+
struct DirBackend {
virtual void RemoveSubsession (const std::filesystem::path& subsession_path) const = 0;
virtual void SwitchSubsessionAway (const std::filesystem::path& subsession_path) const = 0;
virtual void SwitchSubsessionInto (const std::filesystem::path& subsession_path) const = 0;
};
+
+struct DirBackendAdd {
+ virtual fs::path AddSubsessionPrepare (const fs::path& subsession_path, int uid, int gid) const = 0;
+ virtual void AddSubsessionFinalize (const fs::path& tmpdir_path, const fs::path& subsession_path) const = 0;
+};
* THE SOFTWARE. */
#include "dir_backend_regular_dir.hpp"
+#include "os_ops.hpp"
namespace fs = std::filesystem;
using namespace std::string_literals;
+fs::path DirBackendAddRegularDir::AddSubsessionPrepare (const fs::path& subsession_path, int uid, int gid) const
+{
+ auto tmp_subsession_path = subsession_path;
+ tmp_subsession_path.replace_filename(".tmpnew"s + subsession_path.filename().native());
+
+ fs::create_directory(tmp_subsession_path);
+ OS::change_owner_and_group(tmp_subsession_path, uid, gid);
+
+ return tmp_subsession_path;
+}
+
+void DirBackendAddRegularDir::AddSubsessionFinalize (const fs::path& tmpdir_path, const fs::path& subsession_path) const
+{
+ fs::rename(tmpdir_path, subsession_path);
+}
+
void DirBackendRegularDir::RemoveSubsession (const fs::path& subsession_path) const
{
/* We are going to rename the subsession dir before deleting it,
void SwitchSubsessionAway (const std::filesystem::path& subsession_path) const override;
void SwitchSubsessionInto (const std::filesystem::path& subsession_path) const override;
};
+
+struct DirBackendAddRegularDir : public DirBackendAdd {
+ fs::path AddSubsessionPrepare (const fs::path& subsession_path, int uid, int gid) const override;
+ void AddSubsessionFinalize (const fs::path& tmpdir_path, const fs::path& subsession_path) const override;
+};
return Directory_Class::Users;
}
-void add_user_subsession(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)
{
try {
fs::path main_path = get_main_dir_by_user_id(session_uid);
throw std::system_error(EEXIST, std::generic_category(),
"Subsession directory already exists");
- auto tmp_subsession_path = fs::path(subsession_path);
- tmp_subsession_path.replace_filename(".tmpnew"s + subsession_path.filename().native());
+ const int system_share_gid = OS::get_gid_from_name(system_share_group);
- fs::create_directory(tmp_subsession_path);
-
- int system_share_gid = OS::get_gid_from_name(system_share_group);
- OS::change_owner_and_group(tmp_subsession_path, session_uid, system_share_gid);
+ // Work off a temporary dir and then switch it at once so that it appears atomically
+ const auto tmp_subsession_path = backend.AddSubsessionPrepare
+ ( subsession_path
+ , session_uid, system_share_gid
+ );
const auto apps_rw_path = tmp_subsession_path / "apps_rw";
const fs::path source_path = "/etc/skel/apps_rw";
fs::permissions(apps_rw_path, apps_rw_dir_perms);
OS::copy_smack_attributes(source_path, apps_rw_path);
- // Copy + rename so that the replacement is atomic
- fs::rename(tmp_subsession_path, subsession_path);
-
+ backend.AddSubsessionFinalize(tmp_subsession_path, subsession_path);
}
catch (std::system_error const &ex) {
LOGE("Logic exception %s\nwhile copying user subsession data [session_uid=%d subsession_id=%s]", ex.what(), session_uid, subsession_id.data());
#pragma once
+#include "dir_backend.hpp"
+
#include <sys/smack.h>
#include <filesystem>
#include <string>
#include <vector>
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);
+void add_user_subsession(const int session_uid, const std::string_view subsession_id, const DirBackendAdd& backend);
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);
std::vector<std::string> get_user_list(const int session_uid);
#include "tuple_g_variant_helpers.hpp"
#include "tuple_hash.hpp"
#include "wait_manager.hpp"
+#include "dir_backend_regular_dir.hpp"
static constexpr const char * get_dbus_error_mapping (subsession_error_e subsession_error)
{
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);
+ add_user_subsession(session_uid, subsession_id, DirBackendAddRegularDir {});
wait_add.try_emplace(session_uid, session_uid, connection, "AddUserCompleted");
wait_add.at(session_uid).on_start(subsession_id, { });