xref: /aosp_15_r20/frameworks/base/libs/androidfw/FileStream.cpp (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
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