QUIC - cleanup changes to sync chromium tree with internal source.
[chromium-blink-merge.git] / base / files / file_win.cc
blobce38d0b0e2af276a080105374d1d0fa5fc10c282
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/logging.h"
10 #include "base/metrics/sparse_histogram.h"
11 #include "base/threading/thread_restrictions.h"
13 namespace base {
15 // Make sure our Whence mappings match the system headers.
16 COMPILE_ASSERT(File::FROM_BEGIN == FILE_BEGIN &&
17 File::FROM_CURRENT == FILE_CURRENT &&
18 File::FROM_END == FILE_END, whence_matches_system);
20 bool File::IsValid() const {
21 return file_.IsValid();
24 PlatformFile File::GetPlatformFile() const {
25 return file_.Get();
28 PlatformFile File::TakePlatformFile() {
29 return file_.Take();
32 void File::Close() {
33 if (!file_.IsValid())
34 return;
36 ThreadRestrictions::AssertIOAllowed();
37 SCOPED_FILE_TRACE("Close");
38 file_.Close();
41 int64 File::Seek(Whence whence, int64 offset) {
42 ThreadRestrictions::AssertIOAllowed();
43 DCHECK(IsValid());
45 SCOPED_FILE_TRACE_WITH_SIZE("Seek", offset);
47 LARGE_INTEGER distance, res;
48 distance.QuadPart = offset;
49 DWORD move_method = static_cast<DWORD>(whence);
50 if (!SetFilePointerEx(file_.Get(), distance, &res, move_method))
51 return -1;
52 return res.QuadPart;
55 int File::Read(int64 offset, char* data, int size) {
56 ThreadRestrictions::AssertIOAllowed();
57 DCHECK(IsValid());
58 DCHECK(!async_);
59 if (size < 0)
60 return -1;
62 SCOPED_FILE_TRACE_WITH_SIZE("Read", size);
64 LARGE_INTEGER offset_li;
65 offset_li.QuadPart = offset;
67 OVERLAPPED overlapped = {0};
68 overlapped.Offset = offset_li.LowPart;
69 overlapped.OffsetHigh = offset_li.HighPart;
71 DWORD bytes_read;
72 if (::ReadFile(file_.Get(), data, size, &bytes_read, &overlapped))
73 return bytes_read;
74 if (ERROR_HANDLE_EOF == GetLastError())
75 return 0;
77 return -1;
80 int File::ReadAtCurrentPos(char* data, int size) {
81 ThreadRestrictions::AssertIOAllowed();
82 DCHECK(IsValid());
83 DCHECK(!async_);
84 if (size < 0)
85 return -1;
87 SCOPED_FILE_TRACE_WITH_SIZE("ReadAtCurrentPos", size);
89 DWORD bytes_read;
90 if (::ReadFile(file_.Get(), data, size, &bytes_read, NULL))
91 return bytes_read;
92 if (ERROR_HANDLE_EOF == GetLastError())
93 return 0;
95 return -1;
98 int File::ReadNoBestEffort(int64 offset, char* data, int size) {
99 // TODO(dbeam): trace this separately?
100 return Read(offset, data, size);
103 int File::ReadAtCurrentPosNoBestEffort(char* data, int size) {
104 // TODO(dbeam): trace this separately?
105 return ReadAtCurrentPos(data, size);
108 int File::Write(int64 offset, const char* data, int size) {
109 ThreadRestrictions::AssertIOAllowed();
110 DCHECK(IsValid());
111 DCHECK(!async_);
113 SCOPED_FILE_TRACE_WITH_SIZE("Write", size);
115 LARGE_INTEGER offset_li;
116 offset_li.QuadPart = offset;
118 OVERLAPPED overlapped = {0};
119 overlapped.Offset = offset_li.LowPart;
120 overlapped.OffsetHigh = offset_li.HighPart;
122 DWORD bytes_written;
123 if (::WriteFile(file_.Get(), data, size, &bytes_written, &overlapped))
124 return bytes_written;
126 return -1;
129 int File::WriteAtCurrentPos(const char* data, int size) {
130 ThreadRestrictions::AssertIOAllowed();
131 DCHECK(IsValid());
132 DCHECK(!async_);
133 if (size < 0)
134 return -1;
136 SCOPED_FILE_TRACE_WITH_SIZE("WriteAtCurrentPos", size);
138 DWORD bytes_written;
139 if (::WriteFile(file_.Get(), data, size, &bytes_written, NULL))
140 return bytes_written;
142 return -1;
145 int File::WriteAtCurrentPosNoBestEffort(const char* data, int size) {
146 return WriteAtCurrentPos(data, size);
149 int64 File::GetLength() {
150 ThreadRestrictions::AssertIOAllowed();
151 DCHECK(IsValid());
153 SCOPED_FILE_TRACE("GetLength");
155 LARGE_INTEGER size;
156 if (!::GetFileSizeEx(file_.Get(), &size))
157 return -1;
159 return static_cast<int64>(size.QuadPart);
162 bool File::SetLength(int64 length) {
163 ThreadRestrictions::AssertIOAllowed();
164 DCHECK(IsValid());
166 SCOPED_FILE_TRACE_WITH_SIZE("SetLength", length);
168 // Get the current file pointer.
169 LARGE_INTEGER file_pointer;
170 LARGE_INTEGER zero;
171 zero.QuadPart = 0;
172 if (!::SetFilePointerEx(file_.Get(), zero, &file_pointer, FILE_CURRENT))
173 return false;
175 LARGE_INTEGER length_li;
176 length_li.QuadPart = length;
177 // If length > file size, SetFilePointerEx() should extend the file
178 // with zeroes on all Windows standard file systems (NTFS, FATxx).
179 if (!::SetFilePointerEx(file_.Get(), length_li, NULL, FILE_BEGIN))
180 return false;
182 // Set the new file length and move the file pointer to its old position.
183 // This is consistent with ftruncate()'s behavior, even when the file
184 // pointer points to a location beyond the end of the file.
185 // TODO(rvargas): Emulating ftruncate details seem suspicious and it is not
186 // promised by the interface (nor was promised by PlatformFile). See if this
187 // implementation detail can be removed.
188 return ((::SetEndOfFile(file_.Get()) != FALSE) &&
189 (::SetFilePointerEx(file_.Get(), file_pointer, NULL, FILE_BEGIN) !=
190 FALSE));
193 bool File::SetTimes(Time last_access_time, Time last_modified_time) {
194 ThreadRestrictions::AssertIOAllowed();
195 DCHECK(IsValid());
197 SCOPED_FILE_TRACE("SetTimes");
199 FILETIME last_access_filetime = last_access_time.ToFileTime();
200 FILETIME last_modified_filetime = last_modified_time.ToFileTime();
201 return (::SetFileTime(file_.Get(), NULL, &last_access_filetime,
202 &last_modified_filetime) != FALSE);
205 bool File::GetInfo(Info* info) {
206 ThreadRestrictions::AssertIOAllowed();
207 DCHECK(IsValid());
209 SCOPED_FILE_TRACE("GetInfo");
211 BY_HANDLE_FILE_INFORMATION file_info;
212 if (!GetFileInformationByHandle(file_.Get(), &file_info))
213 return false;
215 LARGE_INTEGER size;
216 size.HighPart = file_info.nFileSizeHigh;
217 size.LowPart = file_info.nFileSizeLow;
218 info->size = size.QuadPart;
219 info->is_directory =
220 (file_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
221 info->is_symbolic_link = false; // Windows doesn't have symbolic links.
222 info->last_modified = Time::FromFileTime(file_info.ftLastWriteTime);
223 info->last_accessed = Time::FromFileTime(file_info.ftLastAccessTime);
224 info->creation_time = Time::FromFileTime(file_info.ftCreationTime);
225 return true;
228 File::Error File::Lock() {
229 DCHECK(IsValid());
231 SCOPED_FILE_TRACE("Lock");
233 BOOL result = LockFile(file_.Get(), 0, 0, MAXDWORD, MAXDWORD);
234 if (!result)
235 return OSErrorToFileError(GetLastError());
236 return FILE_OK;
239 File::Error File::Unlock() {
240 DCHECK(IsValid());
242 SCOPED_FILE_TRACE("Unlock");
244 BOOL result = UnlockFile(file_.Get(), 0, 0, MAXDWORD, MAXDWORD);
245 if (!result)
246 return OSErrorToFileError(GetLastError());
247 return FILE_OK;
250 File File::Duplicate() {
251 if (!IsValid())
252 return File();
254 SCOPED_FILE_TRACE("Duplicate");
256 HANDLE other_handle = nullptr;
258 if (!::DuplicateHandle(GetCurrentProcess(), // hSourceProcessHandle
259 GetPlatformFile(),
260 GetCurrentProcess(), // hTargetProcessHandle
261 &other_handle,
262 0, // dwDesiredAccess ignored due to SAME_ACCESS
263 FALSE, // !bInheritHandle
264 DUPLICATE_SAME_ACCESS)) {
265 return File(OSErrorToFileError(GetLastError()));
268 File other(other_handle);
269 if (async())
270 other.async_ = true;
271 return other.Pass();
274 // Static.
275 File::Error File::OSErrorToFileError(DWORD last_error) {
276 switch (last_error) {
277 case ERROR_SHARING_VIOLATION:
278 return FILE_ERROR_IN_USE;
279 case ERROR_FILE_EXISTS:
280 return FILE_ERROR_EXISTS;
281 case ERROR_FILE_NOT_FOUND:
282 case ERROR_PATH_NOT_FOUND:
283 return FILE_ERROR_NOT_FOUND;
284 case ERROR_ACCESS_DENIED:
285 return FILE_ERROR_ACCESS_DENIED;
286 case ERROR_TOO_MANY_OPEN_FILES:
287 return FILE_ERROR_TOO_MANY_OPENED;
288 case ERROR_OUTOFMEMORY:
289 case ERROR_NOT_ENOUGH_MEMORY:
290 return FILE_ERROR_NO_MEMORY;
291 case ERROR_HANDLE_DISK_FULL:
292 case ERROR_DISK_FULL:
293 case ERROR_DISK_RESOURCES_EXHAUSTED:
294 return FILE_ERROR_NO_SPACE;
295 case ERROR_USER_MAPPED_FILE:
296 return FILE_ERROR_INVALID_OPERATION;
297 case ERROR_NOT_READY:
298 case ERROR_SECTOR_NOT_FOUND:
299 case ERROR_DEV_NOT_EXIST:
300 case ERROR_IO_DEVICE:
301 case ERROR_FILE_CORRUPT:
302 case ERROR_DISK_CORRUPT:
303 return FILE_ERROR_IO;
304 default:
305 UMA_HISTOGRAM_SPARSE_SLOWLY("PlatformFile.UnknownErrors.Windows",
306 last_error);
307 return FILE_ERROR_FAILED;
311 void File::DoInitialize(const FilePath& path, uint32 flags) {
312 ThreadRestrictions::AssertIOAllowed();
313 DCHECK(!IsValid());
315 DWORD disposition = 0;
317 if (flags & FLAG_OPEN)
318 disposition = OPEN_EXISTING;
320 if (flags & FLAG_CREATE) {
321 DCHECK(!disposition);
322 disposition = CREATE_NEW;
325 if (flags & FLAG_OPEN_ALWAYS) {
326 DCHECK(!disposition);
327 disposition = OPEN_ALWAYS;
330 if (flags & FLAG_CREATE_ALWAYS) {
331 DCHECK(!disposition);
332 DCHECK(flags & FLAG_WRITE);
333 disposition = CREATE_ALWAYS;
336 if (flags & FLAG_OPEN_TRUNCATED) {
337 DCHECK(!disposition);
338 DCHECK(flags & FLAG_WRITE);
339 disposition = TRUNCATE_EXISTING;
342 if (!disposition) {
343 NOTREACHED();
344 return;
347 DWORD access = 0;
348 if (flags & FLAG_WRITE)
349 access = GENERIC_WRITE;
350 if (flags & FLAG_APPEND) {
351 DCHECK(!access);
352 access = FILE_APPEND_DATA;
354 if (flags & FLAG_READ)
355 access |= GENERIC_READ;
356 if (flags & FLAG_WRITE_ATTRIBUTES)
357 access |= FILE_WRITE_ATTRIBUTES;
358 if (flags & FLAG_EXECUTE)
359 access |= GENERIC_EXECUTE;
361 DWORD sharing = (flags & FLAG_EXCLUSIVE_READ) ? 0 : FILE_SHARE_READ;
362 if (!(flags & FLAG_EXCLUSIVE_WRITE))
363 sharing |= FILE_SHARE_WRITE;
364 if (flags & FLAG_SHARE_DELETE)
365 sharing |= FILE_SHARE_DELETE;
367 DWORD create_flags = 0;
368 if (flags & FLAG_ASYNC)
369 create_flags |= FILE_FLAG_OVERLAPPED;
370 if (flags & FLAG_TEMPORARY)
371 create_flags |= FILE_ATTRIBUTE_TEMPORARY;
372 if (flags & FLAG_HIDDEN)
373 create_flags |= FILE_ATTRIBUTE_HIDDEN;
374 if (flags & FLAG_DELETE_ON_CLOSE)
375 create_flags |= FILE_FLAG_DELETE_ON_CLOSE;
376 if (flags & FLAG_BACKUP_SEMANTICS)
377 create_flags |= FILE_FLAG_BACKUP_SEMANTICS;
379 file_.Set(CreateFile(path.value().c_str(), access, sharing, NULL,
380 disposition, create_flags, NULL));
382 if (file_.IsValid()) {
383 error_details_ = FILE_OK;
384 async_ = ((flags & FLAG_ASYNC) == FLAG_ASYNC);
386 if (flags & (FLAG_OPEN_ALWAYS))
387 created_ = (ERROR_ALREADY_EXISTS != GetLastError());
388 else if (flags & (FLAG_CREATE_ALWAYS | FLAG_CREATE))
389 created_ = true;
390 } else {
391 error_details_ = OSErrorToFileError(GetLastError());
395 bool File::DoFlush() {
396 ThreadRestrictions::AssertIOAllowed();
397 DCHECK(IsValid());
398 return ::FlushFileBuffers(file_.Get()) != FALSE;
401 void File::SetPlatformFile(PlatformFile file) {
402 file_.Set(file);
405 } // namespace base