• 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 
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