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
3 // found in the LICENSE file.
5 #include "base/platform_file.h"
12 #include "base/files/file_path.h"
13 #include "base/logging.h"
14 #include "base/metrics/sparse_histogram.h"
15 #include "base/posix/eintr_wrapper.h"
16 #include "base/threading/thread_restrictions.h"
17 #include "base/utf_string_conversions.h"
19 #if defined(OS_ANDROID)
20 #include "base/os_compat_android.h"
25 // Make sure our Whence mappings match the system headers.
26 COMPILE_ASSERT(PLATFORM_FILE_FROM_BEGIN
== SEEK_SET
&&
27 PLATFORM_FILE_FROM_CURRENT
== SEEK_CUR
&&
28 PLATFORM_FILE_FROM_END
== SEEK_END
, whence_matches_system
);
30 #if defined(OS_BSD) || defined(OS_MACOSX)
31 typedef struct stat stat_wrapper_t
;
32 static int CallFstat(int fd
, stat_wrapper_t
*sb
) {
33 base::ThreadRestrictions::AssertIOAllowed();
37 typedef struct stat64 stat_wrapper_t
;
38 static int CallFstat(int fd
, stat_wrapper_t
*sb
) {
39 base::ThreadRestrictions::AssertIOAllowed();
40 return fstat64(fd
, sb
);
44 // TODO(erikkay): does it make sense to support PLATFORM_FILE_EXCLUSIVE_* here?
45 PlatformFile
CreatePlatformFileUnsafe(const FilePath
& name
,
48 PlatformFileError
* error
) {
49 base::ThreadRestrictions::AssertIOAllowed();
52 if (flags
& PLATFORM_FILE_CREATE
)
53 open_flags
= O_CREAT
| O_EXCL
;
58 if (flags
& PLATFORM_FILE_CREATE_ALWAYS
) {
60 open_flags
= O_CREAT
| O_TRUNC
;
63 if (flags
& PLATFORM_FILE_OPEN_TRUNCATED
) {
65 DCHECK(flags
& PLATFORM_FILE_WRITE
);
69 if (!open_flags
&& !(flags
& PLATFORM_FILE_OPEN
) &&
70 !(flags
& PLATFORM_FILE_OPEN_ALWAYS
)) {
74 *error
= PLATFORM_FILE_ERROR_FAILED
;
75 return kInvalidPlatformFileValue
;
78 if (flags
& PLATFORM_FILE_WRITE
&& flags
& PLATFORM_FILE_READ
) {
80 } else if (flags
& PLATFORM_FILE_WRITE
) {
81 open_flags
|= O_WRONLY
;
82 } else if (!(flags
& PLATFORM_FILE_READ
) &&
83 !(flags
& PLATFORM_FILE_WRITE_ATTRIBUTES
) &&
84 !(flags
& PLATFORM_FILE_OPEN_ALWAYS
)) {
88 if (flags
& PLATFORM_FILE_TERMINAL_DEVICE
)
89 open_flags
|= O_NOCTTY
| O_NDELAY
;
91 COMPILE_ASSERT(O_RDONLY
== 0, O_RDONLY_must_equal_zero
);
93 int mode
= S_IRUSR
| S_IWUSR
;
94 #if defined(OS_CHROMEOS)
95 mode
|= S_IRGRP
| S_IROTH
;
99 HANDLE_EINTR(open(name
.value().c_str(), open_flags
, mode
));
101 if (flags
& PLATFORM_FILE_OPEN_ALWAYS
) {
102 if (descriptor
< 0) {
103 open_flags
|= O_CREAT
;
104 if (flags
& PLATFORM_FILE_EXCLUSIVE_READ
||
105 flags
& PLATFORM_FILE_EXCLUSIVE_WRITE
) {
106 open_flags
|= O_EXCL
; // together with O_CREAT implies O_NOFOLLOW
108 descriptor
= HANDLE_EINTR(
109 open(name
.value().c_str(), open_flags
, mode
));
110 if (created
&& descriptor
>= 0)
115 if (created
&& (descriptor
>= 0) &&
116 (flags
& (PLATFORM_FILE_CREATE_ALWAYS
| PLATFORM_FILE_CREATE
)))
119 if ((descriptor
>= 0) && (flags
& PLATFORM_FILE_DELETE_ON_CLOSE
)) {
120 unlink(name
.value().c_str());
125 *error
= PLATFORM_FILE_OK
;
127 *error
= ErrnoToPlatformFileError(errno
);
133 FILE* FdopenPlatformFile(PlatformFile file
, const char* mode
) {
134 return fdopen(file
, mode
);
137 bool ClosePlatformFile(PlatformFile file
) {
138 base::ThreadRestrictions::AssertIOAllowed();
139 return !HANDLE_EINTR(close(file
));
142 int64
SeekPlatformFile(PlatformFile file
,
143 PlatformFileWhence whence
,
145 base::ThreadRestrictions::AssertIOAllowed();
146 if (file
< 0 || offset
< 0)
149 return lseek(file
, static_cast<off_t
>(offset
), static_cast<int>(whence
));
152 int ReadPlatformFile(PlatformFile file
, int64 offset
, char* data
, int size
) {
153 base::ThreadRestrictions::AssertIOAllowed();
154 if (file
< 0 || size
< 0)
160 rv
= HANDLE_EINTR(pread(file
, data
+ bytes_read
,
161 size
- bytes_read
, offset
+ bytes_read
));
166 } while (bytes_read
< size
);
168 return bytes_read
? bytes_read
: rv
;
171 int ReadPlatformFileAtCurrentPos(PlatformFile file
, char* data
, int size
) {
172 base::ThreadRestrictions::AssertIOAllowed();
173 if (file
< 0 || size
< 0)
179 rv
= HANDLE_EINTR(read(file
, data
, size
));
184 } while (bytes_read
< size
);
186 return bytes_read
? bytes_read
: rv
;
189 int ReadPlatformFileNoBestEffort(PlatformFile file
, int64 offset
,
190 char* data
, int size
) {
191 base::ThreadRestrictions::AssertIOAllowed();
195 return HANDLE_EINTR(pread(file
, data
, size
, offset
));
198 int ReadPlatformFileCurPosNoBestEffort(PlatformFile file
,
199 char* data
, int size
) {
200 base::ThreadRestrictions::AssertIOAllowed();
201 if (file
< 0 || size
< 0)
204 return HANDLE_EINTR(read(file
, data
, size
));
207 int WritePlatformFile(PlatformFile file
, int64 offset
,
208 const char* data
, int size
) {
209 base::ThreadRestrictions::AssertIOAllowed();
210 if (file
< 0 || size
< 0)
213 int bytes_written
= 0;
216 rv
= HANDLE_EINTR(pwrite(file
, data
+ bytes_written
,
217 size
- bytes_written
, offset
+ bytes_written
));
222 } while (bytes_written
< size
);
224 return bytes_written
? bytes_written
: rv
;
227 int WritePlatformFileAtCurrentPos(PlatformFile file
,
228 const char* data
, int size
) {
229 base::ThreadRestrictions::AssertIOAllowed();
230 if (file
< 0 || size
< 0)
233 int bytes_written
= 0;
236 rv
= HANDLE_EINTR(write(file
, data
, size
));
241 } while (bytes_written
< size
);
243 return bytes_written
? bytes_written
: rv
;
246 int WritePlatformFileCurPosNoBestEffort(PlatformFile file
,
247 const char* data
, int size
) {
248 base::ThreadRestrictions::AssertIOAllowed();
249 if (file
< 0 || size
< 0)
252 return HANDLE_EINTR(write(file
, data
, size
));
255 bool TruncatePlatformFile(PlatformFile file
, int64 length
) {
256 base::ThreadRestrictions::AssertIOAllowed();
257 return ((file
>= 0) && !HANDLE_EINTR(ftruncate(file
, length
)));
260 bool FlushPlatformFile(PlatformFile file
) {
261 base::ThreadRestrictions::AssertIOAllowed();
262 return !HANDLE_EINTR(fsync(file
));
265 bool TouchPlatformFile(PlatformFile file
, const base::Time
& last_access_time
,
266 const base::Time
& last_modified_time
) {
267 base::ThreadRestrictions::AssertIOAllowed();
272 times
[0] = last_access_time
.ToTimeVal();
273 times
[1] = last_modified_time
.ToTimeVal();
275 #ifdef __USE_XOPEN2K8
276 // futimens should be available, but futimes might not be
277 // http://pubs.opengroup.org/onlinepubs/9699919799/
279 timespec ts_times
[2];
280 ts_times
[0].tv_sec
= times
[0].tv_sec
;
281 ts_times
[0].tv_nsec
= times
[0].tv_usec
* 1000;
282 ts_times
[1].tv_sec
= times
[1].tv_sec
;
283 ts_times
[1].tv_nsec
= times
[1].tv_usec
* 1000;
285 return !futimens(file
, ts_times
);
287 return !futimes(file
, times
);
291 bool GetPlatformFileInfo(PlatformFile file
, PlatformFileInfo
* info
) {
295 stat_wrapper_t file_info
;
296 if (CallFstat(file
, &file_info
))
299 info
->is_directory
= S_ISDIR(file_info
.st_mode
);
300 info
->is_symbolic_link
= S_ISLNK(file_info
.st_mode
);
301 info
->size
= file_info
.st_size
;
302 info
->last_modified
= base::Time::FromTimeT(file_info
.st_mtime
);
303 info
->last_accessed
= base::Time::FromTimeT(file_info
.st_atime
);
304 info
->creation_time
= base::Time::FromTimeT(file_info
.st_ctime
);
308 PlatformFileError
ErrnoToPlatformFileError(int saved_errno
) {
309 switch (saved_errno
) {
314 return PLATFORM_FILE_ERROR_ACCESS_DENIED
;
316 return PLATFORM_FILE_ERROR_IN_USE
;
318 return PLATFORM_FILE_ERROR_EXISTS
;
320 return PLATFORM_FILE_ERROR_NOT_FOUND
;
322 return PLATFORM_FILE_ERROR_TOO_MANY_OPENED
;
324 return PLATFORM_FILE_ERROR_NO_MEMORY
;
326 return PLATFORM_FILE_ERROR_NO_SPACE
;
328 return PLATFORM_FILE_ERROR_NOT_A_DIRECTORY
;
330 #if !defined(OS_NACL) // NaCl build has no metrics code.
331 UMA_HISTOGRAM_SPARSE_SLOWLY("PlatformFile.UnknownErrors.Posix",
334 return PLATFORM_FILE_ERROR_FAILED
;