1 /*
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
17 #include "androidfw/FileStream.h"
18
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
25 #include "android-base/logging.h"
26 #include "android-base/macros.h"
27 #include "android-base/utf8.h"
28
29 #if defined(_WIN32)
30 // This is only needed for O_CLOEXEC.
31 #include <windows.h>
32 #define O_CLOEXEC O_NOINHERIT
33 #endif
34
35 using ::android::base::SystemErrorCodeToString;
36 using ::android::base::unique_fd;
37
38 namespace android {
39
FileInputStream(const std::string & path,size_t buffer_capacity)40 FileInputStream::FileInputStream(const std::string& path, size_t buffer_capacity)
41 : should_close_(true), buffer_capacity_(buffer_capacity) {
42 int mode = O_RDONLY | O_CLOEXEC | O_BINARY;
43 fd_ = TEMP_FAILURE_RETRY(::android::base::utf8::open(path.c_str(), mode));
44 if (fd_ == -1) {
45 error_ = SystemErrorCodeToString(errno);
46 } else {
47 buffer_.reset(new uint8_t[buffer_capacity_]);
48 }
49 }
50
FileInputStream(int fd,size_t buffer_capacity)51 FileInputStream::FileInputStream(int fd, size_t buffer_capacity)
52 : fd_(fd), should_close_(true), buffer_capacity_(buffer_capacity) {
53 if (fd_ < 0) {
54 error_ = "Bad File Descriptor";
55 } else {
56 buffer_.reset(new uint8_t[buffer_capacity_]);
57 }
58 }
59
FileInputStream(android::base::borrowed_fd fd,size_t buffer_capacity)60 FileInputStream::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
Next(const void ** data,size_t * size)71 bool 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);
88 if (fd_ != -1) {
89 if (should_close_) {
90 close(fd_);
91 }
92 fd_ = -1;
93 }
94 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
BackUp(size_t count)107 void 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
ByteCount() const115 size_t FileInputStream::ByteCount() const {
116 return total_byte_count_;
117 }
118
HadError() const119 bool FileInputStream::HadError() const {
120 return fd_ == -1;
121 }
122
GetError() const123 std::string FileInputStream::GetError() const {
124 return error_;
125 }
126
ReadFullyAtOffset(void * data,size_t byte_count,off64_t offset)127 bool FileInputStream::ReadFullyAtOffset(void* data, size_t byte_count, off64_t offset) {
128 return base::ReadFullyAtOffset(fd_, data, byte_count, offset);
129 }
130
FileOutputStream(const std::string & path,size_t buffer_capacity)131 FileOutputStream::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 }
141 }
142
FileOutputStream(unique_fd fd,size_t buffer_capacity)143 FileOutputStream::FileOutputStream(unique_fd fd, size_t buffer_capacity)
144 : FileOutputStream(fd.get(), buffer_capacity) {
145 owned_fd_ = std::move(fd);
146 }
147
FileOutputStream(int fd,size_t buffer_capacity)148 FileOutputStream::FileOutputStream(int fd, size_t buffer_capacity)
149 : fd_(fd), buffer_capacity_(buffer_capacity) {
150 if (fd_ < 0) {
151 error_ = "Bad File Descriptor";
152 } else {
153 buffer_.reset(new uint8_t[buffer_capacity_]);
154 }
155 }
156
~FileOutputStream()157 FileOutputStream::~FileOutputStream() {
158 // Flush the buffer.
159 Flush();
160 }
161
Next(void ** data,size_t * size)162 bool FileOutputStream::Next(void** data, size_t* size) {
163 if (HadError()) {
164 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
BackUp(size_t count)181 void 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
ByteCount() const189 size_t FileOutputStream::ByteCount() const {
190 return total_byte_count_;
191 }
192
Flush()193 bool FileOutputStream::Flush() {
194 if (!HadError()) {
195 return FlushImpl();
196 }
197 return false;
198 }
199
FlushImpl()200 bool FileOutputStream::FlushImpl() {
201 ssize_t n = TEMP_FAILURE_RETRY(write(fd_, buffer_.get(), buffer_offset_));
202 if (n < 0) {
203 error_ = SystemErrorCodeToString(errno);
204 owned_fd_.reset();
205 fd_ = -1;
206 buffer_.reset();
207 return false;
208 }
209
210 buffer_offset_ = 0u;
211 return true;
212 }
213
HadError() const214 bool FileOutputStream::HadError() const {
215 return fd_ == -1;
216 }
217
GetError() const218 std::string FileOutputStream::GetError() const {
219 return error_;
220 }
221
222 } // namespace android
223