Move GetLightUserList() to user_util.h
[platform/core/appfw/app-installers.git] / src / common / utils / file_util.cc
index fe4fe3c..76ce1de 100644 (file)
@@ -21,6 +21,7 @@
 #include <vector>
 
 #include "common/utils/byte_size_literals.h"
+#include "common/utils/paths.h"
 
 namespace ba = boost::algorithm;
 namespace bs = boost::system;
@@ -97,13 +98,7 @@ FSFlag operator|(FSFlag a, FSFlag b) {
 }
 
 bool SetOwnership(const bf::path& path, uid_t uid, gid_t gid) {
-  int fd = open(path.c_str(), O_RDONLY);
-  if (fd < 0) {
-    LOG(ERROR) << "Can't open directory : " << path;
-    return false;
-  }
-  int ret = fchown(fd, uid, gid);
-  close(fd);
+  int ret = lchown(path.c_str(), uid, gid);
   if (ret != 0) {
     LOG(ERROR) << "Failed to change owner of: " << path;
     return false;
@@ -120,8 +115,6 @@ bool SetOwnershipAll(const bf::path& path, uid_t uid, gid_t gid) {
     iter != bf::recursive_directory_iterator();
     ++iter) {
     bf::path current(iter->path());
-    if (bf::is_symlink(symlink_status(current)))
-      continue;
     if (!SetOwnership(current, uid, gid))
       return false;
   }
@@ -156,6 +149,43 @@ bool SetDirPermissions(const boost::filesystem::path& path,
   return true;
 }
 
+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 {
@@ -171,12 +201,16 @@ bool CopyDir(const bf::path& src, const bf::path& 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) << "Failed to copy directory: " << error.what();
@@ -197,7 +231,13 @@ bool CopyDir(const bf::path& src, const bf::path& dst,
         if ((flags & (FS_MERGE_SKIP | FS_MERGE_OVERWRITE)) &&
             bf::exists(target))
           continue;
-        bf::copy_symlink(current, target);
+        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, target, flags, skip_symlink)) {
@@ -218,6 +258,9 @@ bool CopyDir(const bf::path& src, const bf::path& dst,
         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);
@@ -243,6 +286,63 @@ bool CopyFile(const bf::path& src, const bf::path& dst) {
   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))) {
@@ -267,8 +367,8 @@ bool MoveDir(const bf::path& src, const bf::path& dst, FSFlag flags) {
   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);
@@ -290,11 +390,26 @@ bool MoveFile(const bf::path& src, const bf::path& dst) {
   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;
 
@@ -333,7 +448,6 @@ int64_t GetUnpackedPackageSize(const bf::path& path) {
 int64_t GetDirectorySize(const boost::filesystem::path& path) {
   int64_t block_size = GetBlockSizeForPath(path);
 
-  // if failed to stat path
   if (block_size == -1)
     return -1;
 
@@ -352,6 +466,28 @@ int64_t GetDirectorySize(const boost::filesystem::path& path) {
   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);
@@ -373,9 +509,11 @@ boost::filesystem::path GenerateTemporaryPath(
   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;
 }
 
@@ -425,7 +563,6 @@ bool ExtractToTmpDir(const char* zip_path, const bf::path& tmp_dir,
         std::string(raw_file_name_in_zip).find(filter_prefix) == 0) {
       bf::path filename_in_zip_path(raw_file_name_in_zip);
 
-      // prevent "directory climbing" attack
       if (HasDirectoryClimbing(filename_in_zip_path)) {
         LOG(ERROR) << "Relative path in widget in malformed";
         return false;
@@ -445,7 +582,7 @@ bool ExtractToTmpDir(const char* zip_path, const bf::path& tmp_dir,
       }
 
       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 ";
           return false;
@@ -456,6 +593,7 @@ bool ExtractToTmpDir(const char* zip_path, const bf::path& tmp_dir,
           ret = unzReadCurrentFile(zip_file.Get(), read_buffer, kZipBufSize);
           if (ret < 0) {
             LOG(ERROR) << "Failed to read data: " << ret;
+            fclose(out);
             return false;
           } else {
             fwrite(read_buffer, sizeof(char), ret, out);
@@ -540,9 +678,12 @@ bool HasDirectoryClimbing(const boost::filesystem::path& path) {
 
 boost::filesystem::path MakeRelativePath(const boost::filesystem::path& input,
                                          const boost::filesystem::path& base) {
-  bf::path input_absolute = bf::absolute(input);
-  bf::path base_absolute = bf::absolute(base);
-  return input_absolute.string().substr(base_absolute.string().length() + 1);
+  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,
@@ -554,7 +695,48 @@ bool IsSubDir(const boost::filesystem::path& path,
     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;
+}
+
 }  // namespace common_installer