Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / base / files / file_posix.cc
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.
4
5 #include "base/files/file.h"
6
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <sys/stat.h>
10 #include <unistd.h>
11
12 #include "base/files/file_path.h"
13 #include "base/logging.h"
14 #include "base/metrics/sparse_histogram.h"
15 // TODO(rvargas): remove this (needed for kInvalidPlatformFileValue).
16 #include "base/platform_file.h"
17 #include "base/posix/eintr_wrapper.h"
18 #include "base/strings/utf_string_conversions.h"
19 #include "base/threading/thread_restrictions.h"
20
21 #if defined(OS_ANDROID)
22 #include "base/os_compat_android.h"
23 #endif
24
25 namespace base {
26
27 // Make sure our Whence mappings match the system headers.
28 COMPILE_ASSERT(File::FROM_BEGIN   == SEEK_SET &&
29                File::FROM_CURRENT == SEEK_CUR &&
30                File::FROM_END     == SEEK_END, whence_matches_system);
31
32 namespace {
33
34 #if defined(OS_BSD) || defined(OS_MACOSX) || defined(OS_NACL)
35 static int CallFstat(int fd, stat_wrapper_t *sb) {
36   base::ThreadRestrictions::AssertIOAllowed();
37   return fstat(fd, sb);
38 }
39 #else
40 static int CallFstat(int fd, stat_wrapper_t *sb) {
41   base::ThreadRestrictions::AssertIOAllowed();
42   return fstat64(fd, sb);
43 }
44 #endif
45
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;
51 }
52
53 static int CallFtruncate(PlatformFile file, int64 length) {
54   return HANDLE_EINTR(ftruncate(file, length));
55 }
56
57 static int CallFsync(PlatformFile file) {
58   return HANDLE_EINTR(fsync(file));
59 }
60
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/
65
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;
71
72   return futimens(file, ts_times);
73 #else
74   return futimes(file, times);
75 #endif
76 }
77
78 static File::Error 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 File::OSErrorToFileError(errno);
86   return File::FILE_OK;
87 }
88 #else  // defined(OS_NACL)
89
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;
95 }
96
97 static int CallFtruncate(PlatformFile file, int64 length) {
98   NOTIMPLEMENTED();  // NaCl doesn't implement ftruncate.
99   return 0;
100 }
101
102 static int CallFsync(PlatformFile file) {
103   NOTIMPLEMENTED();  // NaCl doesn't implement fsync.
104   return 0;
105 }
106
107 static int CallFutimes(PlatformFile file, const struct timeval times[2]) {
108   NOTIMPLEMENTED();  // NaCl doesn't implement futimes.
109   return 0;
110 }
111
112 static File::Error CallFctnlFlock(PlatformFile file, bool do_lock) {
113   NOTIMPLEMENTED();  // NaCl doesn't implement flock struct.
114   return File::FILE_ERROR_INVALID_OPERATION;
115 }
116 #endif  // defined(OS_NACL)
117
118 }  // namespace
119
120 void File::Info::FromStat(const stat_wrapper_t& stat_info) {
121   is_directory = S_ISDIR(stat_info.st_mode);
122   is_symbolic_link = S_ISLNK(stat_info.st_mode);
123   size = stat_info.st_size;
124
125 #if defined(OS_LINUX)
126   time_t last_modified_sec = stat_info.st_mtim.tv_sec;
127   int64 last_modified_nsec = stat_info.st_mtim.tv_nsec;
128   time_t last_accessed_sec = stat_info.st_atim.tv_sec;
129   int64 last_accessed_nsec = stat_info.st_atim.tv_nsec;
130   time_t creation_time_sec = stat_info.st_ctim.tv_sec;
131   int64 creation_time_nsec = stat_info.st_ctim.tv_nsec;
132 #elif defined(OS_ANDROID)
133   time_t last_modified_sec = stat_info.st_mtime;
134   int64 last_modified_nsec = stat_info.st_mtime_nsec;
135   time_t last_accessed_sec = stat_info.st_atime;
136   int64 last_accessed_nsec = stat_info.st_atime_nsec;
137   time_t creation_time_sec = stat_info.st_ctime;
138   int64 creation_time_nsec = stat_info.st_ctime_nsec;
139 #elif defined(OS_MACOSX) || defined(OS_IOS) || defined(OS_BSD)
140   time_t last_modified_sec = stat_info.st_mtimespec.tv_sec;
141   int64 last_modified_nsec = stat_info.st_mtimespec.tv_nsec;
142   time_t last_accessed_sec = stat_info.st_atimespec.tv_sec;
143   int64 last_accessed_nsec = stat_info.st_atimespec.tv_nsec;
144   time_t creation_time_sec = stat_info.st_ctimespec.tv_sec;
145   int64 creation_time_nsec = stat_info.st_ctimespec.tv_nsec;
146 #else
147   time_t last_modified_sec = stat_info.st_mtime;
148   int64 last_modified_nsec = 0;
149   time_t last_accessed_sec = stat_info.st_atime;
150   int64 last_accessed_nsec = 0;
151   time_t creation_time_sec = stat_info.st_ctime;
152   int64 creation_time_nsec = 0;
153 #endif
154
155   last_modified =
156       Time::FromTimeT(last_modified_sec) +
157       TimeDelta::FromMicroseconds(last_modified_nsec /
158                                   Time::kNanosecondsPerMicrosecond);
159
160   last_accessed =
161       Time::FromTimeT(last_accessed_sec) +
162       TimeDelta::FromMicroseconds(last_accessed_nsec /
163                                   Time::kNanosecondsPerMicrosecond);
164
165   creation_time =
166       Time::FromTimeT(creation_time_sec) +
167       TimeDelta::FromMicroseconds(creation_time_nsec /
168                                   Time::kNanosecondsPerMicrosecond);
169 }
170
171 // NaCl doesn't implement system calls to open files directly.
172 #if !defined(OS_NACL)
173 // TODO(erikkay): does it make sense to support FLAG_EXCLUSIVE_* here?
174 void File::InitializeUnsafe(const FilePath& name, uint32 flags) {
175   base::ThreadRestrictions::AssertIOAllowed();
176   DCHECK(!IsValid());
177
178   int open_flags = 0;
179   if (flags & FLAG_CREATE)
180     open_flags = O_CREAT | O_EXCL;
181
182   created_ = false;
183
184   if (flags & FLAG_CREATE_ALWAYS) {
185     DCHECK(!open_flags);
186     open_flags = O_CREAT | O_TRUNC;
187   }
188
189   if (flags & FLAG_OPEN_TRUNCATED) {
190     DCHECK(!open_flags);
191     DCHECK(flags & FLAG_WRITE);
192     open_flags = O_TRUNC;
193   }
194
195   if (!open_flags && !(flags & FLAG_OPEN) && !(flags & FLAG_OPEN_ALWAYS)) {
196     NOTREACHED();
197     errno = EOPNOTSUPP;
198     error_details_ = FILE_ERROR_FAILED;
199     return;
200   }
201
202   if (flags & FLAG_WRITE && flags & FLAG_READ) {
203     open_flags |= O_RDWR;
204   } else if (flags & FLAG_WRITE) {
205     open_flags |= O_WRONLY;
206   } else if (!(flags & FLAG_READ) &&
207              !(flags & FLAG_WRITE_ATTRIBUTES) &&
208              !(flags & FLAG_APPEND) &&
209              !(flags & FLAG_OPEN_ALWAYS)) {
210     NOTREACHED();
211   }
212
213   if (flags & FLAG_TERMINAL_DEVICE)
214     open_flags |= O_NOCTTY | O_NDELAY;
215
216   if (flags & FLAG_APPEND && flags & FLAG_READ)
217     open_flags |= O_APPEND | O_RDWR;
218   else if (flags & FLAG_APPEND)
219     open_flags |= O_APPEND | O_WRONLY;
220
221   COMPILE_ASSERT(O_RDONLY == 0, O_RDONLY_must_equal_zero);
222
223   int mode = S_IRUSR | S_IWUSR;
224 #if defined(OS_CHROMEOS)
225   mode |= S_IRGRP | S_IROTH;
226 #endif
227
228   int descriptor = HANDLE_EINTR(open(name.value().c_str(), open_flags, mode));
229
230   if (flags & FLAG_OPEN_ALWAYS) {
231     if (descriptor < 0) {
232       open_flags |= O_CREAT;
233       if (flags & FLAG_EXCLUSIVE_READ || flags & FLAG_EXCLUSIVE_WRITE)
234         open_flags |= O_EXCL;   // together with O_CREAT implies O_NOFOLLOW
235
236       descriptor = HANDLE_EINTR(open(name.value().c_str(), open_flags, mode));
237       if (descriptor >= 0)
238         created_ = true;
239     }
240   }
241
242   if (descriptor < 0) {
243     error_details_ = File::OSErrorToFileError(errno);
244     return;
245   }
246
247   if (flags & (FLAG_CREATE_ALWAYS | FLAG_CREATE))
248     created_ = true;
249
250   if (flags & FLAG_DELETE_ON_CLOSE)
251     unlink(name.value().c_str());
252
253   async_ = ((flags & FLAG_ASYNC) == FLAG_ASYNC);
254   error_details_ = FILE_OK;
255   file_.reset(descriptor);
256 }
257 #endif  // !defined(OS_NACL)
258
259 bool File::IsValid() const {
260   return file_.is_valid();
261 }
262
263 PlatformFile File::GetPlatformFile() const {
264   return file_.get();
265 }
266
267 PlatformFile File::TakePlatformFile() {
268   return file_.release();
269 }
270
271 void File::Close() {
272   if (!IsValid())
273     return;
274
275   base::ThreadRestrictions::AssertIOAllowed();
276   file_.reset();
277 }
278
279 int64 File::Seek(Whence whence, int64 offset) {
280   base::ThreadRestrictions::AssertIOAllowed();
281   DCHECK(IsValid());
282   if (offset < 0)
283     return -1;
284
285   return lseek(file_.get(), static_cast<off_t>(offset),
286                static_cast<int>(whence));
287 }
288
289 int File::Read(int64 offset, char* data, int size) {
290   base::ThreadRestrictions::AssertIOAllowed();
291   DCHECK(IsValid());
292   if (size < 0)
293     return -1;
294
295   int bytes_read = 0;
296   int rv;
297   do {
298     rv = HANDLE_EINTR(pread(file_.get(), data + bytes_read,
299                             size - bytes_read, offset + bytes_read));
300     if (rv <= 0)
301       break;
302
303     bytes_read += rv;
304   } while (bytes_read < size);
305
306   return bytes_read ? bytes_read : rv;
307 }
308
309 int File::ReadAtCurrentPos(char* data, int size) {
310   base::ThreadRestrictions::AssertIOAllowed();
311   DCHECK(IsValid());
312   if (size < 0)
313     return -1;
314
315   int bytes_read = 0;
316   int rv;
317   do {
318     rv = HANDLE_EINTR(read(file_.get(), data + bytes_read, size - bytes_read));
319     if (rv <= 0)
320       break;
321
322     bytes_read += rv;
323   } while (bytes_read < size);
324
325   return bytes_read ? bytes_read : rv;
326 }
327
328 int File::ReadNoBestEffort(int64 offset, char* data, int size) {
329   base::ThreadRestrictions::AssertIOAllowed();
330   DCHECK(IsValid());
331
332   return HANDLE_EINTR(pread(file_.get(), data, size, offset));
333 }
334
335 int File::ReadAtCurrentPosNoBestEffort(char* data, int size) {
336   base::ThreadRestrictions::AssertIOAllowed();
337   DCHECK(IsValid());
338   if (size < 0)
339     return -1;
340
341   return HANDLE_EINTR(read(file_.get(), data, size));
342 }
343
344 int File::Write(int64 offset, const char* data, int size) {
345   base::ThreadRestrictions::AssertIOAllowed();
346
347   if (IsOpenAppend(file_.get()))
348     return WriteAtCurrentPos(data, size);
349
350   DCHECK(IsValid());
351   if (size < 0)
352     return -1;
353
354   int bytes_written = 0;
355   int rv;
356   do {
357     rv = HANDLE_EINTR(pwrite(file_.get(), data + bytes_written,
358                              size - bytes_written, offset + bytes_written));
359     if (rv <= 0)
360       break;
361
362     bytes_written += rv;
363   } while (bytes_written < size);
364
365   return bytes_written ? bytes_written : rv;
366 }
367
368 int File::WriteAtCurrentPos(const char* data, int size) {
369   base::ThreadRestrictions::AssertIOAllowed();
370   DCHECK(IsValid());
371   if (size < 0)
372     return -1;
373
374   int bytes_written = 0;
375   int rv;
376   do {
377     rv = HANDLE_EINTR(write(file_.get(), data + bytes_written,
378                             size - bytes_written));
379     if (rv <= 0)
380       break;
381
382     bytes_written += rv;
383   } while (bytes_written < size);
384
385   return bytes_written ? bytes_written : rv;
386 }
387
388 int File::WriteAtCurrentPosNoBestEffort(const char* data, int size) {
389   base::ThreadRestrictions::AssertIOAllowed();
390   DCHECK(IsValid());
391   if (size < 0)
392     return -1;
393
394   return HANDLE_EINTR(write(file_.get(), data, size));
395 }
396
397 int64 File::GetLength() {
398   DCHECK(IsValid());
399
400   stat_wrapper_t file_info;
401   if (CallFstat(file_.get(), &file_info))
402     return false;
403
404   return file_info.st_size;
405 }
406
407 bool File::SetLength(int64 length) {
408   base::ThreadRestrictions::AssertIOAllowed();
409   DCHECK(IsValid());
410   return !CallFtruncate(file_.get(), length);
411 }
412
413 bool File::Flush() {
414   base::ThreadRestrictions::AssertIOAllowed();
415   DCHECK(IsValid());
416   return !CallFsync(file_.get());
417 }
418
419 bool File::SetTimes(Time last_access_time, Time last_modified_time) {
420   base::ThreadRestrictions::AssertIOAllowed();
421   DCHECK(IsValid());
422
423   timeval times[2];
424   times[0] = last_access_time.ToTimeVal();
425   times[1] = last_modified_time.ToTimeVal();
426
427   return !CallFutimes(file_.get(), times);
428 }
429
430 bool File::GetInfo(Info* info) {
431   DCHECK(IsValid());
432
433   stat_wrapper_t file_info;
434   if (CallFstat(file_.get(), &file_info))
435     return false;
436
437   info->FromStat(file_info);
438   return true;
439 }
440
441 File::Error File::Lock() {
442   return CallFctnlFlock(file_.get(), true);
443 }
444
445 File::Error File::Unlock() {
446   return CallFctnlFlock(file_.get(), false);
447 }
448
449 // Static.
450 File::Error File::OSErrorToFileError(int saved_errno) {
451   switch (saved_errno) {
452     case EACCES:
453     case EISDIR:
454     case EROFS:
455     case EPERM:
456       return FILE_ERROR_ACCESS_DENIED;
457 #if !defined(OS_NACL)  // ETXTBSY not defined by NaCl.
458     case ETXTBSY:
459       return FILE_ERROR_IN_USE;
460 #endif
461     case EEXIST:
462       return FILE_ERROR_EXISTS;
463     case ENOENT:
464       return FILE_ERROR_NOT_FOUND;
465     case EMFILE:
466       return FILE_ERROR_TOO_MANY_OPENED;
467     case ENOMEM:
468       return FILE_ERROR_NO_MEMORY;
469     case ENOSPC:
470       return FILE_ERROR_NO_SPACE;
471     case ENOTDIR:
472       return FILE_ERROR_NOT_A_DIRECTORY;
473     default:
474 #if !defined(OS_NACL)  // NaCl build has no metrics code.
475       UMA_HISTOGRAM_SPARSE_SLOWLY("PlatformFile.UnknownErrors.Posix",
476                                   saved_errno);
477 #endif
478       return FILE_ERROR_FAILED;
479   }
480 }
481
482 void File::SetPlatformFile(PlatformFile file) {
483   DCHECK(!file_.is_valid());
484   file_.reset(file);
485 }
486
487 }  // namespace base