xref: /aosp_15_r20/external/private-join-and-compute/private_join_and_compute/util/file_posix.cc (revision a6aa18fbfbf9cb5cd47356a9d1b057768998488c)
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