Fix validating light user name
[platform/core/appfw/app-installers.git] / src / common / utils / file_util.cc
index 93916ea..45bd5bc 100644 (file)
@@ -4,24 +4,35 @@
 
 #include <fcntl.h>
 #include <sys/stat.h>
+#include <linux/limits.h>
 #include <unzip.h>
 #include <zlib.h>
 
+#include <sessiond.h>
+
+#include <boost/algorithm/string/classification.hpp>
+#include <boost/algorithm/string/split.hpp>
+#include <boost/filesystem/operations.hpp>
 #include <boost/filesystem/path.hpp>
 #include <boost/system/error_code.hpp>
 
+#include <manifest_parser/utils/logging.h>
+
+#include <algorithm>
 #include <string>
+#include <vector>
 
 #include "common/utils/byte_size_literals.h"
-#include "common/utils/logging.h"
+#include "common/utils/paths.h"
 
+namespace ba = boost::algorithm;
 namespace bs = boost::system;
 namespace bf = boost::filesystem;
 
 namespace {
 
 unsigned kZipBufSize = 8_kB;
-unsigned kZipMaxPath = 256;
+unsigned kZipMaxPath = PATH_MAX;
 
 int64_t GetBlockSizeForPath(const bf::path& path_in_partition) {
   struct stat stats;
@@ -37,53 +48,175 @@ int64_t RoundUpToBlockSizeOf(int64_t size, int64_t block_size) {
   return ((size + block_size - 1) / block_size) * block_size;
 }
 
+class UnzFilePointer {
+ public:
+  UnzFilePointer()
+    : zipFile_(nullptr),
+      fileOpened_(false),
+      currentFileOpened_(false) { }
+
+  ~UnzFilePointer() {
+    if (currentFileOpened_)
+      unzCloseCurrentFile(zipFile_);
+    if (fileOpened_)
+      unzClose(zipFile_);
+  }
+
+  bool Open(const char* zip_path) {
+    zipFile_ = static_cast<unzFile*>(unzOpen(zip_path));
+    if (!zipFile_)
+       return false;
+    fileOpened_ = true;
+    return true;
+  }
+
+  bool OpenCurrent() {
+    if (unzOpenCurrentFile(zipFile_) != UNZ_OK)
+      return false;
+    currentFileOpened_ = true;
+    return true;
+  }
+
+  void CloseCurrent() {
+    if (currentFileOpened_)
+      unzCloseCurrentFile(zipFile_);
+    currentFileOpened_ = false;
+  }
+
+  unzFile* Get() { return zipFile_; }
+
+ private:
+  unzFile* zipFile_;
+  bool fileOpened_;
+  bool currentFileOpened_;
+};
+
 }  // namespace
 
 namespace common_installer {
 
+FSFlag operator|(FSFlag a, FSFlag b) {
+  return static_cast<FSFlag>(static_cast<int>(a) | static_cast<int>(b));
+}
+
+bool SetOwnership(const bf::path& path, uid_t uid, gid_t gid) {
+  int ret = lchown(path.c_str(), uid, gid);
+  if (ret != 0) {
+    LOG(ERROR) << "Failed to change owner of: " << path;
+    return false;
+  }
+  return true;
+}
+
+bool SetOwnershipAll(const bf::path& path, uid_t uid, gid_t gid) {
+  if (!SetOwnership(path, uid, gid))
+    return false;
+  if (!bf::is_directory(path))
+    return true;
+  for (bf::recursive_directory_iterator iter(path);
+    iter != bf::recursive_directory_iterator();
+    ++iter) {
+    bf::path current(iter->path());
+    if (!SetOwnership(current, uid, gid))
+      return false;
+  }
+  return true;
+}
+
 bool CreateDir(const bf::path& path) {
   if (bf::exists(path))
     return true;
 
   boost::system::error_code error;
   bf::create_directories(path, error);
+
   if (error) {
     LOG(ERROR) << "Failed to create directory: "
                << boost::system::system_error(error).what();
     return false;
   }
+  return true;
+}
+
+bool SetDirPermissions(const boost::filesystem::path& path,
+                      boost::filesystem::perms permissions) {
+  boost::system::error_code error;
+  bf::permissions(path, permissions, error);
 
-  bf::permissions(path, bf::owner_all
-      | bf::group_read | bf::others_read,
-      error);
   if (error) {
-    LOG(ERROR) << "Failed to set permission: "
+    LOG(ERROR) << "Failed to set permissions for directory: " << path
                << boost::system::system_error(error).what();
     return false;
   }
   return true;
 }
 
-bool CopyDir(const bf::path& src, const bf::path& dst) {
+bool SetDirOwnershipAndPermissions(const boost::filesystem::path& path,
+                      boost::filesystem::perms permissions, uid_t uid,
+                      gid_t gid) {
+  if (!SetOwnership(path, uid, gid)) {
+    LOG(ERROR) << "Failed to change owner: " << path
+               << "(" << uid << ", " << gid << ")";
+    return false;
+  }
+  if (!SetDirPermissions(path, permissions)) {
+    LOG(ERROR) << "Failed to change permission: " << path
+               << std::oct << permissions;
+    return false;
+  }
+
+  return true;
+}
+
+bool CopyOwnershipAndPermissions(const boost::filesystem::path& src,
+                                 const boost::filesystem::path& dst) {
+  if (!bf::exists(src)) {
+    LOG(ERROR) << "Failed to copy ownership and permissions"
+               << " from " << src << " to " << dst;
+    return false;
+  }
+  bf::perms permissions = bf::status(src).permissions();
+  struct stat stats;
+  if (stat(src.c_str(), &stats) != 0)
+    return false;
+  if (!SetDirOwnershipAndPermissions(dst, permissions, stats.st_uid,
+                                    stats.st_gid)) {
+    LOG(ERROR) << "Failed to copy ownership and permissions"
+               << " from " << src << " to " << dst;
+    return false;
+  }
+  return true;
+}
+
+bool CopyDir(const bf::path& src, const bf::path& dst,
+             FSFlag flags, bool skip_symlink) {
   try {
     // Check whether the function call is valid
     if (!bf::exists(src) || !bf::is_directory(src)) {
-      LOG(ERROR) << "Source directory " << src.string()
+      LOG(ERROR) << "Source directory " << src
                  << " does not exist or is not a directory.";
       return false;
     }
-    if (bf::exists(dst)) {
-      LOG(ERROR) << "Destination directory " << dst.string()
-                 << " already exists.";
-      return false;
-    }
-    // Create the destination directory
-    if (!CreateDir(dst)) {
-      LOG(ERROR) << "Unable to create destination directory" << dst.string();
-      return false;
+    if (!bf::exists(dst)) {
+      // Create the destination directory
+      if (!CreateDir(dst)) {
+        LOG(ERROR) << "Unable to create destination directory" << dst;
+        return false;
+      }
+      if (flags & FS_PRESERVE_OWNERSHIP_AND_PERMISSIONS)
+        CopyOwnershipAndPermissions(src, dst);
+    } else {
+      if (!(flags & (FS_MERGE_SKIP | FS_MERGE_OVERWRITE))) {
+        LOG(ERROR) << "Destination directory " << dst.string()
+                   << " already exists.";
+        return false;
+      }
+      if (flags & (FS_MERGE_OVERWRITE | FS_PRESERVE_OWNERSHIP_AND_PERMISSIONS))
+        CopyOwnershipAndPermissions(src, dst);
     }
   } catch (const bf::filesystem_error& error) {
-      LOG(ERROR) << error.what();
+    LOG(ERROR) << "Failed to copy directory: " << error.what();
+    return false;
   }
 
   // Iterate through the source directory
@@ -92,33 +225,138 @@ bool CopyDir(const bf::path& src, const bf::path& dst) {
       ++file) {
     try {
       bf::path current(file->path());
-      if (bf::is_directory(current)) {
+      bf::path target = dst / current.filename();
+
+      if (bf::is_symlink(symlink_status(current))) {
+        if (skip_symlink)
+          continue;
+        if ((flags & (FS_MERGE_SKIP | FS_MERGE_OVERWRITE)) &&
+            bf::exists(target))
+          continue;
+        bs::error_code error;
+        bf::copy_symlink(current, target, error);
+        if (error) {
+          LOG(ERROR) << "Failed to copy symlink: " << current << ", "
+                     << error.message();
+          return false;
+        }
+      } else if (bf::is_directory(current)) {
         // Found directory: Recursion
-        if (!CopyDir(current, dst / current.filename())) {
+        if (!CopyDir(current, target, flags, skip_symlink)) {
           return false;
         }
-      } else if (bf::is_symlink(current)) {
-        // Found symlink
-        bf::copy_symlink(current, dst / current.filename());
       } else {
-        // Found file: Copy
-        bf::copy_file(current, dst / current.filename());
+        if ((flags & FS_MERGE_SKIP) && bf::exists(target))
+          continue;
+        bf::path destination = target;
+
+        if (flags & FS_COMMIT_COPY_FILE)
+          destination =
+              bf::unique_path(target.parent_path() / "%%%%-%%%%-%%%%-%%%%");
+
+        if (flags & FS_MERGE_OVERWRITE)
+          bf::copy_file(current, destination,
+                        bf::copy_option::overwrite_if_exists);
+        else
+          bf::copy_file(current, destination);
+
+        if (flags & FS_PRESERVE_OWNERSHIP_AND_PERMISSIONS)
+          CopyOwnershipAndPermissions(current, destination);
+
+        if (flags & FS_COMMIT_COPY_FILE) {
+          if (flags & FS_MERGE_OVERWRITE)
+            bf::remove(target);
+          bf::rename(destination, target);
+        }
       }
     } catch (const bf::filesystem_error& error) {
-        LOG(ERROR) << error.what();
+      LOG(ERROR) << "Failed to copy directory: " << error.what();
+      return false;
     }
   }
   return true;
 }
 
-bool MoveDir(const bf::path& src, const bf::path& dst) {
-  if (bf::exists(dst))
+bool CopyFile(const bf::path& src, const bf::path& dst) {
+  bs::error_code error;
+
+  bf::copy_file(src, dst, bf::copy_option::overwrite_if_exists, error);
+  if (error) {
+    LOG(WARNING) << "copy file " << src << " due to error [" << error << "]";
+    return false;
+  }
+  return true;
+}
+
+bool RestoreBackup(const bf::path& path) {
+  bf::path backup_path = GetBackupPathForPackagePath(path);
+  if (!bf::exists(backup_path) &&
+      !bf::is_symlink(bf::symlink_status(backup_path))) {
+    LOG(WARNING) << backup_path << " does not exist";
+    return true;
+  }
+  return MoveDir(backup_path, path);
+}
+
+bool MakeBackup(const bf::path& path) {
+  if (!bf::exists(path) && !bf::is_symlink(bf::symlink_status(path))) {
+    LOG(WARNING) << path << " does not exist";
+    return true;
+  }
+  bf::path backup_path = GetBackupPathForPackagePath(path);
+  return MoveDir(path, backup_path);
+}
+
+bool RemoveBackup(const bf::path& path) {
+  bf::path backup_path = GetBackupPathForPackagePath(path);
+  if (!bf::exists(backup_path) &&
+      !bf::is_symlink(bf::symlink_status(backup_path))) {
+    LOG(WARNING) << backup_path << " does not exist";
+    return true;
+  }
+  return RemoveAll(backup_path);
+}
+
+bool RemoveAll(const bf::path& path) {
+  if (!bf::exists(path) && !bf::is_symlink(bf::symlink_status(path)))
+    return true;
+
+  bs::error_code error;
+  bf::remove_all(path, error);
+
+  if (error) {
+    LOG(ERROR) << "Cannot remove: " << path << ", " << error.message();
+    return false;
+  }
+
+  return true;
+}
+
+bool Remove(const bf::path& path) {
+  bs::error_code error;
+  if (!bf::exists(bf::symlink_status(path, error)))
+    return true;
+
+  bf::remove(path, error);
+  if (error) {
+    LOG(ERROR) << "Cannot remove: " << path << ", " << error.message();
     return false;
+  }
+  return true;
+}
+
+bool MoveDir(const bf::path& src, const bf::path& dst, FSFlag flags) {
+  if (bf::exists(dst) &&
+      !(flags & (FS_MERGE_SKIP | FS_MERGE_OVERWRITE))) {
+    LOG(ERROR) << "Destination directory does exist: " << dst;
+    return false;
+  }
+
   bs::error_code error;
   bf::rename(src, dst, error);
   if (error) {
     LOG(WARNING) << "Cannot move directory: " << src << ". Will copy/remove...";
-    if (!CopyDir(src, dst)) {
+    if (!CopyDir(src, dst, flags, false)) {
       LOG(ERROR) << "Cannot copy directory: " << src;
       return false;
     }
@@ -131,30 +369,49 @@ bool MoveDir(const bf::path& src, const bf::path& dst) {
   return true;
 }
 
-bool MoveFile(const bf::path& src, const bf::path& dst) {
-  if (bf::exists(dst))
+bool MoveFile(const bf::path& src, const bf::path& dst, bool force) {
+  if (!force && bf::exists(dst))
     return false;
   bs::error_code error;
   bf::rename(src, dst, error);
   if (error) {
-    LOG(WARNING) << "Cannot move file: " << src << ". Will copy/remove...";
+    LOG(WARNING) << "Cannot move file: " << src <<
+        ". Will copy/remove... with error [" << error << "]";
     bf::copy_file(src, dst, bf::copy_option::overwrite_if_exists, error);
     if (error) {
+      LOG(WARNING) << "Cannot copy file " << src <<
+          " due to error [" << error << "]";
       return false;
     }
     bf::remove_all(src, error);
     if (error) {
-      LOG(ERROR) << "Cannot remove old file when coping: " << src;
+      LOG(ERROR) << "Cannot remove old file when coping: " << src <<
+          "with error [" << error << "]";
     }
   }
   return true;
 }
 
+bool BackupDir(const boost::filesystem::path& src,
+    const boost::filesystem::path& dst, const std::string& entry) {
+  if (!bf::exists(src / entry))
+    return true;
+
+  if (!MoveDir(src / entry, dst / entry,
+      FS_MERGE_OVERWRITE |
+      FS_COMMIT_COPY_FILE |
+      FS_PRESERVE_OWNERSHIP_AND_PERMISSIONS)) {
+    LOG(ERROR) << "Failed to backup file";
+    return false;
+  }
+
+  return true;
+}
+
 int64_t GetUnpackedPackageSize(const bf::path& path) {
   int64_t size = 0;
   int64_t block_size = GetBlockSizeForPath(path);
 
-  // if failed to stat path
   if (block_size == -1)
     return -1;
 
@@ -178,9 +435,11 @@ int64_t GetUnpackedPackageSize(const bf::path& path) {
     if (unzGetCurrentFileInfo64(zip_file, &raw_file_info, raw_file_name_in_zip,
         sizeof(raw_file_name_in_zip), nullptr, 0, nullptr, 0) != UNZ_OK) {
       LOG(ERROR) << "Failed to read file info";
+      unzClose(zip_file);
       return -1;
     }
     size += RoundUpToBlockSizeOf(raw_file_info.uncompressed_size, block_size);
+    unzGoToNextFile(zip_file);
   }
 
   // FIXME: calculate space needed for directories
@@ -188,6 +447,49 @@ int64_t GetUnpackedPackageSize(const bf::path& path) {
   return size;
 }
 
+int64_t GetDirectorySize(const boost::filesystem::path& path) {
+  int64_t block_size = GetBlockSizeForPath(path);
+
+  if (block_size == -1)
+    return -1;
+
+  int64_t size = 0;
+  for (bf::recursive_directory_iterator iter(path);
+      iter != bf::recursive_directory_iterator(); ++iter) {
+      struct stat buf;
+      if (lstat(iter->path().c_str(), &buf) == -1) {
+        LOG(ERROR) << "lstat() failed for: " << iter->path();
+        return -1;
+      }
+      size += RoundUpToBlockSizeOf(buf.st_size, block_size);
+  }
+
+  // FIXME: block size for external device may differ...
+  return size;
+}
+
+bool CheckFreeSpaceAtPath(int64_t required_size,
+    const boost::filesystem::path& target_location) {
+  bs::error_code error;
+  boost::filesystem::path root = target_location;
+
+  while (!bf::exists(root) && root != root.root_path())
+    root = root.parent_path();
+
+  if (!bf::exists(root)) {
+    LOG(ERROR) << "No mount point for path: " << target_location;
+    return false;
+  }
+
+  bf::space_info space_info = bf::space(root, error);
+  if (error) {
+    LOG(ERROR) << "Failed to get space_info: " << error.message();
+    return false;
+  }
+
+  return (space_info.free >= static_cast<uint64_t>(required_size));
+}
+
 boost::filesystem::path GenerateTmpDir(const bf::path &app_path) {
   boost::filesystem::path install_tmp_dir;
   boost::filesystem::path tmp_dir(app_path);
@@ -204,6 +506,19 @@ boost::filesystem::path GenerateTmpDir(const bf::path &app_path) {
   return install_tmp_dir;
 }
 
+boost::filesystem::path GenerateTemporaryPath(
+    const boost::filesystem::path& path) {
+  bf::path pattern = path;
+  pattern += "-%%%%%%";
+  bf::path tmp_path;
+
+  do {
+    tmp_path = boost::filesystem::unique_path(pattern);
+  } while (boost::filesystem::exists(tmp_path));
+
+  return tmp_path;
+}
+
 bool ExtractToTmpDir(const char* zip_path,
                      const boost::filesystem::path& tmp_dir) {
   return ExtractToTmpDir(zip_path, tmp_dir, "");
@@ -218,23 +533,27 @@ bool ExtractToTmpDir(const char* zip_path, const bf::path& tmp_dir,
 
   current_path(tmp_dir);
 
-  unzFile* zip_file = static_cast<unzFile*>(unzOpen(zip_path));
-  if (!zip_file) {
-    LOG(ERROR) << "Failed to open the source dir: " << zip_file;
+  UnzFilePointer zip_file;
+  if (!zip_file.Open(zip_path)) {
+    LOG(WARNING) << "Failed to open the source dir: " << zip_path;
     return false;
   }
 
-  if (unzGetGlobalInfo(zip_file, &info) != UNZ_OK) {
+  if (unzGetGlobalInfo(zip_file.Get(), &info) != UNZ_OK) {
     LOG(ERROR) << "Failed to read global info";
-    unzClose(zip_file);
     return false;
   }
 
   for (uLong i = 0; i < info.number_entry; i++) {
-    if (unzGetCurrentFileInfo(zip_file, &raw_file_info, raw_file_name_in_zip,
-        sizeof(raw_file_name_in_zip), nullptr, 0, nullptr, 0) != UNZ_OK) {
+    if (unzGetCurrentFileInfo(zip_file.Get(),
+                              &raw_file_info,
+                              raw_file_name_in_zip,
+                              sizeof(raw_file_name_in_zip),
+                              nullptr,
+                              0,
+                              nullptr,
+                              0) != UNZ_OK) {
       LOG(ERROR) << "Failed to read file info";
-      unzClose(zip_file);
       return false;
     }
 
@@ -245,6 +564,12 @@ bool ExtractToTmpDir(const char* zip_path, const bf::path& tmp_dir,
     if (filter_prefix.empty() ||
         std::string(raw_file_name_in_zip).find(filter_prefix) == 0) {
       bf::path filename_in_zip_path(raw_file_name_in_zip);
+
+      if (HasDirectoryClimbing(filename_in_zip_path)) {
+        LOG(ERROR) << "Relative path in widget in malformed";
+        return false;
+      }
+
       if (!filename_in_zip_path.parent_path().empty()) {
         if (!CreateDir(filename_in_zip_path.parent_path())) {
           LOG(ERROR) << "Failed to create directory: "
@@ -253,26 +578,24 @@ bool ExtractToTmpDir(const char* zip_path, const bf::path& tmp_dir,
         }
       }
 
-      if (unzOpenCurrentFile(zip_file) != UNZ_OK) {
+      if (!zip_file.OpenCurrent()) {
         LOG(ERROR) << "Failed to open file";
-        unzClose(zip_file);
         return false;
       }
 
       if (!is_directory(filename_in_zip_path)) {
-        FILE *out = fopen(raw_file_name_in_zip, "wb");
+        FILE* out = fopen(raw_file_name_in_zip, "wbx");
         if (!out) {
           LOG(ERROR) << "Failed to open destination ";
-          unzCloseCurrentFile(zip_file);
           return false;
         }
 
         int ret = UNZ_OK;
         do {
-          ret = unzReadCurrentFile(zip_file, read_buffer, kZipBufSize);
+          ret = unzReadCurrentFile(zip_file.Get(), read_buffer, kZipBufSize);
           if (ret < 0) {
             LOG(ERROR) << "Failed to read data: " << ret;
-            unzCloseCurrentFile(zip_file);
+            fclose(out);
             return false;
           } else {
             fwrite(read_buffer, sizeof(char), ret, out);
@@ -281,19 +604,163 @@ bool ExtractToTmpDir(const char* zip_path, const bf::path& tmp_dir,
 
         fclose(out);
       }
+
+      zip_file.CloseCurrent();
     }
 
     if ((i+1) < info.number_entry) {
-      if (unzGoToNextFile(zip_file) != UNZ_OK) {
+      if (unzGoToNextFile(zip_file.Get()) != UNZ_OK) {
         LOG(ERROR) << "Failed to read next file";
-        unzCloseCurrentFile(zip_file);
         return false;
       }
     }
   }
 
-  unzClose(zip_file);
   return true;
 }
 
+bool CheckPathInZipArchive(const char* zip_archive_path,
+                           const boost::filesystem::path& relative_zip_path,
+                           bool* found) {
+  *found = false;
+  UnzFilePointer zip_file;
+  if (!zip_file.Open(zip_archive_path)) {
+    LOG(ERROR) << "Failed to open the source dir: " << zip_archive_path;
+    return false;
+  }
+
+  unz_global_info info;
+  if (unzGetGlobalInfo(zip_file.Get(), &info) != UNZ_OK) {
+    LOG(ERROR) << "Failed to read global info";
+    return false;
+  }
+
+  char raw_file_name_in_zip[kZipMaxPath];
+  unz_file_info raw_file_info;
+  for (uLong i = 0; i < info.number_entry; i++) {
+    if (unzGetCurrentFileInfo(zip_file.Get(),
+                              &raw_file_info,
+                              raw_file_name_in_zip,
+                              sizeof(raw_file_name_in_zip),
+                              nullptr,
+                              0,
+                              nullptr,
+                              0) != UNZ_OK) {
+      LOG(ERROR) << "Failed to read file info";
+      return false;
+    }
+
+    if (raw_file_name_in_zip[0] == '\0')
+      return false;
+
+    if (relative_zip_path.string() == raw_file_name_in_zip) {
+      *found = true;
+      return true;
+    }
+
+    if ((i + 1) < info.number_entry) {
+      if (unzGoToNextFile(zip_file.Get()) != UNZ_OK) {
+        LOG(ERROR) << "Failed to read next file";
+        return false;
+      }
+    }
+  }
+
+  return true;
+}
+
+bool HasDirectoryClimbing(const boost::filesystem::path& path) {
+  std::vector<std::string> segments;
+  ba::split(segments, path.string(), ba::is_any_of("/\\"));
+  return std::any_of(segments.begin(), segments.end(),
+                  [](const std::string& segment) {
+                    return segment == "..";
+                  });
+}
+
+boost::filesystem::path MakeRelativePath(const boost::filesystem::path& input,
+                                         const boost::filesystem::path& base) {
+  if (input.string().find(base.string()) == std::string::npos) {
+      LOG(ERROR) << base.string() << " is not base path for " << input.string();
+      return input;
+  }
+
+  return input.string().substr(base.string().length() + 1);
+}
+
+bool IsSubDir(const boost::filesystem::path& path,
+    const boost::filesystem::path& root) {
+  boost::filesystem::path p = path;
+  while (p != boost::filesystem::path()) {
+    if (bf::equivalent(p, root))
+      return true;
+    else
+      p = p.parent_path();
+  }
+
+  return false;
+}
+
+bf::path RelativePath(const bf::path& from,
+                                     const bf::path& to) {
+  bf::path::const_iterator itr_path = from.begin();
+  bf::path::const_iterator itr_relative_to = to.begin();
+
+  while (itr_path != from.end() && itr_relative_to != to.end() &&
+         *itr_path == *itr_relative_to) {
+    ++itr_path;
+    ++itr_relative_to;
+  }
+
+  bf::path result;
+  if (itr_relative_to != to.end()) {
+    ++itr_relative_to;
+    while (itr_relative_to != to.end()) {
+      result /= "..";
+      ++itr_relative_to;
+    }
+  }
+
+  while (itr_path != from.end()) {
+    result /= *itr_path;
+    ++itr_path;
+  }
+
+  bs::error_code error;
+  bf::path resolved_path = bf::canonical(result, error);
+  if (error) {
+    LOG(ERROR) << "Failed to get canonical path";
+    return {};
+  }
+
+  if (from != resolved_path) {
+    LOG(ERROR) << "Failed to get right relative path :" << resolved_path;
+    return {};
+  }
+
+  return result;
+}
+
+std::vector<std::string> GetLightUserList(uid_t uid) {
+  int user_count = 0;
+  subsession_user_t* user_list = nullptr;
+  int ret = subsession_get_user_list(
+      static_cast<int>(uid), &user_list, &user_count);
+  if (ret != TIZEN_ERROR_NONE) {
+    LOG(ERROR) << "Failed to get light user list : " << ret;
+    return {};
+  }
+
+  std::vector<std::string> result_list;
+  for (int i = 0; i < user_count; i++) {
+    if (strlen(user_list[i]) == 0)
+      continue;
+
+    result_list.emplace_back(user_list[i]);
+  }
+
+  std::free(user_list);
+  return result_list;
+}
+
 }  // namespace common_installer