1 // Copyright (c) 2009 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.
4
5 #include "base/platform_file.h"
6
7 #include <fcntl.h>
8 #include <errno.h>
9 #include <sys/stat.h>
10
11 #include "base/eintr_wrapper.h"
12 #include "base/file_path.h"
13 #include "base/logging.h"
14 #include "base/utf_string_conversions.h"
15
16 namespace base {
17
18 #if defined(OS_OPENBSD) || defined(OS_FREEBSD) || \
19 (defined(OS_MACOSX) && \
20 MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5)
21 typedef struct stat stat_wrapper_t;
CallFstat(int fd,stat_wrapper_t * sb)22 static int CallFstat(int fd, stat_wrapper_t *sb) {
23 return fstat(fd, sb);
24 }
25 #else
26 typedef struct stat64 stat_wrapper_t;
27 static int CallFstat(int fd, stat_wrapper_t *sb) {
28 return fstat64(fd, sb);
29 }
30 #endif
31
32 // TODO(erikkay): does it make sense to support PLATFORM_FILE_EXCLUSIVE_* here?
CreatePlatformFile(const FilePath & name,int flags,bool * created,PlatformFileError * error_code)33 PlatformFile CreatePlatformFile(const FilePath& name, int flags,
34 bool* created, PlatformFileError* error_code) {
35 int open_flags = 0;
36 if (flags & PLATFORM_FILE_CREATE)
37 open_flags = O_CREAT | O_EXCL;
38
39 if (flags & PLATFORM_FILE_CREATE_ALWAYS) {
40 DCHECK(!open_flags);
41 open_flags = O_CREAT | O_TRUNC;
42 }
43
44 if (!open_flags && !(flags & PLATFORM_FILE_OPEN) &&
45 !(flags & PLATFORM_FILE_OPEN_ALWAYS)) {
46 NOTREACHED();
47 errno = EOPNOTSUPP;
48 *error_code = error_code ? PLATFORM_FILE_ERROR_FAILED : PLATFORM_FILE_OK;
49 return kInvalidPlatformFileValue;
50 }
51
52 if (flags & PLATFORM_FILE_WRITE && flags & PLATFORM_FILE_READ) {
53 open_flags |= O_RDWR;
54 } else if (flags & PLATFORM_FILE_WRITE) {
55 open_flags |= O_WRONLY;
56 } else if (!(flags & PLATFORM_FILE_READ) &&
57 !(flags & PLATFORM_FILE_WRITE_ATTRIBUTES) &&
58 !(flags & PLATFORM_FILE_OPEN_ALWAYS)) {
59 NOTREACHED();
60 }
61
62 if (flags & PLATFORM_FILE_TRUNCATE) {
63 DCHECK(flags & PLATFORM_FILE_WRITE);
64 open_flags |= O_TRUNC;
65 }
66
67 COMPILE_ASSERT(O_RDONLY == 0, O_RDONLY_must_equal_zero);
68
69 int descriptor =
70 HANDLE_EINTR(open(name.value().c_str(), open_flags, S_IRUSR | S_IWUSR));
71
72 if (flags & PLATFORM_FILE_OPEN_ALWAYS) {
73 if (descriptor > 0) {
74 if (created)
75 *created = false;
76 } else {
77 open_flags |= O_CREAT;
78 if (flags & PLATFORM_FILE_EXCLUSIVE_READ ||
79 flags & PLATFORM_FILE_EXCLUSIVE_WRITE) {
80 open_flags |= O_EXCL; // together with O_CREAT implies O_NOFOLLOW
81 }
82 descriptor = HANDLE_EINTR(
83 open(name.value().c_str(), open_flags, S_IRUSR | S_IWUSR));
84 if (created && descriptor > 0)
85 *created = true;
86 }
87 }
88
89 if (created && (descriptor > 0) &&
90 (flags & (PLATFORM_FILE_CREATE_ALWAYS | PLATFORM_FILE_CREATE)))
91 *created = true;
92
93 if ((descriptor > 0) && (flags & PLATFORM_FILE_DELETE_ON_CLOSE)) {
94 unlink(name.value().c_str());
95 }
96
97 if (error_code) {
98 if (descriptor >= 0)
99 *error_code = PLATFORM_FILE_OK;
100 else {
101 switch (errno) {
102 case EACCES:
103 case EISDIR:
104 case EROFS:
105 case EPERM:
106 *error_code = PLATFORM_FILE_ERROR_ACCESS_DENIED;
107 break;
108 case ETXTBSY:
109 *error_code = PLATFORM_FILE_ERROR_IN_USE;
110 break;
111 case EEXIST:
112 *error_code = PLATFORM_FILE_ERROR_EXISTS;
113 break;
114 case ENOENT:
115 *error_code = PLATFORM_FILE_ERROR_NOT_FOUND;
116 break;
117 case EMFILE:
118 *error_code = PLATFORM_FILE_ERROR_TOO_MANY_OPENED;
119 break;
120 case ENOMEM:
121 *error_code = PLATFORM_FILE_ERROR_NO_MEMORY;
122 break;
123 case ENOSPC:
124 *error_code = PLATFORM_FILE_ERROR_NO_SPACE;
125 break;
126 case ENOTDIR:
127 *error_code = PLATFORM_FILE_ERROR_NOT_A_DIRECTORY;
128 break;
129 default:
130 *error_code = PLATFORM_FILE_ERROR_FAILED;
131 }
132 }
133 }
134
135 return descriptor;
136 }
137
ClosePlatformFile(PlatformFile file)138 bool ClosePlatformFile(PlatformFile file) {
139 return !HANDLE_EINTR(close(file));
140 }
141
ReadPlatformFile(PlatformFile file,int64 offset,char * data,int size)142 int ReadPlatformFile(PlatformFile file, int64 offset, char* data, int size) {
143 if (file < 0)
144 return -1;
145
146 return HANDLE_EINTR(pread(file, data, size, offset));
147 }
148
WritePlatformFile(PlatformFile file,int64 offset,const char * data,int size)149 int WritePlatformFile(PlatformFile file, int64 offset,
150 const char* data, int size) {
151 if (file < 0)
152 return -1;
153
154 return HANDLE_EINTR(pwrite(file, data, size, offset));
155 }
156
TruncatePlatformFile(PlatformFile file,int64 length)157 bool TruncatePlatformFile(PlatformFile file, int64 length) {
158 return ((file >= 0) && !HANDLE_EINTR(ftruncate(file, length)));
159 }
160
FlushPlatformFile(PlatformFile file)161 bool FlushPlatformFile(PlatformFile file) {
162 return !HANDLE_EINTR(fsync(file));
163 }
164
TouchPlatformFile(PlatformFile file,const base::Time & last_access_time,const base::Time & last_modified_time)165 bool TouchPlatformFile(PlatformFile file, const base::Time& last_access_time,
166 const base::Time& last_modified_time) {
167 #ifdef ANDROID
168 // futimes() isn't actually POSIX.
169 // TODO: Check all callers to see if this needs to work correctly on Android.
170 return false;
171 #else
172 if (file < 0)
173 return false;
174
175 timeval times[2];
176 times[0] = last_access_time.ToTimeVal();
177 times[1] = last_modified_time.ToTimeVal();
178 return !futimes(file, times);
179 #endif
180 }
181
GetPlatformFileInfo(PlatformFile file,PlatformFileInfo * info)182 bool GetPlatformFileInfo(PlatformFile file, PlatformFileInfo* info) {
183 if (!info)
184 return false;
185
186 stat_wrapper_t file_info;
187 if (CallFstat(file, &file_info))
188 return false;
189
190 info->is_directory = S_ISDIR(file_info.st_mode);
191 info->is_symbolic_link = S_ISLNK(file_info.st_mode);
192 info->size = file_info.st_size;
193 info->last_modified = base::Time::FromTimeT(file_info.st_mtime);
194 info->last_accessed = base::Time::FromTimeT(file_info.st_atime);
195 info->creation_time = base::Time::FromTimeT(file_info.st_ctime);
196 return true;
197 }
198
199 } // namespace base
200