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