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