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 <io.h> 8 9 #include "base/files/file_path.h" 10 #include "base/logging.h" 11 #include "base/metrics/sparse_histogram.h" 12 #include "base/threading/thread_restrictions.h" 13 14 namespace base { 15 16 void File::CreateBaseFileUnsafe(const FilePath& name, uint32 flags) { 17 base::ThreadRestrictions::AssertIOAllowed(); 18 DCHECK(!IsValid()); 19 20 DWORD disposition = 0; 21 22 if (flags & FLAG_OPEN) 23 disposition = OPEN_EXISTING; 24 25 if (flags & FLAG_CREATE) { 26 DCHECK(!disposition); 27 disposition = CREATE_NEW; 28 } 29 30 if (flags & FLAG_OPEN_ALWAYS) { 31 DCHECK(!disposition); 32 disposition = OPEN_ALWAYS; 33 } 34 35 if (flags & FLAG_CREATE_ALWAYS) { 36 DCHECK(!disposition); 37 disposition = CREATE_ALWAYS; 38 } 39 40 if (flags & FLAG_OPEN_TRUNCATED) { 41 DCHECK(!disposition); 42 DCHECK(flags & FLAG_WRITE); 43 disposition = TRUNCATE_EXISTING; 44 } 45 46 if (!disposition) { 47 NOTREACHED(); 48 return; 49 } 50 51 DWORD access = 0; 52 if (flags & FLAG_WRITE) 53 access = GENERIC_WRITE; 54 if (flags & FLAG_APPEND) { 55 DCHECK(!access); 56 access = FILE_APPEND_DATA; 57 } 58 if (flags & FLAG_READ) 59 access |= GENERIC_READ; 60 if (flags & FLAG_WRITE_ATTRIBUTES) 61 access |= FILE_WRITE_ATTRIBUTES; 62 if (flags & FLAG_EXECUTE) 63 access |= GENERIC_EXECUTE; 64 65 DWORD sharing = (flags & FLAG_EXCLUSIVE_READ) ? 0 : FILE_SHARE_READ; 66 if (!(flags & FLAG_EXCLUSIVE_WRITE)) 67 sharing |= FILE_SHARE_WRITE; 68 if (flags & FLAG_SHARE_DELETE) 69 sharing |= FILE_SHARE_DELETE; 70 71 DWORD create_flags = 0; 72 if (flags & FLAG_ASYNC) 73 create_flags |= FILE_FLAG_OVERLAPPED; 74 if (flags & FLAG_TEMPORARY) 75 create_flags |= FILE_ATTRIBUTE_TEMPORARY; 76 if (flags & FLAG_HIDDEN) 77 create_flags |= FILE_ATTRIBUTE_HIDDEN; 78 if (flags & FLAG_DELETE_ON_CLOSE) 79 create_flags |= FILE_FLAG_DELETE_ON_CLOSE; 80 if (flags & FLAG_BACKUP_SEMANTICS) 81 create_flags |= FILE_FLAG_BACKUP_SEMANTICS; 82 83 file_.Set(CreateFile(name.value().c_str(), access, sharing, NULL, 84 disposition, create_flags, NULL)); 85 86 if (file_.IsValid()) { 87 error_ = FILE_OK; 88 async_ = ((flags & FLAG_ASYNC) == FLAG_ASYNC); 89 90 if (flags & (FLAG_OPEN_ALWAYS)) 91 created_ = (ERROR_ALREADY_EXISTS != GetLastError()); 92 else if (flags & (FLAG_CREATE_ALWAYS | FLAG_CREATE)) 93 created_ = true; 94 } else { 95 error_ = OSErrorToFileError(GetLastError()); 96 } 97 } 98 99 bool File::IsValid() const { 100 return file_.IsValid(); 101 } 102 PlatformFile File::TakePlatformFile() { 103 return file_.Take(); 104 } 105 106 void File::Close() { 107 base::ThreadRestrictions::AssertIOAllowed(); 108 file_.Close(); 109 } 110 111 int64 File::Seek(Whence whence, int64 offset) { 112 base::ThreadRestrictions::AssertIOAllowed(); 113 DCHECK(IsValid()); 114 if (offset < 0) 115 return -1; 116 117 LARGE_INTEGER distance, res; 118 distance.QuadPart = offset; 119 DWORD move_method = static_cast<DWORD>(whence); 120 if (!SetFilePointerEx(file_, distance, &res, move_method)) 121 return -1; 122 return res.QuadPart; 123 } 124 125 int File::Read(int64 offset, char* data, int size) { 126 base::ThreadRestrictions::AssertIOAllowed(); 127 DCHECK(IsValid()); 128 DCHECK(!async_); 129 if (size < 0) 130 return -1; 131 132 LARGE_INTEGER offset_li; 133 offset_li.QuadPart = offset; 134 135 OVERLAPPED overlapped = {0}; 136 overlapped.Offset = offset_li.LowPart; 137 overlapped.OffsetHigh = offset_li.HighPart; 138 139 DWORD bytes_read; 140 if (::ReadFile(file_, data, size, &bytes_read, &overlapped) != 0) 141 return bytes_read; 142 if (ERROR_HANDLE_EOF == GetLastError()) 143 return 0; 144 145 return -1; 146 } 147 148 int File::ReadAtCurrentPos(char* data, int size) { 149 base::ThreadRestrictions::AssertIOAllowed(); 150 DCHECK(IsValid()); 151 DCHECK(!async_); 152 if (size < 0) 153 return -1; 154 155 DWORD bytes_read; 156 if (::ReadFile(file_, data, size, &bytes_read, NULL) != 0) 157 return bytes_read; 158 if (ERROR_HANDLE_EOF == GetLastError()) 159 return 0; 160 161 return -1; 162 } 163 164 int File::ReadNoBestEffort(int64 offset, char* data, int size) { 165 return Read(offset, data, size); 166 } 167 168 int File::ReadAtCurrentPosNoBestEffort(char* data, int size) { 169 return ReadAtCurrentPos(data, size); 170 } 171 172 int File::Write(int64 offset, const char* data, int size) { 173 base::ThreadRestrictions::AssertIOAllowed(); 174 DCHECK(IsValid()); 175 DCHECK(!async_); 176 177 LARGE_INTEGER offset_li; 178 offset_li.QuadPart = offset; 179 180 OVERLAPPED overlapped = {0}; 181 overlapped.Offset = offset_li.LowPart; 182 overlapped.OffsetHigh = offset_li.HighPart; 183 184 DWORD bytes_written; 185 if (::WriteFile(file_, data, size, &bytes_written, &overlapped) != 0) 186 return bytes_written; 187 188 return -1; 189 } 190 191 int File::WriteAtCurrentPos(const char* data, int size) { 192 NOTREACHED(); 193 return -1; 194 } 195 196 int File::WriteAtCurrentPosNoBestEffort(const char* data, int size) { 197 return WriteAtCurrentPos(data, size); 198 } 199 200 bool File::Truncate(int64 length) { 201 base::ThreadRestrictions::AssertIOAllowed(); 202 DCHECK(IsValid()); 203 204 // Get the current file pointer. 205 LARGE_INTEGER file_pointer; 206 LARGE_INTEGER zero; 207 zero.QuadPart = 0; 208 if (::SetFilePointerEx(file_, zero, &file_pointer, FILE_CURRENT) == 0) 209 return false; 210 211 LARGE_INTEGER length_li; 212 length_li.QuadPart = length; 213 // If length > file size, SetFilePointerEx() should extend the file 214 // with zeroes on all Windows standard file systems (NTFS, FATxx). 215 if (!::SetFilePointerEx(file_, length_li, NULL, FILE_BEGIN)) 216 return false; 217 218 // Set the new file length and move the file pointer to its old position. 219 // This is consistent with ftruncate()'s behavior, even when the file 220 // pointer points to a location beyond the end of the file. 221 return ((::SetEndOfFile(file_) != 0) && 222 (::SetFilePointerEx(file_, file_pointer, NULL, FILE_BEGIN) != 0)); 223 } 224 225 bool File::Flush() { 226 base::ThreadRestrictions::AssertIOAllowed(); 227 DCHECK(IsValid()); 228 return ::FlushFileBuffers(file_) != FALSE; 229 } 230 231 bool File::SetTimes(Time last_access_time, Time last_modified_time) { 232 base::ThreadRestrictions::AssertIOAllowed(); 233 DCHECK(IsValid()); 234 235 FILETIME last_access_filetime = last_access_time.ToFileTime(); 236 FILETIME last_modified_filetime = last_modified_time.ToFileTime(); 237 return (::SetFileTime(file_, NULL, &last_access_filetime, 238 &last_modified_filetime) != 0); 239 } 240 241 bool File::GetInfo(Info* info) { 242 base::ThreadRestrictions::AssertIOAllowed(); 243 DCHECK(IsValid()); 244 245 BY_HANDLE_FILE_INFORMATION file_info; 246 if (GetFileInformationByHandle(file_, &file_info) == 0) 247 return false; 248 249 LARGE_INTEGER size; 250 size.HighPart = file_info.nFileSizeHigh; 251 size.LowPart = file_info.nFileSizeLow; 252 info->size = size.QuadPart; 253 info->is_directory = 254 (file_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; 255 info->is_symbolic_link = false; // Windows doesn't have symbolic links. 256 info->last_modified = base::Time::FromFileTime(file_info.ftLastWriteTime); 257 info->last_accessed = base::Time::FromFileTime(file_info.ftLastAccessTime); 258 info->creation_time = base::Time::FromFileTime(file_info.ftCreationTime); 259 return true; 260 } 261 262 File::Error base::File::Lock() { 263 DCHECK(IsValid()); 264 BOOL result = LockFile(file_, 0, 0, MAXDWORD, MAXDWORD); 265 if (!result) 266 return OSErrorToFileError(GetLastError()); 267 return FILE_OK; 268 } 269 270 File::Error File::Unlock() { 271 DCHECK(IsValid()); 272 BOOL result = UnlockFile(file_, 0, 0, MAXDWORD, MAXDWORD); 273 if (!result) 274 return OSErrorToFileError(GetLastError()); 275 return FILE_OK; 276 } 277 278 // Static. 279 File::Error File::OSErrorToFileError(DWORD last_error) { 280 switch (last_error) { 281 case ERROR_SHARING_VIOLATION: 282 return FILE_ERROR_IN_USE; 283 case ERROR_FILE_EXISTS: 284 return FILE_ERROR_EXISTS; 285 case ERROR_FILE_NOT_FOUND: 286 case ERROR_PATH_NOT_FOUND: 287 return FILE_ERROR_NOT_FOUND; 288 case ERROR_ACCESS_DENIED: 289 return FILE_ERROR_ACCESS_DENIED; 290 case ERROR_TOO_MANY_OPEN_FILES: 291 return FILE_ERROR_TOO_MANY_OPENED; 292 case ERROR_OUTOFMEMORY: 293 case ERROR_NOT_ENOUGH_MEMORY: 294 return FILE_ERROR_NO_MEMORY; 295 case ERROR_HANDLE_DISK_FULL: 296 case ERROR_DISK_FULL: 297 case ERROR_DISK_RESOURCES_EXHAUSTED: 298 return FILE_ERROR_NO_SPACE; 299 case ERROR_USER_MAPPED_FILE: 300 return FILE_ERROR_INVALID_OPERATION; 301 case ERROR_NOT_READY: 302 case ERROR_SECTOR_NOT_FOUND: 303 case ERROR_DEV_NOT_EXIST: 304 case ERROR_IO_DEVICE: 305 case ERROR_FILE_CORRUPT: 306 case ERROR_DISK_CORRUPT: 307 return FILE_ERROR_IO; 308 default: 309 UMA_HISTOGRAM_SPARSE_SLOWLY("PlatformFile.UnknownErrors.Windows", 310 last_error); 311 return FILE_ERROR_FAILED; 312 } 313 } 314 315 void File::SetPlatformFile(PlatformFile file) { 316 file_.Set(file); 317 } 318 319 } // namespace base 320