Remove boost dependency
[platform/core/appfw/app-installers.git] / src / common / utils / file_util.cc
index 8df33f4..aa87c78 100644 (file)
@@ -8,34 +8,30 @@
 #include <unzip.h>
 #include <zlib.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 <filesystem>
+#include <random>
+#include <regex>
 #include <string>
+#include <system_error>
 #include <vector>
 
 #include "common/utils/byte_size_literals.h"
 #include "common/utils/paths.h"
 
-namespace ba = boost::algorithm;
-namespace bs = boost::system;
-namespace bf = boost::filesystem;
+namespace fs = std::filesystem;
 
 namespace {
 
 unsigned kZipBufSize = 8_kB;
 unsigned kZipMaxPath = PATH_MAX;
 
-int64_t GetBlockSizeForPath(const bf::path& path_in_partition) {
+int64_t GetBlockSizeForPath(const fs::path& path_in_partition) {
   struct stat stats;
-  if (stat(path_in_partition.string().c_str(), &stats)) {
-    LOG(ERROR) << "stat(" << path_in_partition.string()
+  if (stat(path_in_partition.c_str(), &stats)) {
+    LOG(ERROR) << "stat(" << path_in_partition
                << ") failed - error code: " << errno;
     return -1;
   }
@@ -97,7 +93,7 @@ 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) {
+bool SetOwnership(const fs::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;
@@ -106,51 +102,51 @@ bool SetOwnership(const bf::path& path, uid_t uid, gid_t gid) {
   return true;
 }
 
-bool SetOwnershipAll(const bf::path& path, uid_t uid, gid_t gid) {
+bool SetOwnershipAll(const fs::path& path, uid_t uid, gid_t gid) {
   if (!SetOwnership(path, uid, gid))
     return false;
-  if (!bf::is_directory(path))
+  if (!fs::is_directory(path))
     return true;
-  for (bf::recursive_directory_iterator iter(path);
-    iter != bf::recursive_directory_iterator();
+  for (fs::recursive_directory_iterator iter(path);
+    iter != fs::recursive_directory_iterator();
     ++iter) {
-    bf::path current(iter->path());
+    fs::path current(iter->path());
     if (!SetOwnership(current, uid, gid))
       return false;
   }
   return true;
 }
 
-bool CreateDir(const bf::path& path) {
-  if (bf::exists(path))
+bool CreateDir(const fs::path& path) {
+  if (fs::exists(path))
     return true;
 
-  boost::system::error_code error;
-  bf::create_directories(path, error);
+  std::error_code error;
+  fs::create_directories(path, error);
 
   if (error) {
-    LOG(ERROR) << "Failed to create directory: "
-               << boost::system::system_error(error).what();
+    LOG(ERROR) << "Failed to create directory: " << error.message();
     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);
+bool SetDirPermissions(const fs::path& path,
+                      fs::perms permissions, bool add_perms) {
+  std::error_code error;
+  fs::permissions(path, permissions,
+      add_perms ? fs::perm_options::add : fs::perm_options::replace, error);
 
   if (error) {
     LOG(ERROR) << "Failed to set permissions for directory: " << path
-               << boost::system::system_error(error).what();
+               << error.message();
     return false;
   }
   return true;
 }
 
-bool SetDirOwnershipAndPermissions(const boost::filesystem::path& path,
-                      boost::filesystem::perms permissions, uid_t uid,
+bool SetDirOwnershipAndPermissions(const fs::path& path,
+                      fs::perms permissions, uid_t uid,
                       gid_t gid) {
   if (!SetOwnership(path, uid, gid)) {
     LOG(ERROR) << "Failed to change owner: " << path
@@ -158,22 +154,20 @@ bool SetDirOwnershipAndPermissions(const boost::filesystem::path& path,
     return false;
   }
   if (!SetDirPermissions(path, permissions)) {
-    LOG(ERROR) << "Failed to change permission: " << path
-               << std::oct << permissions;
+    LOG(ERROR) << "Failed to change permission: " << path;
     return false;
   }
 
   return true;
 }
 
-bool CopyOwnershipAndPermissions(const boost::filesystem::path& src,
-                                 const boost::filesystem::path& dst) {
-  if (!bf::exists(src)) {
+bool CopyOwnershipAndPermissions(const fs::path& src, const fs::path& dst) {
+  if (!fs::exists(src)) {
     LOG(ERROR) << "Failed to copy ownership and permissions"
                << " from " << src << " to " << dst;
     return false;
   }
-  bf::perms permissions = bf::status(src).permissions();
+  fs::perms permissions = fs::status(src).permissions();
   struct stat stats;
   if (stat(src.c_str(), &stats) != 0)
     return false;
@@ -186,16 +180,16 @@ bool CopyOwnershipAndPermissions(const boost::filesystem::path& src,
   return true;
 }
 
-bool CopyDir(const bf::path& src, const bf::path& dst,
+bool CopyDir(const fs::path& src, const fs::path& dst,
              FSFlag flags, bool skip_symlink) {
   try {
     // Check whether the function call is valid
-    if (!bf::exists(src) || !bf::is_directory(src)) {
+    if (!fs::exists(src) || !fs::is_directory(src)) {
       LOG(ERROR) << "Source directory " << src
                  << " does not exist or is not a directory.";
       return false;
     }
-    if (!bf::exists(dst)) {
+    if (!fs::exists(dst)) {
       // Create the destination directory
       if (!CreateDir(dst)) {
         LOG(ERROR) << "Unable to create destination directory" << dst;
@@ -212,62 +206,59 @@ bool CopyDir(const bf::path& src, const bf::path& dst,
       if (flags & (FS_MERGE_OVERWRITE | FS_PRESERVE_OWNERSHIP_AND_PERMISSIONS))
         CopyOwnershipAndPermissions(src, dst);
     }
-  } catch (const bf::filesystem_error& error) {
+  } catch (const fs::filesystem_error& error) {
     LOG(ERROR) << "Failed to copy directory: " << error.what();
     return false;
   }
 
   // Iterate through the source directory
-  for (bf::directory_iterator file(src);
-      file != bf::directory_iterator();
-      ++file) {
+  for (const auto& current : fs::directory_iterator(src)) {
     try {
-      bf::path current(file->path());
-      bf::path target = dst / current.filename();
+      fs::path target = dst / current.path().filename();
 
-      if (bf::is_symlink(symlink_status(current))) {
+      if (fs::is_symlink(symlink_status(current))) {
         if (skip_symlink)
           continue;
         if ((flags & (FS_MERGE_SKIP | FS_MERGE_OVERWRITE)) &&
-            bf::exists(target))
+            fs::exists(target))
           continue;
-        bs::error_code error;
-        bf::copy_symlink(current, target, error);
+        std::error_code error;
+        fs::copy_symlink(current, target, error);
         if (error) {
           LOG(ERROR) << "Failed to copy symlink: " << current << ", "
                      << error.message();
           return false;
         }
-      } else if (bf::is_directory(current)) {
+      } else if (fs::is_directory(current)) {
         // Found directory: Recursion
         if (!CopyDir(current, target, flags, skip_symlink)) {
           return false;
         }
       } else {
-        if ((flags & FS_MERGE_SKIP) && bf::exists(target))
+        if ((flags & FS_MERGE_SKIP) && fs::exists(target))
           continue;
-        bf::path destination = target;
+        fs::path destination = target;
 
         if (flags & FS_COMMIT_COPY_FILE)
-          destination =
-              bf::unique_path(target.parent_path() / "%%%%-%%%%-%%%%-%%%%");
+          destination = target.parent_path() /
+              GenerateUniquePathString("%%%%-%%%%-%%%%-%%%%");
 
         if (flags & FS_MERGE_OVERWRITE)
-          bf::copy_file(current, destination,
-                        bf::copy_option::overwrite_if_exists);
+          fs::copy_file(current, destination,
+                        fs::copy_options::overwrite_existing);
         else
-          bf::copy_file(current, destination);
+          fs::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);
+            fs::remove(target);
+          fs::rename(destination, target);
         }
       }
-    } catch (const bf::filesystem_error& error) {
+    } catch (const fs::filesystem_error& error) {
       LOG(ERROR) << "Failed to copy directory: " << error.what();
       return false;
     }
@@ -275,10 +266,10 @@ bool CopyDir(const bf::path& src, const bf::path& dst,
   return true;
 }
 
-bool CopyFile(const bf::path& src, const bf::path& dst) {
-  bs::error_code error;
+bool CopyFile(const fs::path& src, const fs::path& dst) {
+  std::error_code error;
 
-  bf::copy_file(src, dst, bf::copy_option::overwrite_if_exists, error);
+  fs::copy_file(src, dst, fs::copy_options::overwrite_existing, error);
   if (error) {
     LOG(WARNING) << "copy file " << src << " due to error [" << error << "]";
     return false;
@@ -286,41 +277,41 @@ 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))) {
+bool RestoreBackup(const fs::path& path) {
+  fs::path backup_path = GetBackupPathForPackagePath(path);
+  if (!fs::exists(backup_path) &&
+      !fs::is_symlink(fs::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))) {
+bool MakeBackup(const fs::path& path) {
+  if (!fs::exists(path) && !fs::is_symlink(fs::symlink_status(path))) {
     LOG(WARNING) << path << " does not exist";
     return true;
   }
-  bf::path backup_path = GetBackupPathForPackagePath(path);
+  fs::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))) {
+bool RemoveBackup(const fs::path& path) {
+  fs::path backup_path = GetBackupPathForPackagePath(path);
+  if (!fs::exists(backup_path) &&
+      !fs::is_symlink(fs::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)))
+bool RemoveAll(const fs::path& path) {
+  if (!fs::exists(path) && !fs::is_symlink(fs::symlink_status(path)))
     return true;
 
-  bs::error_code error;
-  bf::remove_all(path, error);
+  std::error_code error;
+  fs::remove_all(path, error);
 
   if (error) {
     LOG(ERROR) << "Cannot remove: " << path << ", " << error.message();
@@ -330,12 +321,12 @@ bool RemoveAll(const bf::path& path) {
   return true;
 }
 
-bool Remove(const bf::path& path) {
-  bs::error_code error;
-  if (!bf::exists(bf::symlink_status(path, error)))
+bool Remove(const fs::path& path) {
+  std::error_code error;
+  if (!fs::exists(fs::symlink_status(path, error)))
     return true;
 
-  bf::remove(path, error);
+  fs::remove(path, error);
   if (error) {
     LOG(ERROR) << "Cannot remove: " << path << ", " << error.message();
     return false;
@@ -343,22 +334,22 @@ bool Remove(const bf::path& path) {
   return true;
 }
 
-bool MoveDir(const bf::path& src, const bf::path& dst, FSFlag flags) {
-  if (bf::exists(dst) &&
+bool MoveDir(const fs::path& src, const fs::path& dst, FSFlag flags) {
+  if (fs::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);
+  std::error_code error;
+  fs::rename(src, dst, error);
   if (error) {
     LOG(WARNING) << "Cannot move directory: " << src << ". Will copy/remove...";
     if (!CopyDir(src, dst, flags, false)) {
       LOG(ERROR) << "Cannot copy directory: " << src;
       return false;
     }
-    bf::remove_all(src, error);
+    fs::remove_all(src, error);
     if (error) {
       LOG(ERROR) << "Cannot remove old directory when coping: " << src;
       return false;
@@ -367,21 +358,21 @@ bool MoveDir(const bf::path& src, const bf::path& dst, FSFlag flags) {
   return true;
 }
 
-bool MoveFile(const bf::path& src, const bf::path& dst, bool force) {
-  if (!force && bf::exists(dst))
+bool MoveFile(const fs::path& src, const fs::path& dst, bool force) {
+  if (!force && fs::exists(dst))
     return false;
-  bs::error_code error;
-  bf::rename(src, dst, error);
+  std::error_code error;
+  fs::rename(src, dst, error);
   if (error) {
     LOG(WARNING) << "Cannot move file: " << src <<
         ". Will copy/remove... with error [" << error << "]";
-    bf::copy_file(src, dst, bf::copy_option::overwrite_if_exists, error);
+    fs::copy_file(src, dst, fs::copy_options::overwrite_existing, error);
     if (error) {
       LOG(WARNING) << "Cannot copy file " << src <<
           " due to error [" << error << "]";
       return false;
     }
-    bf::remove_all(src, error);
+    fs::remove_all(src, error);
     if (error) {
       LOG(ERROR) << "Cannot remove old file when coping: " << src <<
           "with error [" << error << "]";
@@ -390,9 +381,9 @@ bool MoveFile(const bf::path& src, const bf::path& dst, bool force) {
   return true;
 }
 
-bool BackupDir(const boost::filesystem::path& src,
-    const boost::filesystem::path& dst, const std::string& entry) {
-  if (!bf::exists(src / entry))
+bool BackupDir(const fs::path& src,
+    const fs::path& dst, const std::string& entry) {
+  if (!fs::exists(src / entry))
     return true;
 
   if (!MoveDir(src / entry, dst / entry,
@@ -406,7 +397,7 @@ bool BackupDir(const boost::filesystem::path& src,
   return true;
 }
 
-int64_t GetUnpackedPackageSize(const bf::path& path) {
+int64_t GetUnpackedPackageSize(const fs::path& path) {
   int64_t size = 0;
   int64_t block_size = GetBlockSizeForPath(path);
 
@@ -417,7 +408,7 @@ int64_t GetUnpackedPackageSize(const bf::path& path) {
   unz_file_info64 raw_file_info;
   char raw_file_name_in_zip[kZipMaxPath];
 
-  unzFile* zip_file = static_cast<unzFile*>(unzOpen(path.string().c_str()));
+  unzFile* zip_file = static_cast<unzFile*>(unzOpen(path.c_str()));
   if (zip_file == nullptr) {
     LOG(ERROR) << "Failed to open the source dir: " << path.string();
     return -1;
@@ -445,15 +436,15 @@ int64_t GetUnpackedPackageSize(const bf::path& path) {
   return size;
 }
 
-int64_t GetDirectorySize(const boost::filesystem::path& path) {
+int64_t GetDirectorySize(const fs::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) {
+  for (fs::recursive_directory_iterator iter(path);
+      iter != fs::recursive_directory_iterator(); ++iter) {
       struct stat buf;
       if (lstat(iter->path().c_str(), &buf) == -1) {
         LOG(ERROR) << "lstat() failed for: " << iter->path();
@@ -467,19 +458,19 @@ int64_t GetDirectorySize(const boost::filesystem::path& path) {
 }
 
 bool CheckFreeSpaceAtPath(int64_t required_size,
-    const boost::filesystem::path& target_location) {
-  bs::error_code error;
-  boost::filesystem::path root = target_location;
+    const fs::path& target_location) {
+  std::error_code error;
+  fs::path root = target_location;
 
-  while (!bf::exists(root) && root != root.root_path())
+  while (!fs::exists(root) && root != root.root_path())
     root = root.parent_path();
 
-  if (!bf::exists(root)) {
+  if (!fs::exists(root)) {
     LOG(ERROR) << "No mount point for path: " << target_location;
     return false;
   }
 
-  bf::space_info space_info = bf::space(root, error);
+  fs::space_info space_info = fs::space(root, error);
   if (error) {
     LOG(ERROR) << "Failed to get space_info: " << error.message();
     return false;
@@ -488,41 +479,38 @@ bool CheckFreeSpaceAtPath(int64_t required_size,
   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);
+fs::path GenerateTmpDir(const fs::path &app_path) {
+  fs::path install_tmp_dir;
+  fs::path tmp_dir(app_path);
 
   do {
-    boost::filesystem::path model;
-    boost::filesystem::path unique_dir =
-        boost::filesystem::unique_path(model = "unpack-%%%%%%");
+    fs::path unique_dir = GenerateUniquePathString("unpack-%%%%%%");
 
     install_tmp_dir = tmp_dir /= unique_dir;
-  } while (boost::filesystem::exists(install_tmp_dir) &&
-           boost::filesystem::is_directory(install_tmp_dir));
+  } while (fs::exists(install_tmp_dir) &&
+           fs::is_directory(install_tmp_dir));
 
   return install_tmp_dir;
 }
 
-boost::filesystem::path GenerateTemporaryPath(
-    const boost::filesystem::path& path) {
-  bf::path pattern = path;
+fs::path GenerateTemporaryPath(const fs::path& path) {
+  fs::path pattern = path;
   pattern += "-%%%%%%";
-  bf::path tmp_path;
+  fs::path tmp_path;
 
   do {
-    tmp_path = boost::filesystem::unique_path(pattern);
-  } while (boost::filesystem::exists(tmp_path));
+    tmp_path = GenerateUniquePathString(pattern);
+  } while (fs::exists(tmp_path));
 
   return tmp_path;
 }
 
 bool ExtractToTmpDir(const char* zip_path,
-                     const boost::filesystem::path& tmp_dir) {
+                     const fs::path& tmp_dir) {
   return ExtractToTmpDir(zip_path, tmp_dir, "");
 }
 
-bool ExtractToTmpDir(const char* zip_path, const bf::path& tmp_dir,
+bool ExtractToTmpDir(const char* zip_path, const fs::path& tmp_dir,
                      const std::string& filter_prefix) {
   unz_global_info info;
   char read_buffer[kZipBufSize];
@@ -561,7 +549,7 @@ bool ExtractToTmpDir(const char* zip_path, const bf::path& tmp_dir,
     // unpack if filter is empty or path is matched
     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);
+      fs::path filename_in_zip_path(raw_file_name_in_zip);
 
       if (HasDirectoryClimbing(filename_in_zip_path)) {
         LOG(ERROR) << "Relative path in widget in malformed";
@@ -618,7 +606,7 @@ bool ExtractToTmpDir(const char* zip_path, const bf::path& tmp_dir,
 }
 
 bool CheckPathInZipArchive(const char* zip_archive_path,
-                           const boost::filesystem::path& relative_zip_path,
+                           const fs::path& relative_zip_path,
                            bool* found) {
   *found = false;
   UnzFilePointer zip_file;
@@ -667,17 +655,18 @@ bool CheckPathInZipArchive(const char* zip_archive_path,
   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 == "..";
-                  });
+bool HasDirectoryClimbing(const fs::path& path) {
+  std::regex re("[\\/\\\\]");
+  std::string path_str = path.string();
+  std::sregex_token_iterator first(path_str.begin(), path_str.end(), re, -1);
+  std::sregex_token_iterator last;
+  std::vector<std::string> segments(first, last);
+
+  return std::find(segments.begin(), segments.end(), "..") != segments.end();
 }
 
-boost::filesystem::path MakeRelativePath(const boost::filesystem::path& input,
-                                         const boost::filesystem::path& base) {
+fs::path MakeRelativePath(const fs::path& input,
+                                         const fs::path& base) {
   if (input.string().find(base.string()) == std::string::npos) {
       LOG(ERROR) << base.string() << " is not base path for " << input.string();
       return input;
@@ -686,72 +675,75 @@ boost::filesystem::path MakeRelativePath(const boost::filesystem::path& 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;
+bool IsSubDir(const fs::path& path, const fs::path& root) {
+  std::string relative = fs::relative(path, root);
+  return relative.size() == 1 || (relative[0] != '.' && relative[1] != '.');
 }
 
-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;
-    }
-  }
+std::vector<std::string> GetDirectoryList(const fs::path& cwd) {
+  if (!fs::exists(cwd))
+    return {};
 
-  while (itr_path != from.end()) {
-    result /= *itr_path;
-    ++itr_path;
+  std::vector<std::string> list;
+  for (fs::directory_iterator file(cwd); file != fs::directory_iterator();
+      ++file) {
+    if (!fs::is_directory(file->path()))
+      continue;
+    list.emplace_back(file->path().filename().string());
   }
 
-  bs::error_code error;
-  bf::path resolved_path = bf::canonical(result, error);
-  if (error) {
-    LOG(ERROR) << "Failed to get canonical path";
-    return {};
-  }
+  return list;
+}
 
-  if (from != resolved_path) {
-    LOG(ERROR) << "Failed to get right relative path :" << resolved_path;
-    return {};
-  }
+// To replace with std::filesystem::unique_path()
+fs::path GenerateUniquePathString(const std::string& format) {
+  static constexpr auto chars =
+      "0123456789"
+      "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+      "abcdefghijklmnopqrstuvwxyz";
+  std::random_device rd;
+  std::mt19937 gen(rd());
+  auto dist = std::uniform_int_distribution{{}, std::strlen(chars) - 1};
+  size_t len = std::count_if(format.begin(), format.end(),
+      [](char c) { return c == '%'; });
+
+  auto random_string = std::string(len, '\0');
+  std::generate_n(begin(random_string), len,
+      [&]() {
+        return chars[dist(gen)];
+      });
+
+  auto iter = random_string.begin();
+  std::string result(format);
+  std::transform(result.begin(), result.end(), result.begin(),
+      [&](char c) {
+        return c == '%' ? *iter++ : c;
+      });
 
   return result;
 }
 
-std::vector<std::string> GetDirectoryList(const boost::filesystem::path& cwd) {
-  if (!bf::exists(cwd))
-    return {};
+bool SyncFile(const fs::path& path) {
+  if (!fs::exists(path)) {
+    LOG(ERROR) << "File does not exist: " << path;
+    return false;
+  }
 
-  std::vector<std::string> list;
-  for (bf::directory_iterator file(cwd); file != bf::directory_iterator();
-      ++file) {
-    if (!bf::is_directory(file->path()))
-      continue;
-    list.emplace_back(file->path().filename().string());
+  int fd = open(path.c_str(), O_WRONLY);
+  if (fd == -1) {
+    LOG(ERROR) << "Failed to open file: " << path << ", errno: " << errno;
+    return false;
   }
 
-  return list;
+  int ret = fsync(fd);
+  if (ret == -1) {
+    LOG(ERROR) << "Failed to fsync() file: " << path << ", errno: " << errno;
+    close(fd);
+    return false;
+  }
+
+  close(fd);
+  return true;
 }
 
 }  // namespace common_installer