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 "io/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/macros.h"
26 #include "android-base/utf8.h"
27 
28 #if defined(_WIN32)
29 // This is only needed for O_CLOEXEC.
30 #include <windows.h>
31 #define O_CLOEXEC O_NOINHERIT
32 #endif
33 
34 using ::android::base::SystemErrorCodeToString;
35 using ::android::base::unique_fd;
36 
37 namespace aapt {
38 namespace io {
39 
FileInputStream(const std::string & path,size_t buffer_capacity)40 FileInputStream::FileInputStream(const std::string& path, size_t buffer_capacity)
41     : buffer_capacity_(buffer_capacity) {
42   int mode = O_RDONLY | O_CLOEXEC | O_BINARY;
43   fd_.reset(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), 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 
Next(const void ** data,size_t * size)60 bool FileInputStream::Next(const void** data, size_t* size) {
61   if (HadError()) {
62     return false;
63   }
64 
65   // Deal with any remaining bytes after BackUp was called.
66   if (buffer_offset_ != buffer_size_) {
67     *data = buffer_.get() + buffer_offset_;
68     *size = buffer_size_ - buffer_offset_;
69     total_byte_count_ += buffer_size_ - buffer_offset_;
70     buffer_offset_ = buffer_size_;
71     return true;
72   }
73 
74   ssize_t n = TEMP_FAILURE_RETRY(read(fd_, buffer_.get(), buffer_capacity_));
75   if (n < 0) {
76     error_ = SystemErrorCodeToString(errno);
77     fd_.reset();
78     buffer_.reset();
79     return false;
80   }
81 
82   buffer_size_ = static_cast<size_t>(n);
83   buffer_offset_ = buffer_size_;
84   total_byte_count_ += buffer_size_;
85 
86   *data = buffer_.get();
87   *size = buffer_size_;
88   return buffer_size_ != 0u;
89 }
90 
BackUp(size_t count)91 void FileInputStream::BackUp(size_t count) {
92   if (count > buffer_offset_) {
93     count = buffer_offset_;
94   }
95   buffer_offset_ -= count;
96   total_byte_count_ -= count;
97 }
98 
ByteCount() const99 size_t FileInputStream::ByteCount() const {
100   return total_byte_count_;
101 }
102 
HadError() const103 bool FileInputStream::HadError() const {
104   return fd_ == -1;
105 }
106 
GetError() const107 std::string FileInputStream::GetError() const {
108   return error_;
109 }
110 
FileOutputStream(const std::string & path,size_t buffer_capacity)111 FileOutputStream::FileOutputStream(const std::string& path, size_t buffer_capacity)
112     : buffer_capacity_(buffer_capacity) {
113   int mode = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_BINARY;
114   owned_fd_.reset(TEMP_FAILURE_RETRY(::android::base::utf8::open(path.c_str(), mode, 0666)));
115   fd_ = owned_fd_.get();
116   if (fd_ < 0) {
117     error_ = SystemErrorCodeToString(errno);
118   } else {
119     buffer_.reset(new uint8_t[buffer_capacity_]);
120   }
121 }
122 
FileOutputStream(unique_fd fd,size_t buffer_capacity)123 FileOutputStream::FileOutputStream(unique_fd fd, size_t buffer_capacity)
124     : FileOutputStream(fd.get(), buffer_capacity) {
125   owned_fd_ = std::move(fd);
126 }
127 
FileOutputStream(int fd,size_t buffer_capacity)128 FileOutputStream::FileOutputStream(int fd, size_t buffer_capacity)
129     : fd_(fd), buffer_capacity_(buffer_capacity) {
130   if (fd_ < 0) {
131     error_ = "Bad File Descriptor";
132   } else {
133     buffer_.reset(new uint8_t[buffer_capacity_]);
134   }
135 }
136 
~FileOutputStream()137 FileOutputStream::~FileOutputStream() {
138   // Flush the buffer.
139   Flush();
140 }
141 
Next(void ** data,size_t * size)142 bool FileOutputStream::Next(void** data, size_t* size) {
143   if (HadError()) {
144     return false;
145   }
146 
147   if (buffer_offset_ == buffer_capacity_) {
148     if (!FlushImpl()) {
149       return false;
150     }
151   }
152 
153   const size_t buffer_size = buffer_capacity_ - buffer_offset_;
154   *data = buffer_.get() + buffer_offset_;
155   *size = buffer_size;
156   total_byte_count_ += buffer_size;
157   buffer_offset_ = buffer_capacity_;
158   return true;
159 }
160 
BackUp(size_t count)161 void FileOutputStream::BackUp(size_t count) {
162   if (count > buffer_offset_) {
163     count = buffer_offset_;
164   }
165   buffer_offset_ -= count;
166   total_byte_count_ -= count;
167 }
168 
ByteCount() const169 size_t FileOutputStream::ByteCount() const {
170   return total_byte_count_;
171 }
172 
Flush()173 bool FileOutputStream::Flush() {
174   if (!HadError()) {
175     return FlushImpl();
176   }
177   return false;
178 }
179 
FlushImpl()180 bool FileOutputStream::FlushImpl() {
181   ssize_t n = TEMP_FAILURE_RETRY(write(fd_, buffer_.get(), buffer_offset_));
182   if (n < 0) {
183     error_ = SystemErrorCodeToString(errno);
184     owned_fd_.reset();
185     fd_ = -1;
186     buffer_.reset();
187     return false;
188   }
189 
190   buffer_offset_ = 0u;
191   return true;
192 }
193 
HadError() const194 bool FileOutputStream::HadError() const {
195   return fd_ == -1;
196 }
197 
GetError() const198 std::string FileOutputStream::GetError() const {
199   return error_;
200 }
201 
202 }  // namespace io
203 }  // namespace aapt
204