using ::aidl::com::android::server::art::FsPermission; using ::android::base::make_scope_guard; using ::android::base::Result; using ::android::base::unique_fd;
Result<void> NewFile::Keep() { if (close(std::exchange(fd_, -1)) != 0) { return ErrnoErrorf("Failed to close file '{}'", temp_path_);
} return {};
}
Result<void> NewFile::CommitOrAbandon() { auto cleanup = make_scope_guard([this] { Unlink(); });
OR_RETURN(Keep());
std::error_code ec;
std::filesystem::rename(temp_path_, final_path_, ec); if (ec) { // If this fails because the temp file doesn't exist, it could be that the file is deleted by // `Artd::cleanup` if that method is run simultaneously. At the time of writing, this should // never happen because `Artd::cleanup` is only called at the end of the backgrond dexopt job. return Errorf( "Failed to move new file '{}' to path '{}': {}", temp_path_, final_path_, ec.message());
}
cleanup.Disable(); return {};
}
void NewFile::Cleanup() { if (fd_ >= 0) {
Unlink(); if (close(std::exchange(fd_, -1)) != 0) { // Nothing we can do. If the file is already unlinked, it will go away when the process exits.
PLOG(WARNING) << "Failed to close file '" << temp_path_ << "'";
}
}
}
auto cleanup = make_scope_guard([&]() { // Clean up `files_to_move`. for (constauto& [src_path, dst_path] : files_to_move) { if (committed_files.find(dst_path) != committed_files.end()) {
UnlinkIfExists(dst_path);
} else {
UnlinkIfExists(src_path);
}
}
// Move old files back. for (constauto& [original_path, temp_path] : moved_files) {
std::error_code ec;
std::filesystem::rename(temp_path, original_path, ec); if (ec) { // This should never happen. We were able to move the file from `original_path` to // `temp_path`. We should be able to move it back.
LOG(WARNING) << ART_FORMAT("Failed to move old file '{}' back from temporary path '{}': {}",
original_path,
temp_path,
ec.message());
}
}
});
// Move old files to temporary locations.
std::vector<std::string_view> all_files_to_remove;
all_files_to_remove.reserve(files_to_move.size() + files_to_remove.size()); for (constauto& [src_path, dst_path] : files_to_move) {
all_files_to_remove.push_back(dst_path);
}
all_files_to_remove.insert(
all_files_to_remove.end(), files_to_remove.begin(), files_to_remove.end());
for (std::string_view original_path : all_files_to_remove) {
std::error_code ec;
std::filesystem::file_status status = std::filesystem::status(original_path, ec); if (!std::filesystem::status_known(status)) { return Errorf("Failed to get status of old file '{}': {}", original_path, ec.message());
} if (std::filesystem::is_directory(status)) { return ErrnoErrorf("Old file '{}' is a directory", original_path);
} if (std::filesystem::exists(status)) {
std::string temp_path = NewFile::BuildTempPath(original_path, "XXXXXX"); int fd = mkstemps(temp_path.data(), /*suffixlen=*/4); if (fd < 0) { return ErrnoErrorf("Failed to create temporary path for old file '{}'", original_path);
}
close(fd);
std::filesystem::rename(original_path, temp_path, ec); if (ec) {
UnlinkIfExists(temp_path); return Errorf("Failed to move old file '{}' to temporary path '{}': {}",
original_path,
temp_path,
ec.message());
}
// Move `files_to_move`. for (constauto& [src_path, dst_path] : files_to_move) {
std::error_code ec;
std::filesystem::rename(src_path, dst_path, ec); if (ec) { return Errorf("Failed to move file from '{}' to '{}': {}", src_path, dst_path, ec.message());
}
committed_files.insert(dst_path);
}
cleanup.Disable();
// Clean up old files. for (constauto& [original_path, temp_path] : moved_files) { // This should never fail. We were able to move the file to `temp_path`. We should be able to // remove it.
UnlinkIfExists(temp_path);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.