xref: /aosp_15_r20/external/tink/cc/util/file_input_stream.cc (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
1*e7b1675dSTing-Kang Chang // Copyright 2018 Google Inc.
2*e7b1675dSTing-Kang Chang //
3*e7b1675dSTing-Kang Chang // Licensed under the Apache License, Version 2.0 (the "License");
4*e7b1675dSTing-Kang Chang // you may not use this file except in compliance with the License.
5*e7b1675dSTing-Kang Chang // You may obtain a copy of the License at
6*e7b1675dSTing-Kang Chang //
7*e7b1675dSTing-Kang Chang //     http://www.apache.org/licenses/LICENSE-2.0
8*e7b1675dSTing-Kang Chang //
9*e7b1675dSTing-Kang Chang // Unless required by applicable law or agreed to in writing, software
10*e7b1675dSTing-Kang Chang // distributed under the License is distributed on an "AS IS" BASIS,
11*e7b1675dSTing-Kang Chang // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*e7b1675dSTing-Kang Chang // See the License for the specific language governing permissions and
13*e7b1675dSTing-Kang Chang // limitations under the License.
14*e7b1675dSTing-Kang Chang //
15*e7b1675dSTing-Kang Chang ///////////////////////////////////////////////////////////////////////////////
16*e7b1675dSTing-Kang Chang 
17*e7b1675dSTing-Kang Chang #include "tink/util/file_input_stream.h"
18*e7b1675dSTing-Kang Chang 
19*e7b1675dSTing-Kang Chang #include <unistd.h>
20*e7b1675dSTing-Kang Chang #include <algorithm>
21*e7b1675dSTing-Kang Chang 
22*e7b1675dSTing-Kang Chang #include "absl/status/status.h"
23*e7b1675dSTing-Kang Chang #include "tink/util/errors.h"
24*e7b1675dSTing-Kang Chang #include "tink/util/status.h"
25*e7b1675dSTing-Kang Chang #include "tink/util/statusor.h"
26*e7b1675dSTing-Kang Chang 
27*e7b1675dSTing-Kang Chang namespace crypto {
28*e7b1675dSTing-Kang Chang namespace tink {
29*e7b1675dSTing-Kang Chang namespace util {
30*e7b1675dSTing-Kang Chang namespace {
31*e7b1675dSTing-Kang Chang 
32*e7b1675dSTing-Kang Chang constexpr int kDefaultBufferSize = 128 * 1024;
33*e7b1675dSTing-Kang Chang 
34*e7b1675dSTing-Kang Chang // Attempts to close file descriptor fd, while ignoring EINTR.
35*e7b1675dSTing-Kang Chang // (code borrowed from ZeroCopy-streams)
close_ignoring_eintr(int fd)36*e7b1675dSTing-Kang Chang int close_ignoring_eintr(int fd) {
37*e7b1675dSTing-Kang Chang   int result;
38*e7b1675dSTing-Kang Chang   do {
39*e7b1675dSTing-Kang Chang     result = close(fd);
40*e7b1675dSTing-Kang Chang   } while (result < 0 && errno == EINTR);
41*e7b1675dSTing-Kang Chang   return result;
42*e7b1675dSTing-Kang Chang }
43*e7b1675dSTing-Kang Chang 
44*e7b1675dSTing-Kang Chang // Attempts to read 'count' bytes of data data from file descriptor fd
45*e7b1675dSTing-Kang Chang // to 'buf' while ignoring EINTR.
read_ignoring_eintr(int fd,void * buf,size_t count)46*e7b1675dSTing-Kang Chang int read_ignoring_eintr(int fd, void *buf, size_t count) {
47*e7b1675dSTing-Kang Chang   int result;
48*e7b1675dSTing-Kang Chang   do {
49*e7b1675dSTing-Kang Chang     result = read(fd, buf, count);
50*e7b1675dSTing-Kang Chang   } while (result < 0 && errno == EINTR);
51*e7b1675dSTing-Kang Chang   return result;
52*e7b1675dSTing-Kang Chang }
53*e7b1675dSTing-Kang Chang 
54*e7b1675dSTing-Kang Chang }  // anonymous namespace
55*e7b1675dSTing-Kang Chang 
FileInputStream(int file_descriptor,int buffer_size)56*e7b1675dSTing-Kang Chang FileInputStream::FileInputStream(int file_descriptor, int buffer_size)
57*e7b1675dSTing-Kang Chang     : status_(util::OkStatus()),
58*e7b1675dSTing-Kang Chang       fd_(file_descriptor),
59*e7b1675dSTing-Kang Chang       buffer_(buffer_size > 0 ? buffer_size : kDefaultBufferSize) {}
60*e7b1675dSTing-Kang Chang 
Next(const void ** data)61*e7b1675dSTing-Kang Chang util::StatusOr<int> FileInputStream::Next(const void** data) {
62*e7b1675dSTing-Kang Chang   if (data == nullptr) {
63*e7b1675dSTing-Kang Chang     return util::Status(absl::StatusCode::kInvalidArgument,
64*e7b1675dSTing-Kang Chang                         "Data pointer must not be nullptr");
65*e7b1675dSTing-Kang Chang   }
66*e7b1675dSTing-Kang Chang   if (!status_.ok()) return status_;
67*e7b1675dSTing-Kang Chang   if (count_backedup_ > 0) {  // Return the backed-up bytes.
68*e7b1675dSTing-Kang Chang     buffer_offset_ = buffer_offset_ + (count_in_buffer_ - count_backedup_);
69*e7b1675dSTing-Kang Chang     count_in_buffer_ = count_backedup_;
70*e7b1675dSTing-Kang Chang     count_backedup_ = 0;
71*e7b1675dSTing-Kang Chang     *data = buffer_.data() + buffer_offset_;
72*e7b1675dSTing-Kang Chang     position_ = position_ + count_in_buffer_;
73*e7b1675dSTing-Kang Chang     return count_in_buffer_;
74*e7b1675dSTing-Kang Chang   }
75*e7b1675dSTing-Kang Chang   // Read new bytes to buffer_.
76*e7b1675dSTing-Kang Chang   int read_result = read_ignoring_eintr(fd_, buffer_.data(), buffer_.size());
77*e7b1675dSTing-Kang Chang   if (read_result <= 0) {  // EOF or an I/O error.
78*e7b1675dSTing-Kang Chang     if (read_result == 0) {
79*e7b1675dSTing-Kang Chang       status_ = Status(absl::StatusCode::kOutOfRange, "EOF");
80*e7b1675dSTing-Kang Chang     } else {
81*e7b1675dSTing-Kang Chang       status_ =
82*e7b1675dSTing-Kang Chang           ToStatusF(absl::StatusCode::kInternal, "I/O error: %d", read_result);
83*e7b1675dSTing-Kang Chang     }
84*e7b1675dSTing-Kang Chang     return status_;
85*e7b1675dSTing-Kang Chang   }
86*e7b1675dSTing-Kang Chang   buffer_offset_ = 0;
87*e7b1675dSTing-Kang Chang   count_backedup_ = 0;
88*e7b1675dSTing-Kang Chang   count_in_buffer_ = read_result;
89*e7b1675dSTing-Kang Chang   position_ = position_ + count_in_buffer_;
90*e7b1675dSTing-Kang Chang   *data = buffer_.data();
91*e7b1675dSTing-Kang Chang   return count_in_buffer_;
92*e7b1675dSTing-Kang Chang }
93*e7b1675dSTing-Kang Chang 
BackUp(int count)94*e7b1675dSTing-Kang Chang void FileInputStream::BackUp(int count) {
95*e7b1675dSTing-Kang Chang   if (!status_.ok() || count < 1 || count_backedup_ == count_in_buffer_) return;
96*e7b1675dSTing-Kang Chang   int actual_count = std::min(count, count_in_buffer_ - count_backedup_);
97*e7b1675dSTing-Kang Chang   count_backedup_ = count_backedup_ + actual_count;
98*e7b1675dSTing-Kang Chang   position_ = position_ - actual_count;
99*e7b1675dSTing-Kang Chang }
100*e7b1675dSTing-Kang Chang 
~FileInputStream()101*e7b1675dSTing-Kang Chang FileInputStream::~FileInputStream() { close_ignoring_eintr(fd_); }
102*e7b1675dSTing-Kang Chang 
Position() const103*e7b1675dSTing-Kang Chang int64_t FileInputStream::Position() const { return position_; }
104*e7b1675dSTing-Kang Chang 
105*e7b1675dSTing-Kang Chang }  // namespace util
106*e7b1675dSTing-Kang Chang }  // namespace tink
107*e7b1675dSTing-Kang Chang }  // namespace crypto
108