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 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 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 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 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 99 size_t FileInputStream::ByteCount() const { 100 return total_byte_count_; 101 } 102 103 bool FileInputStream::HadError() const { 104 return fd_ == -1; 105 } 106 107 std::string FileInputStream::GetError() const { 108 return error_; 109 } 110 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 123 FileOutputStream::FileOutputStream(unique_fd fd, size_t buffer_capacity) 124 : FileOutputStream(fd.get(), buffer_capacity) { 125 owned_fd_ = std::move(fd); 126 } 127 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 137 FileOutputStream::~FileOutputStream() { 138 // Flush the buffer. 139 Flush(); 140 } 141 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 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 169 size_t FileOutputStream::ByteCount() const { 170 return total_byte_count_; 171 } 172 173 bool FileOutputStream::Flush() { 174 if (!HadError()) { 175 return FlushImpl(); 176 } 177 return false; 178 } 179 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 194 bool FileOutputStream::HadError() const { 195 return fd_ == -1; 196 } 197 198 std::string FileOutputStream::GetError() const { 199 return error_; 200 } 201 202 } // namespace io 203 } // namespace aapt 204