[email protected] | 21da6eb | 2008-11-03 17:18:14 | [diff] [blame] | 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 | |
[email protected] | f294da7 | 2009-10-12 21:39:37 | [diff] [blame] | 7 | #include "base/file_path.h" |
[email protected] | 21da6eb | 2008-11-03 17:18:14 | [diff] [blame] | 8 | #include "base/logging.h" |
[email protected] | 45446a5 | 2010-11-04 17:41:00 | [diff] [blame] | 9 | #include "base/thread_restrictions.h" |
[email protected] | 21da6eb | 2008-11-03 17:18:14 | [diff] [blame] | 10 | |
| 11 | namespace base { |
| 12 | |
[email protected] | f294da7 | 2009-10-12 21:39:37 | [diff] [blame] | 13 | PlatformFile CreatePlatformFile(const FilePath& name, |
[email protected] | 21da6eb | 2008-11-03 17:18:14 | [diff] [blame] | 14 | int flags, |
[email protected] | ed65fec | 2010-08-31 19:30:27 | [diff] [blame] | 15 | bool* created, |
| 16 | PlatformFileError* error_code) { |
[email protected] | 45446a5 | 2010-11-04 17:41:00 | [diff] [blame] | 17 | base::ThreadRestrictions::AssertIOAllowed(); |
| 18 | |
[email protected] | 21da6eb | 2008-11-03 17:18:14 | [diff] [blame] | 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 | |
[email protected] | ed65fec | 2010-08-31 19:30:27 | [diff] [blame] | 39 | if (flags & PLATFORM_FILE_TRUNCATE) { |
| 40 | DCHECK(!disposition); |
| 41 | DCHECK(flags & PLATFORM_FILE_WRITE); |
| 42 | disposition = TRUNCATE_EXISTING; |
| 43 | } |
| 44 | |
[email protected] | 21da6eb | 2008-11-03 17:18:14 | [diff] [blame] | 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; |
[email protected] | 507fb9a | 2010-09-23 23:28:22 | [diff] [blame] | 53 | if (flags & PLATFORM_FILE_WRITE_ATTRIBUTES) |
| 54 | access |= FILE_WRITE_ATTRIBUTES; |
[email protected] | 21da6eb | 2008-11-03 17:18:14 | [diff] [blame] | 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; |
[email protected] | 017022b | 2009-07-27 23:06:34 | [diff] [blame] | 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; |
[email protected] | 21da6eb | 2008-11-03 17:18:14 | [diff] [blame] | 69 | |
[email protected] | f294da7 | 2009-10-12 21:39:37 | [diff] [blame] | 70 | HANDLE file = CreateFile(name.value().c_str(), access, sharing, NULL, |
| 71 | disposition, create_flags, NULL); |
[email protected] | 21da6eb | 2008-11-03 17:18:14 | [diff] [blame] | 72 | |
[email protected] | 3fb43ed1 | 2010-09-10 03:01:14 | [diff] [blame] | 73 | if (created && (INVALID_HANDLE_VALUE != file)) { |
[email protected] | fd55c28 | 2010-10-15 00:37:34 | [diff] [blame] | 74 | if (flags & (PLATFORM_FILE_OPEN_ALWAYS)) |
[email protected] | 3fb43ed1 | 2010-09-10 03:01:14 | [diff] [blame] | 75 | *created = (ERROR_ALREADY_EXISTS != GetLastError()); |
[email protected] | fd55c28 | 2010-10-15 00:37:34 | [diff] [blame] | 76 | else if (flags & (PLATFORM_FILE_CREATE_ALWAYS | PLATFORM_FILE_CREATE)) |
[email protected] | 3fb43ed1 | 2010-09-10 03:01:14 | [diff] [blame] | 77 | *created = true; |
[email protected] | 21da6eb | 2008-11-03 17:18:14 | [diff] [blame] | 78 | } |
| 79 | |
[email protected] | 3fb43ed1 | 2010-09-10 03:01:14 | [diff] [blame] | 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 | } |
[email protected] | ed65fec | 2010-08-31 19:30:27 | [diff] [blame] | 101 | } |
| 102 | } |
| 103 | |
[email protected] | 21da6eb | 2008-11-03 17:18:14 | [diff] [blame] | 104 | return file; |
| 105 | } |
| 106 | |
[email protected] | f294da7 | 2009-10-12 21:39:37 | [diff] [blame] | 107 | PlatformFile CreatePlatformFile(const std::wstring& name, int flags, |
| 108 | bool* created) { |
[email protected] | ed65fec | 2010-08-31 19:30:27 | [diff] [blame] | 109 | return CreatePlatformFile(FilePath::FromWStringHack(name), flags, |
| 110 | created, NULL); |
[email protected] | f294da7 | 2009-10-12 21:39:37 | [diff] [blame] | 111 | } |
| 112 | |
[email protected] | ee8d4c8 | 2009-08-28 21:58:28 | [diff] [blame] | 113 | bool ClosePlatformFile(PlatformFile file) { |
[email protected] | 45446a5 | 2010-11-04 17:41:00 | [diff] [blame] | 114 | base::ThreadRestrictions::AssertIOAllowed(); |
[email protected] | 3fb43ed1 | 2010-09-10 03:01:14 | [diff] [blame] | 115 | return (CloseHandle(file) != 0); |
| 116 | } |
| 117 | |
| 118 | int ReadPlatformFile(PlatformFile file, int64 offset, char* data, int size) { |
[email protected] | 45446a5 | 2010-11-04 17:41:00 | [diff] [blame] | 119 | base::ThreadRestrictions::AssertIOAllowed(); |
[email protected] | 3fb43ed1 | 2010-09-10 03:01:14 | [diff] [blame] | 120 | if (file == kInvalidPlatformFileValue) |
| 121 | return -1; |
| 122 | |
| 123 | LARGE_INTEGER offset_li; |
| 124 | offset_li.QuadPart = offset; |
| 125 | |
| 126 | OVERLAPPED overlapped = {0}; |
| 127 | overlapped.Offset = offset_li.LowPart; |
| 128 | overlapped.OffsetHigh = offset_li.HighPart; |
| 129 | |
| 130 | DWORD bytes_read; |
| 131 | if (::ReadFile(file, data, size, &bytes_read, &overlapped) != 0) |
| 132 | return bytes_read; |
| 133 | else if (ERROR_HANDLE_EOF == GetLastError()) |
| 134 | return 0; |
| 135 | |
| 136 | return -1; |
| 137 | } |
| 138 | |
| 139 | int WritePlatformFile(PlatformFile file, int64 offset, |
| 140 | const char* data, int size) { |
[email protected] | 45446a5 | 2010-11-04 17:41:00 | [diff] [blame] | 141 | base::ThreadRestrictions::AssertIOAllowed(); |
[email protected] | 3fb43ed1 | 2010-09-10 03:01:14 | [diff] [blame] | 142 | if (file == kInvalidPlatformFileValue) |
| 143 | return -1; |
| 144 | |
| 145 | LARGE_INTEGER offset_li; |
| 146 | offset_li.QuadPart = offset; |
| 147 | |
| 148 | OVERLAPPED overlapped = {0}; |
| 149 | overlapped.Offset = offset_li.LowPart; |
| 150 | overlapped.OffsetHigh = offset_li.HighPart; |
| 151 | |
| 152 | DWORD bytes_written; |
| 153 | if (::WriteFile(file, data, size, &bytes_written, &overlapped) != 0) |
| 154 | return bytes_written; |
| 155 | |
| 156 | return -1; |
| 157 | } |
| 158 | |
| 159 | bool TruncatePlatformFile(PlatformFile file, int64 length) { |
[email protected] | 45446a5 | 2010-11-04 17:41:00 | [diff] [blame] | 160 | base::ThreadRestrictions::AssertIOAllowed(); |
[email protected] | 3fb43ed1 | 2010-09-10 03:01:14 | [diff] [blame] | 161 | if (file == kInvalidPlatformFileValue) |
| 162 | return false; |
| 163 | |
| 164 | // Get the current file pointer. |
| 165 | LARGE_INTEGER file_pointer; |
| 166 | LARGE_INTEGER zero; |
| 167 | zero.QuadPart = 0; |
| 168 | if (::SetFilePointerEx(file, zero, &file_pointer, FILE_CURRENT) == 0) |
| 169 | return false; |
| 170 | |
| 171 | LARGE_INTEGER length_li; |
| 172 | length_li.QuadPart = length; |
| 173 | // If length > file size, SetFilePointerEx() should extend the file |
| 174 | // with zeroes on all Windows standard file systems (NTFS, FATxx). |
| 175 | if (!::SetFilePointerEx(file, length_li, NULL, FILE_BEGIN)) |
| 176 | return false; |
| 177 | |
| 178 | // Set the new file length and move the file pointer to its old position. |
| 179 | // This is consistent with ftruncate()'s behavior, even when the file |
| 180 | // pointer points to a location beyond the end of the file. |
| 181 | return ((::SetEndOfFile(file) != 0) && |
| 182 | (::SetFilePointerEx(file, file_pointer, NULL, FILE_BEGIN) != 0)); |
| 183 | } |
| 184 | |
| 185 | bool FlushPlatformFile(PlatformFile file) { |
[email protected] | 45446a5 | 2010-11-04 17:41:00 | [diff] [blame] | 186 | base::ThreadRestrictions::AssertIOAllowed(); |
[email protected] | 3fb43ed1 | 2010-09-10 03:01:14 | [diff] [blame] | 187 | return ((file != kInvalidPlatformFileValue) && ::FlushFileBuffers(file)); |
| 188 | } |
| 189 | |
| 190 | bool TouchPlatformFile(PlatformFile file, const base::Time& last_access_time, |
| 191 | const base::Time& last_modified_time) { |
[email protected] | 45446a5 | 2010-11-04 17:41:00 | [diff] [blame] | 192 | base::ThreadRestrictions::AssertIOAllowed(); |
[email protected] | 3fb43ed1 | 2010-09-10 03:01:14 | [diff] [blame] | 193 | if (file == kInvalidPlatformFileValue) |
| 194 | return false; |
| 195 | |
| 196 | FILETIME last_access_filetime = last_access_time.ToFileTime(); |
| 197 | FILETIME last_modified_filetime = last_modified_time.ToFileTime(); |
| 198 | return (::SetFileTime(file, NULL, &last_access_filetime, |
| 199 | &last_modified_filetime) != 0); |
| 200 | } |
| 201 | |
| 202 | bool GetPlatformFileInfo(PlatformFile file, PlatformFileInfo* info) { |
[email protected] | 45446a5 | 2010-11-04 17:41:00 | [diff] [blame] | 203 | base::ThreadRestrictions::AssertIOAllowed(); |
[email protected] | 3fb43ed1 | 2010-09-10 03:01:14 | [diff] [blame] | 204 | if (!info) |
| 205 | return false; |
| 206 | |
| 207 | BY_HANDLE_FILE_INFORMATION file_info; |
| 208 | if (GetFileInformationByHandle(file, &file_info) == 0) |
| 209 | return false; |
| 210 | |
| 211 | LARGE_INTEGER size; |
| 212 | size.HighPart = file_info.nFileSizeHigh; |
| 213 | size.LowPart = file_info.nFileSizeLow; |
| 214 | info->size = size.QuadPart; |
| 215 | info->is_directory = |
| 216 | file_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY != 0; |
[email protected] | 2e733d10 | 2010-11-30 00:43:37 | [diff] [blame^] | 217 | info->is_symbolic_link = false; // Windows doesn't have symbolic links. |
[email protected] | 3fb43ed1 | 2010-09-10 03:01:14 | [diff] [blame] | 218 | info->last_modified = base::Time::FromFileTime(file_info.ftLastWriteTime); |
| 219 | info->last_accessed = base::Time::FromFileTime(file_info.ftLastAccessTime); |
| 220 | info->creation_time = base::Time::FromFileTime(file_info.ftCreationTime); |
| 221 | return true; |
[email protected] | ee8d4c8 | 2009-08-28 21:58:28 | [diff] [blame] | 222 | } |
| 223 | |
[email protected] | 21da6eb | 2008-11-03 17:18:14 | [diff] [blame] | 224 | } // namespace disk_cache |