blob: b86c9cb729d40be7d85165fa2aedd8fde259326a [file] [log] [blame]
Adam Lesinski00451162017-10-03 07:44:08 -07001/*
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
Jeremy Meyerb4f83ff2023-11-30 19:29:50 +000017#include "androidfw/FileStream.h"
Adam Lesinski00451162017-10-03 07:44:08 -070018
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
Adam Lesinskia693c4a2017-11-09 11:29:39 -080028#if defined(_WIN32)
29// This is only needed for O_CLOEXEC.
30#include <windows.h>
31#define O_CLOEXEC O_NOINHERIT
32#endif
33
Adam Lesinski00451162017-10-03 07:44:08 -070034using ::android::base::SystemErrorCodeToString;
Adam Lesinski93190b72017-11-03 15:20:17 -070035using ::android::base::unique_fd;
Adam Lesinski00451162017-10-03 07:44:08 -070036
Jeremy Meyerb4f83ff2023-11-30 19:29:50 +000037namespace android {
Adam Lesinski00451162017-10-03 07:44:08 -070038
39FileInputStream::FileInputStream(const std::string& path, size_t buffer_capacity)
Adam Lesinskia693c4a2017-11-09 11:29:39 -080040 : buffer_capacity_(buffer_capacity) {
41 int mode = O_RDONLY | O_CLOEXEC | O_BINARY;
42 fd_.reset(TEMP_FAILURE_RETRY(::android::base::utf8::open(path.c_str(), mode)));
43 if (fd_ == -1) {
44 error_ = SystemErrorCodeToString(errno);
45 } else {
46 buffer_.reset(new uint8_t[buffer_capacity_]);
47 }
Adam Lesinski00451162017-10-03 07:44:08 -070048}
49
50FileInputStream::FileInputStream(int fd, size_t buffer_capacity)
Adam Lesinskia693c4a2017-11-09 11:29:39 -080051 : fd_(fd), buffer_capacity_(buffer_capacity) {
52 if (fd_ < 0) {
53 error_ = "Bad File Descriptor";
Adam Lesinski00451162017-10-03 07:44:08 -070054 } else {
55 buffer_.reset(new uint8_t[buffer_capacity_]);
56 }
57}
58
59bool FileInputStream::Next(const void** data, size_t* size) {
60 if (HadError()) {
61 return false;
62 }
63
64 // Deal with any remaining bytes after BackUp was called.
65 if (buffer_offset_ != buffer_size_) {
66 *data = buffer_.get() + buffer_offset_;
67 *size = buffer_size_ - buffer_offset_;
68 total_byte_count_ += buffer_size_ - buffer_offset_;
69 buffer_offset_ = buffer_size_;
70 return true;
71 }
72
73 ssize_t n = TEMP_FAILURE_RETRY(read(fd_, buffer_.get(), buffer_capacity_));
74 if (n < 0) {
75 error_ = SystemErrorCodeToString(errno);
76 fd_.reset();
77 buffer_.reset();
78 return false;
79 }
80
81 buffer_size_ = static_cast<size_t>(n);
82 buffer_offset_ = buffer_size_;
83 total_byte_count_ += buffer_size_;
84
85 *data = buffer_.get();
86 *size = buffer_size_;
87 return buffer_size_ != 0u;
88}
89
90void FileInputStream::BackUp(size_t count) {
91 if (count > buffer_offset_) {
92 count = buffer_offset_;
93 }
94 buffer_offset_ -= count;
95 total_byte_count_ -= count;
96}
97
98size_t FileInputStream::ByteCount() const {
99 return total_byte_count_;
100}
101
102bool FileInputStream::HadError() const {
103 return fd_ == -1;
104}
105
106std::string FileInputStream::GetError() const {
107 return error_;
108}
109
Jeremy Meyerb4f83ff2023-11-30 19:29:50 +0000110bool FileInputStream::ReadFullyAtOffset(void* data, size_t byte_count, off64_t offset) {
111 return base::ReadFullyAtOffset(fd_, data, byte_count, offset);
112}
113
Adam Lesinskia693c4a2017-11-09 11:29:39 -0800114FileOutputStream::FileOutputStream(const std::string& path, size_t buffer_capacity)
115 : buffer_capacity_(buffer_capacity) {
116 int mode = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_BINARY;
117 owned_fd_.reset(TEMP_FAILURE_RETRY(::android::base::utf8::open(path.c_str(), mode, 0666)));
118 fd_ = owned_fd_.get();
119 if (fd_ < 0) {
120 error_ = SystemErrorCodeToString(errno);
121 } else {
122 buffer_.reset(new uint8_t[buffer_capacity_]);
123 }
Adam Lesinski93190b72017-11-03 15:20:17 -0700124}
125
126FileOutputStream::FileOutputStream(unique_fd fd, size_t buffer_capacity)
127 : FileOutputStream(fd.get(), buffer_capacity) {
128 owned_fd_ = std::move(fd);
Adam Lesinski00451162017-10-03 07:44:08 -0700129}
130
131FileOutputStream::FileOutputStream(int fd, size_t buffer_capacity)
Adam Lesinskia693c4a2017-11-09 11:29:39 -0800132 : fd_(fd), buffer_capacity_(buffer_capacity) {
133 if (fd_ < 0) {
134 error_ = "Bad File Descriptor";
Adam Lesinski00451162017-10-03 07:44:08 -0700135 } else {
136 buffer_.reset(new uint8_t[buffer_capacity_]);
137 }
138}
139
140FileOutputStream::~FileOutputStream() {
141 // Flush the buffer.
142 Flush();
143}
144
145bool FileOutputStream::Next(void** data, size_t* size) {
Adam Lesinski93190b72017-11-03 15:20:17 -0700146 if (HadError()) {
Adam Lesinski00451162017-10-03 07:44:08 -0700147 return false;
148 }
149
150 if (buffer_offset_ == buffer_capacity_) {
151 if (!FlushImpl()) {
152 return false;
153 }
154 }
155
156 const size_t buffer_size = buffer_capacity_ - buffer_offset_;
157 *data = buffer_.get() + buffer_offset_;
158 *size = buffer_size;
159 total_byte_count_ += buffer_size;
160 buffer_offset_ = buffer_capacity_;
161 return true;
162}
163
164void FileOutputStream::BackUp(size_t count) {
165 if (count > buffer_offset_) {
166 count = buffer_offset_;
167 }
168 buffer_offset_ -= count;
169 total_byte_count_ -= count;
170}
171
172size_t FileOutputStream::ByteCount() const {
173 return total_byte_count_;
174}
175
176bool FileOutputStream::Flush() {
177 if (!HadError()) {
178 return FlushImpl();
179 }
180 return false;
181}
182
183bool FileOutputStream::FlushImpl() {
184 ssize_t n = TEMP_FAILURE_RETRY(write(fd_, buffer_.get(), buffer_offset_));
185 if (n < 0) {
186 error_ = SystemErrorCodeToString(errno);
Adam Lesinski93190b72017-11-03 15:20:17 -0700187 owned_fd_.reset();
188 fd_ = -1;
Adam Lesinski00451162017-10-03 07:44:08 -0700189 buffer_.reset();
190 return false;
191 }
192
193 buffer_offset_ = 0u;
194 return true;
195}
196
197bool FileOutputStream::HadError() const {
198 return fd_ == -1;
199}
200
201std::string FileOutputStream::GetError() const {
202 return error_;
203}
204
Jeremy Meyerb4f83ff2023-11-30 19:29:50 +0000205} // namespace android