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 |