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/platform_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"
15 PlatformFile
CreatePlatformFileUnsafe(const FilePath
& name
,
18 PlatformFileError
* error
) {
19 base::ThreadRestrictions::AssertIOAllowed();
21 DWORD disposition
= 0;
25 if (flags
& PLATFORM_FILE_OPEN
)
26 disposition
= OPEN_EXISTING
;
28 if (flags
& PLATFORM_FILE_CREATE
) {
30 disposition
= CREATE_NEW
;
33 if (flags
& PLATFORM_FILE_OPEN_ALWAYS
) {
35 disposition
= OPEN_ALWAYS
;
38 if (flags
& PLATFORM_FILE_CREATE_ALWAYS
) {
40 disposition
= CREATE_ALWAYS
;
43 if (flags
& PLATFORM_FILE_OPEN_TRUNCATED
) {
45 DCHECK(flags
& PLATFORM_FILE_WRITE
);
46 disposition
= TRUNCATE_EXISTING
;
55 if (flags
& PLATFORM_FILE_WRITE
)
56 access
= GENERIC_WRITE
;
57 if (flags
& PLATFORM_FILE_APPEND
) {
59 access
= FILE_APPEND_DATA
;
61 if (flags
& PLATFORM_FILE_READ
)
62 access
|= GENERIC_READ
;
63 if (flags
& PLATFORM_FILE_WRITE_ATTRIBUTES
)
64 access
|= FILE_WRITE_ATTRIBUTES
;
65 if (flags
& PLATFORM_FILE_EXECUTE
)
66 access
|= GENERIC_EXECUTE
;
68 DWORD sharing
= (flags
& PLATFORM_FILE_EXCLUSIVE_READ
) ? 0 : FILE_SHARE_READ
;
69 if (!(flags
& PLATFORM_FILE_EXCLUSIVE_WRITE
))
70 sharing
|= FILE_SHARE_WRITE
;
71 if (flags
& PLATFORM_FILE_SHARE_DELETE
)
72 sharing
|= FILE_SHARE_DELETE
;
74 DWORD create_flags
= 0;
75 if (flags
& PLATFORM_FILE_ASYNC
)
76 create_flags
|= FILE_FLAG_OVERLAPPED
;
77 if (flags
& PLATFORM_FILE_TEMPORARY
)
78 create_flags
|= FILE_ATTRIBUTE_TEMPORARY
;
79 if (flags
& PLATFORM_FILE_HIDDEN
)
80 create_flags
|= FILE_ATTRIBUTE_HIDDEN
;
81 if (flags
& PLATFORM_FILE_DELETE_ON_CLOSE
)
82 create_flags
|= FILE_FLAG_DELETE_ON_CLOSE
;
83 if (flags
& PLATFORM_FILE_BACKUP_SEMANTICS
)
84 create_flags
|= FILE_FLAG_BACKUP_SEMANTICS
;
86 HANDLE file
= CreateFile(name
.value().c_str(), access
, sharing
, NULL
,
87 disposition
, create_flags
, NULL
);
89 if (INVALID_HANDLE_VALUE
!= file
){
90 // Don't allow directories to be opened without the proper flag (block ADS).
91 if (!(flags
& PLATFORM_FILE_BACKUP_SEMANTICS
)) {
92 BY_HANDLE_FILE_INFORMATION info
= { 0 };
93 BOOL result
= GetFileInformationByHandle(file
, &info
);
95 if (info
.dwFileAttributes
& (FILE_ATTRIBUTE_DIRECTORY
|
96 FILE_ATTRIBUTE_REPARSE_POINT
)) {
98 file
= INVALID_HANDLE_VALUE
;
103 if (created
&& (INVALID_HANDLE_VALUE
!= file
)) {
104 if (flags
& (PLATFORM_FILE_OPEN_ALWAYS
))
105 *created
= (ERROR_ALREADY_EXISTS
!= GetLastError());
106 else if (flags
& (PLATFORM_FILE_CREATE_ALWAYS
| PLATFORM_FILE_CREATE
))
111 if (file
!= kInvalidPlatformFileValue
)
112 *error
= PLATFORM_FILE_OK
;
114 *error
= LastErrorToPlatformFileError(GetLastError());
120 FILE* FdopenPlatformFile(PlatformFile file
, const char* mode
) {
121 if (file
== kInvalidPlatformFileValue
)
123 int fd
= _open_osfhandle(reinterpret_cast<intptr_t>(file
), 0);
126 return _fdopen(fd
, mode
);
129 bool ClosePlatformFile(PlatformFile file
) {
130 base::ThreadRestrictions::AssertIOAllowed();
131 return (CloseHandle(file
) != 0);
134 int64
SeekPlatformFile(PlatformFile file
,
135 PlatformFileWhence whence
,
137 base::ThreadRestrictions::AssertIOAllowed();
138 if (file
== kInvalidPlatformFileValue
|| offset
< 0)
141 LARGE_INTEGER distance
, res
;
142 distance
.QuadPart
= offset
;
143 DWORD move_method
= static_cast<DWORD
>(whence
);
144 if (!SetFilePointerEx(file
, distance
, &res
, move_method
))
149 int ReadPlatformFile(PlatformFile file
, int64 offset
, char* data
, int size
) {
150 base::ThreadRestrictions::AssertIOAllowed();
151 if (file
== kInvalidPlatformFileValue
|| size
< 0)
154 LARGE_INTEGER offset_li
;
155 offset_li
.QuadPart
= offset
;
157 OVERLAPPED overlapped
= {0};
158 overlapped
.Offset
= offset_li
.LowPart
;
159 overlapped
.OffsetHigh
= offset_li
.HighPart
;
162 if (::ReadFile(file
, data
, size
, &bytes_read
, &overlapped
) != 0)
164 if (ERROR_HANDLE_EOF
== GetLastError())
170 int ReadPlatformFileAtCurrentPos(PlatformFile file
, char* data
, int size
) {
171 base::ThreadRestrictions::AssertIOAllowed();
172 if (file
== kInvalidPlatformFileValue
|| size
< 0)
176 if (::ReadFile(file
, data
, size
, &bytes_read
, NULL
) != 0)
178 if (ERROR_HANDLE_EOF
== GetLastError())
184 int ReadPlatformFileNoBestEffort(PlatformFile file
, int64 offset
, char* data
,
186 return ReadPlatformFile(file
, offset
, data
, size
);
189 int ReadPlatformFileCurPosNoBestEffort(PlatformFile file
,
190 char* data
, int size
) {
191 return ReadPlatformFileAtCurrentPos(file
, data
, size
);
194 int WritePlatformFile(PlatformFile file
, int64 offset
,
195 const char* data
, int size
) {
196 base::ThreadRestrictions::AssertIOAllowed();
197 if (file
== kInvalidPlatformFileValue
)
200 LARGE_INTEGER offset_li
;
201 offset_li
.QuadPart
= offset
;
203 OVERLAPPED overlapped
= {0};
204 overlapped
.Offset
= offset_li
.LowPart
;
205 overlapped
.OffsetHigh
= offset_li
.HighPart
;
208 if (::WriteFile(file
, data
, size
, &bytes_written
, &overlapped
) != 0)
209 return bytes_written
;
214 int WritePlatformFileAtCurrentPos(PlatformFile file
, const char* data
,
216 return WritePlatformFile(file
, 0, data
, size
);
219 int WritePlatformFileCurPosNoBestEffort(PlatformFile file
,
220 const char* data
, int size
) {
221 return WritePlatformFile(file
, 0, data
, size
);
224 bool TruncatePlatformFile(PlatformFile file
, int64 length
) {
225 base::ThreadRestrictions::AssertIOAllowed();
226 if (file
== kInvalidPlatformFileValue
)
229 // Get the current file pointer.
230 LARGE_INTEGER file_pointer
;
233 if (::SetFilePointerEx(file
, zero
, &file_pointer
, FILE_CURRENT
) == 0)
236 LARGE_INTEGER length_li
;
237 length_li
.QuadPart
= length
;
238 // If length > file size, SetFilePointerEx() should extend the file
239 // with zeroes on all Windows standard file systems (NTFS, FATxx).
240 if (!::SetFilePointerEx(file
, length_li
, NULL
, FILE_BEGIN
))
243 // Set the new file length and move the file pointer to its old position.
244 // This is consistent with ftruncate()'s behavior, even when the file
245 // pointer points to a location beyond the end of the file.
246 return ((::SetEndOfFile(file
) != 0) &&
247 (::SetFilePointerEx(file
, file_pointer
, NULL
, FILE_BEGIN
) != 0));
250 bool FlushPlatformFile(PlatformFile file
) {
251 base::ThreadRestrictions::AssertIOAllowed();
252 return ((file
!= kInvalidPlatformFileValue
) && ::FlushFileBuffers(file
));
255 bool TouchPlatformFile(PlatformFile file
, const base::Time
& last_access_time
,
256 const base::Time
& last_modified_time
) {
257 base::ThreadRestrictions::AssertIOAllowed();
258 if (file
== kInvalidPlatformFileValue
)
261 FILETIME last_access_filetime
= last_access_time
.ToFileTime();
262 FILETIME last_modified_filetime
= last_modified_time
.ToFileTime();
263 return (::SetFileTime(file
, NULL
, &last_access_filetime
,
264 &last_modified_filetime
) != 0);
267 bool GetPlatformFileInfo(PlatformFile file
, PlatformFileInfo
* info
) {
268 base::ThreadRestrictions::AssertIOAllowed();
272 BY_HANDLE_FILE_INFORMATION file_info
;
273 if (GetFileInformationByHandle(file
, &file_info
) == 0)
277 size
.HighPart
= file_info
.nFileSizeHigh
;
278 size
.LowPart
= file_info
.nFileSizeLow
;
279 info
->size
= size
.QuadPart
;
281 (file_info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
) != 0;
282 info
->is_symbolic_link
= false; // Windows doesn't have symbolic links.
283 info
->last_modified
= base::Time::FromFileTime(file_info
.ftLastWriteTime
);
284 info
->last_accessed
= base::Time::FromFileTime(file_info
.ftLastAccessTime
);
285 info
->creation_time
= base::Time::FromFileTime(file_info
.ftCreationTime
);
289 PlatformFileError
LockPlatformFile(PlatformFile file
) {
290 BOOL result
= LockFile(file
, 0, 0, MAXDWORD
, MAXDWORD
);
292 return LastErrorToPlatformFileError(GetLastError());
293 return PLATFORM_FILE_OK
;
296 PlatformFileError
UnlockPlatformFile(PlatformFile file
) {
297 BOOL result
= UnlockFile(file
, 0, 0, MAXDWORD
, MAXDWORD
);
299 return LastErrorToPlatformFileError(GetLastError());
300 return PLATFORM_FILE_OK
;
303 PlatformFileError
LastErrorToPlatformFileError(DWORD last_error
) {
304 switch (last_error
) {
305 case ERROR_SHARING_VIOLATION
:
306 return PLATFORM_FILE_ERROR_IN_USE
;
307 case ERROR_FILE_EXISTS
:
308 return PLATFORM_FILE_ERROR_EXISTS
;
309 case ERROR_FILE_NOT_FOUND
:
310 case ERROR_PATH_NOT_FOUND
:
311 return PLATFORM_FILE_ERROR_NOT_FOUND
;
312 case ERROR_ACCESS_DENIED
:
313 return PLATFORM_FILE_ERROR_ACCESS_DENIED
;
314 case ERROR_TOO_MANY_OPEN_FILES
:
315 return PLATFORM_FILE_ERROR_TOO_MANY_OPENED
;
316 case ERROR_OUTOFMEMORY
:
317 case ERROR_NOT_ENOUGH_MEMORY
:
318 return PLATFORM_FILE_ERROR_NO_MEMORY
;
319 case ERROR_HANDLE_DISK_FULL
:
320 case ERROR_DISK_FULL
:
321 case ERROR_DISK_RESOURCES_EXHAUSTED
:
322 return PLATFORM_FILE_ERROR_NO_SPACE
;
323 case ERROR_USER_MAPPED_FILE
:
324 return PLATFORM_FILE_ERROR_INVALID_OPERATION
;
325 case ERROR_NOT_READY
:
326 case ERROR_SECTOR_NOT_FOUND
:
327 case ERROR_DEV_NOT_EXIST
:
328 case ERROR_IO_DEVICE
:
329 case ERROR_FILE_CORRUPT
:
330 case ERROR_DISK_CORRUPT
:
331 return PLATFORM_FILE_ERROR_IO
;
333 UMA_HISTOGRAM_SPARSE_SLOWLY("PlatformFile.UnknownErrors.Windows",
335 return PLATFORM_FILE_ERROR_FAILED
;