--- /dev/null
+/* MIT License
+ *
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is furnished
+ * to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE. */
+
+#include <pwd.h>
+#include <unistd.h>
+#include <filesystem>
+#include <iostream>
+#include <string>
+#include "fs_helpers.h"
+
+namespace fs = std::filesystem;
+
+std::string fs_helpers::get_home_dir_by_user_id(const int uid)
+{
+ auto max_buf_size = static_cast<ssize_t>(sysconf(_SC_GETPW_R_SIZE_MAX));
+ std::system_error err(std::error_code()
+ , "Couldn't get home directory for session_uid=" + std::to_string(uid));
+
+ if (max_buf_size <= 0)
+ throw err;
+
+ std::unique_ptr<char[]> str_buf(new char[max_buf_size]);
+ // N.B. `new` throws `std::bad_alloc` exception if it runs out of memory,
+ // so there's no need to check if it's successful here
+
+ passwd pass_buf, *pass_ptr;
+ getpwuid_r(uid, &pass_buf, str_buf.get(), max_buf_size, &pass_ptr);
+
+ if (!pass_ptr)
+ throw err;
+
+ return std::string(pass_ptr->pw_dir);
+}
+
+void fs_helpers::add_user_subsession(const int session_uid, const int subsession_id)
+{
+ std::system_error add_ex(std::error_code(), "Couldn't add user subsession data");
+ try {
+ std::string home_dir = get_home_dir_by_user_id(session_uid);
+ std::string subsession_dir = std::move(home_dir) + "/subsessions/" + std::to_string(subsession_id);
+ fs::path subsession_path { subsession_dir };
+
+ if (fs::exists(subsession_path))
+ throw add_ex;
+
+ fs::path subsession_tmp_path { std::move(subsession_dir) + ".tmpnew" };
+ fs::copy
+ ( fs::path{ "/etc/skel" }
+ , subsession_tmp_path
+ , fs::copy_options::recursive
+ );
+
+ // Copy + rename so that the replacement is atomic
+ fs::rename(subsession_tmp_path, subsession_path);
+
+ // TODO: chown/chmod of the copied files & directories
+ // TODO: copy/set SMACK attributes
+ }
+ catch (fs::filesystem_error const &ex) {
+ std::cerr << "Exception " << ex.what() << std::endl
+ << "while copying user subsession data [session_uid=" << session_uid
+ << " subsession_id=" << subsession_id << "]" << std::endl;
+ throw add_ex;
+ }
+ catch (std::exception const &ex) {
+ std::cerr << "Exception " << ex.what() << std::endl
+ << "when invoking fs_helpers::get_home_dir_by_user_id() "
+ << "while copying user subsession data [session_uid=" << session_uid
+ << " subsession_id=" << subsession_id << "]" << std::endl;
+ throw add_ex;
+ }
+}
+
+void fs_helpers::remove_user_subsession(const int session_uid, const int subsession_id)
+{
+ std::system_error remove_ex(std::error_code(), "Couldn't remove user subsession data");
+ try {
+ std::string home_dir = get_home_dir_by_user_id(session_uid);
+ fs::path subsession_path {
+ std::move(home_dir) + "/subsessions/" + std::to_string(subsession_id)
+ };
+
+ if (!fs::exists(subsession_path))
+ throw remove_ex;
+
+ fs::remove_all(subsession_path);
+ }
+ catch (fs::filesystem_error const &ex) {
+ std::cerr << "Exception " << ex.what() << std::endl
+ << "while deleting user subsession data [session_uid=" << session_uid
+ << " subsession_id=" << subsession_id << "]" << std::endl;
+ throw remove_ex;
+ }
+ catch (std::exception const &ex) {
+ std::cerr << "Exception " << ex.what() << std::endl
+ << "when invoking fs_helpers::get_home_dir_by_user_id() "
+ << "while removing user subsession data [session_uid=" << session_uid
+ << " subsession_id=" << subsession_id << "]" << std::endl;
+ throw remove_ex;
+ }
+}
+