Home | History | Annotate | Download | only in io
      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