platform_file_posix.cc revision dc0f95d653279beabeb9817299e2902918ba123e
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 if (error_code) 49 *error_code = PLATFORM_FILE_ERROR_FAILED; 50 return kInvalidPlatformFileValue; 51 } 52 53 if (flags & PLATFORM_FILE_WRITE && flags & PLATFORM_FILE_READ) { 54 open_flags |= O_RDWR; 55 } else if (flags & PLATFORM_FILE_WRITE) { 56 open_flags |= O_WRONLY; 57 } else if (!(flags & PLATFORM_FILE_READ) && 58 !(flags & PLATFORM_FILE_WRITE_ATTRIBUTES) && 59 !(flags & PLATFORM_FILE_OPEN_ALWAYS)) { 60 NOTREACHED(); 61 } 62 63 if (flags & PLATFORM_FILE_TRUNCATE) { 64 DCHECK(flags & PLATFORM_FILE_WRITE); 65 open_flags |= O_TRUNC; 66 } 67 68 COMPILE_ASSERT(O_RDONLY == 0, O_RDONLY_must_equal_zero); 69 70 int descriptor = 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 = open(name.value().c_str(), open_flags, S_IRUSR | S_IWUSR); 83 if (created && descriptor > 0) 84 *created = true; 85 } 86 } 87 88 if (created && (descriptor > 0) && 89 (flags & (PLATFORM_FILE_CREATE_ALWAYS | PLATFORM_FILE_CREATE))) 90 *created = true; 91 92 if ((descriptor > 0) && (flags & PLATFORM_FILE_DELETE_ON_CLOSE)) { 93 unlink(name.value().c_str()); 94 } 95 96 if (error_code) { 97 if (descriptor >= 0) 98 *error_code = PLATFORM_FILE_OK; 99 else { 100 switch (errno) { 101 case EACCES: 102 case EISDIR: 103 case EROFS: 104 case EPERM: 105 *error_code = PLATFORM_FILE_ERROR_ACCESS_DENIED; 106 break; 107 case ETXTBSY: 108 *error_code = PLATFORM_FILE_ERROR_IN_USE; 109 break; 110 case EEXIST: 111 *error_code = PLATFORM_FILE_ERROR_EXISTS; 112 break; 113 case ENOENT: 114 *error_code = PLATFORM_FILE_ERROR_NOT_FOUND; 115 break; 116 case EMFILE: 117 *error_code = PLATFORM_FILE_ERROR_TOO_MANY_OPENED; 118 break; 119 case ENOMEM: 120 *error_code = PLATFORM_FILE_ERROR_NO_MEMORY; 121 break; 122 case ENOSPC: 123 *error_code = PLATFORM_FILE_ERROR_NO_SPACE; 124 break; 125 case ENOTDIR: 126 *error_code = PLATFORM_FILE_ERROR_NOT_A_DIRECTORY; 127 break; 128 default: 129 *error_code = PLATFORM_FILE_ERROR_FAILED; 130 } 131 } 132 } 133 134 return descriptor; 135} 136 137PlatformFile CreatePlatformFile(const std::wstring& name, int flags, 138 bool* created) { 139 return CreatePlatformFile(FilePath::FromWStringHack(name), flags, 140 created, NULL); 141} 142 143bool ClosePlatformFile(PlatformFile file) { 144 return !close(file); 145} 146 147int ReadPlatformFile(PlatformFile file, int64 offset, char* data, int size) { 148 if (file < 0) 149 return -1; 150 151 return HANDLE_EINTR(pread(file, data, size, offset)); 152} 153 154int WritePlatformFile(PlatformFile file, int64 offset, 155 const char* data, int size) { 156 if (file < 0) 157 return -1; 158 159 return HANDLE_EINTR(pwrite(file, data, size, offset)); 160} 161 162bool TruncatePlatformFile(PlatformFile file, int64 length) { 163 return ((file >= 0) && !HANDLE_EINTR(ftruncate(file, length))); 164} 165 166bool FlushPlatformFile(PlatformFile file) { 167 return !fsync(file); 168} 169 170bool TouchPlatformFile(PlatformFile file, const base::Time& last_access_time, 171 const base::Time& last_modified_time) { 172#ifdef ANDROID 173 // futimes() isn't actually POSIX. 174 // TODO: Check all callers to see if this needs to work correctly on Android. 175 return false; 176#else 177 if (file < 0) 178 return false; 179 180 timeval times[2]; 181 times[0] = last_access_time.ToTimeVal(); 182 times[1] = last_modified_time.ToTimeVal(); 183 return !futimes(file, times); 184#endif 185} 186 187bool GetPlatformFileInfo(PlatformFile file, PlatformFileInfo* info) { 188 if (!info) 189 return false; 190 191 stat_wrapper_t file_info; 192 if (CallFstat(file, &file_info)) 193 return false; 194 195 info->is_directory = S_ISDIR(file_info.st_mode); 196 info->is_symbolic_link = S_ISLNK(file_info.st_mode); 197 info->size = file_info.st_size; 198 info->last_modified = base::Time::FromTimeT(file_info.st_mtime); 199 info->last_accessed = base::Time::FromTimeT(file_info.st_atime); 200 info->creation_time = base::Time::FromTimeT(file_info.st_ctime); 201 return true; 202} 203 204} // namespace base 205