Revert 271602 "Implementation of leveldb-backed PrefStore."
[chromium-blink-merge.git] / base / files / file_win.cc
blob1e13381e255f00be678f0c224b933b729bd47ab8
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 void File::InitializeUnsafe(const FilePath& name, uint32 flags) {
17 base::ThreadRestrictions::AssertIOAllowed();
18 DCHECK(!IsValid());
20 DWORD disposition = 0;
22 if (flags & FLAG_OPEN)
23 disposition = OPEN_EXISTING;
25 if (flags & FLAG_CREATE) {
26 DCHECK(!disposition);
27 disposition = CREATE_NEW;
30 if (flags & FLAG_OPEN_ALWAYS) {
31 DCHECK(!disposition);
32 disposition = OPEN_ALWAYS;
35 if (flags & FLAG_CREATE_ALWAYS) {
36 DCHECK(!disposition);
37 disposition = CREATE_ALWAYS;
40 if (flags & FLAG_OPEN_TRUNCATED) {
41 DCHECK(!disposition);
42 DCHECK(flags & FLAG_WRITE);
43 disposition = TRUNCATE_EXISTING;
46 if (!disposition) {
47 NOTREACHED();
48 return;
51 DWORD access = 0;
52 if (flags & FLAG_WRITE)
53 access = GENERIC_WRITE;
54 if (flags & FLAG_APPEND) {
55 DCHECK(!access);
56 access = FILE_APPEND_DATA;
58 if (flags & FLAG_READ)
59 access |= GENERIC_READ;
60 if (flags & FLAG_WRITE_ATTRIBUTES)
61 access |= FILE_WRITE_ATTRIBUTES;
62 if (flags & FLAG_EXECUTE)
63 access |= GENERIC_EXECUTE;
65 DWORD sharing = (flags & FLAG_EXCLUSIVE_READ) ? 0 : FILE_SHARE_READ;
66 if (!(flags & FLAG_EXCLUSIVE_WRITE))
67 sharing |= FILE_SHARE_WRITE;
68 if (flags & FLAG_SHARE_DELETE)
69 sharing |= FILE_SHARE_DELETE;
71 DWORD create_flags = 0;
72 if (flags & FLAG_ASYNC)
73 create_flags |= FILE_FLAG_OVERLAPPED;
74 if (flags & FLAG_TEMPORARY)
75 create_flags |= FILE_ATTRIBUTE_TEMPORARY;
76 if (flags & FLAG_HIDDEN)
77 create_flags |= FILE_ATTRIBUTE_HIDDEN;
78 if (flags & FLAG_DELETE_ON_CLOSE)
79 create_flags |= FILE_FLAG_DELETE_ON_CLOSE;
80 if (flags & FLAG_BACKUP_SEMANTICS)
81 create_flags |= FILE_FLAG_BACKUP_SEMANTICS;
83 file_.Set(CreateFile(name.value().c_str(), access, sharing, NULL,
84 disposition, create_flags, NULL));
86 if (file_.IsValid()) {
87 error_details_ = FILE_OK;
88 async_ = ((flags & FLAG_ASYNC) == FLAG_ASYNC);
90 if (flags & (FLAG_OPEN_ALWAYS))
91 created_ = (ERROR_ALREADY_EXISTS != GetLastError());
92 else if (flags & (FLAG_CREATE_ALWAYS | FLAG_CREATE))
93 created_ = true;
94 } else {
95 error_details_ = OSErrorToFileError(GetLastError());
99 bool File::IsValid() const {
100 return file_.IsValid();
103 PlatformFile File::GetPlatformFile() const {
104 return file_;
107 PlatformFile File::TakePlatformFile() {
108 return file_.Take();
111 void File::Close() {
112 if (file_.IsValid()) {
113 base::ThreadRestrictions::AssertIOAllowed();
114 file_.Close();
118 int64 File::Seek(Whence whence, int64 offset) {
119 base::ThreadRestrictions::AssertIOAllowed();
120 DCHECK(IsValid());
121 if (offset < 0)
122 return -1;
124 LARGE_INTEGER distance, res;
125 distance.QuadPart = offset;
126 DWORD move_method = static_cast<DWORD>(whence);
127 if (!SetFilePointerEx(file_, distance, &res, move_method))
128 return -1;
129 return res.QuadPart;
132 int File::Read(int64 offset, char* data, int size) {
133 base::ThreadRestrictions::AssertIOAllowed();
134 DCHECK(IsValid());
135 DCHECK(!async_);
136 if (size < 0)
137 return -1;
139 LARGE_INTEGER offset_li;
140 offset_li.QuadPart = offset;
142 OVERLAPPED overlapped = {0};
143 overlapped.Offset = offset_li.LowPart;
144 overlapped.OffsetHigh = offset_li.HighPart;
146 DWORD bytes_read;
147 if (::ReadFile(file_, data, size, &bytes_read, &overlapped))
148 return bytes_read;
149 if (ERROR_HANDLE_EOF == GetLastError())
150 return 0;
152 return -1;
155 int File::ReadAtCurrentPos(char* data, int size) {
156 base::ThreadRestrictions::AssertIOAllowed();
157 DCHECK(IsValid());
158 DCHECK(!async_);
159 if (size < 0)
160 return -1;
162 DWORD bytes_read;
163 if (::ReadFile(file_, data, size, &bytes_read, NULL))
164 return bytes_read;
165 if (ERROR_HANDLE_EOF == GetLastError())
166 return 0;
168 return -1;
171 int File::ReadNoBestEffort(int64 offset, char* data, int size) {
172 return Read(offset, data, size);
175 int File::ReadAtCurrentPosNoBestEffort(char* data, int size) {
176 return ReadAtCurrentPos(data, size);
179 int File::Write(int64 offset, const char* data, int size) {
180 base::ThreadRestrictions::AssertIOAllowed();
181 DCHECK(IsValid());
182 DCHECK(!async_);
184 LARGE_INTEGER offset_li;
185 offset_li.QuadPart = offset;
187 OVERLAPPED overlapped = {0};
188 overlapped.Offset = offset_li.LowPart;
189 overlapped.OffsetHigh = offset_li.HighPart;
191 DWORD bytes_written;
192 if (::WriteFile(file_, data, size, &bytes_written, &overlapped))
193 return bytes_written;
195 return -1;
198 int File::WriteAtCurrentPos(const char* data, int size) {
199 base::ThreadRestrictions::AssertIOAllowed();
200 DCHECK(IsValid());
201 DCHECK(!async_);
202 if (size < 0)
203 return -1;
205 DWORD bytes_written;
206 if (::WriteFile(file_, data, size, &bytes_written, NULL))
207 return bytes_written;
209 return -1;
212 int File::WriteAtCurrentPosNoBestEffort(const char* data, int size) {
213 return WriteAtCurrentPos(data, size);
216 int64 File::GetLength() {
217 base::ThreadRestrictions::AssertIOAllowed();
218 DCHECK(IsValid());
219 LARGE_INTEGER size;
220 if (!::GetFileSizeEx(file_.Get(), &size))
221 return -1;
223 return static_cast<int64>(size.QuadPart);
226 bool File::SetLength(int64 length) {
227 base::ThreadRestrictions::AssertIOAllowed();
228 DCHECK(IsValid());
230 // Get the current file pointer.
231 LARGE_INTEGER file_pointer;
232 LARGE_INTEGER zero;
233 zero.QuadPart = 0;
234 if (!::SetFilePointerEx(file_, zero, &file_pointer, FILE_CURRENT))
235 return false;
237 LARGE_INTEGER length_li;
238 length_li.QuadPart = length;
239 // If length > file size, SetFilePointerEx() should extend the file
240 // with zeroes on all Windows standard file systems (NTFS, FATxx).
241 if (!::SetFilePointerEx(file_, length_li, NULL, FILE_BEGIN))
242 return false;
244 // Set the new file length and move the file pointer to its old position.
245 // This is consistent with ftruncate()'s behavior, even when the file
246 // pointer points to a location beyond the end of the file.
247 // TODO(rvargas): Emulating ftruncate details seem suspicious and it is not
248 // promised by the interface (nor was promised by PlatformFile). See if this
249 // implementation detail can be removed.
250 return ((::SetEndOfFile(file_) != FALSE) &&
251 (::SetFilePointerEx(file_, file_pointer, NULL, FILE_BEGIN) != FALSE));
254 bool File::Flush() {
255 base::ThreadRestrictions::AssertIOAllowed();
256 DCHECK(IsValid());
257 return ::FlushFileBuffers(file_) != FALSE;
260 bool File::SetTimes(Time last_access_time, Time last_modified_time) {
261 base::ThreadRestrictions::AssertIOAllowed();
262 DCHECK(IsValid());
264 FILETIME last_access_filetime = last_access_time.ToFileTime();
265 FILETIME last_modified_filetime = last_modified_time.ToFileTime();
266 return (::SetFileTime(file_, NULL, &last_access_filetime,
267 &last_modified_filetime) != FALSE);
270 bool File::GetInfo(Info* info) {
271 base::ThreadRestrictions::AssertIOAllowed();
272 DCHECK(IsValid());
274 BY_HANDLE_FILE_INFORMATION file_info;
275 if (!GetFileInformationByHandle(file_, &file_info))
276 return false;
278 LARGE_INTEGER size;
279 size.HighPart = file_info.nFileSizeHigh;
280 size.LowPart = file_info.nFileSizeLow;
281 info->size = size.QuadPart;
282 info->is_directory =
283 (file_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
284 info->is_symbolic_link = false; // Windows doesn't have symbolic links.
285 info->last_modified = base::Time::FromFileTime(file_info.ftLastWriteTime);
286 info->last_accessed = base::Time::FromFileTime(file_info.ftLastAccessTime);
287 info->creation_time = base::Time::FromFileTime(file_info.ftCreationTime);
288 return true;
291 File::Error base::File::Lock() {
292 DCHECK(IsValid());
293 BOOL result = LockFile(file_, 0, 0, MAXDWORD, MAXDWORD);
294 if (!result)
295 return OSErrorToFileError(GetLastError());
296 return FILE_OK;
299 File::Error File::Unlock() {
300 DCHECK(IsValid());
301 BOOL result = UnlockFile(file_, 0, 0, MAXDWORD, MAXDWORD);
302 if (!result)
303 return OSErrorToFileError(GetLastError());
304 return FILE_OK;
307 // Static.
308 File::Error File::OSErrorToFileError(DWORD last_error) {
309 switch (last_error) {
310 case ERROR_SHARING_VIOLATION:
311 return FILE_ERROR_IN_USE;
312 case ERROR_FILE_EXISTS:
313 return FILE_ERROR_EXISTS;
314 case ERROR_FILE_NOT_FOUND:
315 case ERROR_PATH_NOT_FOUND:
316 return FILE_ERROR_NOT_FOUND;
317 case ERROR_ACCESS_DENIED:
318 return FILE_ERROR_ACCESS_DENIED;
319 case ERROR_TOO_MANY_OPEN_FILES:
320 return FILE_ERROR_TOO_MANY_OPENED;
321 case ERROR_OUTOFMEMORY:
322 case ERROR_NOT_ENOUGH_MEMORY:
323 return FILE_ERROR_NO_MEMORY;
324 case ERROR_HANDLE_DISK_FULL:
325 case ERROR_DISK_FULL:
326 case ERROR_DISK_RESOURCES_EXHAUSTED:
327 return FILE_ERROR_NO_SPACE;
328 case ERROR_USER_MAPPED_FILE:
329 return FILE_ERROR_INVALID_OPERATION;
330 case ERROR_NOT_READY:
331 case ERROR_SECTOR_NOT_FOUND:
332 case ERROR_DEV_NOT_EXIST:
333 case ERROR_IO_DEVICE:
334 case ERROR_FILE_CORRUPT:
335 case ERROR_DISK_CORRUPT:
336 return FILE_ERROR_IO;
337 default:
338 UMA_HISTOGRAM_SPARSE_SLOWLY("PlatformFile.UnknownErrors.Windows",
339 last_error);
340 return FILE_ERROR_FAILED;
344 void File::SetPlatformFile(PlatformFile file) {
345 file_.Set(file);
348 } // namespace base