| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "components/filesystem/file_impl.h" | 5 #include "components/filesystem/file_impl.h" |
| 6 | 6 |
| 7 #include <stdint.h> | |
| 8 #include <limits> | 7 #include <limits> |
| 9 | 8 |
| 10 #include "base/files/file_path.h" | 9 #include "base/files/file_path.h" |
| 11 #include "base/files/scoped_file.h" | 10 #include "base/files/scoped_file.h" |
| 12 #include "base/logging.h" | 11 #include "base/logging.h" |
| 13 #include "components/filesystem/util.h" | 12 #include "components/filesystem/util.h" |
| 14 #include "mojo/platform_handle/platform_handle_functions.h" | 13 #include "mojo/platform_handle/platform_handle_functions.h" |
| 15 | 14 |
| 16 static_assert(sizeof(off_t) <= sizeof(int64_t), "off_t too big"); | 15 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"); | 16 static_assert(sizeof(size_t) >= sizeof(uint32_t), "size_t too small"); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 38 FileImpl::~FileImpl() { | 37 FileImpl::~FileImpl() { |
| 39 } | 38 } |
| 40 | 39 |
| 41 void FileImpl::Close(const CloseCallback& callback) { | 40 void FileImpl::Close(const CloseCallback& callback) { |
| 42 if (!file_.IsValid()) { | 41 if (!file_.IsValid()) { |
| 43 callback.Run(GetError(file_)); | 42 callback.Run(GetError(file_)); |
| 44 return; | 43 return; |
| 45 } | 44 } |
| 46 | 45 |
| 47 file_.Close(); | 46 file_.Close(); |
| 48 callback.Run(FILE_ERROR_OK); | 47 callback.Run(ERROR_OK); |
| 49 } | 48 } |
| 50 | 49 |
| 51 // TODO(vtl): Move the implementation to a thread pool. | 50 // TODO(vtl): Move the implementation to a thread pool. |
| 52 void FileImpl::Read(uint32_t num_bytes_to_read, | 51 void FileImpl::Read(uint32_t num_bytes_to_read, |
| 53 int64_t offset, | 52 int64_t offset, |
| 54 Whence whence, | 53 Whence whence, |
| 55 const ReadCallback& callback) { | 54 const ReadCallback& callback) { |
| 56 if (!file_.IsValid()) { | 55 if (!file_.IsValid()) { |
| 57 callback.Run(GetError(file_), mojo::Array<uint8_t>()); | 56 callback.Run(GetError(file_), mojo::Array<uint8_t>()); |
| 58 return; | 57 return; |
| 59 } | 58 } |
| 60 if (num_bytes_to_read > kMaxReadSize) { | 59 if (num_bytes_to_read > kMaxReadSize) { |
| 61 callback.Run(FILE_ERROR_INVALID_OPERATION, mojo::Array<uint8_t>()); | 60 callback.Run(ERROR_INVALID_OPERATION, mojo::Array<uint8_t>()); |
| 62 return; | 61 return; |
| 63 } | 62 } |
| 64 if (FileError error = IsOffsetValid(offset)) { | 63 if (Error error = IsOffsetValid(offset)) { |
| 65 callback.Run(error, mojo::Array<uint8_t>()); | 64 callback.Run(error, mojo::Array<uint8_t>()); |
| 66 return; | 65 return; |
| 67 } | 66 } |
| 68 if (FileError error = IsWhenceValid(whence)) { | 67 if (Error error = IsWhenceValid(whence)) { |
| 69 callback.Run(error, mojo::Array<uint8_t>()); | 68 callback.Run(error, mojo::Array<uint8_t>()); |
| 70 return; | 69 return; |
| 71 } | 70 } |
| 72 | 71 |
| 73 if (file_.Seek(static_cast<base::File::Whence>(whence), offset) == -1) { | 72 if (file_.Seek(static_cast<base::File::Whence>(whence), offset) == -1) { |
| 74 callback.Run(FILE_ERROR_FAILED, mojo::Array<uint8_t>()); | 73 callback.Run(ERROR_FAILED, mojo::Array<uint8_t>()); |
| 75 return; | 74 return; |
| 76 } | 75 } |
| 77 | 76 |
| 78 mojo::Array<uint8_t> bytes_read(num_bytes_to_read); | 77 mojo::Array<uint8_t> bytes_read(num_bytes_to_read); |
| 79 int num_bytes_read = file_.ReadAtCurrentPos( | 78 int num_bytes_read = file_.ReadAtCurrentPos( |
| 80 reinterpret_cast<char*>(&bytes_read.front()), num_bytes_to_read); | 79 reinterpret_cast<char*>(&bytes_read.front()), num_bytes_to_read); |
| 81 if (num_bytes_read < 0) { | 80 if (num_bytes_read < 0) { |
| 82 callback.Run(FILE_ERROR_FAILED, mojo::Array<uint8_t>()); | 81 callback.Run(ERROR_FAILED, mojo::Array<uint8_t>()); |
| 83 return; | 82 return; |
| 84 } | 83 } |
| 85 | 84 |
| 86 DCHECK_LE(static_cast<size_t>(num_bytes_read), num_bytes_to_read); | 85 DCHECK_LE(static_cast<size_t>(num_bytes_read), num_bytes_to_read); |
| 87 bytes_read.resize(static_cast<size_t>(num_bytes_read)); | 86 bytes_read.resize(static_cast<size_t>(num_bytes_read)); |
| 88 callback.Run(FILE_ERROR_OK, bytes_read.Pass()); | 87 callback.Run(ERROR_OK, bytes_read.Pass()); |
| 89 } | 88 } |
| 90 | 89 |
| 91 // TODO(vtl): Move the implementation to a thread pool. | 90 // TODO(vtl): Move the implementation to a thread pool. |
| 92 void FileImpl::Write(mojo::Array<uint8_t> bytes_to_write, | 91 void FileImpl::Write(mojo::Array<uint8_t> bytes_to_write, |
| 93 int64_t offset, | 92 int64_t offset, |
| 94 Whence whence, | 93 Whence whence, |
| 95 const WriteCallback& callback) { | 94 const WriteCallback& callback) { |
| 96 DCHECK(!bytes_to_write.is_null()); | 95 DCHECK(!bytes_to_write.is_null()); |
| 97 if (!file_.IsValid()) { | 96 if (!file_.IsValid()) { |
| 98 callback.Run(GetError(file_), 0); | 97 callback.Run(GetError(file_), 0); |
| 99 return; | 98 return; |
| 100 } | 99 } |
| 101 // Who knows what |write()| would return if the size is that big (and it | 100 // Who knows what |write()| would return if the size is that big (and it |
| 102 // actually wrote that much). | 101 // actually wrote that much). |
| 103 if (bytes_to_write.size() > | 102 if (bytes_to_write.size() > |
| 104 #if defined(OS_WIN) | |
| 105 std::numeric_limits<DWORD>::max()) { | |
| 106 #else | |
| 107 static_cast<size_t>(std::numeric_limits<ssize_t>::max())) { | 103 static_cast<size_t>(std::numeric_limits<ssize_t>::max())) { |
| 108 #endif | 104 callback.Run(ERROR_INVALID_OPERATION, 0); |
| 109 callback.Run(FILE_ERROR_INVALID_OPERATION, 0); | |
| 110 return; | 105 return; |
| 111 } | 106 } |
| 112 if (FileError error = IsOffsetValid(offset)) { | 107 if (Error error = IsOffsetValid(offset)) { |
| 113 callback.Run(error, 0); | 108 callback.Run(error, 0); |
| 114 return; | 109 return; |
| 115 } | 110 } |
| 116 if (FileError error = IsWhenceValid(whence)) { | 111 if (Error error = IsWhenceValid(whence)) { |
| 117 callback.Run(error, 0); | 112 callback.Run(error, 0); |
| 118 return; | 113 return; |
| 119 } | 114 } |
| 120 | 115 |
| 121 if (file_.Seek(static_cast<base::File::Whence>(whence), offset) == -1) { | 116 if (file_.Seek(static_cast<base::File::Whence>(whence), offset) == -1) { |
| 122 callback.Run(FILE_ERROR_FAILED, 0); | 117 callback.Run(ERROR_FAILED, 0); |
| 123 return; | 118 return; |
| 124 } | 119 } |
| 125 | 120 |
| 126 const char* buf = (bytes_to_write.size() > 0) | 121 const char* buf = (bytes_to_write.size() > 0) |
| 127 ? reinterpret_cast<char*>(&bytes_to_write.front()) | 122 ? reinterpret_cast<char*>(&bytes_to_write.front()) |
| 128 : nullptr; | 123 : nullptr; |
| 129 int num_bytes_written = file_.WriteAtCurrentPos(buf, bytes_to_write.size()); | 124 int num_bytes_written = file_.WriteAtCurrentPos(buf, bytes_to_write.size()); |
| 130 if (num_bytes_written < 0) { | 125 if (num_bytes_written < 0) { |
| 131 callback.Run(FILE_ERROR_FAILED, 0); | 126 callback.Run(ERROR_FAILED, 0); |
| 132 return; | 127 return; |
| 133 } | 128 } |
| 134 | 129 |
| 135 DCHECK_LE(static_cast<size_t>(num_bytes_written), | 130 DCHECK_LE(static_cast<size_t>(num_bytes_written), |
| 136 std::numeric_limits<uint32_t>::max()); | 131 std::numeric_limits<uint32_t>::max()); |
| 137 callback.Run(FILE_ERROR_OK, static_cast<uint32_t>(num_bytes_written)); | 132 callback.Run(ERROR_OK, static_cast<uint32_t>(num_bytes_written)); |
| 138 } | 133 } |
| 139 | 134 |
| 140 void FileImpl::Tell(const TellCallback& callback) { | 135 void FileImpl::Tell(const TellCallback& callback) { |
| 141 Seek(0, WHENCE_FROM_CURRENT, callback); | 136 Seek(0, WHENCE_FROM_CURRENT, callback); |
| 142 } | 137 } |
| 143 | 138 |
| 144 void FileImpl::Seek(int64_t offset, | 139 void FileImpl::Seek(int64_t offset, |
| 145 Whence whence, | 140 Whence whence, |
| 146 const SeekCallback& callback) { | 141 const SeekCallback& callback) { |
| 147 if (!file_.IsValid()) { | 142 if (!file_.IsValid()) { |
| 148 callback.Run(GetError(file_), 0); | 143 callback.Run(GetError(file_), 0); |
| 149 return; | 144 return; |
| 150 } | 145 } |
| 151 if (FileError error = IsOffsetValid(offset)) { | 146 if (Error error = IsOffsetValid(offset)) { |
| 152 callback.Run(error, 0); | 147 callback.Run(error, 0); |
| 153 return; | 148 return; |
| 154 } | 149 } |
| 155 if (FileError error = IsWhenceValid(whence)) { | 150 if (Error error = IsWhenceValid(whence)) { |
| 156 callback.Run(error, 0); | 151 callback.Run(error, 0); |
| 157 return; | 152 return; |
| 158 } | 153 } |
| 159 | 154 |
| 160 int64 position = file_.Seek(static_cast<base::File::Whence>(whence), offset); | 155 int64 position = file_.Seek(static_cast<base::File::Whence>(whence), offset); |
| 161 if (position < 0) { | 156 if (position < 0) { |
| 162 callback.Run(FILE_ERROR_FAILED, 0); | 157 callback.Run(ERROR_FAILED, 0); |
| 163 return; | 158 return; |
| 164 } | 159 } |
| 165 | 160 |
| 166 callback.Run(FILE_ERROR_OK, static_cast<int64>(position)); | 161 callback.Run(ERROR_OK, static_cast<int64>(position)); |
| 167 } | 162 } |
| 168 | 163 |
| 169 void FileImpl::Stat(const StatCallback& callback) { | 164 void FileImpl::Stat(const StatCallback& callback) { |
| 170 if (!file_.IsValid()) { | 165 if (!file_.IsValid()) { |
| 171 callback.Run(GetError(file_), nullptr); | 166 callback.Run(GetError(file_), nullptr); |
| 172 return; | 167 return; |
| 173 } | 168 } |
| 174 | 169 |
| 175 base::File::Info info; | 170 base::File::Info info; |
| 176 if (!file_.GetInfo(&info)) { | 171 if (!file_.GetInfo(&info)) { |
| 177 callback.Run(FILE_ERROR_FAILED, nullptr); | 172 callback.Run(ERROR_FAILED, nullptr); |
| 178 return; | 173 return; |
| 179 } | 174 } |
| 180 | 175 |
| 181 callback.Run(FILE_ERROR_OK, MakeFileInformation(info).Pass()); | 176 callback.Run(ERROR_OK, MakeFileInformation(info).Pass()); |
| 182 } | 177 } |
| 183 | 178 |
| 184 void FileImpl::Truncate(int64_t size, const TruncateCallback& callback) { | 179 void FileImpl::Truncate(int64_t size, const TruncateCallback& callback) { |
| 185 if (!file_.IsValid()) { | 180 if (!file_.IsValid()) { |
| 186 callback.Run(GetError(file_)); | 181 callback.Run(GetError(file_)); |
| 187 return; | 182 return; |
| 188 } | 183 } |
| 189 if (size < 0) { | 184 if (size < 0) { |
| 190 callback.Run(FILE_ERROR_INVALID_OPERATION); | 185 callback.Run(ERROR_INVALID_OPERATION); |
| 191 return; | 186 return; |
| 192 } | 187 } |
| 193 if (FileError error = IsOffsetValid(size)) { | 188 if (Error error = IsOffsetValid(size)) { |
| 194 callback.Run(error); | 189 callback.Run(error); |
| 195 return; | 190 return; |
| 196 } | 191 } |
| 197 | 192 |
| 198 if (!file_.SetLength(size)) { | 193 if (!file_.SetLength(size)) { |
| 199 callback.Run(FILE_ERROR_NOT_FOUND); | 194 callback.Run(ERROR_NOT_FOUND); |
| 200 return; | 195 return; |
| 201 } | 196 } |
| 202 | 197 |
| 203 callback.Run(FILE_ERROR_OK); | 198 callback.Run(ERROR_OK); |
| 204 } | 199 } |
| 205 | 200 |
| 206 void FileImpl::Touch(TimespecOrNowPtr atime, | 201 void FileImpl::Touch(TimespecOrNowPtr atime, |
| 207 TimespecOrNowPtr mtime, | 202 TimespecOrNowPtr mtime, |
| 208 const TouchCallback& callback) { | 203 const TouchCallback& callback) { |
| 209 if (!file_.IsValid()) { | 204 if (!file_.IsValid()) { |
| 210 callback.Run(GetError(file_)); | 205 callback.Run(GetError(file_)); |
| 211 return; | 206 return; |
| 212 } | 207 } |
| 213 | 208 |
| 214 base::Time base_atime = Time::Now(); | 209 base::Time base_atime = Time::Now(); |
| 215 if (!atime) { | 210 if (!atime) { |
| 216 base::File::Info info; | 211 base::File::Info info; |
| 217 if (!file_.GetInfo(&info)) { | 212 if (!file_.GetInfo(&info)) { |
| 218 callback.Run(FILE_ERROR_FAILED); | 213 callback.Run(ERROR_FAILED); |
| 219 return; | 214 return; |
| 220 } | 215 } |
| 221 | 216 |
| 222 base_atime = info.last_accessed; | 217 base_atime = info.last_accessed; |
| 223 } else if (!atime->now) { | 218 } else if (!atime->now) { |
| 224 base_atime = Time::FromDoubleT(atime->seconds); | 219 base_atime = Time::FromDoubleT(atime->seconds); |
| 225 } | 220 } |
| 226 | 221 |
| 227 base::Time base_mtime = Time::Now(); | 222 base::Time base_mtime = Time::Now(); |
| 228 if (!mtime) { | 223 if (!mtime) { |
| 229 base::File::Info info; | 224 base::File::Info info; |
| 230 if (!file_.GetInfo(&info)) { | 225 if (!file_.GetInfo(&info)) { |
| 231 callback.Run(FILE_ERROR_FAILED); | 226 callback.Run(ERROR_FAILED); |
| 232 return; | 227 return; |
| 233 } | 228 } |
| 234 | 229 |
| 235 base_mtime = info.last_modified; | 230 base_mtime = info.last_modified; |
| 236 } else if (!mtime->now) { | 231 } else if (!mtime->now) { |
| 237 base_mtime = Time::FromDoubleT(mtime->seconds); | 232 base_mtime = Time::FromDoubleT(mtime->seconds); |
| 238 } | 233 } |
| 239 | 234 |
| 240 file_.SetTimes(base_atime, base_mtime); | 235 file_.SetTimes(base_atime, base_mtime); |
| 241 callback.Run(FILE_ERROR_OK); | 236 callback.Run(ERROR_OK); |
| 242 } | 237 } |
| 243 | 238 |
| 244 void FileImpl::Dup(mojo::InterfaceRequest<File> file, | 239 void FileImpl::Dup(mojo::InterfaceRequest<File> file, |
| 245 const DupCallback& callback) { | 240 const DupCallback& callback) { |
| 246 if (!file_.IsValid()) { | 241 if (!file_.IsValid()) { |
| 247 callback.Run(GetError(file_)); | 242 callback.Run(GetError(file_)); |
| 248 return; | 243 return; |
| 249 } | 244 } |
| 250 | 245 |
| 251 base::File new_file = file_.Duplicate(); | 246 base::File new_file = file_.Duplicate(); |
| 252 if (!new_file.IsValid()) { | 247 if (!new_file.IsValid()) { |
| 253 callback.Run(GetError(new_file)); | 248 callback.Run(GetError(new_file)); |
| 254 return; | 249 return; |
| 255 } | 250 } |
| 256 | 251 |
| 257 if (file.is_pending()) | 252 if (file.is_pending()) |
| 258 new FileImpl(file.Pass(), new_file.Pass()); | 253 new FileImpl(file.Pass(), new_file.Pass()); |
| 259 callback.Run(FILE_ERROR_OK); | 254 callback.Run(ERROR_OK); |
| 260 } | 255 } |
| 261 | 256 |
| 262 void FileImpl::AsHandle(const AsHandleCallback& callback) { | 257 void FileImpl::AsHandle(const AsHandleCallback& callback) { |
| 263 if (!file_.IsValid()) { | 258 if (!file_.IsValid()) { |
| 264 callback.Run(GetError(file_), ScopedHandle()); | 259 callback.Run(GetError(file_), ScopedHandle()); |
| 265 return; | 260 return; |
| 266 } | 261 } |
| 267 | 262 |
| 268 base::File new_file = file_.Duplicate(); | 263 base::File new_file = file_.Duplicate(); |
| 269 if (!new_file.IsValid()) { | 264 if (!new_file.IsValid()) { |
| 270 callback.Run(GetError(new_file), ScopedHandle()); | 265 callback.Run(GetError(new_file), ScopedHandle()); |
| 271 return; | 266 return; |
| 272 } | 267 } |
| 273 | 268 |
| 274 base::File::Info info; | 269 base::File::Info info; |
| 275 if (!new_file.GetInfo(&info)) { | 270 if (!new_file.GetInfo(&info)) { |
| 276 callback.Run(FILE_ERROR_FAILED, ScopedHandle()); | 271 callback.Run(ERROR_FAILED, ScopedHandle()); |
| 277 return; | 272 return; |
| 278 } | 273 } |
| 279 | 274 |
| 280 // Perform one additional check right before we send the file's file | 275 // Perform one additional check right before we send the file's file |
| 281 // descriptor over mojo. This is theoretically redundant, but given that | 276 // descriptor over mojo. This is theoretically redundant, but given that |
| 282 // passing a file descriptor to a directory is a sandbox escape on Windows, | 277 // passing a file descriptor to a directory is a sandbox escape on Windows, |
| 283 // we should be absolutely paranoid. | 278 // we should be absolutely paranoid. |
| 284 if (info.is_directory) { | 279 if (info.is_directory) { |
| 285 callback.Run(FILE_ERROR_NOT_A_FILE, ScopedHandle()); | 280 callback.Run(ERROR_NOT_A_FILE, ScopedHandle()); |
| 286 return; | 281 return; |
| 287 } | 282 } |
| 288 | 283 |
| 289 MojoHandle mojo_handle; | 284 MojoHandle mojo_handle; |
| 290 MojoResult create_result = MojoCreatePlatformHandleWrapper( | 285 MojoResult create_result = MojoCreatePlatformHandleWrapper( |
| 291 new_file.TakePlatformFile(), &mojo_handle); | 286 new_file.TakePlatformFile(), &mojo_handle); |
| 292 if (create_result != MOJO_RESULT_OK) { | 287 if (create_result != MOJO_RESULT_OK) { |
| 293 callback.Run(FILE_ERROR_FAILED, ScopedHandle()); | 288 callback.Run(ERROR_FAILED, ScopedHandle()); |
| 294 return; | 289 return; |
| 295 } | 290 } |
| 296 | 291 |
| 297 callback.Run(FILE_ERROR_OK, ScopedHandle(mojo::Handle(mojo_handle)).Pass()); | 292 callback.Run(ERROR_OK, ScopedHandle(mojo::Handle(mojo_handle)).Pass()); |
| 298 } | 293 } |
| 299 | 294 |
| 300 } // namespace filesystem | 295 } // namespace filesystem |
| OLD | NEW |