Update .DEPS.git
[chromium-blink-merge.git] / base / platform_file_posix.cc
blobaf79198a0ceb4fc479af3bbdcba4e303a7ec9296
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"
7 #include <fcntl.h>
8 #include <errno.h>
9 #include <sys/stat.h>
10 #include <unistd.h>
12 #include "base/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"
20 #endif
22 namespace base {
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();
33 return fstat(fd, sb);
35 #else
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);
41 #endif
43 // TODO(erikkay): does it make sense to support PLATFORM_FILE_EXCLUSIVE_* here?
44 PlatformFile CreatePlatformFile(const FilePath& name, int flags,
45 bool* created, PlatformFileError* error_code) {
46 base::ThreadRestrictions::AssertIOAllowed();
48 int open_flags = 0;
49 if (flags & PLATFORM_FILE_CREATE)
50 open_flags = O_CREAT | O_EXCL;
52 if (created)
53 *created = false;
55 if (flags & PLATFORM_FILE_CREATE_ALWAYS) {
56 DCHECK(!open_flags);
57 open_flags = O_CREAT | O_TRUNC;
60 if (flags & PLATFORM_FILE_OPEN_TRUNCATED) {
61 DCHECK(!open_flags);
62 DCHECK(flags & PLATFORM_FILE_WRITE);
63 open_flags = O_TRUNC;
66 if (!open_flags && !(flags & PLATFORM_FILE_OPEN) &&
67 !(flags & PLATFORM_FILE_OPEN_ALWAYS)) {
68 NOTREACHED();
69 errno = EOPNOTSUPP;
70 if (error_code)
71 *error_code = PLATFORM_FILE_ERROR_FAILED;
72 return kInvalidPlatformFileValue;
75 if (flags & PLATFORM_FILE_WRITE && flags & PLATFORM_FILE_READ) {
76 open_flags |= O_RDWR;
77 } else if (flags & PLATFORM_FILE_WRITE) {
78 open_flags |= O_WRONLY;
79 } else if (!(flags & PLATFORM_FILE_READ) &&
80 !(flags & PLATFORM_FILE_WRITE_ATTRIBUTES) &&
81 !(flags & PLATFORM_FILE_OPEN_ALWAYS)) {
82 NOTREACHED();
85 if (flags & PLATFORM_FILE_TERMINAL_DEVICE)
86 open_flags |= O_NOCTTY | O_NDELAY;
88 COMPILE_ASSERT(O_RDONLY == 0, O_RDONLY_must_equal_zero);
90 int mode = S_IRUSR | S_IWUSR;
91 #if defined(OS_CHROMEOS)
92 mode |= S_IRGRP | S_IROTH;
93 #endif
95 int descriptor =
96 HANDLE_EINTR(open(name.value().c_str(), open_flags, mode));
98 if (flags & PLATFORM_FILE_OPEN_ALWAYS) {
99 if (descriptor < 0) {
100 open_flags |= O_CREAT;
101 if (flags & PLATFORM_FILE_EXCLUSIVE_READ ||
102 flags & PLATFORM_FILE_EXCLUSIVE_WRITE) {
103 open_flags |= O_EXCL; // together with O_CREAT implies O_NOFOLLOW
105 descriptor = HANDLE_EINTR(
106 open(name.value().c_str(), open_flags, mode));
107 if (created && descriptor >= 0)
108 *created = true;
112 if (created && (descriptor >= 0) &&
113 (flags & (PLATFORM_FILE_CREATE_ALWAYS | PLATFORM_FILE_CREATE)))
114 *created = true;
116 if ((descriptor >= 0) && (flags & PLATFORM_FILE_DELETE_ON_CLOSE)) {
117 unlink(name.value().c_str());
120 if (error_code) {
121 if (descriptor >= 0)
122 *error_code = PLATFORM_FILE_OK;
123 else {
124 switch (errno) {
125 case EACCES:
126 case EISDIR:
127 case EROFS:
128 case EPERM:
129 *error_code = PLATFORM_FILE_ERROR_ACCESS_DENIED;
130 break;
131 case ETXTBSY:
132 *error_code = PLATFORM_FILE_ERROR_IN_USE;
133 break;
134 case EEXIST:
135 *error_code = PLATFORM_FILE_ERROR_EXISTS;
136 break;
137 case ENOENT:
138 *error_code = PLATFORM_FILE_ERROR_NOT_FOUND;
139 break;
140 case EMFILE:
141 *error_code = PLATFORM_FILE_ERROR_TOO_MANY_OPENED;
142 break;
143 case ENOMEM:
144 *error_code = PLATFORM_FILE_ERROR_NO_MEMORY;
145 break;
146 case ENOSPC:
147 *error_code = PLATFORM_FILE_ERROR_NO_SPACE;
148 break;
149 case ENOTDIR:
150 *error_code = PLATFORM_FILE_ERROR_NOT_A_DIRECTORY;
151 break;
152 default:
153 *error_code = PLATFORM_FILE_ERROR_FAILED;
158 return descriptor;
161 bool ClosePlatformFile(PlatformFile file) {
162 base::ThreadRestrictions::AssertIOAllowed();
163 return !HANDLE_EINTR(close(file));
166 int64 SeekPlatformFile(PlatformFile file,
167 PlatformFileWhence whence,
168 int64 offset) {
169 base::ThreadRestrictions::AssertIOAllowed();
170 if (file < 0 || offset < 0)
171 return -1;
173 return lseek(file, static_cast<off_t>(offset), static_cast<int>(whence));
176 int ReadPlatformFile(PlatformFile file, int64 offset, char* data, int size) {
177 base::ThreadRestrictions::AssertIOAllowed();
178 if (file < 0 || size < 0)
179 return -1;
181 int bytes_read = 0;
182 int rv;
183 do {
184 rv = HANDLE_EINTR(pread(file, data + bytes_read,
185 size - bytes_read, offset + bytes_read));
186 if (rv <= 0)
187 break;
189 bytes_read += rv;
190 } while (bytes_read < size);
192 return bytes_read ? bytes_read : rv;
195 int ReadPlatformFileAtCurrentPos(PlatformFile file, char* data, int size) {
196 base::ThreadRestrictions::AssertIOAllowed();
197 if (file < 0 || size < 0)
198 return -1;
200 int bytes_read = 0;
201 int rv;
202 do {
203 rv = HANDLE_EINTR(read(file, data, size));
204 if (rv <= 0)
205 break;
207 bytes_read += rv;
208 } while (bytes_read < size);
210 return bytes_read ? bytes_read : rv;
213 int ReadPlatformFileNoBestEffort(PlatformFile file, int64 offset,
214 char* data, int size) {
215 base::ThreadRestrictions::AssertIOAllowed();
216 if (file < 0)
217 return -1;
219 return HANDLE_EINTR(pread(file, data, size, offset));
222 int ReadPlatformFileCurPosNoBestEffort(PlatformFile file,
223 char* data, int size) {
224 base::ThreadRestrictions::AssertIOAllowed();
225 if (file < 0 || size < 0)
226 return -1;
228 return HANDLE_EINTR(read(file, data, size));
231 int WritePlatformFile(PlatformFile file, int64 offset,
232 const char* data, int size) {
233 base::ThreadRestrictions::AssertIOAllowed();
234 if (file < 0 || size < 0)
235 return -1;
237 int bytes_written = 0;
238 int rv;
239 do {
240 rv = HANDLE_EINTR(pwrite(file, data + bytes_written,
241 size - bytes_written, offset + bytes_written));
242 if (rv <= 0)
243 break;
245 bytes_written += rv;
246 } while (bytes_written < size);
248 return bytes_written ? bytes_written : rv;
251 int WritePlatformFileAtCurrentPos(PlatformFile file,
252 const char* data, int size) {
253 base::ThreadRestrictions::AssertIOAllowed();
254 if (file < 0 || size < 0)
255 return -1;
257 int bytes_written = 0;
258 int rv;
259 do {
260 rv = HANDLE_EINTR(write(file, data, size));
261 if (rv <= 0)
262 break;
264 bytes_written += rv;
265 } while (bytes_written < size);
267 return bytes_written ? bytes_written : rv;
270 int WritePlatformFileCurPosNoBestEffort(PlatformFile file,
271 const char* data, int size) {
272 base::ThreadRestrictions::AssertIOAllowed();
273 if (file < 0 || size < 0)
274 return -1;
276 return HANDLE_EINTR(write(file, data, size));
279 bool TruncatePlatformFile(PlatformFile file, int64 length) {
280 base::ThreadRestrictions::AssertIOAllowed();
281 return ((file >= 0) && !HANDLE_EINTR(ftruncate(file, length)));
284 bool FlushPlatformFile(PlatformFile file) {
285 base::ThreadRestrictions::AssertIOAllowed();
286 return !HANDLE_EINTR(fsync(file));
289 bool TouchPlatformFile(PlatformFile file, const base::Time& last_access_time,
290 const base::Time& last_modified_time) {
291 base::ThreadRestrictions::AssertIOAllowed();
292 if (file < 0)
293 return false;
295 timeval times[2];
296 times[0] = last_access_time.ToTimeVal();
297 times[1] = last_modified_time.ToTimeVal();
298 return !futimes(file, times);
301 bool GetPlatformFileInfo(PlatformFile file, PlatformFileInfo* info) {
302 if (!info)
303 return false;
305 stat_wrapper_t file_info;
306 if (CallFstat(file, &file_info))
307 return false;
309 info->is_directory = S_ISDIR(file_info.st_mode);
310 info->is_symbolic_link = S_ISLNK(file_info.st_mode);
311 info->size = file_info.st_size;
312 info->last_modified = base::Time::FromTimeT(file_info.st_mtime);
313 info->last_accessed = base::Time::FromTimeT(file_info.st_atime);
314 info->creation_time = base::Time::FromTimeT(file_info.st_ctime);
315 return true;
318 } // namespace base