blob: e8989490fe2c991ab4985a4ef339fa4e0c140ef1 [file] [log] [blame]
Adam Lesinski00451162017-10-03 07:44:08 -07001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Jeremy Meyerb4f83ff2023-11-30 19:29:50 +000017#include "androidfw/FileStream.h"
Adam Lesinski00451162017-10-03 07:44:08 -070018
19#include <errno.h> // for errno
20#include <fcntl.h> // for O_RDONLY
21#include <unistd.h> // for read
22
23#include "android-base/errors.h"
24#include "android-base/file.h" // for O_BINARY
Jeremy Meyerdeb46f312023-11-08 12:20:24 -080025#include "android-base/logging.h"
Adam Lesinski00451162017-10-03 07:44:08 -070026#include "android-base/macros.h"
27#include "android-base/utf8.h"
28
Adam Lesinskia693c4a2017-11-09 11:29:39 -080029#if defined(_WIN32)
30// This is only needed for O_CLOEXEC.
31#include <windows.h>
32#define O_CLOEXEC O_NOINHERIT
33#endif
34
Adam Lesinski00451162017-10-03 07:44:08 -070035using ::android::base::SystemErrorCodeToString;
Adam Lesinski93190b72017-11-03 15:20:17 -070036using ::android::base::unique_fd;
Adam Lesinski00451162017-10-03 07:44:08 -070037
Jeremy Meyerb4f83ff2023-11-30 19:29:50 +000038namespace android {
Adam Lesinski00451162017-10-03 07:44:08 -070039
40FileInputStream::FileInputStream(const std::string& path, size_t buffer_capacity)
Jeremy Meyerdeb46f312023-11-08 12:20:24 -080041 : should_close_(true), buffer_capacity_(buffer_capacity) {
Adam Lesinskia693c4a2017-11-09 11:29:39 -080042 int mode = O_RDONLY | O_CLOEXEC | O_BINARY;
Jeremy Meyerdeb46f312023-11-08 12:20:24 -080043 fd_ = TEMP_FAILURE_RETRY(::android::base::utf8::open(path.c_str(), mode));
Adam Lesinskia693c4a2017-11-09 11:29:39 -080044 if (fd_ == -1) {
45 error_ = SystemErrorCodeToString(errno);
46 } else {
47 buffer_.reset(new uint8_t[buffer_capacity_]);
48 }
Adam Lesinski00451162017-10-03 07:44:08 -070049}
50
51FileInputStream::FileInputStream(int fd, size_t buffer_capacity)
Jeremy Meyerdeb46f312023-11-08 12:20:24 -080052 : fd_(fd), should_close_(true), buffer_capacity_(buffer_capacity) {
Adam Lesinskia693c4a2017-11-09 11:29:39 -080053 if (fd_ < 0) {
54 error_ = "Bad File Descriptor";
Adam Lesinski00451162017-10-03 07:44:08 -070055 } else {
56 buffer_.reset(new uint8_t[buffer_capacity_]);
57 }
58}
59
Jeremy Meyerdeb46f312023-11-08 12:20:24 -080060FileInputStream::FileInputStream(android::base::borrowed_fd fd, size_t buffer_capacity)
61 : fd_(fd.get()), should_close_(false), buffer_capacity_(buffer_capacity) {
62
63 if (fd_ < 0) {
64 error_ = "Bad File Descriptor";
65 } else {
66 buffer_.reset(new uint8_t[buffer_capacity_]);
67 }
68}
69
70
Adam Lesinski00451162017-10-03 07:44:08 -070071bool FileInputStream::Next(const void** data, size_t* size) {
72 if (HadError()) {
73 return false;
74 }
75
76 // Deal with any remaining bytes after BackUp was called.
77 if (buffer_offset_ != buffer_size_) {
78 *data = buffer_.get() + buffer_offset_;
79 *size = buffer_size_ - buffer_offset_;
80 total_byte_count_ += buffer_size_ - buffer_offset_;
81 buffer_offset_ = buffer_size_;
82 return true;
83 }
84
85 ssize_t n = TEMP_FAILURE_RETRY(read(fd_, buffer_.get(), buffer_capacity_));
86 if (n < 0) {
87 error_ = SystemErrorCodeToString(errno);
Jeremy Meyerdeb46f312023-11-08 12:20:24 -080088 if (fd_ != -1) {
89 if (should_close_) {
90 close(fd_);
91 }
92 fd_ = -1;
93 }
Adam Lesinski00451162017-10-03 07:44:08 -070094 buffer_.reset();
95 return false;
96 }
97
98 buffer_size_ = static_cast<size_t>(n);
99 buffer_offset_ = buffer_size_;
100 total_byte_count_ += buffer_size_;
101
102 *data = buffer_.get();
103 *size = buffer_size_;
104 return buffer_size_ != 0u;
105}
106
107void FileInputStream::BackUp(size_t count) {
108 if (count > buffer_offset_) {
109 count = buffer_offset_;
110 }
111 buffer_offset_ -= count;
112 total_byte_count_ -= count;
113}
114
115size_t FileInputStream::ByteCount() const {
116 return total_byte_count_;
117}
118
119bool FileInputStream::HadError() const {
120 return fd_ == -1;
121}
122
123std::string FileInputStream::GetError() const {
124 return error_;
125}
126
Jeremy Meyerb4f83ff2023-11-30 19:29:50 +0000127bool FileInputStream::ReadFullyAtOffset(void* data, size_t byte_count, off64_t offset) {
128 return base::ReadFullyAtOffset(fd_, data, byte_count, offset);
129}
130
Adam Lesinskia693c4a2017-11-09 11:29:39 -0800131FileOutputStream::FileOutputStream(const std::string& path, size_t buffer_capacity)
132 : buffer_capacity_(buffer_capacity) {
133 int mode = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_BINARY;
134 owned_fd_.reset(TEMP_FAILURE_RETRY(::android::base::utf8::open(path.c_str(), mode, 0666)));
135 fd_ = owned_fd_.get();
136 if (fd_ < 0) {
137 error_ = SystemErrorCodeToString(errno);
138 } else {
139 buffer_.reset(new uint8_t[buffer_capacity_]);
140 }
Adam Lesinski93190b72017-11-03 15:20:17 -0700141}
142
143FileOutputStream::FileOutputStream(unique_fd fd, size_t buffer_capacity)
144 : FileOutputStream(fd.get(), buffer_capacity) {
145 owned_fd_ = std::move(fd);
Adam Lesinski00451162017-10-03 07:44:08 -0700146}
147
148FileOutputStream::FileOutputStream(int fd, size_t buffer_capacity)
Adam Lesinskia693c4a2017-11-09 11:29:39 -0800149 : fd_(fd), buffer_capacity_(buffer_capacity) {
150 if (fd_ < 0) {
151 error_ = "Bad File Descriptor";
Adam Lesinski00451162017-10-03 07:44:08 -0700152 } else {
153 buffer_.reset(new uint8_t[buffer_capacity_]);
154 }
155}
156
157FileOutputStream::~FileOutputStream() {
158 // Flush the buffer.
159 Flush();
160}
161
162bool FileOutputStream::Next(void** data, size_t* size) {
Adam Lesinski93190b72017-11-03 15:20:17 -0700163 if (HadError()) {
Adam Lesinski00451162017-10-03 07:44:08 -0700164 return false;
165 }
166
167 if (buffer_offset_ == buffer_capacity_) {
168 if (!FlushImpl()) {
169 return false;
170 }
171 }
172
173 const size_t buffer_size = buffer_capacity_ - buffer_offset_;
174 *data = buffer_.get() + buffer_offset_;
175 *size = buffer_size;
176 total_byte_count_ += buffer_size;
177 buffer_offset_ = buffer_capacity_;
178 return true;
179}
180
181void FileOutputStream::BackUp(size_t count) {
182 if (count > buffer_offset_) {
183 count = buffer_offset_;
184 }
185 buffer_offset_ -= count;
186 total_byte_count_ -= count;
187}
188
189size_t FileOutputStream::ByteCount() const {
190 return total_byte_count_;
191}
192
193bool FileOutputStream::Flush() {
194 if (!HadError()) {
195 return FlushImpl();
196 }
197 return false;
198}
199
200bool FileOutputStream::FlushImpl() {
201 ssize_t n = TEMP_FAILURE_RETRY(write(fd_, buffer_.get(), buffer_offset_));
202 if (n < 0) {
203 error_ = SystemErrorCodeToString(errno);
Adam Lesinski93190b72017-11-03 15:20:17 -0700204 owned_fd_.reset();
205 fd_ = -1;
Adam Lesinski00451162017-10-03 07:44:08 -0700206 buffer_.reset();
207 return false;
208 }
209
210 buffer_offset_ = 0u;
211 return true;
212}
213
214bool FileOutputStream::HadError() const {
215 return fd_ == -1;
216}
217
218std::string FileOutputStream::GetError() const {
219 return error_;
220}
221
Jeremy Meyerb4f83ff2023-11-30 19:29:50 +0000222} // namespace android