xref: /aosp_15_r20/external/tink/cc/util/file_random_access_stream.cc (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
1 // Copyright 2019 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_random_access_stream.h"
18 
19 #include <sys/stat.h>
20 #include <unistd.h>
21 #include <algorithm>
22 
23 #include "absl/memory/memory.h"
24 #include "absl/status/status.h"
25 #include "tink/random_access_stream.h"
26 #include "tink/util/buffer.h"
27 #include "tink/util/errors.h"
28 #include "tink/util/status.h"
29 #include "tink/util/statusor.h"
30 
31 namespace crypto {
32 namespace tink {
33 namespace util {
34 
35 using crypto::tink::util::Status;
36 using crypto::tink::util::StatusOr;
37 
38 namespace {
39 
40 // Attempts to close file descriptor fd, while ignoring EINTR.
41 // (code borrowed from ZeroCopy-streams)
close_ignoring_eintr(int fd)42 int close_ignoring_eintr(int fd) {
43   int result;
44   do {
45     result = close(fd);
46   } while (result < 0 && errno == EINTR);
47   return result;
48 }
49 
50 }  // anonymous namespace
51 
FileRandomAccessStream(int file_descriptor)52 FileRandomAccessStream::FileRandomAccessStream(int file_descriptor) {
53   fd_ = file_descriptor;
54 }
55 
PRead(int64_t position,int count,Buffer * dest_buffer)56 Status FileRandomAccessStream::PRead(int64_t position, int count,
57                                      Buffer* dest_buffer) {
58   if (dest_buffer == nullptr) {
59     return util::Status(absl::StatusCode::kInvalidArgument,
60                         "dest_buffer must be non-null");
61   }
62   if (count <= 0) {
63     return util::Status(absl::StatusCode::kInvalidArgument,
64                         "count must be positive");
65   }
66   if (count > dest_buffer->allocated_size()) {
67     return util::Status(absl::StatusCode::kInvalidArgument, "buffer too small");
68   }
69   if (position < 0) {
70     return util::Status(absl::StatusCode::kInvalidArgument,
71                         "position cannot be negative");
72   }
73   crypto::tink::util::Status status = dest_buffer->set_size(count);
74   if (!status.ok()) return status;
75   int read_count = pread(fd_, dest_buffer->get_mem_block(), count, position);
76   if (read_count == 0) {
77     dest_buffer->set_size(0).IgnoreError();
78     return Status(absl::StatusCode::kOutOfRange, "EOF");
79   }
80   if (read_count < 0) {
81     dest_buffer->set_size(0).IgnoreError();
82     return ToStatusF(absl::StatusCode::kUnknown, "I/O error: %d", errno);
83   }
84   status = dest_buffer->set_size(read_count);
85   if (!status.ok()) return status;
86   return util::OkStatus();
87 }
88 
~FileRandomAccessStream()89 FileRandomAccessStream::~FileRandomAccessStream() {
90   close_ignoring_eintr(fd_);
91 }
92 
size()93 StatusOr<int64_t> FileRandomAccessStream::size() {
94   struct stat s;
95   if (fstat(fd_, &s) == -1) {
96     return Status(absl::StatusCode::kUnavailable, "size unavailable");
97   } else {
98     return s.st_size;
99   }
100 }
101 
102 }  // namespace util
103 }  // namespace tink
104 }  // namespace crypto
105