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 16namespace 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) 21typedef struct stat stat_wrapper_t; 22static int CallFstat(int fd, stat_wrapper_t *sb) { 23 return fstat(fd, sb); 24} 25#else 26typedef struct stat64 stat_wrapper_t; 27static 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? 33PlatformFile 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 138bool ClosePlatformFile(PlatformFile file) { 139 return !HANDLE_EINTR(close(file)); 140} 141 142int 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 149int 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 157bool TruncatePlatformFile(PlatformFile file, int64 length) { 158 return ((file >= 0) && !HANDLE_EINTR(ftruncate(file, length))); 159} 160 161bool FlushPlatformFile(PlatformFile file) { 162 return !HANDLE_EINTR(fsync(file)); 163} 164 165bool 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 182bool 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