Rename GetIconID to GetIconId
[chromium-blink-merge.git] / components / filesystem / file_impl.cc
blob4925f9acaec5bd574ec9ec86af782d47f90ee70c
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "components/filesystem/file_impl.h"
7 #include <stdint.h>
8 #include <limits>
10 #include "base/files/file_path.h"
11 #include "base/files/scoped_file.h"
12 #include "base/logging.h"
13 #include "components/filesystem/util.h"
14 #include "mojo/platform_handle/platform_handle_functions.h"
16 static_assert(sizeof(off_t) <= sizeof(int64_t), "off_t too big");
17 static_assert(sizeof(size_t) >= sizeof(uint32_t), "size_t too small");
19 using base::Time;
20 using mojo::ScopedHandle;
22 namespace filesystem {
24 const size_t kMaxReadSize = 1 * 1024 * 1024; // 1 MB.
26 FileImpl::FileImpl(mojo::InterfaceRequest<File> request,
27 const base::FilePath& path,
28 uint32 flags)
29 : binding_(this, request.Pass()), file_(path, flags) {
30 DCHECK(file_.IsValid());
33 FileImpl::FileImpl(mojo::InterfaceRequest<File> request, base::File file)
34 : binding_(this, request.Pass()), file_(file.Pass()) {
35 DCHECK(file_.IsValid());
38 FileImpl::~FileImpl() {
41 void FileImpl::Close(const CloseCallback& callback) {
42 if (!file_.IsValid()) {
43 callback.Run(GetError(file_));
44 return;
47 file_.Close();
48 callback.Run(FILE_ERROR_OK);
51 // TODO(vtl): Move the implementation to a thread pool.
52 void FileImpl::Read(uint32_t num_bytes_to_read,
53 int64_t offset,
54 Whence whence,
55 const ReadCallback& callback) {
56 if (!file_.IsValid()) {
57 callback.Run(GetError(file_), mojo::Array<uint8_t>());
58 return;
60 if (num_bytes_to_read > kMaxReadSize) {
61 callback.Run(FILE_ERROR_INVALID_OPERATION, mojo::Array<uint8_t>());
62 return;
64 if (FileError error = IsOffsetValid(offset)) {
65 callback.Run(error, mojo::Array<uint8_t>());
66 return;
68 if (FileError error = IsWhenceValid(whence)) {
69 callback.Run(error, mojo::Array<uint8_t>());
70 return;
73 if (file_.Seek(static_cast<base::File::Whence>(whence), offset) == -1) {
74 callback.Run(FILE_ERROR_FAILED, mojo::Array<uint8_t>());
75 return;
78 mojo::Array<uint8_t> bytes_read(num_bytes_to_read);
79 int num_bytes_read = file_.ReadAtCurrentPos(
80 reinterpret_cast<char*>(&bytes_read.front()), num_bytes_to_read);
81 if (num_bytes_read < 0) {
82 callback.Run(FILE_ERROR_FAILED, mojo::Array<uint8_t>());
83 return;
86 DCHECK_LE(static_cast<size_t>(num_bytes_read), num_bytes_to_read);
87 bytes_read.resize(static_cast<size_t>(num_bytes_read));
88 callback.Run(FILE_ERROR_OK, bytes_read.Pass());
91 // TODO(vtl): Move the implementation to a thread pool.
92 void FileImpl::Write(mojo::Array<uint8_t> bytes_to_write,
93 int64_t offset,
94 Whence whence,
95 const WriteCallback& callback) {
96 DCHECK(!bytes_to_write.is_null());
97 if (!file_.IsValid()) {
98 callback.Run(GetError(file_), 0);
99 return;
101 // Who knows what |write()| would return if the size is that big (and it
102 // actually wrote that much).
103 if (bytes_to_write.size() >
104 #if defined(OS_WIN)
105 static_cast<size_t>(std::numeric_limits<int>::max())) {
106 #else
107 static_cast<size_t>(std::numeric_limits<ssize_t>::max())) {
108 #endif
109 callback.Run(FILE_ERROR_INVALID_OPERATION, 0);
110 return;
112 if (FileError error = IsOffsetValid(offset)) {
113 callback.Run(error, 0);
114 return;
116 if (FileError error = IsWhenceValid(whence)) {
117 callback.Run(error, 0);
118 return;
121 if (file_.Seek(static_cast<base::File::Whence>(whence), offset) == -1) {
122 callback.Run(FILE_ERROR_FAILED, 0);
123 return;
126 const char* buf = (bytes_to_write.size() > 0)
127 ? reinterpret_cast<char*>(&bytes_to_write.front())
128 : nullptr;
129 int num_bytes_written = file_.WriteAtCurrentPos(
130 buf, static_cast<int>(bytes_to_write.size()));
131 if (num_bytes_written < 0) {
132 callback.Run(FILE_ERROR_FAILED, 0);
133 return;
136 DCHECK_LE(static_cast<size_t>(num_bytes_written),
137 std::numeric_limits<uint32_t>::max());
138 callback.Run(FILE_ERROR_OK, static_cast<uint32_t>(num_bytes_written));
141 void FileImpl::Tell(const TellCallback& callback) {
142 Seek(0, WHENCE_FROM_CURRENT, callback);
145 void FileImpl::Seek(int64_t offset,
146 Whence whence,
147 const SeekCallback& callback) {
148 if (!file_.IsValid()) {
149 callback.Run(GetError(file_), 0);
150 return;
152 if (FileError error = IsOffsetValid(offset)) {
153 callback.Run(error, 0);
154 return;
156 if (FileError error = IsWhenceValid(whence)) {
157 callback.Run(error, 0);
158 return;
161 int64 position = file_.Seek(static_cast<base::File::Whence>(whence), offset);
162 if (position < 0) {
163 callback.Run(FILE_ERROR_FAILED, 0);
164 return;
167 callback.Run(FILE_ERROR_OK, static_cast<int64>(position));
170 void FileImpl::Stat(const StatCallback& callback) {
171 if (!file_.IsValid()) {
172 callback.Run(GetError(file_), nullptr);
173 return;
176 base::File::Info info;
177 if (!file_.GetInfo(&info)) {
178 callback.Run(FILE_ERROR_FAILED, nullptr);
179 return;
182 callback.Run(FILE_ERROR_OK, MakeFileInformation(info).Pass());
185 void FileImpl::Truncate(int64_t size, const TruncateCallback& callback) {
186 if (!file_.IsValid()) {
187 callback.Run(GetError(file_));
188 return;
190 if (size < 0) {
191 callback.Run(FILE_ERROR_INVALID_OPERATION);
192 return;
194 if (FileError error = IsOffsetValid(size)) {
195 callback.Run(error);
196 return;
199 if (!file_.SetLength(size)) {
200 callback.Run(FILE_ERROR_NOT_FOUND);
201 return;
204 callback.Run(FILE_ERROR_OK);
207 void FileImpl::Touch(TimespecOrNowPtr atime,
208 TimespecOrNowPtr mtime,
209 const TouchCallback& callback) {
210 if (!file_.IsValid()) {
211 callback.Run(GetError(file_));
212 return;
215 base::Time base_atime = Time::Now();
216 if (!atime) {
217 base::File::Info info;
218 if (!file_.GetInfo(&info)) {
219 callback.Run(FILE_ERROR_FAILED);
220 return;
223 base_atime = info.last_accessed;
224 } else if (!atime->now) {
225 base_atime = Time::FromDoubleT(atime->seconds);
228 base::Time base_mtime = Time::Now();
229 if (!mtime) {
230 base::File::Info info;
231 if (!file_.GetInfo(&info)) {
232 callback.Run(FILE_ERROR_FAILED);
233 return;
236 base_mtime = info.last_modified;
237 } else if (!mtime->now) {
238 base_mtime = Time::FromDoubleT(mtime->seconds);
241 file_.SetTimes(base_atime, base_mtime);
242 callback.Run(FILE_ERROR_OK);
245 void FileImpl::Dup(mojo::InterfaceRequest<File> file,
246 const DupCallback& callback) {
247 if (!file_.IsValid()) {
248 callback.Run(GetError(file_));
249 return;
252 base::File new_file = file_.Duplicate();
253 if (!new_file.IsValid()) {
254 callback.Run(GetError(new_file));
255 return;
258 if (file.is_pending())
259 new FileImpl(file.Pass(), new_file.Pass());
260 callback.Run(FILE_ERROR_OK);
263 void FileImpl::Flush(const FlushCallback& callback) {
264 if (!file_.IsValid()) {
265 callback.Run(GetError(file_));
266 return;
269 bool ret = file_.Flush();
270 callback.Run(ret ? FILE_ERROR_OK : FILE_ERROR_FAILED);
273 void FileImpl::AsHandle(const AsHandleCallback& callback) {
274 if (!file_.IsValid()) {
275 callback.Run(GetError(file_), ScopedHandle());
276 return;
279 base::File new_file = file_.Duplicate();
280 if (!new_file.IsValid()) {
281 callback.Run(GetError(new_file), ScopedHandle());
282 return;
285 base::File::Info info;
286 if (!new_file.GetInfo(&info)) {
287 callback.Run(FILE_ERROR_FAILED, ScopedHandle());
288 return;
291 // Perform one additional check right before we send the file's file
292 // descriptor over mojo. This is theoretically redundant, but given that
293 // passing a file descriptor to a directory is a sandbox escape on Windows,
294 // we should be absolutely paranoid.
295 if (info.is_directory) {
296 callback.Run(FILE_ERROR_NOT_A_FILE, ScopedHandle());
297 return;
300 MojoHandle mojo_handle;
301 MojoResult create_result = MojoCreatePlatformHandleWrapper(
302 new_file.TakePlatformFile(), &mojo_handle);
303 if (create_result != MOJO_RESULT_OK) {
304 callback.Run(FILE_ERROR_FAILED, ScopedHandle());
305 return;
308 callback.Run(FILE_ERROR_OK, ScopedHandle(mojo::Handle(mojo_handle)).Pass());
311 } // namespace filesystem