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/posix/eintr_wrapper.h"
15 #include "base/threading/thread_restrictions.h"
16 #include "base/utf_string_conversions.h"
18 #if defined(OS_ANDROID)
19 #include "base/os_compat_android.h"
24 // Make sure our Whence mappings match the system headers.
25 COMPILE_ASSERT(PLATFORM_FILE_FROM_BEGIN
== SEEK_SET
&&
26 PLATFORM_FILE_FROM_CURRENT
== SEEK_CUR
&&
27 PLATFORM_FILE_FROM_END
== SEEK_END
, whence_matches_system
);
29 #if defined(OS_BSD) || defined(OS_MACOSX)
30 typedef struct stat stat_wrapper_t
;
31 static int CallFstat(int fd
, stat_wrapper_t
*sb
) {
32 base::ThreadRestrictions::AssertIOAllowed();
36 typedef struct stat64 stat_wrapper_t
;
37 static int CallFstat(int fd
, stat_wrapper_t
*sb
) {
38 base::ThreadRestrictions::AssertIOAllowed();
39 return fstat64(fd
, sb
);
43 // TODO(erikkay): does it make sense to support PLATFORM_FILE_EXCLUSIVE_* here?
44 PlatformFile
CreatePlatformFileUnsafe(const FilePath
& name
,
47 PlatformFileError
* error
) {
48 base::ThreadRestrictions::AssertIOAllowed();
51 if (flags
& PLATFORM_FILE_CREATE
)
52 open_flags
= O_CREAT
| O_EXCL
;
57 if (flags
& PLATFORM_FILE_CREATE_ALWAYS
) {
59 open_flags
= O_CREAT
| O_TRUNC
;
62 if (flags
& PLATFORM_FILE_OPEN_TRUNCATED
) {
64 DCHECK(flags
& PLATFORM_FILE_WRITE
);
68 if (!open_flags
&& !(flags
& PLATFORM_FILE_OPEN
) &&
69 !(flags
& PLATFORM_FILE_OPEN_ALWAYS
)) {
73 *error
= PLATFORM_FILE_ERROR_FAILED
;
74 return kInvalidPlatformFileValue
;
77 if (flags
& PLATFORM_FILE_WRITE
&& flags
& PLATFORM_FILE_READ
) {
79 } else if (flags
& PLATFORM_FILE_WRITE
) {
80 open_flags
|= O_WRONLY
;
81 } else if (!(flags
& PLATFORM_FILE_READ
) &&
82 !(flags
& PLATFORM_FILE_WRITE_ATTRIBUTES
) &&
83 !(flags
& PLATFORM_FILE_OPEN_ALWAYS
)) {
87 if (flags
& PLATFORM_FILE_TERMINAL_DEVICE
)
88 open_flags
|= O_NOCTTY
| O_NDELAY
;
90 COMPILE_ASSERT(O_RDONLY
== 0, O_RDONLY_must_equal_zero
);
92 int mode
= S_IRUSR
| S_IWUSR
;
93 #if defined(OS_CHROMEOS)
94 mode
|= S_IRGRP
| S_IROTH
;
98 HANDLE_EINTR(open(name
.value().c_str(), open_flags
, mode
));
100 if (flags
& PLATFORM_FILE_OPEN_ALWAYS
) {
101 if (descriptor
< 0) {
102 open_flags
|= O_CREAT
;
103 if (flags
& PLATFORM_FILE_EXCLUSIVE_READ
||
104 flags
& PLATFORM_FILE_EXCLUSIVE_WRITE
) {
105 open_flags
|= O_EXCL
; // together with O_CREAT implies O_NOFOLLOW
107 descriptor
= HANDLE_EINTR(
108 open(name
.value().c_str(), open_flags
, mode
));
109 if (created
&& descriptor
>= 0)
114 if (created
&& (descriptor
>= 0) &&
115 (flags
& (PLATFORM_FILE_CREATE_ALWAYS
| PLATFORM_FILE_CREATE
)))
118 if ((descriptor
>= 0) && (flags
& PLATFORM_FILE_DELETE_ON_CLOSE
)) {
119 unlink(name
.value().c_str());
124 *error
= PLATFORM_FILE_OK
;
126 *error
= ErrnoToPlatformFileError(errno
);
132 FILE* FdopenPlatformFile(PlatformFile file
, const char* mode
) {
133 return fdopen(file
, mode
);
136 bool ClosePlatformFile(PlatformFile file
) {
137 base::ThreadRestrictions::AssertIOAllowed();
138 return !HANDLE_EINTR(close(file
));
141 int64
SeekPlatformFile(PlatformFile file
,
142 PlatformFileWhence whence
,
144 base::ThreadRestrictions::AssertIOAllowed();
145 if (file
< 0 || offset
< 0)
148 return lseek(file
, static_cast<off_t
>(offset
), static_cast<int>(whence
));
151 int ReadPlatformFile(PlatformFile file
, int64 offset
, char* data
, int size
) {
152 base::ThreadRestrictions::AssertIOAllowed();
153 if (file
< 0 || size
< 0)
159 rv
= HANDLE_EINTR(pread(file
, data
+ bytes_read
,
160 size
- bytes_read
, offset
+ bytes_read
));
165 } while (bytes_read
< size
);
167 return bytes_read
? bytes_read
: rv
;
170 int ReadPlatformFileAtCurrentPos(PlatformFile file
, char* data
, int size
) {
171 base::ThreadRestrictions::AssertIOAllowed();
172 if (file
< 0 || size
< 0)
178 rv
= HANDLE_EINTR(read(file
, data
, size
));
183 } while (bytes_read
< size
);
185 return bytes_read
? bytes_read
: rv
;
188 int ReadPlatformFileNoBestEffort(PlatformFile file
, int64 offset
,
189 char* data
, int size
) {
190 base::ThreadRestrictions::AssertIOAllowed();
194 return HANDLE_EINTR(pread(file
, data
, size
, offset
));
197 int ReadPlatformFileCurPosNoBestEffort(PlatformFile file
,
198 char* data
, int size
) {
199 base::ThreadRestrictions::AssertIOAllowed();
200 if (file
< 0 || size
< 0)
203 return HANDLE_EINTR(read(file
, data
, size
));
206 int WritePlatformFile(PlatformFile file
, int64 offset
,
207 const char* data
, int size
) {
208 base::ThreadRestrictions::AssertIOAllowed();
209 if (file
< 0 || size
< 0)
212 int bytes_written
= 0;
215 rv
= HANDLE_EINTR(pwrite(file
, data
+ bytes_written
,
216 size
- bytes_written
, offset
+ bytes_written
));
221 } while (bytes_written
< size
);
223 return bytes_written
? bytes_written
: rv
;
226 int WritePlatformFileAtCurrentPos(PlatformFile file
,
227 const char* data
, int size
) {
228 base::ThreadRestrictions::AssertIOAllowed();
229 if (file
< 0 || size
< 0)
232 int bytes_written
= 0;
235 rv
= HANDLE_EINTR(write(file
, data
, size
));
240 } while (bytes_written
< size
);
242 return bytes_written
? bytes_written
: rv
;
245 int WritePlatformFileCurPosNoBestEffort(PlatformFile file
,
246 const char* data
, int size
) {
247 base::ThreadRestrictions::AssertIOAllowed();
248 if (file
< 0 || size
< 0)
251 return HANDLE_EINTR(write(file
, data
, size
));
254 bool TruncatePlatformFile(PlatformFile file
, int64 length
) {
255 base::ThreadRestrictions::AssertIOAllowed();
256 return ((file
>= 0) && !HANDLE_EINTR(ftruncate(file
, length
)));
259 bool FlushPlatformFile(PlatformFile file
) {
260 base::ThreadRestrictions::AssertIOAllowed();
261 return !HANDLE_EINTR(fsync(file
));
264 bool TouchPlatformFile(PlatformFile file
, const base::Time
& last_access_time
,
265 const base::Time
& last_modified_time
) {
266 base::ThreadRestrictions::AssertIOAllowed();
271 times
[0] = last_access_time
.ToTimeVal();
272 times
[1] = last_modified_time
.ToTimeVal();
274 #ifdef __USE_XOPEN2K8
275 // futimens should be available, but futimes might not be
276 // http://pubs.opengroup.org/onlinepubs/9699919799/
278 timespec ts_times
[2];
279 ts_times
[0].tv_sec
= times
[0].tv_sec
;
280 ts_times
[0].tv_nsec
= times
[0].tv_usec
* 1000;
281 ts_times
[1].tv_sec
= times
[1].tv_sec
;
282 ts_times
[1].tv_nsec
= times
[1].tv_usec
* 1000;
284 return !futimens(file
, ts_times
);
286 return !futimes(file
, times
);
290 bool GetPlatformFileInfo(PlatformFile file
, PlatformFileInfo
* info
) {
294 stat_wrapper_t file_info
;
295 if (CallFstat(file
, &file_info
))
298 info
->is_directory
= S_ISDIR(file_info
.st_mode
);
299 info
->is_symbolic_link
= S_ISLNK(file_info
.st_mode
);
300 info
->size
= file_info
.st_size
;
301 info
->last_modified
= base::Time::FromTimeT(file_info
.st_mtime
);
302 info
->last_accessed
= base::Time::FromTimeT(file_info
.st_atime
);
303 info
->creation_time
= base::Time::FromTimeT(file_info
.st_ctime
);
307 PlatformFileError
ErrnoToPlatformFileError(int saved_errno
) {
308 switch (saved_errno
) {
313 return PLATFORM_FILE_ERROR_ACCESS_DENIED
;
315 return PLATFORM_FILE_ERROR_IN_USE
;
317 return PLATFORM_FILE_ERROR_EXISTS
;
319 return PLATFORM_FILE_ERROR_NOT_FOUND
;
321 return PLATFORM_FILE_ERROR_TOO_MANY_OPENED
;
323 return PLATFORM_FILE_ERROR_NO_MEMORY
;
325 return PLATFORM_FILE_ERROR_NO_SPACE
;
327 return PLATFORM_FILE_ERROR_NOT_A_DIRECTORY
;
329 return PLATFORM_FILE_ERROR_FAILED
;