/* * Copyright 2019 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 * * https://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 "absl/strings/str_cat.h" #include "private_join_and_compute/util/file.h" #include "private_join_and_compute/util/status.inc" namespace private_join_and_compute { namespace { class PosixFile : public File { public: PosixFile() : File(), f_(nullptr), current_fname_() {} ~PosixFile() override { if (f_) Close().IgnoreError(); } Status Open(absl::string_view file_name, absl::string_view mode) final { if (nullptr != f_) { return InternalError( absl::StrCat("Open failed:", "File with name ", current_fname_, " has already been opened, close it first.")); } f_ = fopen(file_name.data(), mode.data()); if (nullptr == f_) { return absl::NotFoundError( absl::StrCat("Open failed:", "Error opening file ", file_name)); } current_fname_ = std::string(file_name); return OkStatus(); } Status Close() final { if (nullptr == f_) { return InternalError( absl::StrCat("Close failed:", "There is no opened file.")); } if (fclose(f_)) { return InternalError( absl::StrCat("Close failed:", "Error closing file ", current_fname_)); } f_ = nullptr; return OkStatus(); } StatusOr HasMore() final { if (nullptr == f_) { return InternalError( absl::StrCat("HasMore failed:", "There is no opened file.")); } if (feof(f_)) return false; if (ferror(f_)) { return InternalError(absl::StrCat( "HasMore failed:", "Error indicator has been set for file ", current_fname_)); } int c = getc(f_); if (ferror(f_)) { return InternalError(absl::StrCat( "HasMore failed:", "Error reading a single character from the file ", current_fname_)); } if (ungetc(c, f_) != c) { return InternalError(absl::StrCat( "HasMore failed:", "Error putting back the peeked character ", "into the file ", current_fname_)); } return c != EOF; } StatusOr Read(size_t length) final { if (nullptr == f_) { return InternalError( absl::StrCat("Read failed:", "There is no opened file.")); } std::vector data(length); if (fread(data.data(), 1, length, f_) != length) { return InternalError(absl::StrCat( "condition failed:", "Error reading the file ", current_fname_)); } return std::string(data.begin(), data.end()); } StatusOr ReadLine() final { if (nullptr == f_) { return InternalError( absl::StrCat("ReadLine failed:", "There is no opened file.")); } if (fgets(buffer_, LINE_MAX, f_) == nullptr || ferror(f_)) { return InternalError( absl::StrCat("ReadLine failed:", "Error reading line from the file ", current_fname_)); } std::string content; int len = strlen(buffer_); // Remove trailing '\n' if present. if (len > 0 && buffer_[len - 1] == '\n') { // Remove trailing '\r' if present (e.g. on Windows) if (len > 1 && buffer_[len - 2] == '\r') { content.append(buffer_, len - 2); } else { content.append(buffer_, len - 1); } } else { // No trailing newline characters content.append(buffer_, len); } return content; } Status Write(absl::string_view content, size_t length) final { if (nullptr == f_) { return InternalError( absl::StrCat("ReadLine failed:", "There is no opened file.")); } if (fwrite(content.data(), 1, length, f_) != length) { return InternalError(absl::StrCat( "ReadLine failed:", "Error writing the given data into the file ", current_fname_)); } return OkStatus(); } private: FILE* f_; std::string current_fname_; char buffer_[LINE_MAX]; }; } // namespace File* File::GetFile() { return new PosixFile(); } Status RenameFile(absl::string_view from, absl::string_view to) { if (0 != rename(from.data(), to.data())) { return InternalError(absl::StrCat( "RenameFile failed:", "Cannot rename file, ", from, " to file, ", to)); } return OkStatus(); } Status DeleteFile(absl::string_view file_name) { if (0 != remove(file_name.data())) { return InternalError( absl::StrCat("DeleteFile failed:", "Cannot delete file, ", file_name)); } return OkStatus(); } } // namespace private_join_and_compute