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"
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"
16 void File::InitializeUnsafe(const FilePath
& name
, uint32 flags
) {
17 base::ThreadRestrictions::AssertIOAllowed();
20 DWORD disposition
= 0;
22 if (flags
& FLAG_OPEN
)
23 disposition
= OPEN_EXISTING
;
25 if (flags
& FLAG_CREATE
) {
27 disposition
= CREATE_NEW
;
30 if (flags
& FLAG_OPEN_ALWAYS
) {
32 disposition
= OPEN_ALWAYS
;
35 if (flags
& FLAG_CREATE_ALWAYS
) {
37 disposition
= CREATE_ALWAYS
;
40 if (flags
& FLAG_OPEN_TRUNCATED
) {
42 DCHECK(flags
& FLAG_WRITE
);
43 disposition
= TRUNCATE_EXISTING
;
52 if (flags
& FLAG_WRITE
)
53 access
= GENERIC_WRITE
;
54 if (flags
& FLAG_APPEND
) {
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
))
95 error_details_
= OSErrorToFileError(GetLastError());
99 bool File::IsValid() const {
100 return file_
.IsValid();
103 PlatformFile
File::GetPlatformFile() const {
107 PlatformFile
File::TakePlatformFile() {
112 if (file_
.IsValid()) {
113 base::ThreadRestrictions::AssertIOAllowed();
118 int64
File::Seek(Whence whence
, int64 offset
) {
119 base::ThreadRestrictions::AssertIOAllowed();
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
))
132 int File::Read(int64 offset
, char* data
, int size
) {
133 base::ThreadRestrictions::AssertIOAllowed();
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
;
147 if (::ReadFile(file_
, data
, size
, &bytes_read
, &overlapped
))
149 if (ERROR_HANDLE_EOF
== GetLastError())
155 int File::ReadAtCurrentPos(char* data
, int size
) {
156 base::ThreadRestrictions::AssertIOAllowed();
163 if (::ReadFile(file_
, data
, size
, &bytes_read
, NULL
))
165 if (ERROR_HANDLE_EOF
== GetLastError())
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();
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
;
192 if (::WriteFile(file_
, data
, size
, &bytes_written
, &overlapped
))
193 return bytes_written
;
198 int File::WriteAtCurrentPos(const char* data
, int size
) {
199 base::ThreadRestrictions::AssertIOAllowed();
206 if (::WriteFile(file_
, data
, size
, &bytes_written
, NULL
))
207 return bytes_written
;
212 int File::WriteAtCurrentPosNoBestEffort(const char* data
, int size
) {
213 return WriteAtCurrentPos(data
, size
);
216 int64
File::GetLength() {
217 base::ThreadRestrictions::AssertIOAllowed();
220 if (!::GetFileSizeEx(file_
.Get(), &size
))
223 return static_cast<int64
>(size
.QuadPart
);
226 bool File::SetLength(int64 length
) {
227 base::ThreadRestrictions::AssertIOAllowed();
230 // Get the current file pointer.
231 LARGE_INTEGER file_pointer
;
234 if (!::SetFilePointerEx(file_
, zero
, &file_pointer
, FILE_CURRENT
))
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
))
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
));
255 base::ThreadRestrictions::AssertIOAllowed();
257 return ::FlushFileBuffers(file_
) != FALSE
;
260 bool File::SetTimes(Time last_access_time
, Time last_modified_time
) {
261 base::ThreadRestrictions::AssertIOAllowed();
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();
274 BY_HANDLE_FILE_INFORMATION file_info
;
275 if (!GetFileInformationByHandle(file_
, &file_info
))
279 size
.HighPart
= file_info
.nFileSizeHigh
;
280 size
.LowPart
= file_info
.nFileSizeLow
;
281 info
->size
= size
.QuadPart
;
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
);
291 File::Error
base::File::Lock() {
293 BOOL result
= LockFile(file_
, 0, 0, MAXDWORD
, MAXDWORD
);
295 return OSErrorToFileError(GetLastError());
299 File::Error
File::Unlock() {
301 BOOL result
= UnlockFile(file_
, 0, 0, MAXDWORD
, MAXDWORD
);
303 return OSErrorToFileError(GetLastError());
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
;
338 UMA_HISTOGRAM_SPARSE_SLOWLY("PlatformFile.UnknownErrors.Windows",
340 return FILE_ERROR_FAILED
;
344 void File::SetPlatformFile(PlatformFile file
) {