blob: e66bcb89c0d291b50f838ebda0eb9318a33b302c [file] [log] [blame]
bungeman@google.com6cab1a42013-05-29 13:43:31 +00001/*
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
mtklein1ee76512015-11-02 10:20:27 -08008#include "SkTypes.h"
9#if defined(SK_BUILD_FOR_WIN32)
10
halcanary4dbbd042016-06-07 17:21:10 -070011#include "SkLeanWindows.h"
Herb Derbyb549cc32017-03-27 13:35:15 -040012#include "SkMalloc.h"
bungeman@google.com6cab1a42013-05-29 13:43:31 +000013#include "SkOSFile.h"
bungeman@google.comf5cc5b12013-07-12 18:22:49 +000014#include "SkTFitsIn.h"
bungeman@google.com11c9a552013-06-03 17:10:35 +000015
bungeman@google.com6cab1a42013-05-29 13:43:31 +000016#include <io.h>
17#include <stdio.h>
18#include <sys/stat.h>
19
Ben Wagnereefa2892017-03-17 13:49:31 -040020size_t sk_fgetsize(FILE* f) {
21 int fileno = sk_fileno(f);
22 if (fileno < 0) {
23 return 0;
24 }
25
26 HANDLE file = (HANDLE)_get_osfhandle(fileno);
27 if (INVALID_HANDLE_VALUE == file) {
28 return 0;
29 }
30
31 LARGE_INTEGER fileSize;
32 if (0 == GetFileSizeEx(file, &fileSize)) {
33 return 0;
34 }
35 if (!SkTFitsIn<size_t>(fileSize.QuadPart)) {
36 return 0;
37 }
38 return static_cast<size_t>(fileSize.QuadPart);
39}
40
bungemanbf0b9ce2014-07-10 15:18:23 -070041bool sk_exists(const char *path, SkFILE_Flags flags) {
42 int mode = 0; // existence
43 if (flags & kRead_SkFILE_Flag) {
44 mode |= 4; // read
45 }
46 if (flags & kWrite_SkFILE_Flag) {
47 mode |= 2; // write
48 }
49 return (0 == _access(path, mode));
50}
51
bungeman@google.com6cab1a42013-05-29 13:43:31 +000052typedef struct {
53 ULONGLONG fVolume;
54 ULONGLONG fLsbSize;
55 ULONGLONG fMsbSize;
56} SkFILEID;
57
halcanaryd76be9c2015-11-20 13:47:49 -080058static bool sk_ino(FILE* f, SkFILEID* id) {
bungeman@google.com6cab1a42013-05-29 13:43:31 +000059 int fileno = _fileno((FILE*)f);
60 if (fileno < 0) {
61 return false;
62 }
63
64 HANDLE file = (HANDLE)_get_osfhandle(fileno);
65 if (INVALID_HANDLE_VALUE == file) {
66 return false;
67 }
68
69 //TODO: call GetFileInformationByHandleEx on Vista and later with FileIdInfo.
70 BY_HANDLE_FILE_INFORMATION info;
71 if (0 == GetFileInformationByHandle(file, &info)) {
72 return false;
73 }
74 id->fVolume = info.dwVolumeSerialNumber;
75 id->fLsbSize = info.nFileIndexLow + (((ULONGLONG)info.nFileIndexHigh) << 32);
76 id->fMsbSize = 0;
77
78 return true;
79}
80
halcanaryd76be9c2015-11-20 13:47:49 -080081bool sk_fidentical(FILE* a, FILE* b) {
bungeman@google.com6cab1a42013-05-29 13:43:31 +000082 SkFILEID aID, bID;
83 return sk_ino(a, &aID) && sk_ino(b, &bID)
84 && aID.fLsbSize == bID.fLsbSize
85 && aID.fMsbSize == bID.fMsbSize
86 && aID.fVolume == bID.fVolume;
87}
88
commit-bot@chromium.org8e13a152014-03-19 19:28:00 +000089class SkAutoNullKernelHandle : SkNoncopyable {
bungeman@google.com6cab1a42013-05-29 13:43:31 +000090public:
commit-bot@chromium.org8e13a152014-03-19 19:28:00 +000091 SkAutoNullKernelHandle(const HANDLE handle) : fHandle(handle) { }
92 ~SkAutoNullKernelHandle() { CloseHandle(fHandle); }
93 operator HANDLE() const { return fHandle; }
bsalomon49f085d2014-09-05 13:34:00 -070094 bool isValid() const { return SkToBool(fHandle); }
bungeman@google.com6cab1a42013-05-29 13:43:31 +000095private:
commit-bot@chromium.org8e13a152014-03-19 19:28:00 +000096 HANDLE fHandle;
bungeman@google.com6cab1a42013-05-29 13:43:31 +000097};
commit-bot@chromium.org8e13a152014-03-19 19:28:00 +000098typedef SkAutoNullKernelHandle SkAutoWinMMap;
bungeman@google.com6cab1a42013-05-29 13:43:31 +000099
100void sk_fmunmap(const void* addr, size_t) {
101 UnmapViewOfFile(addr);
102}
103
bungeman@google.com11c9a552013-06-03 17:10:35 +0000104void* sk_fdmmap(int fileno, size_t* length) {
bungeman@google.com6cab1a42013-05-29 13:43:31 +0000105 HANDLE file = (HANDLE)_get_osfhandle(fileno);
106 if (INVALID_HANDLE_VALUE == file) {
halcanary96fcdcc2015-08-27 07:41:13 -0700107 return nullptr;
bungeman@google.com6cab1a42013-05-29 13:43:31 +0000108 }
109
bungeman@google.com11c9a552013-06-03 17:10:35 +0000110 LARGE_INTEGER fileSize;
111 if (0 == GetFileSizeEx(file, &fileSize)) {
112 //TODO: use SK_TRACEHR(GetLastError(), "Could not get file size.") to report.
halcanary96fcdcc2015-08-27 07:41:13 -0700113 return nullptr;
bungeman@google.com11c9a552013-06-03 17:10:35 +0000114 }
115 if (!SkTFitsIn<size_t>(fileSize.QuadPart)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700116 return nullptr;
bungeman@google.com11c9a552013-06-03 17:10:35 +0000117 }
118
halcanary96fcdcc2015-08-27 07:41:13 -0700119 SkAutoWinMMap mmap(CreateFileMapping(file, nullptr, PAGE_READONLY, 0, 0, nullptr));
bungeman@google.com6cab1a42013-05-29 13:43:31 +0000120 if (!mmap.isValid()) {
121 //TODO: use SK_TRACEHR(GetLastError(), "Could not create file mapping.") to report.
halcanary96fcdcc2015-08-27 07:41:13 -0700122 return nullptr;
bungeman@google.com6cab1a42013-05-29 13:43:31 +0000123 }
124
125 // Eventually call UnmapViewOfFile
126 void* addr = MapViewOfFile(mmap, FILE_MAP_READ, 0, 0, 0);
halcanary96fcdcc2015-08-27 07:41:13 -0700127 if (nullptr == addr) {
bungeman@google.com6cab1a42013-05-29 13:43:31 +0000128 //TODO: use SK_TRACEHR(GetLastError(), "Could not map view of file.") to report.
halcanary96fcdcc2015-08-27 07:41:13 -0700129 return nullptr;
bungeman@google.com6cab1a42013-05-29 13:43:31 +0000130 }
131
bungeman@google.com11c9a552013-06-03 17:10:35 +0000132 *length = static_cast<size_t>(fileSize.QuadPart);
bungeman@google.com6cab1a42013-05-29 13:43:31 +0000133 return addr;
134}
bungeman@google.com11c9a552013-06-03 17:10:35 +0000135
halcanaryd76be9c2015-11-20 13:47:49 -0800136int sk_fileno(FILE* f) {
bungeman@google.com11c9a552013-06-03 17:10:35 +0000137 return _fileno((FILE*)f);
138}
139
halcanaryd76be9c2015-11-20 13:47:49 -0800140void* sk_fmmap(FILE* f, size_t* length) {
bungeman@google.com11c9a552013-06-03 17:10:35 +0000141 int fileno = sk_fileno(f);
142 if (fileno < 0) {
halcanary96fcdcc2015-08-27 07:41:13 -0700143 return nullptr;
bungeman@google.com11c9a552013-06-03 17:10:35 +0000144 }
145
146 return sk_fdmmap(fileno, length);
147}
bungemane998b7f2015-02-12 07:18:27 -0800148
Ben Wagner4d1955c2017-03-10 13:08:15 -0500149size_t sk_qread(FILE* file, void* buffer, size_t count, size_t offset) {
150 int fileno = sk_fileno(file);
151 HANDLE fileHandle = (HANDLE)_get_osfhandle(fileno);
152 if (INVALID_HANDLE_VALUE == file) {
153 return SIZE_MAX;
154 }
155
156 OVERLAPPED overlapped = {0};
157 ULARGE_INTEGER winOffset;
158 winOffset.QuadPart = offset;
159 overlapped.Offset = winOffset.LowPart;
160 overlapped.OffsetHigh = winOffset.HighPart;
161
162 if (!SkTFitsIn<DWORD>(count)) {
163 count = std::numeric_limits<DWORD>::max();
164 }
165
166 DWORD bytesRead;
167 if (ReadFile(fileHandle, buffer, static_cast<DWORD>(count), &bytesRead, &overlapped)) {
168 return bytesRead;
169 }
170 if (GetLastError() == ERROR_HANDLE_EOF) {
171 return 0;
172 }
173 return SIZE_MAX;
174}
175
bungemane998b7f2015-02-12 07:18:27 -0800176////////////////////////////////////////////////////////////////////////////
177
178struct SkOSFileIterData {
halcanary96fcdcc2015-08-27 07:41:13 -0700179 SkOSFileIterData() : fHandle(0), fPath16(nullptr) { }
bungemane998b7f2015-02-12 07:18:27 -0800180 HANDLE fHandle;
181 uint16_t* fPath16;
182};
bungeman99fe8222015-08-20 07:57:51 -0700183static_assert(sizeof(SkOSFileIterData) <= SkOSFile::Iter::kStorageSize, "not_enough_space");
bungemane998b7f2015-02-12 07:18:27 -0800184
185static uint16_t* concat_to_16(const char src[], const char suffix[]) {
186 size_t i, len = strlen(src);
187 size_t len2 = 3 + (suffix ? strlen(suffix) : 0);
188 uint16_t* dst = (uint16_t*)sk_malloc_throw((len + len2) * sizeof(uint16_t));
189
190 for (i = 0; i < len; i++) {
191 dst[i] = src[i];
192 }
193
194 if (i > 0 && dst[i-1] != '/') {
195 dst[i++] = '/';
196 }
197 dst[i++] = '*';
198
199 if (suffix) {
200 while (*suffix) {
201 dst[i++] = *suffix++;
202 }
203 }
204 dst[i] = 0;
205 SkASSERT(i + 1 <= len + len2);
206
207 return dst;
208}
209
halcanary385fe4d2015-08-26 13:07:48 -0700210SkOSFile::Iter::Iter() { new (fSelf.get()) SkOSFileIterData; }
bungemane998b7f2015-02-12 07:18:27 -0800211
212SkOSFile::Iter::Iter(const char path[], const char suffix[]) {
halcanary385fe4d2015-08-26 13:07:48 -0700213 new (fSelf.get()) SkOSFileIterData;
bungemane998b7f2015-02-12 07:18:27 -0800214 this->reset(path, suffix);
215}
216
217SkOSFile::Iter::~Iter() {
218 SkOSFileIterData& self = *static_cast<SkOSFileIterData*>(fSelf.get());
219 sk_free(self.fPath16);
220 if (self.fHandle) {
221 ::FindClose(self.fHandle);
222 }
223 self.~SkOSFileIterData();
224}
225
226void SkOSFile::Iter::reset(const char path[], const char suffix[]) {
227 SkOSFileIterData& self = *static_cast<SkOSFileIterData*>(fSelf.get());
228 if (self.fHandle) {
229 ::FindClose(self.fHandle);
230 self.fHandle = 0;
231 }
halcanary96fcdcc2015-08-27 07:41:13 -0700232 if (nullptr == path) {
bungemane998b7f2015-02-12 07:18:27 -0800233 path = "";
234 }
235
236 sk_free(self.fPath16);
237 self.fPath16 = concat_to_16(path, suffix);
238}
239
240static bool is_magic_dir(const uint16_t dir[]) {
241 // return true for "." and ".."
242 return dir[0] == '.' && (dir[1] == 0 || (dir[1] == '.' && dir[2] == 0));
243}
244
245static bool get_the_file(HANDLE handle, SkString* name, WIN32_FIND_DATAW* dataPtr, bool getDir) {
246 WIN32_FIND_DATAW data;
247
halcanary96fcdcc2015-08-27 07:41:13 -0700248 if (nullptr == dataPtr) {
bungemane998b7f2015-02-12 07:18:27 -0800249 if (::FindNextFileW(handle, &data))
250 dataPtr = &data;
251 else
252 return false;
253 }
254
255 for (;;) {
256 if (getDir) {
257 if ((dataPtr->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
258 !is_magic_dir((uint16_t*)dataPtr->cFileName))
259 {
260 break;
261 }
262 } else {
263 if (!(dataPtr->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
264 break;
265 }
266 }
267 if (!::FindNextFileW(handle, dataPtr)) {
268 return false;
269 }
270 }
271 // if we get here, we've found a file/dir
272 if (name) {
273 name->setUTF16((uint16_t*)dataPtr->cFileName);
274 }
275 return true;
276}
277
278bool SkOSFile::Iter::next(SkString* name, bool getDir) {
279 SkOSFileIterData& self = *static_cast<SkOSFileIterData*>(fSelf.get());
280 WIN32_FIND_DATAW data;
halcanary96fcdcc2015-08-27 07:41:13 -0700281 WIN32_FIND_DATAW* dataPtr = nullptr;
bungemane998b7f2015-02-12 07:18:27 -0800282
283 if (self.fHandle == 0) { // our first time
halcanary96fcdcc2015-08-27 07:41:13 -0700284 if (self.fPath16 == nullptr || *self.fPath16 == 0) { // check for no path
bungemane998b7f2015-02-12 07:18:27 -0800285 return false;
286 }
287
288 self.fHandle = ::FindFirstFileW((LPCWSTR)self.fPath16, &data);
289 if (self.fHandle != 0 && self.fHandle != (HANDLE)~0) {
290 dataPtr = &data;
291 }
292 }
293 return self.fHandle != (HANDLE)~0 && get_the_file(self.fHandle, name, dataPtr, getDir);
294}
mtklein1ee76512015-11-02 10:20:27 -0800295
296#endif//defined(SK_BUILD_FOR_WIN32)