blob: a544168c84b36788087be8b93bdb4883ed7ddfb7 [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
8#include "SkOSFile.h"
9
bungeman@google.comf5cc5b12013-07-12 18:22:49 +000010#include "SkTFitsIn.h"
bungeman@google.com11c9a552013-06-03 17:10:35 +000011
bungeman@google.com6cab1a42013-05-29 13:43:31 +000012#include <io.h>
13#include <stdio.h>
14#include <sys/stat.h>
15
bungemanbf0b9ce2014-07-10 15:18:23 -070016bool sk_exists(const char *path, SkFILE_Flags flags) {
17 int mode = 0; // existence
18 if (flags & kRead_SkFILE_Flag) {
19 mode |= 4; // read
20 }
21 if (flags & kWrite_SkFILE_Flag) {
22 mode |= 2; // write
23 }
24 return (0 == _access(path, mode));
25}
26
bungeman@google.com6cab1a42013-05-29 13:43:31 +000027typedef struct {
28 ULONGLONG fVolume;
29 ULONGLONG fLsbSize;
30 ULONGLONG fMsbSize;
31} SkFILEID;
32
33static bool sk_ino(SkFILE* f, SkFILEID* id) {
34 int fileno = _fileno((FILE*)f);
35 if (fileno < 0) {
36 return false;
37 }
38
39 HANDLE file = (HANDLE)_get_osfhandle(fileno);
40 if (INVALID_HANDLE_VALUE == file) {
41 return false;
42 }
43
44 //TODO: call GetFileInformationByHandleEx on Vista and later with FileIdInfo.
45 BY_HANDLE_FILE_INFORMATION info;
46 if (0 == GetFileInformationByHandle(file, &info)) {
47 return false;
48 }
49 id->fVolume = info.dwVolumeSerialNumber;
50 id->fLsbSize = info.nFileIndexLow + (((ULONGLONG)info.nFileIndexHigh) << 32);
51 id->fMsbSize = 0;
52
53 return true;
54}
55
56bool sk_fidentical(SkFILE* a, SkFILE* b) {
57 SkFILEID aID, bID;
58 return sk_ino(a, &aID) && sk_ino(b, &bID)
59 && aID.fLsbSize == bID.fLsbSize
60 && aID.fMsbSize == bID.fMsbSize
61 && aID.fVolume == bID.fVolume;
62}
63
commit-bot@chromium.org8e13a152014-03-19 19:28:00 +000064class SkAutoNullKernelHandle : SkNoncopyable {
bungeman@google.com6cab1a42013-05-29 13:43:31 +000065public:
commit-bot@chromium.org8e13a152014-03-19 19:28:00 +000066 SkAutoNullKernelHandle(const HANDLE handle) : fHandle(handle) { }
67 ~SkAutoNullKernelHandle() { CloseHandle(fHandle); }
68 operator HANDLE() const { return fHandle; }
bsalomon49f085d2014-09-05 13:34:00 -070069 bool isValid() const { return SkToBool(fHandle); }
bungeman@google.com6cab1a42013-05-29 13:43:31 +000070private:
commit-bot@chromium.org8e13a152014-03-19 19:28:00 +000071 HANDLE fHandle;
bungeman@google.com6cab1a42013-05-29 13:43:31 +000072};
commit-bot@chromium.org8e13a152014-03-19 19:28:00 +000073typedef SkAutoNullKernelHandle SkAutoWinMMap;
bungeman@google.com6cab1a42013-05-29 13:43:31 +000074
75void sk_fmunmap(const void* addr, size_t) {
76 UnmapViewOfFile(addr);
77}
78
bungeman@google.com11c9a552013-06-03 17:10:35 +000079void* sk_fdmmap(int fileno, size_t* length) {
bungeman@google.com6cab1a42013-05-29 13:43:31 +000080 HANDLE file = (HANDLE)_get_osfhandle(fileno);
81 if (INVALID_HANDLE_VALUE == file) {
82 return NULL;
83 }
84
bungeman@google.com11c9a552013-06-03 17:10:35 +000085 LARGE_INTEGER fileSize;
86 if (0 == GetFileSizeEx(file, &fileSize)) {
87 //TODO: use SK_TRACEHR(GetLastError(), "Could not get file size.") to report.
88 return NULL;
89 }
90 if (!SkTFitsIn<size_t>(fileSize.QuadPart)) {
91 return NULL;
92 }
93
bungeman@google.com6cab1a42013-05-29 13:43:31 +000094 SkAutoWinMMap mmap(CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL));
95 if (!mmap.isValid()) {
96 //TODO: use SK_TRACEHR(GetLastError(), "Could not create file mapping.") to report.
97 return NULL;
98 }
99
100 // Eventually call UnmapViewOfFile
101 void* addr = MapViewOfFile(mmap, FILE_MAP_READ, 0, 0, 0);
102 if (NULL == addr) {
103 //TODO: use SK_TRACEHR(GetLastError(), "Could not map view of file.") to report.
104 return NULL;
105 }
106
bungeman@google.com11c9a552013-06-03 17:10:35 +0000107 *length = static_cast<size_t>(fileSize.QuadPart);
bungeman@google.com6cab1a42013-05-29 13:43:31 +0000108 return addr;
109}
bungeman@google.com11c9a552013-06-03 17:10:35 +0000110
111int sk_fileno(SkFILE* f) {
112 return _fileno((FILE*)f);
113}
114
115void* sk_fmmap(SkFILE* f, size_t* length) {
116 int fileno = sk_fileno(f);
117 if (fileno < 0) {
118 return NULL;
119 }
120
121 return sk_fdmmap(fileno, length);
122}
bungemane998b7f2015-02-12 07:18:27 -0800123
124////////////////////////////////////////////////////////////////////////////
125
126struct SkOSFileIterData {
127 SkOSFileIterData() : fHandle(0), fPath16(NULL) { }
128 HANDLE fHandle;
129 uint16_t* fPath16;
130};
131SK_COMPILE_ASSERT(sizeof(SkOSFileIterData) <= SkOSFile::Iter::kStorageSize, not_enough_space);
132
133static uint16_t* concat_to_16(const char src[], const char suffix[]) {
134 size_t i, len = strlen(src);
135 size_t len2 = 3 + (suffix ? strlen(suffix) : 0);
136 uint16_t* dst = (uint16_t*)sk_malloc_throw((len + len2) * sizeof(uint16_t));
137
138 for (i = 0; i < len; i++) {
139 dst[i] = src[i];
140 }
141
142 if (i > 0 && dst[i-1] != '/') {
143 dst[i++] = '/';
144 }
145 dst[i++] = '*';
146
147 if (suffix) {
148 while (*suffix) {
149 dst[i++] = *suffix++;
150 }
151 }
152 dst[i] = 0;
153 SkASSERT(i + 1 <= len + len2);
154
155 return dst;
156}
157
158SkOSFile::Iter::Iter() {
159 SkNEW_PLACEMENT(fSelf.get(), SkOSFileIterData);
160}
161
162SkOSFile::Iter::Iter(const char path[], const char suffix[]) {
163 SkNEW_PLACEMENT(fSelf.get(), SkOSFileIterData);
164 this->reset(path, suffix);
165}
166
167SkOSFile::Iter::~Iter() {
168 SkOSFileIterData& self = *static_cast<SkOSFileIterData*>(fSelf.get());
169 sk_free(self.fPath16);
170 if (self.fHandle) {
171 ::FindClose(self.fHandle);
172 }
173 self.~SkOSFileIterData();
174}
175
176void SkOSFile::Iter::reset(const char path[], const char suffix[]) {
177 SkOSFileIterData& self = *static_cast<SkOSFileIterData*>(fSelf.get());
178 if (self.fHandle) {
179 ::FindClose(self.fHandle);
180 self.fHandle = 0;
181 }
182 if (NULL == path) {
183 path = "";
184 }
185
186 sk_free(self.fPath16);
187 self.fPath16 = concat_to_16(path, suffix);
188}
189
190static bool is_magic_dir(const uint16_t dir[]) {
191 // return true for "." and ".."
192 return dir[0] == '.' && (dir[1] == 0 || (dir[1] == '.' && dir[2] == 0));
193}
194
195static bool get_the_file(HANDLE handle, SkString* name, WIN32_FIND_DATAW* dataPtr, bool getDir) {
196 WIN32_FIND_DATAW data;
197
198 if (NULL == dataPtr) {
199 if (::FindNextFileW(handle, &data))
200 dataPtr = &data;
201 else
202 return false;
203 }
204
205 for (;;) {
206 if (getDir) {
207 if ((dataPtr->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
208 !is_magic_dir((uint16_t*)dataPtr->cFileName))
209 {
210 break;
211 }
212 } else {
213 if (!(dataPtr->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
214 break;
215 }
216 }
217 if (!::FindNextFileW(handle, dataPtr)) {
218 return false;
219 }
220 }
221 // if we get here, we've found a file/dir
222 if (name) {
223 name->setUTF16((uint16_t*)dataPtr->cFileName);
224 }
225 return true;
226}
227
228bool SkOSFile::Iter::next(SkString* name, bool getDir) {
229 SkOSFileIterData& self = *static_cast<SkOSFileIterData*>(fSelf.get());
230 WIN32_FIND_DATAW data;
231 WIN32_FIND_DATAW* dataPtr = NULL;
232
233 if (self.fHandle == 0) { // our first time
234 if (self.fPath16 == NULL || *self.fPath16 == 0) { // check for no path
235 return false;
236 }
237
238 self.fHandle = ::FindFirstFileW((LPCWSTR)self.fPath16, &data);
239 if (self.fHandle != 0 && self.fHandle != (HANDLE)~0) {
240 dataPtr = &data;
241 }
242 }
243 return self.fHandle != (HANDLE)~0 && get_the_file(self.fHandle, name, dataPtr, getDir);
244}