blob: c8386eec1567889a58777901750fa83012363028 [file] [log] [blame]
/*
* 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 <limits.h>
#include <stdio.h>
#include <stdlib.h>
#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<bool> 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<std::string> Read(size_t length) final {
if (nullptr == f_) {
return InternalError(
absl::StrCat("Read failed:", "There is no opened file."));
}
std::vector<char> 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<std::string> 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