Roll src/third_party/WebKit 44e0d7b:d79e3c1 (svn 190013:190016)
[chromium-blink-merge.git] / base / files / file_win.cc
blob727b5ce1dbbe6e5e7be6e22cef8f1d450515b002
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.
5 #include "base/files/file.h"
7 #include <io.h>
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"
14 namespace base {
16 // Make sure our Whence mappings match the system headers.
17 COMPILE_ASSERT(File::FROM_BEGIN == FILE_BEGIN &&
18 File::FROM_CURRENT == FILE_CURRENT &&
19 File::FROM_END == FILE_END, whence_matches_system);
21 void File::InitializeUnsafe(const FilePath& name, uint32 flags) {
22 base::ThreadRestrictions::AssertIOAllowed();
23 DCHECK(!IsValid());
25 DWORD disposition = 0;
27 if (flags & FLAG_OPEN)
28 disposition = OPEN_EXISTING;
30 if (flags & FLAG_CREATE) {
31 DCHECK(!disposition);
32 disposition = CREATE_NEW;
35 if (flags & FLAG_OPEN_ALWAYS) {
36 DCHECK(!disposition);
37 disposition = OPEN_ALWAYS;
40 if (flags & FLAG_CREATE_ALWAYS) {
41 DCHECK(!disposition);
42 DCHECK(flags & FLAG_WRITE);
43 disposition = CREATE_ALWAYS;
46 if (flags & FLAG_OPEN_TRUNCATED) {
47 DCHECK(!disposition);
48 DCHECK(flags & FLAG_WRITE);
49 disposition = TRUNCATE_EXISTING;
52 if (!disposition) {
53 NOTREACHED();
54 return;
57 DWORD access = 0;
58 if (flags & FLAG_WRITE)
59 access = GENERIC_WRITE;
60 if (flags & FLAG_APPEND) {
61 DCHECK(!access);
62 access = FILE_APPEND_DATA;
64 if (flags & FLAG_READ)
65 access |= GENERIC_READ;
66 if (flags & FLAG_WRITE_ATTRIBUTES)
67 access |= FILE_WRITE_ATTRIBUTES;
68 if (flags & FLAG_EXECUTE)
69 access |= GENERIC_EXECUTE;
71 DWORD sharing = (flags & FLAG_EXCLUSIVE_READ) ? 0 : FILE_SHARE_READ;
72 if (!(flags & FLAG_EXCLUSIVE_WRITE))
73 sharing |= FILE_SHARE_WRITE;
74 if (flags & FLAG_SHARE_DELETE)
75 sharing |= FILE_SHARE_DELETE;
77 DWORD create_flags = 0;
78 if (flags & FLAG_ASYNC)
79 create_flags |= FILE_FLAG_OVERLAPPED;
80 if (flags & FLAG_TEMPORARY)
81 create_flags |= FILE_ATTRIBUTE_TEMPORARY;
82 if (flags & FLAG_HIDDEN)
83 create_flags |= FILE_ATTRIBUTE_HIDDEN;
84 if (flags & FLAG_DELETE_ON_CLOSE)
85 create_flags |= FILE_FLAG_DELETE_ON_CLOSE;
86 if (flags & FLAG_BACKUP_SEMANTICS)
87 create_flags |= FILE_FLAG_BACKUP_SEMANTICS;
89 file_.Set(CreateFile(name.value().c_str(), access, sharing, NULL,
90 disposition, create_flags, NULL));
92 if (file_.IsValid()) {
93 error_details_ = FILE_OK;
94 async_ = ((flags & FLAG_ASYNC) == FLAG_ASYNC);
96 if (flags & (FLAG_OPEN_ALWAYS))
97 created_ = (ERROR_ALREADY_EXISTS != GetLastError());
98 else if (flags & (FLAG_CREATE_ALWAYS | FLAG_CREATE))
99 created_ = true;
100 } else {
101 error_details_ = OSErrorToFileError(GetLastError());
105 bool File::IsValid() const {
106 return file_.IsValid();
109 PlatformFile File::GetPlatformFile() const {
110 return file_.Get();
113 PlatformFile File::TakePlatformFile() {
114 return file_.Take();
117 void File::Close() {
118 if (file_.IsValid()) {
119 base::ThreadRestrictions::AssertIOAllowed();
120 file_.Close();
124 int64 File::Seek(Whence whence, int64 offset) {
125 base::ThreadRestrictions::AssertIOAllowed();
126 DCHECK(IsValid());
128 LARGE_INTEGER distance, res;
129 distance.QuadPart = offset;
130 DWORD move_method = static_cast<DWORD>(whence);
131 if (!SetFilePointerEx(file_.Get(), distance, &res, move_method))
132 return -1;
133 return res.QuadPart;
136 int File::Read(int64 offset, char* data, int size) {
137 base::ThreadRestrictions::AssertIOAllowed();
138 DCHECK(IsValid());
139 DCHECK(!async_);
140 if (size < 0)
141 return -1;
143 LARGE_INTEGER offset_li;
144 offset_li.QuadPart = offset;
146 OVERLAPPED overlapped = {0};
147 overlapped.Offset = offset_li.LowPart;
148 overlapped.OffsetHigh = offset_li.HighPart;
150 DWORD bytes_read;
151 if (::ReadFile(file_.Get(), data, size, &bytes_read, &overlapped))
152 return bytes_read;
153 if (ERROR_HANDLE_EOF == GetLastError())
154 return 0;
156 return -1;
159 int File::ReadAtCurrentPos(char* data, int size) {
160 base::ThreadRestrictions::AssertIOAllowed();
161 DCHECK(IsValid());
162 DCHECK(!async_);
163 if (size < 0)
164 return -1;
166 DWORD bytes_read;
167 if (::ReadFile(file_.Get(), data, size, &bytes_read, NULL))
168 return bytes_read;
169 if (ERROR_HANDLE_EOF == GetLastError())
170 return 0;
172 return -1;
175 int File::ReadNoBestEffort(int64 offset, char* data, int size) {
176 return Read(offset, data, size);
179 int File::ReadAtCurrentPosNoBestEffort(char* data, int size) {
180 return ReadAtCurrentPos(data, size);
183 int File::Write(int64 offset, const char* data, int size) {
184 base::ThreadRestrictions::AssertIOAllowed();
185 DCHECK(IsValid());
186 DCHECK(!async_);
188 LARGE_INTEGER offset_li;
189 offset_li.QuadPart = offset;
191 OVERLAPPED overlapped = {0};
192 overlapped.Offset = offset_li.LowPart;
193 overlapped.OffsetHigh = offset_li.HighPart;
195 DWORD bytes_written;
196 if (::WriteFile(file_.Get(), data, size, &bytes_written, &overlapped))
197 return bytes_written;
199 return -1;
202 int File::WriteAtCurrentPos(const char* data, int size) {
203 base::ThreadRestrictions::AssertIOAllowed();
204 DCHECK(IsValid());
205 DCHECK(!async_);
206 if (size < 0)
207 return -1;
209 DWORD bytes_written;
210 if (::WriteFile(file_.Get(), data, size, &bytes_written, NULL))
211 return bytes_written;
213 return -1;
216 int File::WriteAtCurrentPosNoBestEffort(const char* data, int size) {
217 return WriteAtCurrentPos(data, size);
220 int64 File::GetLength() {
221 base::ThreadRestrictions::AssertIOAllowed();
222 DCHECK(IsValid());
223 LARGE_INTEGER size;
224 if (!::GetFileSizeEx(file_.Get(), &size))
225 return -1;
227 return static_cast<int64>(size.QuadPart);
230 bool File::SetLength(int64 length) {
231 base::ThreadRestrictions::AssertIOAllowed();
232 DCHECK(IsValid());
234 // Get the current file pointer.
235 LARGE_INTEGER file_pointer;
236 LARGE_INTEGER zero;
237 zero.QuadPart = 0;
238 if (!::SetFilePointerEx(file_.Get(), zero, &file_pointer, FILE_CURRENT))
239 return false;
241 LARGE_INTEGER length_li;
242 length_li.QuadPart = length;
243 // If length > file size, SetFilePointerEx() should extend the file
244 // with zeroes on all Windows standard file systems (NTFS, FATxx).
245 if (!::SetFilePointerEx(file_.Get(), length_li, NULL, FILE_BEGIN))
246 return false;
248 // Set the new file length and move the file pointer to its old position.
249 // This is consistent with ftruncate()'s behavior, even when the file
250 // pointer points to a location beyond the end of the file.
251 // TODO(rvargas): Emulating ftruncate details seem suspicious and it is not
252 // promised by the interface (nor was promised by PlatformFile). See if this
253 // implementation detail can be removed.
254 return ((::SetEndOfFile(file_.Get()) != FALSE) &&
255 (::SetFilePointerEx(file_.Get(), file_pointer, NULL, FILE_BEGIN) !=
256 FALSE));
259 bool File::Flush() {
260 base::ThreadRestrictions::AssertIOAllowed();
261 DCHECK(IsValid());
262 return ::FlushFileBuffers(file_.Get()) != FALSE;
265 bool File::SetTimes(Time last_access_time, Time last_modified_time) {
266 base::ThreadRestrictions::AssertIOAllowed();
267 DCHECK(IsValid());
269 FILETIME last_access_filetime = last_access_time.ToFileTime();
270 FILETIME last_modified_filetime = last_modified_time.ToFileTime();
271 return (::SetFileTime(file_.Get(), NULL, &last_access_filetime,
272 &last_modified_filetime) != FALSE);
275 bool File::GetInfo(Info* info) {
276 base::ThreadRestrictions::AssertIOAllowed();
277 DCHECK(IsValid());
279 BY_HANDLE_FILE_INFORMATION file_info;
280 if (!GetFileInformationByHandle(file_.Get(), &file_info))
281 return false;
283 LARGE_INTEGER size;
284 size.HighPart = file_info.nFileSizeHigh;
285 size.LowPart = file_info.nFileSizeLow;
286 info->size = size.QuadPart;
287 info->is_directory =
288 (file_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
289 info->is_symbolic_link = false; // Windows doesn't have symbolic links.
290 info->last_modified = base::Time::FromFileTime(file_info.ftLastWriteTime);
291 info->last_accessed = base::Time::FromFileTime(file_info.ftLastAccessTime);
292 info->creation_time = base::Time::FromFileTime(file_info.ftCreationTime);
293 return true;
296 File::Error base::File::Lock() {
297 DCHECK(IsValid());
298 BOOL result = LockFile(file_.Get(), 0, 0, MAXDWORD, MAXDWORD);
299 if (!result)
300 return OSErrorToFileError(GetLastError());
301 return FILE_OK;
304 File::Error File::Unlock() {
305 DCHECK(IsValid());
306 BOOL result = UnlockFile(file_.Get(), 0, 0, MAXDWORD, MAXDWORD);
307 if (!result)
308 return OSErrorToFileError(GetLastError());
309 return FILE_OK;
312 // Static.
313 File::Error File::OSErrorToFileError(DWORD last_error) {
314 switch (last_error) {
315 case ERROR_SHARING_VIOLATION:
316 return FILE_ERROR_IN_USE;
317 case ERROR_FILE_EXISTS:
318 return FILE_ERROR_EXISTS;
319 case ERROR_FILE_NOT_FOUND:
320 case ERROR_PATH_NOT_FOUND:
321 return FILE_ERROR_NOT_FOUND;
322 case ERROR_ACCESS_DENIED:
323 return FILE_ERROR_ACCESS_DENIED;
324 case ERROR_TOO_MANY_OPEN_FILES:
325 return FILE_ERROR_TOO_MANY_OPENED;
326 case ERROR_OUTOFMEMORY:
327 case ERROR_NOT_ENOUGH_MEMORY:
328 return FILE_ERROR_NO_MEMORY;
329 case ERROR_HANDLE_DISK_FULL:
330 case ERROR_DISK_FULL:
331 case ERROR_DISK_RESOURCES_EXHAUSTED:
332 return FILE_ERROR_NO_SPACE;
333 case ERROR_USER_MAPPED_FILE:
334 return FILE_ERROR_INVALID_OPERATION;
335 case ERROR_NOT_READY:
336 case ERROR_SECTOR_NOT_FOUND:
337 case ERROR_DEV_NOT_EXIST:
338 case ERROR_IO_DEVICE:
339 case ERROR_FILE_CORRUPT:
340 case ERROR_DISK_CORRUPT:
341 return FILE_ERROR_IO;
342 default:
343 UMA_HISTOGRAM_SPARSE_SLOWLY("PlatformFile.UnknownErrors.Windows",
344 last_error);
345 return FILE_ERROR_FAILED;
349 void File::SetPlatformFile(PlatformFile file) {
350 file_.Set(file);
353 } // namespace base