blob: ceafc7904f1601e05945918f331e2cb9492d45b9 [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"
bungeman@google.com6cab1a42013-05-29 13:43:31 +000012#include "SkOSFile.h"
bungeman@google.comf5cc5b12013-07-12 18:22:49 +000013#include "SkTFitsIn.h"
bungeman@google.com11c9a552013-06-03 17:10:35 +000014
bungeman@google.com6cab1a42013-05-29 13:43:31 +000015#include <io.h>
16#include <stdio.h>
17#include <sys/stat.h>
18
bungemanbf0b9ce2014-07-10 15:18:23 -070019bool sk_exists(const char *path, SkFILE_Flags flags) {
20 int mode = 0; // existence
21 if (flags & kRead_SkFILE_Flag) {
22 mode |= 4; // read
23 }
24 if (flags & kWrite_SkFILE_Flag) {
25 mode |= 2; // write
26 }
27 return (0 == _access(path, mode));
28}
29
bungeman@google.com6cab1a42013-05-29 13:43:31 +000030typedef struct {
31 ULONGLONG fVolume;
32 ULONGLONG fLsbSize;
33 ULONGLONG fMsbSize;
34} SkFILEID;
35
halcanaryd76be9c2015-11-20 13:47:49 -080036static bool sk_ino(FILE* f, SkFILEID* id) {
bungeman@google.com6cab1a42013-05-29 13:43:31 +000037 int fileno = _fileno((FILE*)f);
38 if (fileno < 0) {
39 return false;
40 }
41
42 HANDLE file = (HANDLE)_get_osfhandle(fileno);
43 if (INVALID_HANDLE_VALUE == file) {
44 return false;
45 }
46
47 //TODO: call GetFileInformationByHandleEx on Vista and later with FileIdInfo.
48 BY_HANDLE_FILE_INFORMATION info;
49 if (0 == GetFileInformationByHandle(file, &info)) {
50 return false;
51 }
52 id->fVolume = info.dwVolumeSerialNumber;
53 id->fLsbSize = info.nFileIndexLow + (((ULONGLONG)info.nFileIndexHigh) << 32);
54 id->fMsbSize = 0;
55
56 return true;
57}
58
halcanaryd76be9c2015-11-20 13:47:49 -080059bool sk_fidentical(FILE* a, FILE* b) {
bungeman@google.com6cab1a42013-05-29 13:43:31 +000060 SkFILEID aID, bID;
61 return sk_ino(a, &aID) && sk_ino(b, &bID)
62 && aID.fLsbSize == bID.fLsbSize
63 && aID.fMsbSize == bID.fMsbSize
64 && aID.fVolume == bID.fVolume;
65}
66
commit-bot@chromium.org8e13a152014-03-19 19:28:00 +000067class SkAutoNullKernelHandle : SkNoncopyable {
bungeman@google.com6cab1a42013-05-29 13:43:31 +000068public:
commit-bot@chromium.org8e13a152014-03-19 19:28:00 +000069 SkAutoNullKernelHandle(const HANDLE handle) : fHandle(handle) { }
70 ~SkAutoNullKernelHandle() { CloseHandle(fHandle); }
71 operator HANDLE() const { return fHandle; }
bsalomon49f085d2014-09-05 13:34:00 -070072 bool isValid() const { return SkToBool(fHandle); }
bungeman@google.com6cab1a42013-05-29 13:43:31 +000073private:
commit-bot@chromium.org8e13a152014-03-19 19:28:00 +000074 HANDLE fHandle;
bungeman@google.com6cab1a42013-05-29 13:43:31 +000075};
commit-bot@chromium.org8e13a152014-03-19 19:28:00 +000076typedef SkAutoNullKernelHandle SkAutoWinMMap;
bungeman@google.com6cab1a42013-05-29 13:43:31 +000077
78void sk_fmunmap(const void* addr, size_t) {
79 UnmapViewOfFile(addr);
80}
81
bungeman@google.com11c9a552013-06-03 17:10:35 +000082void* sk_fdmmap(int fileno, size_t* length) {
bungeman@google.com6cab1a42013-05-29 13:43:31 +000083 HANDLE file = (HANDLE)_get_osfhandle(fileno);
84 if (INVALID_HANDLE_VALUE == file) {
halcanary96fcdcc2015-08-27 07:41:13 -070085 return nullptr;
bungeman@google.com6cab1a42013-05-29 13:43:31 +000086 }
87
bungeman@google.com11c9a552013-06-03 17:10:35 +000088 LARGE_INTEGER fileSize;
89 if (0 == GetFileSizeEx(file, &fileSize)) {
90 //TODO: use SK_TRACEHR(GetLastError(), "Could not get file size.") to report.
halcanary96fcdcc2015-08-27 07:41:13 -070091 return nullptr;
bungeman@google.com11c9a552013-06-03 17:10:35 +000092 }
93 if (!SkTFitsIn<size_t>(fileSize.QuadPart)) {
halcanary96fcdcc2015-08-27 07:41:13 -070094 return nullptr;
bungeman@google.com11c9a552013-06-03 17:10:35 +000095 }
96
halcanary96fcdcc2015-08-27 07:41:13 -070097 SkAutoWinMMap mmap(CreateFileMapping(file, nullptr, PAGE_READONLY, 0, 0, nullptr));
bungeman@google.com6cab1a42013-05-29 13:43:31 +000098 if (!mmap.isValid()) {
99 //TODO: use SK_TRACEHR(GetLastError(), "Could not create file mapping.") to report.
halcanary96fcdcc2015-08-27 07:41:13 -0700100 return nullptr;
bungeman@google.com6cab1a42013-05-29 13:43:31 +0000101 }
102
103 // Eventually call UnmapViewOfFile
104 void* addr = MapViewOfFile(mmap, FILE_MAP_READ, 0, 0, 0);
halcanary96fcdcc2015-08-27 07:41:13 -0700105 if (nullptr == addr) {
bungeman@google.com6cab1a42013-05-29 13:43:31 +0000106 //TODO: use SK_TRACEHR(GetLastError(), "Could not map view of file.") to report.
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 *length = static_cast<size_t>(fileSize.QuadPart);
bungeman@google.com6cab1a42013-05-29 13:43:31 +0000111 return addr;
112}
bungeman@google.com11c9a552013-06-03 17:10:35 +0000113
halcanaryd76be9c2015-11-20 13:47:49 -0800114int sk_fileno(FILE* f) {
bungeman@google.com11c9a552013-06-03 17:10:35 +0000115 return _fileno((FILE*)f);
116}
117
halcanaryd76be9c2015-11-20 13:47:49 -0800118void* sk_fmmap(FILE* f, size_t* length) {
bungeman@google.com11c9a552013-06-03 17:10:35 +0000119 int fileno = sk_fileno(f);
120 if (fileno < 0) {
halcanary96fcdcc2015-08-27 07:41:13 -0700121 return nullptr;
bungeman@google.com11c9a552013-06-03 17:10:35 +0000122 }
123
124 return sk_fdmmap(fileno, length);
125}
bungemane998b7f2015-02-12 07:18:27 -0800126
Ben Wagner4d1955c2017-03-10 13:08:15 -0500127size_t sk_qread(FILE* file, void* buffer, size_t count, size_t offset) {
128 int fileno = sk_fileno(file);
129 HANDLE fileHandle = (HANDLE)_get_osfhandle(fileno);
130 if (INVALID_HANDLE_VALUE == file) {
131 return SIZE_MAX;
132 }
133
134 OVERLAPPED overlapped = {0};
135 ULARGE_INTEGER winOffset;
136 winOffset.QuadPart = offset;
137 overlapped.Offset = winOffset.LowPart;
138 overlapped.OffsetHigh = winOffset.HighPart;
139
140 if (!SkTFitsIn<DWORD>(count)) {
141 count = std::numeric_limits<DWORD>::max();
142 }
143
144 DWORD bytesRead;
145 if (ReadFile(fileHandle, buffer, static_cast<DWORD>(count), &bytesRead, &overlapped)) {
146 return bytesRead;
147 }
148 if (GetLastError() == ERROR_HANDLE_EOF) {
149 return 0;
150 }
151 return SIZE_MAX;
152}
153
bungemane998b7f2015-02-12 07:18:27 -0800154////////////////////////////////////////////////////////////////////////////
155
156struct SkOSFileIterData {
halcanary96fcdcc2015-08-27 07:41:13 -0700157 SkOSFileIterData() : fHandle(0), fPath16(nullptr) { }
bungemane998b7f2015-02-12 07:18:27 -0800158 HANDLE fHandle;
159 uint16_t* fPath16;
160};
bungeman99fe8222015-08-20 07:57:51 -0700161static_assert(sizeof(SkOSFileIterData) <= SkOSFile::Iter::kStorageSize, "not_enough_space");
bungemane998b7f2015-02-12 07:18:27 -0800162
163static uint16_t* concat_to_16(const char src[], const char suffix[]) {
164 size_t i, len = strlen(src);
165 size_t len2 = 3 + (suffix ? strlen(suffix) : 0);
166 uint16_t* dst = (uint16_t*)sk_malloc_throw((len + len2) * sizeof(uint16_t));
167
168 for (i = 0; i < len; i++) {
169 dst[i] = src[i];
170 }
171
172 if (i > 0 && dst[i-1] != '/') {
173 dst[i++] = '/';
174 }
175 dst[i++] = '*';
176
177 if (suffix) {
178 while (*suffix) {
179 dst[i++] = *suffix++;
180 }
181 }
182 dst[i] = 0;
183 SkASSERT(i + 1 <= len + len2);
184
185 return dst;
186}
187
halcanary385fe4d2015-08-26 13:07:48 -0700188SkOSFile::Iter::Iter() { new (fSelf.get()) SkOSFileIterData; }
bungemane998b7f2015-02-12 07:18:27 -0800189
190SkOSFile::Iter::Iter(const char path[], const char suffix[]) {
halcanary385fe4d2015-08-26 13:07:48 -0700191 new (fSelf.get()) SkOSFileIterData;
bungemane998b7f2015-02-12 07:18:27 -0800192 this->reset(path, suffix);
193}
194
195SkOSFile::Iter::~Iter() {
196 SkOSFileIterData& self = *static_cast<SkOSFileIterData*>(fSelf.get());
197 sk_free(self.fPath16);
198 if (self.fHandle) {
199 ::FindClose(self.fHandle);
200 }
201 self.~SkOSFileIterData();
202}
203
204void SkOSFile::Iter::reset(const char path[], const char suffix[]) {
205 SkOSFileIterData& self = *static_cast<SkOSFileIterData*>(fSelf.get());
206 if (self.fHandle) {
207 ::FindClose(self.fHandle);
208 self.fHandle = 0;
209 }
halcanary96fcdcc2015-08-27 07:41:13 -0700210 if (nullptr == path) {
bungemane998b7f2015-02-12 07:18:27 -0800211 path = "";
212 }
213
214 sk_free(self.fPath16);
215 self.fPath16 = concat_to_16(path, suffix);
216}
217
218static bool is_magic_dir(const uint16_t dir[]) {
219 // return true for "." and ".."
220 return dir[0] == '.' && (dir[1] == 0 || (dir[1] == '.' && dir[2] == 0));
221}
222
223static bool get_the_file(HANDLE handle, SkString* name, WIN32_FIND_DATAW* dataPtr, bool getDir) {
224 WIN32_FIND_DATAW data;
225
halcanary96fcdcc2015-08-27 07:41:13 -0700226 if (nullptr == dataPtr) {
bungemane998b7f2015-02-12 07:18:27 -0800227 if (::FindNextFileW(handle, &data))
228 dataPtr = &data;
229 else
230 return false;
231 }
232
233 for (;;) {
234 if (getDir) {
235 if ((dataPtr->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
236 !is_magic_dir((uint16_t*)dataPtr->cFileName))
237 {
238 break;
239 }
240 } else {
241 if (!(dataPtr->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
242 break;
243 }
244 }
245 if (!::FindNextFileW(handle, dataPtr)) {
246 return false;
247 }
248 }
249 // if we get here, we've found a file/dir
250 if (name) {
251 name->setUTF16((uint16_t*)dataPtr->cFileName);
252 }
253 return true;
254}
255
256bool SkOSFile::Iter::next(SkString* name, bool getDir) {
257 SkOSFileIterData& self = *static_cast<SkOSFileIterData*>(fSelf.get());
258 WIN32_FIND_DATAW data;
halcanary96fcdcc2015-08-27 07:41:13 -0700259 WIN32_FIND_DATAW* dataPtr = nullptr;
bungemane998b7f2015-02-12 07:18:27 -0800260
261 if (self.fHandle == 0) { // our first time
halcanary96fcdcc2015-08-27 07:41:13 -0700262 if (self.fPath16 == nullptr || *self.fPath16 == 0) { // check for no path
bungemane998b7f2015-02-12 07:18:27 -0800263 return false;
264 }
265
266 self.fHandle = ::FindFirstFileW((LPCWSTR)self.fPath16, &data);
267 if (self.fHandle != 0 && self.fHandle != (HANDLE)~0) {
268 dataPtr = &data;
269 }
270 }
271 return self.fHandle != (HANDLE)~0 && get_the_file(self.fHandle, name, dataPtr, getDir);
272}
mtklein1ee76512015-11-02 10:20:27 -0800273
274#endif//defined(SK_BUILD_FOR_WIN32)