aboutsummaryrefslogtreecommitdiff
path: root/fcp/client/cache/temp_files.cc
diff options
context:
space:
mode:
Diffstat (limited to 'fcp/client/cache/temp_files.cc')
-rw-r--r--fcp/client/cache/temp_files.cc129
1 files changed, 129 insertions, 0 deletions
diff --git a/fcp/client/cache/temp_files.cc b/fcp/client/cache/temp_files.cc
new file mode 100644
index 0000000..1354109
--- /dev/null
+++ b/fcp/client/cache/temp_files.cc
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2022 Google LLC
+ *
+ * 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 "fcp/client/cache/temp_files.h"
+
+#include <sys/file.h>
+#include <unistd.h>
+
+#include <cstdlib>
+#include <filesystem>
+#include <fstream>
+#include <memory>
+#include <string>
+#include <system_error> // NOLINT
+
+#include "fcp/base/monitoring.h"
+#include "fcp/client/diag_codes.pb.h"
+
+namespace fcp {
+namespace client {
+namespace cache {
+namespace {
+
+absl::Status DeleteFilesInDirectory(const std::filesystem::path& directory) {
+ if (!std::filesystem::exists(directory)) {
+ return absl::InvalidArgumentError(
+ absl::StrCat("Directory does not exist: ", directory.string()));
+ }
+ absl::Status status = absl::OkStatus();
+ // Note this only iterates through the top level directory and will not
+ // traverse subdirectories.
+ for (auto& de : std::filesystem::directory_iterator(directory)) {
+ std::error_code error;
+ // Save the first error, but attempt to delete the other files.
+ if (!std::filesystem::remove(de.path(), error)) {
+ if (status.ok()) {
+ status = absl::InternalError(absl::StrCat(
+ "Failed to delete file with error code: ", error.value()));
+ }
+ }
+ }
+ return status;
+}
+
+} // namespace
+
+absl::StatusOr<std::unique_ptr<TempFiles>> TempFiles::Create(
+ const std::string& cache_dir, LogManager* log_manager) {
+ std::filesystem::path root_path(cache_dir);
+ if (!root_path.is_absolute()) {
+ return absl::InvalidArgumentError(
+ absl::StrCat("The provided path: ", cache_dir,
+ "is invalid. The path must start with \"/\""));
+ }
+
+ // Create fcp parent dir in the passed root dir.
+ std::filesystem::path fcp_base_dir = root_path / kParentDir;
+ std::error_code error;
+ std::filesystem::create_directories(fcp_base_dir, error);
+ if (error.value() != 0) {
+ return absl::InternalError(absl::StrCat(
+ "Failed to create TempFiles base directory ",
+ fcp_base_dir.generic_string(), " with error code ", error.value()));
+ }
+
+ // Create directory in parent dir for temporary files.
+ std::filesystem::path temp_files_dir = fcp_base_dir / kTempFilesDir;
+ std::filesystem::create_directories(temp_files_dir, error);
+ if (error.value() != 0) {
+ return absl::InternalError(
+ absl::StrCat("Failed to create TempFiles temp file directory ",
+ temp_files_dir.generic_string()));
+ }
+
+ // We clean up the temp files dir on creation in case we failed to clean it up
+ // during a previous run (i.e. due to the training process getting killed
+ // etc.) and to make sure we don't end up in the pathological case where we
+ // are always crashing partway through training and stranding temp files
+ // because the TempFiles dtor never runs.
+ auto cleanup_status = DeleteFilesInDirectory(temp_files_dir);
+ if (!cleanup_status.ok()) {
+ log_manager->LogDiag(ProdDiagCode::TEMP_FILES_NATIVE_FAILED_TO_DELETE);
+ return cleanup_status;
+ }
+ return absl::WrapUnique(new TempFiles(temp_files_dir, log_manager));
+}
+
+absl::StatusOr<std::string> TempFiles::CreateTempFile(
+ const std::string& prefix, const std::string& suffix) {
+ std::filesystem::path candidate_path;
+ int fd;
+ do {
+ candidate_path = temp_files_dir_ /
+ absl::StrCat(prefix, std::to_string(std::rand()), suffix);
+ } while ((fd = open(candidate_path.c_str(), O_CREAT | O_EXCL | O_RDWR,
+ S_IRWXU)) == -1 &&
+ errno == EEXIST);
+ close(fd);
+ std::ofstream tmp_file(candidate_path);
+ if (!tmp_file) {
+ return absl::InvalidArgumentError(
+ absl::StrCat("could not create file ", candidate_path.string()));
+ }
+
+ return candidate_path.string();
+}
+
+TempFiles::~TempFiles() {
+ if (!DeleteFilesInDirectory(temp_files_dir_).ok()) {
+ log_manager_.LogDiag(ProdDiagCode::TEMP_FILES_NATIVE_FAILED_TO_DELETE);
+ }
+}
+
+} // namespace cache
+} // namespace client
+} // namespace fcp