Enterprise policy: Ignore the deprecated ForceSafeSearch if ForceGoogleSafeSearch...
[chromium-blink-merge.git] / base / files / file_win.cc
blob08d66125cf36a4942d2fcd431f167f72639feaf1
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::SetTimes(Time last_access_time, Time last_modified_time) {
260 base::ThreadRestrictions::AssertIOAllowed();
261 DCHECK(IsValid());
263 FILETIME last_access_filetime = last_access_time.ToFileTime();
264 FILETIME last_modified_filetime = last_modified_time.ToFileTime();
265 return (::SetFileTime(file_.Get(), NULL, &last_access_filetime,
266 &last_modified_filetime) != FALSE);
269 bool File::GetInfo(Info* info) {
270 base::ThreadRestrictions::AssertIOAllowed();
271 DCHECK(IsValid());
273 BY_HANDLE_FILE_INFORMATION file_info;
274 if (!GetFileInformationByHandle(file_.Get(), &file_info))
275 return false;
277 LARGE_INTEGER size;
278 size.HighPart = file_info.nFileSizeHigh;
279 size.LowPart = file_info.nFileSizeLow;
280 info->size = size.QuadPart;
281 info->is_directory =
282 (file_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
283 info->is_symbolic_link = false; // Windows doesn't have symbolic links.
284 info->last_modified = base::Time::FromFileTime(file_info.ftLastWriteTime);
285 info->last_accessed = base::Time::FromFileTime(file_info.ftLastAccessTime);
286 info->creation_time = base::Time::FromFileTime(file_info.ftCreationTime);
287 return true;
290 File::Error base::File::Lock() {
291 DCHECK(IsValid());
292 BOOL result = LockFile(file_.Get(), 0, 0, MAXDWORD, MAXDWORD);
293 if (!result)
294 return OSErrorToFileError(GetLastError());
295 return FILE_OK;
298 File::Error File::Unlock() {
299 DCHECK(IsValid());
300 BOOL result = UnlockFile(file_.Get(), 0, 0, MAXDWORD, MAXDWORD);
301 if (!result)
302 return OSErrorToFileError(GetLastError());
303 return FILE_OK;
306 File File::Duplicate() {
307 if (!IsValid())
308 return File();
310 HANDLE other_handle = nullptr;
312 if (!::DuplicateHandle(GetCurrentProcess(), // hSourceProcessHandle
313 GetPlatformFile(),
314 GetCurrentProcess(), // hTargetProcessHandle
315 &other_handle,
316 0, // dwDesiredAccess ignored due to SAME_ACCESS
317 FALSE, // !bInheritHandle
318 DUPLICATE_SAME_ACCESS)) {
319 return File(OSErrorToFileError(GetLastError()));
322 File other(other_handle);
323 if (async())
324 other.async_ = true;
325 return other.Pass();
328 // Static.
329 File::Error File::OSErrorToFileError(DWORD last_error) {
330 switch (last_error) {
331 case ERROR_SHARING_VIOLATION:
332 return FILE_ERROR_IN_USE;
333 case ERROR_FILE_EXISTS:
334 return FILE_ERROR_EXISTS;
335 case ERROR_FILE_NOT_FOUND:
336 case ERROR_PATH_NOT_FOUND:
337 return FILE_ERROR_NOT_FOUND;
338 case ERROR_ACCESS_DENIED:
339 return FILE_ERROR_ACCESS_DENIED;
340 case ERROR_TOO_MANY_OPEN_FILES:
341 return FILE_ERROR_TOO_MANY_OPENED;
342 case ERROR_OUTOFMEMORY:
343 case ERROR_NOT_ENOUGH_MEMORY:
344 return FILE_ERROR_NO_MEMORY;
345 case ERROR_HANDLE_DISK_FULL:
346 case ERROR_DISK_FULL:
347 case ERROR_DISK_RESOURCES_EXHAUSTED:
348 return FILE_ERROR_NO_SPACE;
349 case ERROR_USER_MAPPED_FILE:
350 return FILE_ERROR_INVALID_OPERATION;
351 case ERROR_NOT_READY:
352 case ERROR_SECTOR_NOT_FOUND:
353 case ERROR_DEV_NOT_EXIST:
354 case ERROR_IO_DEVICE:
355 case ERROR_FILE_CORRUPT:
356 case ERROR_DISK_CORRUPT:
357 return FILE_ERROR_IO;
358 default:
359 UMA_HISTOGRAM_SPARSE_SLOWLY("PlatformFile.UnknownErrors.Windows",
360 last_error);
361 return FILE_ERROR_FAILED;
365 bool File::DoFlush() {
366 base::ThreadRestrictions::AssertIOAllowed();
367 DCHECK(IsValid());
368 return ::FlushFileBuffers(file_.Get()) != FALSE;
371 void File::SetPlatformFile(PlatformFile file) {
372 file_.Set(file);
375 } // namespace base