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