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