OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "base/platform_file.h" | 5 #include "base/platform_file.h" |
6 | 6 |
7 #include <fcntl.h> | 7 #include <fcntl.h> |
8 #include <errno.h> | 8 #include <errno.h> |
9 #include <sys/stat.h> | 9 #include <sys/stat.h> |
10 #include <unistd.h> | 10 #include <unistd.h> |
11 | 11 |
12 #include "base/files/file_path.h" | 12 #include "base/files/file_path.h" |
13 #include "base/logging.h" | 13 #include "base/logging.h" |
14 #include "base/metrics/sparse_histogram.h" | 14 #include "base/metrics/sparse_histogram.h" |
15 #include "base/posix/eintr_wrapper.h" | 15 #include "base/posix/eintr_wrapper.h" |
16 #include "base/strings/utf_string_conversions.h" | 16 #include "base/strings/utf_string_conversions.h" |
17 #include "base/threading/thread_restrictions.h" | 17 #include "base/threading/thread_restrictions.h" |
18 | 18 |
19 #if defined(OS_ANDROID) | 19 #if defined(OS_ANDROID) |
20 #include "base/os_compat_android.h" | 20 #include "base/os_compat_android.h" |
21 #endif | 21 #endif |
22 | 22 |
23 namespace base { | 23 namespace base { |
24 | 24 |
25 // Make sure our Whence mappings match the system headers. | 25 // Make sure our Whence mappings match the system headers. |
26 COMPILE_ASSERT(PLATFORM_FILE_FROM_BEGIN == SEEK_SET && | 26 COMPILE_ASSERT(PLATFORM_FILE_FROM_BEGIN == SEEK_SET && |
27 PLATFORM_FILE_FROM_CURRENT == SEEK_CUR && | 27 PLATFORM_FILE_FROM_CURRENT == SEEK_CUR && |
28 PLATFORM_FILE_FROM_END == SEEK_END, whence_matches_system); | 28 PLATFORM_FILE_FROM_END == SEEK_END, whence_matches_system); |
29 | 29 |
30 #if defined(OS_BSD) || defined(OS_MACOSX) | 30 namespace { |
| 31 |
| 32 #if defined(OS_BSD) || defined(OS_MACOSX) || defined(OS_NACL) |
31 typedef struct stat stat_wrapper_t; | 33 typedef struct stat stat_wrapper_t; |
32 static int CallFstat(int fd, stat_wrapper_t *sb) { | 34 static int CallFstat(int fd, stat_wrapper_t *sb) { |
33 base::ThreadRestrictions::AssertIOAllowed(); | 35 base::ThreadRestrictions::AssertIOAllowed(); |
34 return fstat(fd, sb); | 36 return fstat(fd, sb); |
35 } | 37 } |
36 #else | 38 #else |
37 typedef struct stat64 stat_wrapper_t; | 39 typedef struct stat64 stat_wrapper_t; |
38 static int CallFstat(int fd, stat_wrapper_t *sb) { | 40 static int CallFstat(int fd, stat_wrapper_t *sb) { |
39 base::ThreadRestrictions::AssertIOAllowed(); | 41 base::ThreadRestrictions::AssertIOAllowed(); |
40 return fstat64(fd, sb); | 42 return fstat64(fd, sb); |
41 } | 43 } |
42 #endif | 44 #endif |
43 | 45 |
| 46 // NaCl doesn't provide the following system calls, so either simulate them or |
| 47 // wrap them in order to minimize the number of #ifdef's in this file. |
| 48 #if !defined(OS_NACL) |
| 49 static int DoPread(PlatformFile file, char* data, int size, int64 offset) { |
| 50 return HANDLE_EINTR(pread(file, data, size, offset)); |
| 51 } |
| 52 |
| 53 static int DoPwrite(PlatformFile file, const char* data, int size, |
| 54 int64 offset) { |
| 55 return HANDLE_EINTR(pwrite(file, data, size, offset)); |
| 56 } |
| 57 |
| 58 static bool IsOpenAppend(PlatformFile file) { |
| 59 return (fcntl(file, F_GETFL) & O_APPEND) != 0; |
| 60 } |
| 61 |
| 62 static int CallFtruncate(PlatformFile file, int64 length) { |
| 63 return HANDLE_EINTR(ftruncate(file, length)); |
| 64 } |
| 65 |
| 66 static int CallFsync(PlatformFile file) { |
| 67 return HANDLE_EINTR(fsync(file)); |
| 68 } |
| 69 |
| 70 static int CallFutimes(PlatformFile file, const struct timeval times[2]) { |
| 71 #ifdef __USE_XOPEN2K8 |
| 72 // futimens should be available, but futimes might not be |
| 73 // http://pubs.opengroup.org/onlinepubs/9699919799/ |
| 74 |
| 75 timespec ts_times[2]; |
| 76 ts_times[0].tv_sec = times[0].tv_sec; |
| 77 ts_times[0].tv_nsec = times[0].tv_usec * 1000; |
| 78 ts_times[1].tv_sec = times[1].tv_sec; |
| 79 ts_times[1].tv_nsec = times[1].tv_usec * 1000; |
| 80 |
| 81 return futimens(file, ts_times); |
| 82 #else |
| 83 return futimes(file, times); |
| 84 #endif |
| 85 } |
| 86 #else // defined(OS_NACL) |
| 87 // TODO(bbudge) Remove DoPread, DoPwrite when NaCl implements pread, pwrite. |
| 88 static int DoPread(PlatformFile file, char* data, int size, int64 offset) { |
| 89 lseek(file, static_cast<off_t>(offset), SEEK_SET); |
| 90 return HANDLE_EINTR(read(file, data, size)); |
| 91 } |
| 92 |
| 93 static int DoPwrite(PlatformFile file, const char* data, int size, |
| 94 int64 offset) { |
| 95 lseek(file, static_cast<off_t>(offset), SEEK_SET); |
| 96 return HANDLE_EINTR(write(file, data, size)); |
| 97 } |
| 98 |
| 99 static bool IsOpenAppend(PlatformFile file) { |
| 100 // NaCl doesn't implement fcntl. Since NaCl's write conforms to the POSIX |
| 101 // standard and always appends if the file is opened with O_APPEND, just |
| 102 // return false here. |
| 103 return false; |
| 104 } |
| 105 |
| 106 static int CallFtruncate(PlatformFile file, int64 length) { |
| 107 NOTIMPLEMENTED(); // NaCl doesn't implement ftruncate. |
| 108 return 0; |
| 109 } |
| 110 |
| 111 static int CallFsync(PlatformFile file) { |
| 112 NOTIMPLEMENTED(); // NaCl doesn't implement fsync. |
| 113 return 0; |
| 114 } |
| 115 |
| 116 static int CallFutimes(PlatformFile file, const struct timeval times[2]) { |
| 117 NOTIMPLEMENTED(); // NaCl doesn't implement futimes. |
| 118 return 0; |
| 119 } |
| 120 #endif // defined(OS_NACL) |
| 121 |
| 122 } // namespace |
| 123 |
| 124 // NaCl doesn't implement system calls to open files directly. |
| 125 #if !defined(OS_NACL) |
44 // TODO(erikkay): does it make sense to support PLATFORM_FILE_EXCLUSIVE_* here? | 126 // TODO(erikkay): does it make sense to support PLATFORM_FILE_EXCLUSIVE_* here? |
45 PlatformFile CreatePlatformFileUnsafe(const FilePath& name, | 127 PlatformFile CreatePlatformFileUnsafe(const FilePath& name, |
46 int flags, | 128 int flags, |
47 bool* created, | 129 bool* created, |
48 PlatformFileError* error) { | 130 PlatformFileError* error) { |
49 base::ThreadRestrictions::AssertIOAllowed(); | 131 base::ThreadRestrictions::AssertIOAllowed(); |
50 | 132 |
51 int open_flags = 0; | 133 int open_flags = 0; |
52 if (flags & PLATFORM_FILE_CREATE) | 134 if (flags & PLATFORM_FILE_CREATE) |
53 open_flags = O_CREAT | O_EXCL; | 135 open_flags = O_CREAT | O_EXCL; |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
132 else | 214 else |
133 *error = ErrnoToPlatformFileError(errno); | 215 *error = ErrnoToPlatformFileError(errno); |
134 } | 216 } |
135 | 217 |
136 return descriptor; | 218 return descriptor; |
137 } | 219 } |
138 | 220 |
139 FILE* FdopenPlatformFile(PlatformFile file, const char* mode) { | 221 FILE* FdopenPlatformFile(PlatformFile file, const char* mode) { |
140 return fdopen(file, mode); | 222 return fdopen(file, mode); |
141 } | 223 } |
| 224 #endif // !defined(OS_NACL) |
142 | 225 |
143 bool ClosePlatformFile(PlatformFile file) { | 226 bool ClosePlatformFile(PlatformFile file) { |
144 base::ThreadRestrictions::AssertIOAllowed(); | 227 base::ThreadRestrictions::AssertIOAllowed(); |
145 return !HANDLE_EINTR(close(file)); | 228 return !HANDLE_EINTR(close(file)); |
146 } | 229 } |
147 | 230 |
148 int64 SeekPlatformFile(PlatformFile file, | 231 int64 SeekPlatformFile(PlatformFile file, |
149 PlatformFileWhence whence, | 232 PlatformFileWhence whence, |
150 int64 offset) { | 233 int64 offset) { |
151 base::ThreadRestrictions::AssertIOAllowed(); | 234 base::ThreadRestrictions::AssertIOAllowed(); |
152 if (file < 0 || offset < 0) | 235 if (file < 0 || offset < 0) |
153 return -1; | 236 return -1; |
154 | 237 |
155 return lseek(file, static_cast<off_t>(offset), static_cast<int>(whence)); | 238 return lseek(file, static_cast<off_t>(offset), static_cast<int>(whence)); |
156 } | 239 } |
157 | 240 |
158 int ReadPlatformFile(PlatformFile file, int64 offset, char* data, int size) { | 241 int ReadPlatformFile(PlatformFile file, int64 offset, char* data, int size) { |
159 base::ThreadRestrictions::AssertIOAllowed(); | 242 base::ThreadRestrictions::AssertIOAllowed(); |
160 if (file < 0 || size < 0) | 243 if (file < 0 || size < 0) |
161 return -1; | 244 return -1; |
162 | 245 |
163 int bytes_read = 0; | 246 int bytes_read = 0; |
164 int rv; | 247 int rv; |
165 do { | 248 do { |
166 rv = HANDLE_EINTR(pread(file, data + bytes_read, | 249 rv = DoPread(file, data + bytes_read, |
167 size - bytes_read, offset + bytes_read)); | 250 size - bytes_read, offset + bytes_read); |
168 if (rv <= 0) | 251 if (rv <= 0) |
169 break; | 252 break; |
170 | 253 |
171 bytes_read += rv; | 254 bytes_read += rv; |
172 } while (bytes_read < size); | 255 } while (bytes_read < size); |
173 | 256 |
174 return bytes_read ? bytes_read : rv; | 257 return bytes_read ? bytes_read : rv; |
175 } | 258 } |
176 | 259 |
177 int ReadPlatformFileAtCurrentPos(PlatformFile file, char* data, int size) { | 260 int ReadPlatformFileAtCurrentPos(PlatformFile file, char* data, int size) { |
(...skipping 13 matching lines...) Expand all Loading... |
191 | 274 |
192 return bytes_read ? bytes_read : rv; | 275 return bytes_read ? bytes_read : rv; |
193 } | 276 } |
194 | 277 |
195 int ReadPlatformFileNoBestEffort(PlatformFile file, int64 offset, | 278 int ReadPlatformFileNoBestEffort(PlatformFile file, int64 offset, |
196 char* data, int size) { | 279 char* data, int size) { |
197 base::ThreadRestrictions::AssertIOAllowed(); | 280 base::ThreadRestrictions::AssertIOAllowed(); |
198 if (file < 0) | 281 if (file < 0) |
199 return -1; | 282 return -1; |
200 | 283 |
201 return HANDLE_EINTR(pread(file, data, size, offset)); | 284 return DoPread(file, data, size, offset); |
202 } | 285 } |
203 | 286 |
204 int ReadPlatformFileCurPosNoBestEffort(PlatformFile file, | 287 int ReadPlatformFileCurPosNoBestEffort(PlatformFile file, |
205 char* data, int size) { | 288 char* data, int size) { |
206 base::ThreadRestrictions::AssertIOAllowed(); | 289 base::ThreadRestrictions::AssertIOAllowed(); |
207 if (file < 0 || size < 0) | 290 if (file < 0 || size < 0) |
208 return -1; | 291 return -1; |
209 | 292 |
210 return HANDLE_EINTR(read(file, data, size)); | 293 return HANDLE_EINTR(read(file, data, size)); |
211 } | 294 } |
212 | 295 |
213 int WritePlatformFile(PlatformFile file, int64 offset, | 296 int WritePlatformFile(PlatformFile file, int64 offset, |
214 const char* data, int size) { | 297 const char* data, int size) { |
215 base::ThreadRestrictions::AssertIOAllowed(); | 298 base::ThreadRestrictions::AssertIOAllowed(); |
216 | 299 |
217 if (fcntl(file, F_GETFL) & O_APPEND) | 300 if (IsOpenAppend(file)) |
218 return WritePlatformFileAtCurrentPos(file, data, size); | 301 return WritePlatformFileAtCurrentPos(file, data, size); |
219 | 302 |
220 if (file < 0 || size < 0) | 303 if (file < 0 || size < 0) |
221 return -1; | 304 return -1; |
222 | 305 |
223 int bytes_written = 0; | 306 int bytes_written = 0; |
224 int rv; | 307 int rv; |
225 do { | 308 do { |
226 rv = HANDLE_EINTR(pwrite(file, data + bytes_written, | 309 rv = DoPwrite(file, data + bytes_written, |
227 size - bytes_written, offset + bytes_written)); | 310 size - bytes_written, offset + bytes_written); |
228 if (rv <= 0) | 311 if (rv <= 0) |
229 break; | 312 break; |
230 | 313 |
231 bytes_written += rv; | 314 bytes_written += rv; |
232 } while (bytes_written < size); | 315 } while (bytes_written < size); |
233 | 316 |
234 return bytes_written ? bytes_written : rv; | 317 return bytes_written ? bytes_written : rv; |
235 } | 318 } |
236 | 319 |
237 int WritePlatformFileAtCurrentPos(PlatformFile file, | 320 int WritePlatformFileAtCurrentPos(PlatformFile file, |
(...skipping 19 matching lines...) Expand all Loading... |
257 const char* data, int size) { | 340 const char* data, int size) { |
258 base::ThreadRestrictions::AssertIOAllowed(); | 341 base::ThreadRestrictions::AssertIOAllowed(); |
259 if (file < 0 || size < 0) | 342 if (file < 0 || size < 0) |
260 return -1; | 343 return -1; |
261 | 344 |
262 return HANDLE_EINTR(write(file, data, size)); | 345 return HANDLE_EINTR(write(file, data, size)); |
263 } | 346 } |
264 | 347 |
265 bool TruncatePlatformFile(PlatformFile file, int64 length) { | 348 bool TruncatePlatformFile(PlatformFile file, int64 length) { |
266 base::ThreadRestrictions::AssertIOAllowed(); | 349 base::ThreadRestrictions::AssertIOAllowed(); |
267 return ((file >= 0) && !HANDLE_EINTR(ftruncate(file, length))); | 350 return ((file >= 0) && !CallFtruncate(file, length)); |
268 } | 351 } |
269 | 352 |
270 bool FlushPlatformFile(PlatformFile file) { | 353 bool FlushPlatformFile(PlatformFile file) { |
271 base::ThreadRestrictions::AssertIOAllowed(); | 354 base::ThreadRestrictions::AssertIOAllowed(); |
272 return !HANDLE_EINTR(fsync(file)); | 355 return !CallFsync(file); |
273 } | 356 } |
274 | 357 |
275 bool TouchPlatformFile(PlatformFile file, const base::Time& last_access_time, | 358 bool TouchPlatformFile(PlatformFile file, const base::Time& last_access_time, |
276 const base::Time& last_modified_time) { | 359 const base::Time& last_modified_time) { |
277 base::ThreadRestrictions::AssertIOAllowed(); | 360 base::ThreadRestrictions::AssertIOAllowed(); |
278 if (file < 0) | 361 if (file < 0) |
279 return false; | 362 return false; |
280 | 363 |
281 timeval times[2]; | 364 timeval times[2]; |
282 times[0] = last_access_time.ToTimeVal(); | 365 times[0] = last_access_time.ToTimeVal(); |
283 times[1] = last_modified_time.ToTimeVal(); | 366 times[1] = last_modified_time.ToTimeVal(); |
284 | 367 |
285 #ifdef __USE_XOPEN2K8 | 368 return !CallFutimes(file, times); |
286 // futimens should be available, but futimes might not be | |
287 // http://pubs.opengroup.org/onlinepubs/9699919799/ | |
288 | |
289 timespec ts_times[2]; | |
290 ts_times[0].tv_sec = times[0].tv_sec; | |
291 ts_times[0].tv_nsec = times[0].tv_usec * 1000; | |
292 ts_times[1].tv_sec = times[1].tv_sec; | |
293 ts_times[1].tv_nsec = times[1].tv_usec * 1000; | |
294 | |
295 return !futimens(file, ts_times); | |
296 #else | |
297 return !futimes(file, times); | |
298 #endif | |
299 } | 369 } |
300 | 370 |
301 bool GetPlatformFileInfo(PlatformFile file, PlatformFileInfo* info) { | 371 bool GetPlatformFileInfo(PlatformFile file, PlatformFileInfo* info) { |
302 if (!info) | 372 if (!info) |
303 return false; | 373 return false; |
304 | 374 |
305 stat_wrapper_t file_info; | 375 stat_wrapper_t file_info; |
306 if (CallFstat(file, &file_info)) | 376 if (CallFstat(file, &file_info)) |
307 return false; | 377 return false; |
308 | 378 |
309 info->is_directory = S_ISDIR(file_info.st_mode); | 379 info->is_directory = S_ISDIR(file_info.st_mode); |
310 info->is_symbolic_link = S_ISLNK(file_info.st_mode); | 380 info->is_symbolic_link = S_ISLNK(file_info.st_mode); |
311 info->size = file_info.st_size; | 381 info->size = file_info.st_size; |
312 info->last_modified = base::Time::FromTimeT(file_info.st_mtime); | 382 info->last_modified = base::Time::FromTimeT(file_info.st_mtime); |
313 info->last_accessed = base::Time::FromTimeT(file_info.st_atime); | 383 info->last_accessed = base::Time::FromTimeT(file_info.st_atime); |
314 info->creation_time = base::Time::FromTimeT(file_info.st_ctime); | 384 info->creation_time = base::Time::FromTimeT(file_info.st_ctime); |
315 return true; | 385 return true; |
316 } | 386 } |
317 | 387 |
318 PlatformFileError ErrnoToPlatformFileError(int saved_errno) { | 388 PlatformFileError ErrnoToPlatformFileError(int saved_errno) { |
319 switch (saved_errno) { | 389 switch (saved_errno) { |
320 case EACCES: | 390 case EACCES: |
321 case EISDIR: | 391 case EISDIR: |
322 case EROFS: | 392 case EROFS: |
323 case EPERM: | 393 case EPERM: |
324 return PLATFORM_FILE_ERROR_ACCESS_DENIED; | 394 return PLATFORM_FILE_ERROR_ACCESS_DENIED; |
| 395 #if !defined(OS_NACL) // ETXTBSY not defined by NaCl. |
325 case ETXTBSY: | 396 case ETXTBSY: |
326 return PLATFORM_FILE_ERROR_IN_USE; | 397 return PLATFORM_FILE_ERROR_IN_USE; |
| 398 #endif |
327 case EEXIST: | 399 case EEXIST: |
328 return PLATFORM_FILE_ERROR_EXISTS; | 400 return PLATFORM_FILE_ERROR_EXISTS; |
329 case ENOENT: | 401 case ENOENT: |
330 return PLATFORM_FILE_ERROR_NOT_FOUND; | 402 return PLATFORM_FILE_ERROR_NOT_FOUND; |
331 case EMFILE: | 403 case EMFILE: |
332 return PLATFORM_FILE_ERROR_TOO_MANY_OPENED; | 404 return PLATFORM_FILE_ERROR_TOO_MANY_OPENED; |
333 case ENOMEM: | 405 case ENOMEM: |
334 return PLATFORM_FILE_ERROR_NO_MEMORY; | 406 return PLATFORM_FILE_ERROR_NO_MEMORY; |
335 case ENOSPC: | 407 case ENOSPC: |
336 return PLATFORM_FILE_ERROR_NO_SPACE; | 408 return PLATFORM_FILE_ERROR_NO_SPACE; |
337 case ENOTDIR: | 409 case ENOTDIR: |
338 return PLATFORM_FILE_ERROR_NOT_A_DIRECTORY; | 410 return PLATFORM_FILE_ERROR_NOT_A_DIRECTORY; |
339 default: | 411 default: |
340 #if !defined(OS_NACL) // NaCl build has no metrics code. | 412 #if !defined(OS_NACL) // NaCl build has no metrics code. |
341 UMA_HISTOGRAM_SPARSE_SLOWLY("PlatformFile.UnknownErrors.Posix", | 413 UMA_HISTOGRAM_SPARSE_SLOWLY("PlatformFile.UnknownErrors.Posix", |
342 saved_errno); | 414 saved_errno); |
343 #endif | 415 #endif |
344 return PLATFORM_FILE_ERROR_FAILED; | 416 return PLATFORM_FILE_ERROR_FAILED; |
345 } | 417 } |
346 } | 418 } |
347 | 419 |
348 } // namespace base | 420 } // namespace base |
OLD | NEW |