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.
4
5 #include "base/files/file.h"
6
7 #include <io.h>
8
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"
13
14 namespace base {
15
CreateBaseFileUnsafe(const FilePath & name,uint32 flags)16 void File::CreateBaseFileUnsafe(const FilePath& name, uint32 flags) {
17 base::ThreadRestrictions::AssertIOAllowed();
18 DCHECK(!IsValid());
19
20 DWORD disposition = 0;
21
22 if (flags & FLAG_OPEN)
23 disposition = OPEN_EXISTING;
24
25 if (flags & FLAG_CREATE) {
26 DCHECK(!disposition);
27 disposition = CREATE_NEW;
28 }
29
30 if (flags & FLAG_OPEN_ALWAYS) {
31 DCHECK(!disposition);
32 disposition = OPEN_ALWAYS;
33 }
34
35 if (flags & FLAG_CREATE_ALWAYS) {
36 DCHECK(!disposition);
37 disposition = CREATE_ALWAYS;
38 }
39
40 if (flags & FLAG_OPEN_TRUNCATED) {
41 DCHECK(!disposition);
42 DCHECK(flags & FLAG_WRITE);
43 disposition = TRUNCATE_EXISTING;
44 }
45
46 if (!disposition) {
47 NOTREACHED();
48 return;
49 }
50
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;
57 }
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;
64
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;
70
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;
82
83 file_.Set(CreateFile(name.value().c_str(), access, sharing, NULL,
84 disposition, create_flags, NULL));
85
86 if (file_.IsValid()) {
87 error_ = FILE_OK;
88 async_ = ((flags & FLAG_ASYNC) == FLAG_ASYNC);
89
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_ = OSErrorToFileError(GetLastError());
96 }
97 }
98
IsValid() const99 bool File::IsValid() const {
100 return file_.IsValid();
101 }
TakePlatformFile()102 PlatformFile File::TakePlatformFile() {
103 return file_.Take();
104 }
105
Close()106 void File::Close() {
107 base::ThreadRestrictions::AssertIOAllowed();
108 file_.Close();
109 }
110
Seek(Whence whence,int64 offset)111 int64 File::Seek(Whence whence, int64 offset) {
112 base::ThreadRestrictions::AssertIOAllowed();
113 DCHECK(IsValid());
114 if (offset < 0)
115 return -1;
116
117 LARGE_INTEGER distance, res;
118 distance.QuadPart = offset;
119 DWORD move_method = static_cast<DWORD>(whence);
120 if (!SetFilePointerEx(file_, distance, &res, move_method))
121 return -1;
122 return res.QuadPart;
123 }
124
Read(int64 offset,char * data,int size)125 int File::Read(int64 offset, char* data, int size) {
126 base::ThreadRestrictions::AssertIOAllowed();
127 DCHECK(IsValid());
128 DCHECK(!async_);
129 if (size < 0)
130 return -1;
131
132 LARGE_INTEGER offset_li;
133 offset_li.QuadPart = offset;
134
135 OVERLAPPED overlapped = {0};
136 overlapped.Offset = offset_li.LowPart;
137 overlapped.OffsetHigh = offset_li.HighPart;
138
139 DWORD bytes_read;
140 if (::ReadFile(file_, data, size, &bytes_read, &overlapped) != 0)
141 return bytes_read;
142 if (ERROR_HANDLE_EOF == GetLastError())
143 return 0;
144
145 return -1;
146 }
147
ReadAtCurrentPos(char * data,int size)148 int File::ReadAtCurrentPos(char* data, int size) {
149 base::ThreadRestrictions::AssertIOAllowed();
150 DCHECK(IsValid());
151 DCHECK(!async_);
152 if (size < 0)
153 return -1;
154
155 DWORD bytes_read;
156 if (::ReadFile(file_, data, size, &bytes_read, NULL) != 0)
157 return bytes_read;
158 if (ERROR_HANDLE_EOF == GetLastError())
159 return 0;
160
161 return -1;
162 }
163
ReadNoBestEffort(int64 offset,char * data,int size)164 int File::ReadNoBestEffort(int64 offset, char* data, int size) {
165 return Read(offset, data, size);
166 }
167
ReadAtCurrentPosNoBestEffort(char * data,int size)168 int File::ReadAtCurrentPosNoBestEffort(char* data, int size) {
169 return ReadAtCurrentPos(data, size);
170 }
171
Write(int64 offset,const char * data,int size)172 int File::Write(int64 offset, const char* data, int size) {
173 base::ThreadRestrictions::AssertIOAllowed();
174 DCHECK(IsValid());
175 DCHECK(!async_);
176
177 LARGE_INTEGER offset_li;
178 offset_li.QuadPart = offset;
179
180 OVERLAPPED overlapped = {0};
181 overlapped.Offset = offset_li.LowPart;
182 overlapped.OffsetHigh = offset_li.HighPart;
183
184 DWORD bytes_written;
185 if (::WriteFile(file_, data, size, &bytes_written, &overlapped) != 0)
186 return bytes_written;
187
188 return -1;
189 }
190
WriteAtCurrentPos(const char * data,int size)191 int File::WriteAtCurrentPos(const char* data, int size) {
192 NOTREACHED();
193 return -1;
194 }
195
WriteAtCurrentPosNoBestEffort(const char * data,int size)196 int File::WriteAtCurrentPosNoBestEffort(const char* data, int size) {
197 return WriteAtCurrentPos(data, size);
198 }
199
Truncate(int64 length)200 bool File::Truncate(int64 length) {
201 base::ThreadRestrictions::AssertIOAllowed();
202 DCHECK(IsValid());
203
204 // Get the current file pointer.
205 LARGE_INTEGER file_pointer;
206 LARGE_INTEGER zero;
207 zero.QuadPart = 0;
208 if (::SetFilePointerEx(file_, zero, &file_pointer, FILE_CURRENT) == 0)
209 return false;
210
211 LARGE_INTEGER length_li;
212 length_li.QuadPart = length;
213 // If length > file size, SetFilePointerEx() should extend the file
214 // with zeroes on all Windows standard file systems (NTFS, FATxx).
215 if (!::SetFilePointerEx(file_, length_li, NULL, FILE_BEGIN))
216 return false;
217
218 // Set the new file length and move the file pointer to its old position.
219 // This is consistent with ftruncate()'s behavior, even when the file
220 // pointer points to a location beyond the end of the file.
221 return ((::SetEndOfFile(file_) != 0) &&
222 (::SetFilePointerEx(file_, file_pointer, NULL, FILE_BEGIN) != 0));
223 }
224
Flush()225 bool File::Flush() {
226 base::ThreadRestrictions::AssertIOAllowed();
227 DCHECK(IsValid());
228 return ::FlushFileBuffers(file_) != FALSE;
229 }
230
SetTimes(Time last_access_time,Time last_modified_time)231 bool File::SetTimes(Time last_access_time, Time last_modified_time) {
232 base::ThreadRestrictions::AssertIOAllowed();
233 DCHECK(IsValid());
234
235 FILETIME last_access_filetime = last_access_time.ToFileTime();
236 FILETIME last_modified_filetime = last_modified_time.ToFileTime();
237 return (::SetFileTime(file_, NULL, &last_access_filetime,
238 &last_modified_filetime) != 0);
239 }
240
GetInfo(Info * info)241 bool File::GetInfo(Info* info) {
242 base::ThreadRestrictions::AssertIOAllowed();
243 DCHECK(IsValid());
244
245 BY_HANDLE_FILE_INFORMATION file_info;
246 if (GetFileInformationByHandle(file_, &file_info) == 0)
247 return false;
248
249 LARGE_INTEGER size;
250 size.HighPart = file_info.nFileSizeHigh;
251 size.LowPart = file_info.nFileSizeLow;
252 info->size = size.QuadPart;
253 info->is_directory =
254 (file_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
255 info->is_symbolic_link = false; // Windows doesn't have symbolic links.
256 info->last_modified = base::Time::FromFileTime(file_info.ftLastWriteTime);
257 info->last_accessed = base::Time::FromFileTime(file_info.ftLastAccessTime);
258 info->creation_time = base::Time::FromFileTime(file_info.ftCreationTime);
259 return true;
260 }
261
Lock()262 File::Error base::File::Lock() {
263 DCHECK(IsValid());
264 BOOL result = LockFile(file_, 0, 0, MAXDWORD, MAXDWORD);
265 if (!result)
266 return OSErrorToFileError(GetLastError());
267 return FILE_OK;
268 }
269
Unlock()270 File::Error File::Unlock() {
271 DCHECK(IsValid());
272 BOOL result = UnlockFile(file_, 0, 0, MAXDWORD, MAXDWORD);
273 if (!result)
274 return OSErrorToFileError(GetLastError());
275 return FILE_OK;
276 }
277
278 // Static.
OSErrorToFileError(DWORD last_error)279 File::Error File::OSErrorToFileError(DWORD last_error) {
280 switch (last_error) {
281 case ERROR_SHARING_VIOLATION:
282 return FILE_ERROR_IN_USE;
283 case ERROR_FILE_EXISTS:
284 return FILE_ERROR_EXISTS;
285 case ERROR_FILE_NOT_FOUND:
286 case ERROR_PATH_NOT_FOUND:
287 return FILE_ERROR_NOT_FOUND;
288 case ERROR_ACCESS_DENIED:
289 return FILE_ERROR_ACCESS_DENIED;
290 case ERROR_TOO_MANY_OPEN_FILES:
291 return FILE_ERROR_TOO_MANY_OPENED;
292 case ERROR_OUTOFMEMORY:
293 case ERROR_NOT_ENOUGH_MEMORY:
294 return FILE_ERROR_NO_MEMORY;
295 case ERROR_HANDLE_DISK_FULL:
296 case ERROR_DISK_FULL:
297 case ERROR_DISK_RESOURCES_EXHAUSTED:
298 return FILE_ERROR_NO_SPACE;
299 case ERROR_USER_MAPPED_FILE:
300 return FILE_ERROR_INVALID_OPERATION;
301 case ERROR_NOT_READY:
302 case ERROR_SECTOR_NOT_FOUND:
303 case ERROR_DEV_NOT_EXIST:
304 case ERROR_IO_DEVICE:
305 case ERROR_FILE_CORRUPT:
306 case ERROR_DISK_CORRUPT:
307 return FILE_ERROR_IO;
308 default:
309 UMA_HISTOGRAM_SPARSE_SLOWLY("PlatformFile.UnknownErrors.Windows",
310 last_error);
311 return FILE_ERROR_FAILED;
312 }
313 }
314
SetPlatformFile(PlatformFile file)315 void File::SetPlatformFile(PlatformFile file) {
316 file_.Set(file);
317 }
318
319 } // namespace base
320