diff options
author | JackLivio <jack@livio.io> | 2018-10-19 15:05:09 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-10-19 15:05:09 -0400 |
commit | d36316738785c96dab2ee892762ed08c059fffde (patch) | |
tree | 168a7c0705b5bc8f0dee7ce4b511ccf71759d9b4 /src/components/utils/src/file_system.cc | |
parent | 7f7fcbb998fb17f2954fd103349af67ea9b71a3f (diff) | |
parent | 83c5e805346d55ec7fb9f4ba8b6f6855d992273e (diff) | |
download | sdl_core-hotfix/templates_updates.tar.gz |
Merge pull request #2572 from smartdevicelink/release/5.0.05.0.0hotfix/templates_updatesfeature/show_app_menufeature/progress_bar_seekfeature/open-menu-rpcfeature/open-menu-rfeature/button
Release 5.0.0
Diffstat (limited to 'src/components/utils/src/file_system.cc')
-rw-r--r-- | src/components/utils/src/file_system.cc | 317 |
1 files changed, 141 insertions, 176 deletions
diff --git a/src/components/utils/src/file_system.cc b/src/components/utils/src/file_system.cc index 62a91ad1f3..f98aeda056 100644 --- a/src/components/utils/src/file_system.cc +++ b/src/components/utils/src/file_system.cc @@ -33,125 +33,114 @@ #include "utils/file_system.h" #include "utils/logger.h" -#include <sys/statvfs.h> #include <sys/stat.h> +#include <sys/statvfs.h> #include <sys/types.h> #include <sstream> #include <dirent.h> #include <unistd.h> // TODO(VS): lint error: Streams are highly discouraged. -#include <fstream> +#include <algorithm> +#include <boost/filesystem.hpp> #include <cstddef> #include <cstdio> -#include <algorithm> +#include <fstream> CREATE_LOGGERPTR_GLOBAL(logger_, "Utils") +// Easier reference +namespace fs = boost::filesystem; +using boost::system::error_code; + uint64_t file_system::GetAvailableDiskSpace(const std::string& path) { - struct statvfs fsInfo = {0}; - if (statvfs(path.c_str(), &fsInfo) == 0) { - return fsInfo.f_bsize * fsInfo.f_bfree; - } else { + error_code ec; + fs::space_info si = fs::space(path, ec); + + if (ec) { + // If something went wrong, assume no free space return 0; + } else { + return si.free; } } -int64_t file_system::FileSize(const std::string& path) { - if (file_system::FileExists(path)) { - struct stat file_info = {0}; - if (0 != stat(path.c_str(), &file_info)) { - LOG4CXX_WARN_WITH_ERRNO(logger_, "Could not get file size: " << path); - } else { - return file_info.st_size; - } +uint64_t file_system::FileSize(const std::string& path) { + error_code ec; + // Boost returns sizes as unsigned + uint64_t fsize = (uint64_t)fs::file_size(path, ec); + + if (ec) { + LOG4CXX_WARN_WITH_ERRNO(logger_, "Could not get file size: " << path); + return 0; } - return 0; + return fsize; } size_t file_system::DirectorySize(const std::string& path) { - size_t size = 0; - int32_t return_code = 0; - DIR* directory = NULL; - struct dirent dir_element_; - struct dirent* dir_element = &dir_element_; - struct dirent* result = NULL; - struct stat file_info = {0}; - directory = opendir(path.c_str()); - if (NULL != directory) { - return_code = readdir_r(directory, dir_element, &result); - for (; NULL != result && 0 == return_code; - return_code = readdir_r(directory, dir_element, &result)) { - if (0 == strcmp(result->d_name, "..") || - 0 == strcmp(result->d_name, ".")) { - continue; - } - std::string full_element_path = path + "/" + result->d_name; - if (file_system::IsDirectory(full_element_path)) { - size += DirectorySize(full_element_path); - } else { - stat(full_element_path.c_str(), &file_info); - size += file_info.st_size; - } + size_t dir_size = 0; + error_code ec; + // Recursively iterate through directory to accumulate file sizes + fs::recursive_directory_iterator iter(path, ec); + // Directory does not exist + if (ec) { + return 0; + } + // default constructor gives end iterator + fs::recursive_directory_iterator end; + while (iter != end) { + size_t fsize = fs::file_size(iter->path(), ec); + // No error means we can add the file + if (!ec) { + dir_size += fsize; } + iter++; // next entry } - closedir(directory); - return size; + return dir_size; } +// NOTE that boost makes 0777 permissions by default std::string file_system::CreateDirectory(const std::string& name) { - if (!DirectoryExists(name)) { - if (0 != mkdir(name.c_str(), S_IRWXU)) { - LOG4CXX_WARN_WITH_ERRNO(logger_, "Unable to create directory: " << name); - } + error_code ec; + bool success = fs::create_directory(name, ec); + if (!success || ec) { + LOG4CXX_WARN_WITH_ERRNO(logger_, "Unable to create directory: " << name); + } else { + // Set 0700 permissions to maintain previous API + fs::permissions(name, fs::perms::owner_all, ec); } - return name; } bool file_system::CreateDirectoryRecursively(const std::string& path) { - size_t pos = 0; - bool ret_val = true; - - while (ret_val == true && pos <= path.length()) { - pos = path.find('/', pos + 1); - if (!DirectoryExists(path.substr(0, pos))) { - if (0 != mkdir(path.substr(0, pos).c_str(), S_IRWXU)) { - ret_val = false; - } - } - } + error_code ec; + // Create directory and all parents + fs::create_directories(path, ec); - return ret_val; -} + if (ec) { + LOG4CXX_WARN_WITH_ERRNO(logger_, + "Unable to create directory recursively: " + << path << " reason: " << ec.message()); -bool file_system::IsDirectory(const std::string& name) { - struct stat status = {0}; - - if (-1 == stat(name.c_str(), &status)) { return false; } - - return S_ISDIR(status.st_mode); + // return true if we made something or if it already existed + return true; } +bool file_system::IsDirectory(const std::string& name) { + error_code ec; + return fs::is_directory(name, ec); +} +// NOTE this may be a duplicate of IsDirectory since it already checks +// existence bool file_system::DirectoryExists(const std::string& name) { - struct stat status = {0}; - - if (-1 == stat(name.c_str(), &status) || !S_ISDIR(status.st_mode)) { - return false; - } - - return true; + return FileExists(name) && IsDirectory(name); } bool file_system::FileExists(const std::string& name) { - struct stat status = {0}; - - if (-1 == stat(name.c_str(), &status)) { - return false; - } - return true; + error_code ec; + return fs::exists(name, ec); } bool file_system::Write(const std::string& file_name, @@ -200,80 +189,75 @@ void file_system::Close(std::ofstream* file_stream) { } std::string file_system::CurrentWorkingDirectory() { - const size_t filename_max_length = 1024; - char path[filename_max_length]; - if (0 == getcwd(path, filename_max_length)) { + error_code ec; + fs::path currpath = fs::current_path(ec); + if (ec) { LOG4CXX_WARN(logger_, "Could not get CWD"); } - return std::string(path); + return currpath.string(); } std::string file_system::GetAbsolutePath(const std::string& path) { - char abs_path[PATH_MAX]; - if (NULL == realpath(path.c_str(), abs_path)) { - return std::string(); + error_code ec; + fs::path absolute = fs::canonical(path, ec); + if (ec) { + return std::string(); // invalid path } - - return std::string(abs_path); + return absolute.string(); } bool file_system::IsFileNameValid(const std::string& file_name) { return file_name.end() == std::find(file_name.begin(), file_name.end(), '/'); } +// Does not remove if file is write-protected bool file_system::DeleteFile(const std::string& name) { if (FileExists(name) && IsAccessible(name, W_OK)) { - return !remove(name.c_str()); + error_code ec; + bool success = fs::remove(name.c_str(), ec); + return success && !ec; } return false; } void file_system::remove_directory_content(const std::string& directory_name) { - int32_t return_code = 0; - DIR* directory = NULL; - struct dirent dir_element_; - struct dirent* dir_element = &dir_element_; - struct dirent* result = NULL; - - directory = opendir(directory_name.c_str()); - - if (NULL != directory) { - return_code = readdir_r(directory, dir_element, &result); - - for (; NULL != result && 0 == return_code; - return_code = readdir_r(directory, dir_element, &result)) { - if (0 == strcmp(result->d_name, "..") || - 0 == strcmp(result->d_name, ".")) { - continue; - } - - std::string full_element_path = directory_name + "/" + result->d_name; - - if (file_system::IsDirectory(full_element_path)) { - remove_directory_content(full_element_path); - rmdir(full_element_path.c_str()); - } else { - if (0 != remove(full_element_path.c_str())) { - LOG4CXX_WARN_WITH_ERRNO( - logger_, "Unable to remove file: " << full_element_path); - } - } - } + error_code ec; + fs::directory_iterator dir_iter(directory_name, ec); + + if (ec) { + LOG4CXX_WARN_WITH_ERRNO(logger_, + "Unable to empty directory: " << directory_name); } - closedir(directory); + // According to Boost's documentation, removing shouldn't invalidate the + // iterator, although it may cause the removed entry to appear again, + // duplicating the warning message. See here: + // https://www.boost.org/doc/libs/1_67_0/libs/filesystem/doc/reference.html#Class-directory_iterator + for (auto& dirent : dir_iter) { + fs::remove_all(dirent, ec); + if (ec) { + LOG4CXX_WARN_WITH_ERRNO( + logger_, "Unable to remove file: " << dirent.path().string()); + } + } } bool file_system::RemoveDirectory(const std::string& directory_name, bool is_recursively) { - if (DirectoryExists(directory_name) && IsAccessible(directory_name, W_OK)) { - if (is_recursively) { - remove_directory_content(directory_name); - } - - return !rmdir(directory_name.c_str()); + // Make sure the directory exists + if (!DirectoryExists(directory_name) && IsAccessible(directory_name, W_OK)) { + return false; } - return false; + error_code ec; + bool success; + // If recursive, just force full remove + if (is_recursively) { + success = (fs::remove_all(directory_name, ec) != 0); + } else { + // Otherwise try to remove + success = fs::remove(directory_name, ec); + } + return success && !ec; } bool file_system::IsAccessible(const std::string& name, int32_t how) { @@ -290,34 +274,20 @@ bool file_system::IsReadingAllowed(const std::string& name) { std::vector<std::string> file_system::ListFiles( const std::string& directory_name) { + error_code ec; + + fs::directory_iterator dir_iter(directory_name, ec); std::vector<std::string> listFiles; - if (!DirectoryExists(directory_name)) { + + // In case the directory doesn't exist / can't be read, second check may be + // redundant + if (ec || !DirectoryExists(directory_name)) { return listFiles; } - int32_t return_code = 0; - DIR* directory = NULL; - struct dirent dir_element_; - struct dirent* dir_element = &dir_element_; - struct dirent* result = NULL; - - directory = opendir(directory_name.c_str()); - if (NULL != directory) { - return_code = readdir_r(directory, dir_element, &result); - - for (; NULL != result && 0 == return_code; - return_code = readdir_r(directory, dir_element, &result)) { - if (0 == strcmp(result->d_name, "..") || - 0 == strcmp(result->d_name, ".")) { - continue; - } - - listFiles.push_back(std::string(result->d_name)); - } - - closedir(directory); + for (auto& dirent : dir_iter) { + listFiles.push_back(dirent.path().filename().string()); } - return listFiles; } @@ -390,47 +360,42 @@ bool file_system::CreateFile(const std::string& path) { } } -uint64_t file_system::GetFileModificationTime(const std::string& path) { - struct stat info; - if (0 != stat(path.c_str(), &info)) { - LOG4CXX_WARN_WITH_ERRNO(logger_, "Could not get file mod time: " << path); +time_t file_system::GetFileModificationTime(const std::string& path) { + error_code ec; + std::time_t time = fs::last_write_time(path, ec); + if (ec) { + return 0; } - return static_cast<uint64_t>(info.st_mtim.tv_nsec); + return time; } bool file_system::CopyFile(const std::string& src, const std::string& dst) { if (!FileExists(src) || FileExists(dst) || !CreateFile(dst)) { return false; } - std::vector<uint8_t> data; - if (!ReadBinaryFile(src, data) || !WriteBinaryFile(dst, data)) { - DeleteFile(dst); + error_code ec; + fs::copy_file(src, dst, ec); + if (ec) { + // something failed return false; } return true; } bool file_system::MoveFile(const std::string& src, const std::string& dst) { + error_code ec; + if (std::rename(src.c_str(), dst.c_str()) == 0) { return true; - } else { - // In case of src and dst on different file systems std::rename returns - // an error (at least on QNX). - // Seems, streams are not recommended for use, so have - // to find another way to do this. - std::ifstream s_src(src, std::ios::binary); - if (!s_src.good()) { - return false; - } - std::ofstream s_dst(dst, std::ios::binary); - if (!s_dst.good()) { - return false; - } - s_dst << s_src.rdbuf(); - s_dst.close(); - s_src.close(); - DeleteFile(src); - return true; } - return false; + // In case of src and dst on different file systems std::rename returns + // an error (at least on QNX). + // Instead, copy the file over and delete the old one + bool success = CopyFile(src, dst); + if (!success) { + return false; + } + DeleteFile(src); + + return true; } |