1 // Copyright (c) 2006-2008 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 "base/file_path.h" 8 #include "base/logging.h" 9 #include "base/threading/thread_restrictions.h" 10 11 namespace base { 12 13 PlatformFile CreatePlatformFile(const FilePath& name, 14 int flags, 15 bool* created, 16 PlatformFileError* error_code) { 17 base::ThreadRestrictions::AssertIOAllowed(); 18 19 DWORD disposition = 0; 20 21 if (flags & PLATFORM_FILE_OPEN) 22 disposition = OPEN_EXISTING; 23 24 if (flags & PLATFORM_FILE_CREATE) { 25 DCHECK(!disposition); 26 disposition = CREATE_NEW; 27 } 28 29 if (flags & PLATFORM_FILE_OPEN_ALWAYS) { 30 DCHECK(!disposition); 31 disposition = OPEN_ALWAYS; 32 } 33 34 if (flags & PLATFORM_FILE_CREATE_ALWAYS) { 35 DCHECK(!disposition); 36 disposition = CREATE_ALWAYS; 37 } 38 39 if (flags & PLATFORM_FILE_TRUNCATE) { 40 DCHECK(!disposition); 41 DCHECK(flags & PLATFORM_FILE_WRITE); 42 disposition = TRUNCATE_EXISTING; 43 } 44 45 if (!disposition) { 46 NOTREACHED(); 47 return NULL; 48 } 49 50 DWORD access = (flags & PLATFORM_FILE_READ) ? GENERIC_READ : 0; 51 if (flags & PLATFORM_FILE_WRITE) 52 access |= GENERIC_WRITE; 53 if (flags & PLATFORM_FILE_WRITE_ATTRIBUTES) 54 access |= FILE_WRITE_ATTRIBUTES; 55 56 DWORD sharing = (flags & PLATFORM_FILE_EXCLUSIVE_READ) ? 0 : FILE_SHARE_READ; 57 if (!(flags & PLATFORM_FILE_EXCLUSIVE_WRITE)) 58 sharing |= FILE_SHARE_WRITE; 59 60 DWORD create_flags = 0; 61 if (flags & PLATFORM_FILE_ASYNC) 62 create_flags |= FILE_FLAG_OVERLAPPED; 63 if (flags & PLATFORM_FILE_TEMPORARY) 64 create_flags |= FILE_ATTRIBUTE_TEMPORARY; 65 if (flags & PLATFORM_FILE_HIDDEN) 66 create_flags |= FILE_ATTRIBUTE_HIDDEN; 67 if (flags & PLATFORM_FILE_DELETE_ON_CLOSE) 68 create_flags |= FILE_FLAG_DELETE_ON_CLOSE; 69 70 HANDLE file = CreateFile(name.value().c_str(), access, sharing, NULL, 71 disposition, create_flags, NULL); 72 73 if (created && (INVALID_HANDLE_VALUE != file)) { 74 if (flags & (PLATFORM_FILE_OPEN_ALWAYS)) 75 *created = (ERROR_ALREADY_EXISTS != GetLastError()); 76 else if (flags & (PLATFORM_FILE_CREATE_ALWAYS | PLATFORM_FILE_CREATE)) 77 *created = true; 78 } 79 80 if (error_code) { 81 if (file != kInvalidPlatformFileValue) 82 *error_code = PLATFORM_FILE_OK; 83 else { 84 DWORD last_error = GetLastError(); 85 switch (last_error) { 86 case ERROR_SHARING_VIOLATION: 87 *error_code = PLATFORM_FILE_ERROR_IN_USE; 88 break; 89 case ERROR_FILE_EXISTS: 90 *error_code = PLATFORM_FILE_ERROR_EXISTS; 91 break; 92 case ERROR_FILE_NOT_FOUND: 93 *error_code = PLATFORM_FILE_ERROR_NOT_FOUND; 94 break; 95 case ERROR_ACCESS_DENIED: 96 *error_code = PLATFORM_FILE_ERROR_ACCESS_DENIED; 97 break; 98 default: 99 *error_code = PLATFORM_FILE_ERROR_FAILED; 100 } 101 } 102 } 103 104 return file; 105 } 106 107 bool ClosePlatformFile(PlatformFile file) { 108 base::ThreadRestrictions::AssertIOAllowed(); 109 return (CloseHandle(file) != 0); 110 } 111 112 int ReadPlatformFile(PlatformFile file, int64 offset, char* data, int size) { 113 base::ThreadRestrictions::AssertIOAllowed(); 114 if (file == kInvalidPlatformFileValue) 115 return -1; 116 117 LARGE_INTEGER offset_li; 118 offset_li.QuadPart = offset; 119 120 OVERLAPPED overlapped = {0}; 121 overlapped.Offset = offset_li.LowPart; 122 overlapped.OffsetHigh = offset_li.HighPart; 123 124 DWORD bytes_read; 125 if (::ReadFile(file, data, size, &bytes_read, &overlapped) != 0) 126 return bytes_read; 127 else if (ERROR_HANDLE_EOF == GetLastError()) 128 return 0; 129 130 return -1; 131 } 132 133 int WritePlatformFile(PlatformFile file, int64 offset, 134 const char* data, int size) { 135 base::ThreadRestrictions::AssertIOAllowed(); 136 if (file == kInvalidPlatformFileValue) 137 return -1; 138 139 LARGE_INTEGER offset_li; 140 offset_li.QuadPart = offset; 141 142 OVERLAPPED overlapped = {0}; 143 overlapped.Offset = offset_li.LowPart; 144 overlapped.OffsetHigh = offset_li.HighPart; 145 146 DWORD bytes_written; 147 if (::WriteFile(file, data, size, &bytes_written, &overlapped) != 0) 148 return bytes_written; 149 150 return -1; 151 } 152 153 bool TruncatePlatformFile(PlatformFile file, int64 length) { 154 base::ThreadRestrictions::AssertIOAllowed(); 155 if (file == kInvalidPlatformFileValue) 156 return false; 157 158 // Get the current file pointer. 159 LARGE_INTEGER file_pointer; 160 LARGE_INTEGER zero; 161 zero.QuadPart = 0; 162 if (::SetFilePointerEx(file, zero, &file_pointer, FILE_CURRENT) == 0) 163 return false; 164 165 LARGE_INTEGER length_li; 166 length_li.QuadPart = length; 167 // If length > file size, SetFilePointerEx() should extend the file 168 // with zeroes on all Windows standard file systems (NTFS, FATxx). 169 if (!::SetFilePointerEx(file, length_li, NULL, FILE_BEGIN)) 170 return false; 171 172 // Set the new file length and move the file pointer to its old position. 173 // This is consistent with ftruncate()'s behavior, even when the file 174 // pointer points to a location beyond the end of the file. 175 return ((::SetEndOfFile(file) != 0) && 176 (::SetFilePointerEx(file, file_pointer, NULL, FILE_BEGIN) != 0)); 177 } 178 179 bool FlushPlatformFile(PlatformFile file) { 180 base::ThreadRestrictions::AssertIOAllowed(); 181 return ((file != kInvalidPlatformFileValue) && ::FlushFileBuffers(file)); 182 } 183 184 bool TouchPlatformFile(PlatformFile file, const base::Time& last_access_time, 185 const base::Time& last_modified_time) { 186 base::ThreadRestrictions::AssertIOAllowed(); 187 if (file == kInvalidPlatformFileValue) 188 return false; 189 190 FILETIME last_access_filetime = last_access_time.ToFileTime(); 191 FILETIME last_modified_filetime = last_modified_time.ToFileTime(); 192 return (::SetFileTime(file, NULL, &last_access_filetime, 193 &last_modified_filetime) != 0); 194 } 195 196 bool GetPlatformFileInfo(PlatformFile file, PlatformFileInfo* info) { 197 base::ThreadRestrictions::AssertIOAllowed(); 198 if (!info) 199 return false; 200 201 BY_HANDLE_FILE_INFORMATION file_info; 202 if (GetFileInformationByHandle(file, &file_info) == 0) 203 return false; 204 205 LARGE_INTEGER size; 206 size.HighPart = file_info.nFileSizeHigh; 207 size.LowPart = file_info.nFileSizeLow; 208 info->size = size.QuadPart; 209 info->is_directory = 210 file_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY != 0; 211 info->is_symbolic_link = false; // Windows doesn't have symbolic links. 212 info->last_modified = base::Time::FromFileTime(file_info.ftLastWriteTime); 213 info->last_accessed = base::Time::FromFileTime(file_info.ftLastAccessTime); 214 info->creation_time = base::Time::FromFileTime(file_info.ftCreationTime); 215 return true; 216 } 217 218 } // namespace disk_cache 219