• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2013 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "SkTypes.h"
9 #if defined(SK_BUILD_FOR_WIN)
10 
11 #include "SkLeanWindows.h"
12 #include "SkMalloc.h"
13 #include "SkOSFile.h"
14 #include "SkStringUtils.h"
15 #include "SkTFitsIn.h"
16 
17 #include <io.h>
18 #include <stdio.h>
19 #include <sys/stat.h>
20 
sk_exists(const char * path,SkFILE_Flags flags)21 bool sk_exists(const char *path, SkFILE_Flags flags) {
22     int mode = 0; // existence
23     if (flags & kRead_SkFILE_Flag) {
24         mode |= 4; // read
25     }
26     if (flags & kWrite_SkFILE_Flag) {
27         mode |= 2; // write
28     }
29     return (0 == _access(path, mode));
30 }
31 
32 typedef struct {
33     ULONGLONG fVolume;
34     ULONGLONG fLsbSize;
35     ULONGLONG fMsbSize;
36 } SkFILEID;
37 
sk_ino(FILE * f,SkFILEID * id)38 static bool sk_ino(FILE* f, SkFILEID* id) {
39     int fileno = _fileno((FILE*)f);
40     if (fileno < 0) {
41         return false;
42     }
43 
44     HANDLE file = (HANDLE)_get_osfhandle(fileno);
45     if (INVALID_HANDLE_VALUE == file) {
46         return false;
47     }
48 
49     //TODO: call GetFileInformationByHandleEx on Vista and later with FileIdInfo.
50     BY_HANDLE_FILE_INFORMATION info;
51     if (0 == GetFileInformationByHandle(file, &info)) {
52         return false;
53     }
54     id->fVolume = info.dwVolumeSerialNumber;
55     id->fLsbSize = info.nFileIndexLow + (((ULONGLONG)info.nFileIndexHigh) << 32);
56     id->fMsbSize = 0;
57 
58     return true;
59 }
60 
sk_fidentical(FILE * a,FILE * b)61 bool sk_fidentical(FILE* a, FILE* b) {
62     SkFILEID aID, bID;
63     return sk_ino(a, &aID) && sk_ino(b, &bID)
64            && aID.fLsbSize == bID.fLsbSize
65            && aID.fMsbSize == bID.fMsbSize
66            && aID.fVolume == bID.fVolume;
67 }
68 
69 class SkAutoNullKernelHandle : SkNoncopyable {
70 public:
SkAutoNullKernelHandle(const HANDLE handle)71     SkAutoNullKernelHandle(const HANDLE handle) : fHandle(handle) { }
~SkAutoNullKernelHandle()72     ~SkAutoNullKernelHandle() { CloseHandle(fHandle); }
operator HANDLE() const73     operator HANDLE() const { return fHandle; }
isValid() const74     bool isValid() const { return SkToBool(fHandle); }
75 private:
76     HANDLE fHandle;
77 };
78 typedef SkAutoNullKernelHandle SkAutoWinMMap;
79 
sk_fmunmap(const void * addr,size_t)80 void sk_fmunmap(const void* addr, size_t) {
81     UnmapViewOfFile(addr);
82 }
83 
sk_fdmmap(int fileno,size_t * length)84 void* sk_fdmmap(int fileno, size_t* length) {
85     HANDLE file = (HANDLE)_get_osfhandle(fileno);
86     if (INVALID_HANDLE_VALUE == file) {
87         return nullptr;
88     }
89 
90     LARGE_INTEGER fileSize;
91     if (0 == GetFileSizeEx(file, &fileSize)) {
92         //TODO: use SK_TRACEHR(GetLastError(), "Could not get file size.") to report.
93         return nullptr;
94     }
95     if (!SkTFitsIn<size_t>(fileSize.QuadPart)) {
96         return nullptr;
97     }
98 
99     SkAutoWinMMap mmap(CreateFileMapping(file, nullptr, PAGE_READONLY, 0, 0, nullptr));
100     if (!mmap.isValid()) {
101         //TODO: use SK_TRACEHR(GetLastError(), "Could not create file mapping.") to report.
102         return nullptr;
103     }
104 
105     // Eventually call UnmapViewOfFile
106     void* addr = MapViewOfFile(mmap, FILE_MAP_READ, 0, 0, 0);
107     if (nullptr == addr) {
108         //TODO: use SK_TRACEHR(GetLastError(), "Could not map view of file.") to report.
109         return nullptr;
110     }
111 
112     *length = static_cast<size_t>(fileSize.QuadPart);
113     return addr;
114 }
115 
sk_fileno(FILE * f)116 int sk_fileno(FILE* f) {
117     return _fileno((FILE*)f);
118 }
119 
sk_fmmap(FILE * f,size_t * length)120 void* sk_fmmap(FILE* f, size_t* length) {
121     int fileno = sk_fileno(f);
122     if (fileno < 0) {
123         return nullptr;
124     }
125 
126     return sk_fdmmap(fileno, length);
127 }
128 
sk_qread(FILE * file,void * buffer,size_t count,size_t offset)129 size_t sk_qread(FILE* file, void* buffer, size_t count, size_t offset) {
130     int fileno = sk_fileno(file);
131     HANDLE fileHandle = (HANDLE)_get_osfhandle(fileno);
132     if (INVALID_HANDLE_VALUE == file) {
133         return SIZE_MAX;
134     }
135 
136     OVERLAPPED overlapped;
137     memset(&overlapped, 0, sizeof(overlapped));
138     ULARGE_INTEGER winOffset;
139     winOffset.QuadPart = offset;
140     overlapped.Offset = winOffset.LowPart;
141     overlapped.OffsetHigh = winOffset.HighPart;
142 
143     if (!SkTFitsIn<DWORD>(count)) {
144         count = std::numeric_limits<DWORD>::max();
145     }
146 
147     DWORD bytesRead;
148     if (ReadFile(fileHandle, buffer, static_cast<DWORD>(count), &bytesRead, &overlapped)) {
149         return bytesRead;
150     }
151     if (GetLastError() == ERROR_HANDLE_EOF) {
152         return 0;
153     }
154     return SIZE_MAX;
155 }
156 
157 ////////////////////////////////////////////////////////////////////////////
158 
159 struct SkOSFileIterData {
SkOSFileIterDataSkOSFileIterData160     SkOSFileIterData() : fHandle(0), fPath16(nullptr) { }
161     HANDLE fHandle;
162     uint16_t* fPath16;
163 };
164 static_assert(sizeof(SkOSFileIterData) <= SkOSFile::Iter::kStorageSize, "not_enough_space");
165 
concat_to_16(const char src[],const char suffix[])166 static uint16_t* concat_to_16(const char src[], const char suffix[]) {
167     size_t  i, len = strlen(src);
168     size_t  len2 = 3 + (suffix ? strlen(suffix) : 0);
169     uint16_t* dst = (uint16_t*)sk_malloc_throw((len + len2) * sizeof(uint16_t));
170 
171     for (i = 0; i < len; i++) {
172         dst[i] = src[i];
173     }
174 
175     if (i > 0 && dst[i-1] != '/') {
176         dst[i++] = '/';
177     }
178     dst[i++] = '*';
179 
180     if (suffix) {
181         while (*suffix) {
182             dst[i++] = *suffix++;
183         }
184     }
185     dst[i] = 0;
186     SkASSERT(i + 1 <= len + len2);
187 
188     return dst;
189 }
190 
Iter()191 SkOSFile::Iter::Iter() { new (fSelf.get()) SkOSFileIterData; }
192 
Iter(const char path[],const char suffix[])193 SkOSFile::Iter::Iter(const char path[], const char suffix[]) {
194     new (fSelf.get()) SkOSFileIterData;
195     this->reset(path, suffix);
196 }
197 
~Iter()198 SkOSFile::Iter::~Iter() {
199     SkOSFileIterData& self = *static_cast<SkOSFileIterData*>(fSelf.get());
200     sk_free(self.fPath16);
201     if (self.fHandle) {
202         ::FindClose(self.fHandle);
203     }
204     self.~SkOSFileIterData();
205 }
206 
reset(const char path[],const char suffix[])207 void SkOSFile::Iter::reset(const char path[], const char suffix[]) {
208     SkOSFileIterData& self = *static_cast<SkOSFileIterData*>(fSelf.get());
209     if (self.fHandle) {
210         ::FindClose(self.fHandle);
211         self.fHandle = 0;
212     }
213     if (nullptr == path) {
214         path = "";
215     }
216 
217     sk_free(self.fPath16);
218     self.fPath16 = concat_to_16(path, suffix);
219 }
220 
is_magic_dir(const uint16_t dir[])221 static bool is_magic_dir(const uint16_t dir[]) {
222     // return true for "." and ".."
223     return dir[0] == '.' && (dir[1] == 0 || (dir[1] == '.' && dir[2] == 0));
224 }
225 
get_the_file(HANDLE handle,SkString * name,WIN32_FIND_DATAW * dataPtr,bool getDir)226 static bool get_the_file(HANDLE handle, SkString* name, WIN32_FIND_DATAW* dataPtr, bool getDir) {
227     WIN32_FIND_DATAW    data;
228 
229     if (nullptr == dataPtr) {
230         if (::FindNextFileW(handle, &data))
231             dataPtr = &data;
232         else
233             return false;
234     }
235 
236     for (;;) {
237         if (getDir) {
238             if ((dataPtr->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
239                 !is_magic_dir((uint16_t*)dataPtr->cFileName))
240             {
241                 break;
242             }
243         } else {
244             if (!(dataPtr->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
245                 break;
246             }
247         }
248         if (!::FindNextFileW(handle, dataPtr)) {
249             return false;
250         }
251     }
252     // if we get here, we've found a file/dir
253     if (name) {
254         const uint16_t* utf16name = (const uint16_t*)dataPtr->cFileName;
255         const uint16_t* ptr = utf16name;
256         while (*ptr != 0) { ++ptr; }
257         *name = SkStringFromUTF16(utf16name, ptr - utf16name);
258     }
259     return true;
260 }
261 
next(SkString * name,bool getDir)262 bool SkOSFile::Iter::next(SkString* name, bool getDir) {
263     SkOSFileIterData& self = *static_cast<SkOSFileIterData*>(fSelf.get());
264     WIN32_FIND_DATAW    data;
265     WIN32_FIND_DATAW*   dataPtr = nullptr;
266 
267     if (self.fHandle == 0) {  // our first time
268         if (self.fPath16 == nullptr || *self.fPath16 == 0) {  // check for no path
269             return false;
270         }
271 
272         self.fHandle = ::FindFirstFileW((LPCWSTR)self.fPath16, &data);
273         if (self.fHandle != 0 && self.fHandle != (HANDLE)~0) {
274             dataPtr = &data;
275         }
276     }
277     return self.fHandle != (HANDLE)~0 && get_the_file(self.fHandle, name, dataPtr, getDir);
278 }
279 
280 #endif//defined(SK_BUILD_FOR_WIN)
281