Simple Cache: a few tests for rare corner cases with CRC check missing.
[chromium-blink-merge.git] / base / platform_file_posix.cc
blobbeae804c629c86a6b8fa4ef716f601552d9a114e
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/threading/thread_restrictions.h"
17 #include "base/utf_string_conversions.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 #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();
34 return fstat(fd, sb);
36 #else
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);
42 #endif
44 // TODO(erikkay): does it make sense to support PLATFORM_FILE_EXCLUSIVE_* here?
45 PlatformFile CreatePlatformFileUnsafe(const FilePath& name,
46 int flags,
47 bool* created,
48 PlatformFileError* error) {
49 base::ThreadRestrictions::AssertIOAllowed();
51 int open_flags = 0;
52 if (flags & PLATFORM_FILE_CREATE)
53 open_flags = O_CREAT | O_EXCL;
55 if (created)
56 *created = false;
58 if (flags & PLATFORM_FILE_CREATE_ALWAYS) {
59 DCHECK(!open_flags);
60 open_flags = O_CREAT | O_TRUNC;
63 if (flags & PLATFORM_FILE_OPEN_TRUNCATED) {
64 DCHECK(!open_flags);
65 DCHECK(flags & PLATFORM_FILE_WRITE);
66 open_flags = O_TRUNC;
69 if (!open_flags && !(flags & PLATFORM_FILE_OPEN) &&
70 !(flags & PLATFORM_FILE_OPEN_ALWAYS)) {
71 NOTREACHED();
72 errno = EOPNOTSUPP;
73 if (error)
74 *error = PLATFORM_FILE_ERROR_FAILED;
75 return kInvalidPlatformFileValue;
78 if (flags & PLATFORM_FILE_WRITE && flags & PLATFORM_FILE_READ) {
79 open_flags |= O_RDWR;
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)) {
85 NOTREACHED();
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;
96 #endif
98 int descriptor =
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)
111 *created = true;
115 if (created && (descriptor >= 0) &&
116 (flags & (PLATFORM_FILE_CREATE_ALWAYS | PLATFORM_FILE_CREATE)))
117 *created = true;
119 if ((descriptor >= 0) && (flags & PLATFORM_FILE_DELETE_ON_CLOSE)) {
120 unlink(name.value().c_str());
123 if (error) {
124 if (descriptor >= 0)
125 *error = PLATFORM_FILE_OK;
126 else
127 *error = ErrnoToPlatformFileError(errno);
130 return descriptor;
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,
144 int64 offset) {
145 base::ThreadRestrictions::AssertIOAllowed();
146 if (file < 0 || offset < 0)
147 return -1;
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)
155 return -1;
157 int bytes_read = 0;
158 int rv;
159 do {
160 rv = HANDLE_EINTR(pread(file, data + bytes_read,
161 size - bytes_read, offset + bytes_read));
162 if (rv <= 0)
163 break;
165 bytes_read += rv;
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)
174 return -1;
176 int bytes_read = 0;
177 int rv;
178 do {
179 rv = HANDLE_EINTR(read(file, data, size));
180 if (rv <= 0)
181 break;
183 bytes_read += rv;
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();
192 if (file < 0)
193 return -1;
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)
202 return -1;
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)
211 return -1;
213 int bytes_written = 0;
214 int rv;
215 do {
216 rv = HANDLE_EINTR(pwrite(file, data + bytes_written,
217 size - bytes_written, offset + bytes_written));
218 if (rv <= 0)
219 break;
221 bytes_written += rv;
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)
231 return -1;
233 int bytes_written = 0;
234 int rv;
235 do {
236 rv = HANDLE_EINTR(write(file, data, size));
237 if (rv <= 0)
238 break;
240 bytes_written += rv;
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)
250 return -1;
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();
268 if (file < 0)
269 return false;
271 timeval times[2];
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);
286 #else
287 return !futimes(file, times);
288 #endif
291 bool GetPlatformFileInfo(PlatformFile file, PlatformFileInfo* info) {
292 if (!info)
293 return false;
295 stat_wrapper_t file_info;
296 if (CallFstat(file, &file_info))
297 return false;
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);
305 return true;
308 PlatformFileError ErrnoToPlatformFileError(int saved_errno) {
309 switch (saved_errno) {
310 case EACCES:
311 case EISDIR:
312 case EROFS:
313 case EPERM:
314 return PLATFORM_FILE_ERROR_ACCESS_DENIED;
315 case ETXTBSY:
316 return PLATFORM_FILE_ERROR_IN_USE;
317 case EEXIST:
318 return PLATFORM_FILE_ERROR_EXISTS;
319 case ENOENT:
320 return PLATFORM_FILE_ERROR_NOT_FOUND;
321 case EMFILE:
322 return PLATFORM_FILE_ERROR_TOO_MANY_OPENED;
323 case ENOMEM:
324 return PLATFORM_FILE_ERROR_NO_MEMORY;
325 case ENOSPC:
326 return PLATFORM_FILE_ERROR_NO_SPACE;
327 case ENOTDIR:
328 return PLATFORM_FILE_ERROR_NOT_A_DIRECTORY;
329 default:
330 #if !defined(OS_NACL) // NaCl build has no metrics code.
331 UMA_HISTOGRAM_SPARSE_SLOWLY("PlatformFile.UnknownErrors.Posix",
332 saved_errno);
333 #endif
334 return PLATFORM_FILE_ERROR_FAILED;
338 } // namespace base