• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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