xref: /aosp_15_r20/external/tink/cc/util/file_input_stream.cc (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
1 // Copyright 2018 Google Inc.
2 //
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 //     http://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 
17 #include "tink/util/file_input_stream.h"
18 
19 #include <unistd.h>
20 #include <algorithm>
21 
22 #include "absl/status/status.h"
23 #include "tink/util/errors.h"
24 #include "tink/util/status.h"
25 #include "tink/util/statusor.h"
26 
27 namespace crypto {
28 namespace tink {
29 namespace util {
30 namespace {
31 
32 constexpr int kDefaultBufferSize = 128 * 1024;
33 
34 // Attempts to close file descriptor fd, while ignoring EINTR.
35 // (code borrowed from ZeroCopy-streams)
close_ignoring_eintr(int fd)36 int close_ignoring_eintr(int fd) {
37   int result;
38   do {
39     result = close(fd);
40   } while (result < 0 && errno == EINTR);
41   return result;
42 }
43 
44 // Attempts to read 'count' bytes of data data from file descriptor fd
45 // to 'buf' while ignoring EINTR.
read_ignoring_eintr(int fd,void * buf,size_t count)46 int read_ignoring_eintr(int fd, void *buf, size_t count) {
47   int result;
48   do {
49     result = read(fd, buf, count);
50   } while (result < 0 && errno == EINTR);
51   return result;
52 }
53 
54 }  // anonymous namespace
55 
FileInputStream(int file_descriptor,int buffer_size)56 FileInputStream::FileInputStream(int file_descriptor, int buffer_size)
57     : status_(util::OkStatus()),
58       fd_(file_descriptor),
59       buffer_(buffer_size > 0 ? buffer_size : kDefaultBufferSize) {}
60 
Next(const void ** data)61 util::StatusOr<int> FileInputStream::Next(const void** data) {
62   if (data == nullptr) {
63     return util::Status(absl::StatusCode::kInvalidArgument,
64                         "Data pointer must not be nullptr");
65   }
66   if (!status_.ok()) return status_;
67   if (count_backedup_ > 0) {  // Return the backed-up bytes.
68     buffer_offset_ = buffer_offset_ + (count_in_buffer_ - count_backedup_);
69     count_in_buffer_ = count_backedup_;
70     count_backedup_ = 0;
71     *data = buffer_.data() + buffer_offset_;
72     position_ = position_ + count_in_buffer_;
73     return count_in_buffer_;
74   }
75   // Read new bytes to buffer_.
76   int read_result = read_ignoring_eintr(fd_, buffer_.data(), buffer_.size());
77   if (read_result <= 0) {  // EOF or an I/O error.
78     if (read_result == 0) {
79       status_ = Status(absl::StatusCode::kOutOfRange, "EOF");
80     } else {
81       status_ =
82           ToStatusF(absl::StatusCode::kInternal, "I/O error: %d", read_result);
83     }
84     return status_;
85   }
86   buffer_offset_ = 0;
87   count_backedup_ = 0;
88   count_in_buffer_ = read_result;
89   position_ = position_ + count_in_buffer_;
90   *data = buffer_.data();
91   return count_in_buffer_;
92 }
93 
BackUp(int count)94 void FileInputStream::BackUp(int count) {
95   if (!status_.ok() || count < 1 || count_backedup_ == count_in_buffer_) return;
96   int actual_count = std::min(count, count_in_buffer_ - count_backedup_);
97   count_backedup_ = count_backedup_ + actual_count;
98   position_ = position_ - actual_count;
99 }
100 
~FileInputStream()101 FileInputStream::~FileInputStream() { close_ignoring_eintr(fd_); }
102 
Position() const103 int64_t FileInputStream::Position() const { return position_; }
104 
105 }  // namespace util
106 }  // namespace tink
107 }  // namespace crypto
108