• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include <stdint.h>
9 
10 #include "base/logging.h"
11 #include "base/win/win_util.h"
12 
13 #include <windows.h>
14 
15 namespace base {
16 
17 // Make sure our Whence mappings match the system headers.
18 static_assert(File::FROM_BEGIN == FILE_BEGIN &&
19                   File::FROM_CURRENT == FILE_CURRENT &&
20                   File::FROM_END == FILE_END,
21               "whence mapping must match the system headers");
22 
IsValid() const23 bool File::IsValid() const {
24   return file_.IsValid();
25 }
26 
GetPlatformFile() const27 PlatformFile File::GetPlatformFile() const {
28   return file_.Get();
29 }
30 
TakePlatformFile()31 PlatformFile File::TakePlatformFile() {
32   return file_.Take();
33 }
34 
Close()35 void File::Close() {
36   if (!file_.IsValid())
37     return;
38 
39   file_.Close();
40 }
41 
Seek(Whence whence,int64_t offset)42 int64_t File::Seek(Whence whence, int64_t offset) {
43   DCHECK(IsValid());
44 
45   LARGE_INTEGER distance, res;
46   distance.QuadPart = offset;
47   DWORD move_method = static_cast<DWORD>(whence);
48   if (!SetFilePointerEx(file_.Get(), distance, &res, move_method))
49     return -1;
50   return res.QuadPart;
51 }
52 
Read(int64_t offset,char * data,int size)53 int File::Read(int64_t offset, char* data, int size) {
54   DCHECK(IsValid());
55   if (size < 0)
56     return -1;
57 
58   LARGE_INTEGER offset_li;
59   offset_li.QuadPart = offset;
60 
61   OVERLAPPED overlapped = {};
62   overlapped.Offset = offset_li.LowPart;
63   overlapped.OffsetHigh = offset_li.HighPart;
64 
65   DWORD bytes_read;
66   if (::ReadFile(file_.Get(), data, size, &bytes_read, &overlapped))
67     return bytes_read;
68   if (ERROR_HANDLE_EOF == GetLastError())
69     return 0;
70 
71   return -1;
72 }
73 
ReadAtCurrentPos(char * data,int size)74 int File::ReadAtCurrentPos(char* data, int size) {
75   DCHECK(IsValid());
76   if (size < 0)
77     return -1;
78 
79   DWORD bytes_read;
80   if (::ReadFile(file_.Get(), data, size, &bytes_read, NULL))
81     return bytes_read;
82   if (ERROR_HANDLE_EOF == GetLastError())
83     return 0;
84 
85   return -1;
86 }
87 
ReadNoBestEffort(int64_t offset,char * data,int size)88 int File::ReadNoBestEffort(int64_t offset, char* data, int size) {
89   // TODO(dbeam): trace this separately?
90   return Read(offset, data, size);
91 }
92 
ReadAtCurrentPosNoBestEffort(char * data,int size)93 int File::ReadAtCurrentPosNoBestEffort(char* data, int size) {
94   // TODO(dbeam): trace this separately?
95   return ReadAtCurrentPos(data, size);
96 }
97 
Write(int64_t offset,const char * data,int size)98 int File::Write(int64_t offset, const char* data, int size) {
99   DCHECK(IsValid());
100 
101   LARGE_INTEGER offset_li;
102   offset_li.QuadPart = offset;
103 
104   OVERLAPPED overlapped = {};
105   overlapped.Offset = offset_li.LowPart;
106   overlapped.OffsetHigh = offset_li.HighPart;
107 
108   DWORD bytes_written;
109   if (::WriteFile(file_.Get(), data, size, &bytes_written, &overlapped))
110     return bytes_written;
111 
112   return -1;
113 }
114 
WriteAtCurrentPos(const char * data,int size)115 int File::WriteAtCurrentPos(const char* data, int size) {
116   DCHECK(IsValid());
117   if (size < 0)
118     return -1;
119 
120   DWORD bytes_written;
121   if (::WriteFile(file_.Get(), data, size, &bytes_written, NULL))
122     return bytes_written;
123 
124   return -1;
125 }
126 
WriteAtCurrentPosNoBestEffort(const char * data,int size)127 int File::WriteAtCurrentPosNoBestEffort(const char* data, int size) {
128   return WriteAtCurrentPos(data, size);
129 }
130 
GetLength()131 int64_t File::GetLength() {
132   DCHECK(IsValid());
133 
134   LARGE_INTEGER size;
135   if (!::GetFileSizeEx(file_.Get(), &size))
136     return -1;
137 
138   return static_cast<int64_t>(size.QuadPart);
139 }
140 
SetLength(int64_t length)141 bool File::SetLength(int64_t length) {
142   DCHECK(IsValid());
143 
144   // Get the current file pointer.
145   LARGE_INTEGER file_pointer;
146   LARGE_INTEGER zero;
147   zero.QuadPart = 0;
148   if (!::SetFilePointerEx(file_.Get(), zero, &file_pointer, FILE_CURRENT))
149     return false;
150 
151   LARGE_INTEGER length_li;
152   length_li.QuadPart = length;
153   // If length > file size, SetFilePointerEx() should extend the file
154   // with zeroes on all Windows standard file systems (NTFS, FATxx).
155   if (!::SetFilePointerEx(file_.Get(), length_li, NULL, FILE_BEGIN))
156     return false;
157 
158   // Set the new file length and move the file pointer to its old position.
159   // This is consistent with ftruncate()'s behavior, even when the file
160   // pointer points to a location beyond the end of the file.
161   // TODO(rvargas): Emulating ftruncate details seem suspicious and it is not
162   // promised by the interface (nor was promised by PlatformFile). See if this
163   // implementation detail can be removed.
164   return ((::SetEndOfFile(file_.Get()) != FALSE) &&
165           (::SetFilePointerEx(file_.Get(), file_pointer, NULL, FILE_BEGIN) !=
166            FALSE));
167 }
168 
GetInfo(Info * info)169 bool File::GetInfo(Info* info) {
170   DCHECK(IsValid());
171 
172   BY_HANDLE_FILE_INFORMATION file_info;
173   if (!GetFileInformationByHandle(file_.Get(), &file_info))
174     return false;
175 
176   LARGE_INTEGER size;
177   size.HighPart = file_info.nFileSizeHigh;
178   size.LowPart = file_info.nFileSizeLow;
179   info->size = size.QuadPart;
180   info->is_directory =
181       (file_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
182   info->is_symbolic_link = false;  // Windows doesn't have symbolic links.
183   info->last_modified =
184       *reinterpret_cast<uint64_t*>(&file_info.ftLastWriteTime);
185   info->last_accessed =
186       *reinterpret_cast<uint64_t*>(&file_info.ftLastAccessTime);
187   info->creation_time = *reinterpret_cast<uint64_t*>(&file_info.ftCreationTime);
188   return true;
189 }
190 
Lock()191 File::Error File::Lock() {
192   DCHECK(IsValid());
193 
194   BOOL result = LockFile(file_.Get(), 0, 0, MAXDWORD, MAXDWORD);
195   if (!result)
196     return GetLastFileError();
197   return FILE_OK;
198 }
199 
Unlock()200 File::Error File::Unlock() {
201   DCHECK(IsValid());
202 
203   BOOL result = UnlockFile(file_.Get(), 0, 0, MAXDWORD, MAXDWORD);
204   if (!result)
205     return GetLastFileError();
206   return FILE_OK;
207 }
208 
Duplicate() const209 File File::Duplicate() const {
210   if (!IsValid())
211     return File();
212 
213   HANDLE other_handle = nullptr;
214 
215   if (!::DuplicateHandle(GetCurrentProcess(),  // hSourceProcessHandle
216                          GetPlatformFile(),
217                          GetCurrentProcess(),  // hTargetProcessHandle
218                          &other_handle,
219                          0,      // dwDesiredAccess ignored due to SAME_ACCESS
220                          FALSE,  // !bInheritHandle
221                          DUPLICATE_SAME_ACCESS)) {
222     return File(GetLastFileError());
223   }
224 
225   File other(other_handle);
226   return other;
227 }
228 
229 // Static.
OSErrorToFileError(DWORD last_error)230 File::Error File::OSErrorToFileError(DWORD last_error) {
231   switch (last_error) {
232     case ERROR_SHARING_VIOLATION:
233       return FILE_ERROR_IN_USE;
234     case ERROR_ALREADY_EXISTS:
235     case ERROR_FILE_EXISTS:
236       return FILE_ERROR_EXISTS;
237     case ERROR_FILE_NOT_FOUND:
238     case ERROR_PATH_NOT_FOUND:
239       return FILE_ERROR_NOT_FOUND;
240     case ERROR_ACCESS_DENIED:
241       return FILE_ERROR_ACCESS_DENIED;
242     case ERROR_TOO_MANY_OPEN_FILES:
243       return FILE_ERROR_TOO_MANY_OPENED;
244     case ERROR_OUTOFMEMORY:
245     case ERROR_NOT_ENOUGH_MEMORY:
246       return FILE_ERROR_NO_MEMORY;
247     case ERROR_HANDLE_DISK_FULL:
248     case ERROR_DISK_FULL:
249 #ifndef __MINGW32__
250     case ERROR_DISK_RESOURCES_EXHAUSTED:
251 #endif
252       return FILE_ERROR_NO_SPACE;
253     case ERROR_USER_MAPPED_FILE:
254       return FILE_ERROR_INVALID_OPERATION;
255     case ERROR_NOT_READY:
256     case ERROR_SECTOR_NOT_FOUND:
257     case ERROR_DEV_NOT_EXIST:
258     case ERROR_IO_DEVICE:
259     case ERROR_FILE_CORRUPT:
260     case ERROR_DISK_CORRUPT:
261       return FILE_ERROR_IO;
262     default:
263       // This function should only be called for errors.
264       DCHECK_NE(static_cast<DWORD>(ERROR_SUCCESS), last_error);
265       return FILE_ERROR_FAILED;
266   }
267 }
268 
DoInitialize(const FilePath & path,uint32_t flags)269 void File::DoInitialize(const FilePath& path, uint32_t flags) {
270   DCHECK(!IsValid());
271 
272   DWORD disposition = 0;
273 
274   if (flags & FLAG_OPEN)
275     disposition = OPEN_EXISTING;
276 
277   if (flags & FLAG_CREATE_ALWAYS) {
278     DCHECK(!disposition);
279     DCHECK(flags & FLAG_WRITE);
280     disposition = CREATE_ALWAYS;
281   }
282 
283   if (!disposition) {
284     ::SetLastError(ERROR_INVALID_PARAMETER);
285     error_details_ = FILE_ERROR_FAILED;
286     NOTREACHED();
287     return;
288   }
289 
290   DWORD access = 0;
291   if (flags & FLAG_WRITE)
292     access = GENERIC_WRITE;
293   if (flags & FLAG_READ)
294     access |= GENERIC_READ;
295 
296   DWORD sharing = FILE_SHARE_READ | FILE_SHARE_WRITE;
297   DWORD create_flags = 0;
298   file_.Set(CreateFile(ToWCharT(&path.value()), access, sharing, NULL,
299                        disposition, create_flags, NULL));
300 
301   if (file_.IsValid()) {
302     error_details_ = FILE_OK;
303   } else {
304     error_details_ = GetLastFileError();
305   }
306 }
307 
Flush()308 bool File::Flush() {
309   DCHECK(IsValid());
310   return ::FlushFileBuffers(file_.Get()) != FALSE;
311 }
312 
SetPlatformFile(PlatformFile file)313 void File::SetPlatformFile(PlatformFile file) {
314   file_.Set(file);
315 }
316 
317 // static
GetLastFileError()318 File::Error File::GetLastFileError() {
319   return File::OSErrorToFileError(GetLastError());
320 }
321 
322 }  // namespace base
323