Revert of non-new-profile-management creates a "no-op" style account_reconcilor,...
[chromium-blink-merge.git] / base / platform_file_posix.cc
blobff92b90a7c3c32fdbb8ad7b15adf59d3be3e44a1
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/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/strings/utf_string_conversions.h"
17 #include "base/threading/thread_restrictions.h"
19 #if defined(OS_ANDROID)
20 #include "base/os_compat_android.h"
21 #endif
23 namespace base {
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 namespace {
32 #if defined(OS_BSD) || defined(OS_MACOSX) || defined(OS_NACL)
33 typedef struct stat stat_wrapper_t;
34 static int CallFstat(int fd, stat_wrapper_t *sb) {
35 base::ThreadRestrictions::AssertIOAllowed();
36 return fstat(fd, sb);
38 #else
39 typedef struct stat64 stat_wrapper_t;
40 static int CallFstat(int fd, stat_wrapper_t *sb) {
41 base::ThreadRestrictions::AssertIOAllowed();
42 return fstat64(fd, sb);
44 #endif
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 bool IsOpenAppend(PlatformFile file) {
50 return (fcntl(file, F_GETFL) & O_APPEND) != 0;
53 static int CallFtruncate(PlatformFile file, int64 length) {
54 return HANDLE_EINTR(ftruncate(file, length));
57 static int CallFsync(PlatformFile file) {
58 return HANDLE_EINTR(fsync(file));
61 static int CallFutimes(PlatformFile file, const struct timeval times[2]) {
62 #ifdef __USE_XOPEN2K8
63 // futimens should be available, but futimes might not be
64 // http://pubs.opengroup.org/onlinepubs/9699919799/
66 timespec ts_times[2];
67 ts_times[0].tv_sec = times[0].tv_sec;
68 ts_times[0].tv_nsec = times[0].tv_usec * 1000;
69 ts_times[1].tv_sec = times[1].tv_sec;
70 ts_times[1].tv_nsec = times[1].tv_usec * 1000;
72 return futimens(file, ts_times);
73 #else
74 return futimes(file, times);
75 #endif
78 static PlatformFileError CallFctnlFlock(PlatformFile file, bool do_lock) {
79 struct flock lock;
80 lock.l_type = F_WRLCK;
81 lock.l_whence = SEEK_SET;
82 lock.l_start = 0;
83 lock.l_len = 0; // Lock entire file.
84 if (HANDLE_EINTR(fcntl(file, do_lock ? F_SETLK : F_UNLCK, &lock)) == -1)
85 return ErrnoToPlatformFileError(errno);
86 return PLATFORM_FILE_OK;
88 #else // defined(OS_NACL)
90 static bool IsOpenAppend(PlatformFile file) {
91 // NaCl doesn't implement fcntl. Since NaCl's write conforms to the POSIX
92 // standard and always appends if the file is opened with O_APPEND, just
93 // return false here.
94 return false;
97 static int CallFtruncate(PlatformFile file, int64 length) {
98 NOTIMPLEMENTED(); // NaCl doesn't implement ftruncate.
99 return 0;
102 static int CallFsync(PlatformFile file) {
103 NOTIMPLEMENTED(); // NaCl doesn't implement fsync.
104 return 0;
107 static int CallFutimes(PlatformFile file, const struct timeval times[2]) {
108 NOTIMPLEMENTED(); // NaCl doesn't implement futimes.
109 return 0;
112 static PlatformFileError CallFctnlFlock(PlatformFile file, bool do_lock) {
113 NOTIMPLEMENTED(); // NaCl doesn't implement flock struct.
114 return PLATFORM_FILE_ERROR_INVALID_OPERATION;
116 #endif // defined(OS_NACL)
118 } // namespace
120 // NaCl doesn't implement system calls to open files directly.
121 #if !defined(OS_NACL)
122 FILE* FdopenPlatformFile(PlatformFile file, const char* mode) {
123 return fdopen(file, mode);
125 #endif // !defined(OS_NACL)
127 bool ClosePlatformFile(PlatformFile file) {
128 base::ThreadRestrictions::AssertIOAllowed();
129 return !IGNORE_EINTR(close(file));
132 int64 SeekPlatformFile(PlatformFile file,
133 PlatformFileWhence whence,
134 int64 offset) {
135 base::ThreadRestrictions::AssertIOAllowed();
136 if (file < 0 || offset < 0)
137 return -1;
139 return lseek(file, static_cast<off_t>(offset), static_cast<int>(whence));
142 int ReadPlatformFile(PlatformFile file, int64 offset, char* data, int size) {
143 base::ThreadRestrictions::AssertIOAllowed();
144 if (file < 0 || size < 0)
145 return -1;
147 int bytes_read = 0;
148 int rv;
149 do {
150 rv = HANDLE_EINTR(pread(file, data + bytes_read,
151 size - bytes_read, offset + bytes_read));
152 if (rv <= 0)
153 break;
155 bytes_read += rv;
156 } while (bytes_read < size);
158 return bytes_read ? bytes_read : rv;
161 int ReadPlatformFileAtCurrentPos(PlatformFile file, char* data, int size) {
162 base::ThreadRestrictions::AssertIOAllowed();
163 if (file < 0 || size < 0)
164 return -1;
166 int bytes_read = 0;
167 int rv;
168 do {
169 rv = HANDLE_EINTR(read(file, data + bytes_read, size - bytes_read));
170 if (rv <= 0)
171 break;
173 bytes_read += rv;
174 } while (bytes_read < size);
176 return bytes_read ? bytes_read : rv;
179 int ReadPlatformFileNoBestEffort(PlatformFile file, int64 offset,
180 char* data, int size) {
181 base::ThreadRestrictions::AssertIOAllowed();
182 if (file < 0)
183 return -1;
185 return HANDLE_EINTR(pread(file, data, size, offset));
188 int ReadPlatformFileCurPosNoBestEffort(PlatformFile file,
189 char* data, int size) {
190 base::ThreadRestrictions::AssertIOAllowed();
191 if (file < 0 || size < 0)
192 return -1;
194 return HANDLE_EINTR(read(file, data, size));
197 int WritePlatformFile(PlatformFile file, int64 offset,
198 const char* data, int size) {
199 base::ThreadRestrictions::AssertIOAllowed();
201 if (IsOpenAppend(file))
202 return WritePlatformFileAtCurrentPos(file, data, size);
204 if (file < 0 || size < 0)
205 return -1;
207 int bytes_written = 0;
208 int rv;
209 do {
210 rv = HANDLE_EINTR(pwrite(file, data + bytes_written,
211 size - bytes_written, offset + bytes_written));
212 if (rv <= 0)
213 break;
215 bytes_written += rv;
216 } while (bytes_written < size);
218 return bytes_written ? bytes_written : rv;
221 int WritePlatformFileAtCurrentPos(PlatformFile file,
222 const char* data, int size) {
223 base::ThreadRestrictions::AssertIOAllowed();
224 if (file < 0 || size < 0)
225 return -1;
227 int bytes_written = 0;
228 int rv;
229 do {
230 rv = HANDLE_EINTR(write(file, data + bytes_written, size - bytes_written));
231 if (rv <= 0)
232 break;
234 bytes_written += rv;
235 } while (bytes_written < size);
237 return bytes_written ? bytes_written : rv;
240 int WritePlatformFileCurPosNoBestEffort(PlatformFile file,
241 const char* data, int size) {
242 base::ThreadRestrictions::AssertIOAllowed();
243 if (file < 0 || size < 0)
244 return -1;
246 return HANDLE_EINTR(write(file, data, size));
249 bool TruncatePlatformFile(PlatformFile file, int64 length) {
250 base::ThreadRestrictions::AssertIOAllowed();
251 return ((file >= 0) && !CallFtruncate(file, length));
254 bool FlushPlatformFile(PlatformFile file) {
255 base::ThreadRestrictions::AssertIOAllowed();
256 return !CallFsync(file);
259 bool TouchPlatformFile(PlatformFile file, const base::Time& last_access_time,
260 const base::Time& last_modified_time) {
261 base::ThreadRestrictions::AssertIOAllowed();
262 if (file < 0)
263 return false;
265 timeval times[2];
266 times[0] = last_access_time.ToTimeVal();
267 times[1] = last_modified_time.ToTimeVal();
269 return !CallFutimes(file, times);
272 bool GetPlatformFileInfo(PlatformFile file, PlatformFileInfo* info) {
273 if (!info)
274 return false;
276 stat_wrapper_t file_info;
277 if (CallFstat(file, &file_info))
278 return false;
280 info->is_directory = S_ISDIR(file_info.st_mode);
281 info->is_symbolic_link = S_ISLNK(file_info.st_mode);
282 info->size = file_info.st_size;
284 #if defined(OS_LINUX)
285 const time_t last_modified_sec = file_info.st_mtim.tv_sec;
286 const int64 last_modified_nsec = file_info.st_mtim.tv_nsec;
287 const time_t last_accessed_sec = file_info.st_atim.tv_sec;
288 const int64 last_accessed_nsec = file_info.st_atim.tv_nsec;
289 const time_t creation_time_sec = file_info.st_ctim.tv_sec;
290 const int64 creation_time_nsec = file_info.st_ctim.tv_nsec;
291 #elif defined(OS_ANDROID)
292 const time_t last_modified_sec = file_info.st_mtime;
293 const int64 last_modified_nsec = file_info.st_mtime_nsec;
294 const time_t last_accessed_sec = file_info.st_atime;
295 const int64 last_accessed_nsec = file_info.st_atime_nsec;
296 const time_t creation_time_sec = file_info.st_ctime;
297 const int64 creation_time_nsec = file_info.st_ctime_nsec;
298 #elif defined(OS_MACOSX) || defined(OS_IOS) || defined(OS_BSD)
299 const time_t last_modified_sec = file_info.st_mtimespec.tv_sec;
300 const int64 last_modified_nsec = file_info.st_mtimespec.tv_nsec;
301 const time_t last_accessed_sec = file_info.st_atimespec.tv_sec;
302 const int64 last_accessed_nsec = file_info.st_atimespec.tv_nsec;
303 const time_t creation_time_sec = file_info.st_ctimespec.tv_sec;
304 const int64 creation_time_nsec = file_info.st_ctimespec.tv_nsec;
305 #else
306 // TODO(gavinp): Investigate a good high resolution option for OS_NACL.
307 const time_t last_modified_sec = file_info.st_mtime;
308 const int64 last_modified_nsec = 0;
309 const time_t last_accessed_sec = file_info.st_atime;
310 const int64 last_accessed_nsec = 0;
311 const time_t creation_time_sec = file_info.st_ctime;
312 const int64 creation_time_nsec = 0;
313 #endif
315 info->last_modified =
316 base::Time::FromTimeT(last_modified_sec) +
317 base::TimeDelta::FromMicroseconds(last_modified_nsec /
318 base::Time::kNanosecondsPerMicrosecond);
319 info->last_accessed =
320 base::Time::FromTimeT(last_accessed_sec) +
321 base::TimeDelta::FromMicroseconds(last_accessed_nsec /
322 base::Time::kNanosecondsPerMicrosecond);
323 info->creation_time =
324 base::Time::FromTimeT(creation_time_sec) +
325 base::TimeDelta::FromMicroseconds(creation_time_nsec /
326 base::Time::kNanosecondsPerMicrosecond);
327 return true;
330 PlatformFileError LockPlatformFile(PlatformFile file) {
331 return CallFctnlFlock(file, true);
334 PlatformFileError UnlockPlatformFile(PlatformFile file) {
335 return CallFctnlFlock(file, false);
338 PlatformFileError ErrnoToPlatformFileError(int saved_errno) {
339 switch (saved_errno) {
340 case EACCES:
341 case EISDIR:
342 case EROFS:
343 case EPERM:
344 return PLATFORM_FILE_ERROR_ACCESS_DENIED;
345 #if !defined(OS_NACL) // ETXTBSY not defined by NaCl.
346 case ETXTBSY:
347 return PLATFORM_FILE_ERROR_IN_USE;
348 #endif
349 case EEXIST:
350 return PLATFORM_FILE_ERROR_EXISTS;
351 case ENOENT:
352 return PLATFORM_FILE_ERROR_NOT_FOUND;
353 case EMFILE:
354 return PLATFORM_FILE_ERROR_TOO_MANY_OPENED;
355 case ENOMEM:
356 return PLATFORM_FILE_ERROR_NO_MEMORY;
357 case ENOSPC:
358 return PLATFORM_FILE_ERROR_NO_SPACE;
359 case ENOTDIR:
360 return PLATFORM_FILE_ERROR_NOT_A_DIRECTORY;
361 default:
362 #if !defined(OS_NACL) // NaCl build has no metrics code.
363 UMA_HISTOGRAM_SPARSE_SLOWLY("PlatformFile.UnknownErrors.Posix",
364 saved_errno);
365 #endif
366 return PLATFORM_FILE_ERROR_FAILED;
370 } // namespace base