/* * Copyright (c) 2017 Trail of Bits, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include "remill/OS/FileSystem.h" #ifdef __APPLE__ # ifndef _DARWIN_USE_64_BIT_INODE # define _DARWIN_USE_64_BIT_INODE 1 # endif # define stat64 stat # define fstat64 fstat #endif namespace remill { // Try to create a directory. Returns `true` if the directory was created or // exists. bool TryCreateDirectory(const std::string &dir_name) { mkdir(dir_name.c_str(), 0777); // Ignore errors. if (auto d = opendir(dir_name.c_str())) { closedir(d); return true; } else { return false; } } std::string CurrentWorkingDirectory(void) { char result[PATH_MAX] = {}; auto res = getcwd(result, PATH_MAX); CHECK(res) << "Could not determine current working directory: " << strerror(errno); return std::string(result); } bool FileExists(const std::string &path) { if (-1 == access(path.c_str(), F_OK)) { return false; } struct stat64 file_info = {}; return stat64(path.c_str(), &file_info) == 0 && (S_ISREG(file_info.st_mode) || S_ISFIFO(file_info.st_mode)); } uint64_t FileSize(int fd) { struct stat64 file_info; CHECK(!fstat64(fd, &file_info)) << "Cannot stat FD " << fd << ": " << strerror(errno); return static_cast(file_info.st_size); } uint64_t FileSize(const std::string &path, int fd) { struct stat64 file_info; CHECK(!fstat64(fd, &file_info)) << "Cannot stat " << path << ": " << strerror(errno); return static_cast(file_info.st_size); } uint64_t FileSize(const std::string &path) { struct stat64 file_info; CHECK(!stat64(path.c_str(), &file_info)) << "Cannot stat " << path << ": " << strerror(errno); return static_cast(file_info.st_size); } void RemoveFile(const std::string &path) { unlink(path.c_str()); } void RenameFile(const std::string &from_path, const std::string &to_path) { rename(from_path.c_str(), to_path.c_str()); } namespace { enum : size_t { kCopyDataSize = 4096ULL }; static uint8_t gCopyData[kCopyDataSize]; } // namespace void CopyFile(const std::string &from_path, const std::string &to_path) { unlink(to_path.c_str()); auto from_fd = open(from_path.c_str(), O_RDONLY); CHECK(-1 != from_fd) << "Unable to open source file " << from_path << " for copying: " << strerror(errno); auto to_fd = open(to_path.c_str(), O_WRONLY | O_TRUNC | O_CREAT, 0666); CHECK(-1 != to_fd) << "Unable to open destination file " << to_path << " for copying: " << strerror(errno); auto file_size = FileSize(from_path); int errno_copy = 0; do { auto num_read = read( from_fd, &(gCopyData[0]), std::min(kCopyDataSize, file_size)); if (-1 == num_read) { errno_copy = errno; break; } auto num_written = write( to_fd, &(gCopyData[0]), static_cast(num_read)); if (num_written != num_read) { errno_copy = errno; break; } file_size -= static_cast(num_written); } while (file_size); close(from_fd); close(to_fd); if (errno_copy) { unlink(to_path.c_str()); LOG(FATAL) << "Unable to copy all data read from " << from_path << " to " << to_path << ": " << strerror(errno_copy); } } void HardLinkOrCopyFile(const std::string &from_path, const std::string &to_path) { unlink(to_path.c_str()); if (!link(from_path.c_str(), to_path.c_str())) { return; } DLOG(WARNING) << "Unable to link " << to_path << " to " << from_path << ": " << strerror(errno); CopyFile(from_path, to_path); } } // namespace remill