1 /*
2 * Copyright 2019 Google LLC.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * https://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <limits.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19
20 #include "absl/strings/str_cat.h"
21 #include "private_join_and_compute/util/file.h"
22 #include "private_join_and_compute/util/status.inc"
23
24 namespace private_join_and_compute {
25 namespace {
26
27 class PosixFile : public File {
28 public:
PosixFile()29 PosixFile() : File(), f_(nullptr), current_fname_() {}
30
~PosixFile()31 ~PosixFile() override {
32 if (f_) Close().IgnoreError();
33 }
34
Open(absl::string_view file_name,absl::string_view mode)35 Status Open(absl::string_view file_name, absl::string_view mode) final {
36 if (nullptr != f_) {
37 return InternalError(
38 absl::StrCat("Open failed:", "File with name ", current_fname_,
39 " has already been opened, close it first."));
40 }
41 f_ = fopen(file_name.data(), mode.data());
42 if (nullptr == f_) {
43 return absl::NotFoundError(
44 absl::StrCat("Open failed:", "Error opening file ", file_name));
45 }
46 current_fname_ = std::string(file_name);
47 return OkStatus();
48 }
49
Close()50 Status Close() final {
51 if (nullptr == f_) {
52 return InternalError(
53 absl::StrCat("Close failed:", "There is no opened file."));
54 }
55 if (fclose(f_)) {
56 return InternalError(
57 absl::StrCat("Close failed:", "Error closing file ", current_fname_));
58 }
59 f_ = nullptr;
60 return OkStatus();
61 }
62
HasMore()63 StatusOr<bool> HasMore() final {
64 if (nullptr == f_) {
65 return InternalError(
66 absl::StrCat("HasMore failed:", "There is no opened file."));
67 }
68 if (feof(f_)) return false;
69 if (ferror(f_)) {
70 return InternalError(absl::StrCat(
71 "HasMore failed:", "Error indicator has been set for file ",
72 current_fname_));
73 }
74 int c = getc(f_);
75 if (ferror(f_)) {
76 return InternalError(absl::StrCat(
77 "HasMore failed:", "Error reading a single character from the file ",
78 current_fname_));
79 }
80 if (ungetc(c, f_) != c) {
81 return InternalError(absl::StrCat(
82 "HasMore failed:", "Error putting back the peeked character ",
83 "into the file ", current_fname_));
84 }
85 return c != EOF;
86 }
87
Read(size_t length)88 StatusOr<std::string> Read(size_t length) final {
89 if (nullptr == f_) {
90 return InternalError(
91 absl::StrCat("Read failed:", "There is no opened file."));
92 }
93 std::vector<char> data(length);
94 if (fread(data.data(), 1, length, f_) != length) {
95 return InternalError(absl::StrCat(
96 "condition failed:", "Error reading the file ", current_fname_));
97 }
98 return std::string(data.begin(), data.end());
99 }
100
ReadLine()101 StatusOr<std::string> ReadLine() final {
102 if (nullptr == f_) {
103 return InternalError(
104 absl::StrCat("ReadLine failed:", "There is no opened file."));
105 }
106 if (fgets(buffer_, LINE_MAX, f_) == nullptr || ferror(f_)) {
107 return InternalError(
108 absl::StrCat("ReadLine failed:", "Error reading line from the file ",
109 current_fname_));
110 }
111 std::string content;
112 int len = strlen(buffer_);
113 // Remove trailing '\n' if present.
114 if (len > 0 && buffer_[len - 1] == '\n') {
115 // Remove trailing '\r' if present (e.g. on Windows)
116 if (len > 1 && buffer_[len - 2] == '\r') {
117 content.append(buffer_, len - 2);
118 } else {
119 content.append(buffer_, len - 1);
120 }
121 } else {
122 // No trailing newline characters
123 content.append(buffer_, len);
124 }
125 return content;
126 }
127
Write(absl::string_view content,size_t length)128 Status Write(absl::string_view content, size_t length) final {
129 if (nullptr == f_) {
130 return InternalError(
131 absl::StrCat("ReadLine failed:", "There is no opened file."));
132 }
133 if (fwrite(content.data(), 1, length, f_) != length) {
134 return InternalError(absl::StrCat(
135 "ReadLine failed:", "Error writing the given data into the file ",
136 current_fname_));
137 }
138 return OkStatus();
139 }
140
141 private:
142 FILE* f_;
143 std::string current_fname_;
144 char buffer_[LINE_MAX];
145 };
146
147 } // namespace
148
GetFile()149 File* File::GetFile() { return new PosixFile(); }
150
RenameFile(absl::string_view from,absl::string_view to)151 Status RenameFile(absl::string_view from, absl::string_view to) {
152 if (0 != rename(from.data(), to.data())) {
153 return InternalError(absl::StrCat(
154 "RenameFile failed:", "Cannot rename file, ", from, " to file, ", to));
155 }
156 return OkStatus();
157 }
158
DeleteFile(absl::string_view file_name)159 Status DeleteFile(absl::string_view file_name) {
160 if (0 != remove(file_name.data())) {
161 return InternalError(
162 absl::StrCat("DeleteFile failed:", "Cannot delete file, ", file_name));
163 }
164 return OkStatus();
165 }
166
167 } // namespace private_join_and_compute
168