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 "SkOSFile.h" 12 13 #include "SkTFitsIn.h" 14 15 #include <io.h> 16 #include <stdio.h> 17 #include <sys/stat.h> 18 19 bool 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 30 typedef struct { 31 ULONGLONG fVolume; 32 ULONGLONG fLsbSize; 33 ULONGLONG fMsbSize; 34 } SkFILEID; 35 36 static bool sk_ino(FILE* f, SkFILEID* id) { 37 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 59 bool sk_fidentical(FILE* a, FILE* b) { 60 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 67 class SkAutoNullKernelHandle : SkNoncopyable { 68 public: 69 SkAutoNullKernelHandle(const HANDLE handle) : fHandle(handle) { } 70 ~SkAutoNullKernelHandle() { CloseHandle(fHandle); } 71 operator HANDLE() const { return fHandle; } 72 bool isValid() const { return SkToBool(fHandle); } 73 private: 74 HANDLE fHandle; 75 }; 76 typedef SkAutoNullKernelHandle SkAutoWinMMap; 77 78 void sk_fmunmap(const void* addr, size_t) { 79 UnmapViewOfFile(addr); 80 } 81 82 void* sk_fdmmap(int fileno, size_t* length) { 83 HANDLE file = (HANDLE)_get_osfhandle(fileno); 84 if (INVALID_HANDLE_VALUE == file) { 85 return nullptr; 86 } 87 88 LARGE_INTEGER fileSize; 89 if (0 == GetFileSizeEx(file, &fileSize)) { 90 //TODO: use SK_TRACEHR(GetLastError(), "Could not get file size.") to report. 91 return nullptr; 92 } 93 if (!SkTFitsIn<size_t>(fileSize.QuadPart)) { 94 return nullptr; 95 } 96 97 SkAutoWinMMap mmap(CreateFileMapping(file, nullptr, PAGE_READONLY, 0, 0, nullptr)); 98 if (!mmap.isValid()) { 99 //TODO: use SK_TRACEHR(GetLastError(), "Could not create file mapping.") to report. 100 return nullptr; 101 } 102 103 // Eventually call UnmapViewOfFile 104 void* addr = MapViewOfFile(mmap, FILE_MAP_READ, 0, 0, 0); 105 if (nullptr == addr) { 106 //TODO: use SK_TRACEHR(GetLastError(), "Could not map view of file.") to report. 107 return nullptr; 108 } 109 110 *length = static_cast<size_t>(fileSize.QuadPart); 111 return addr; 112 } 113 114 int sk_fileno(FILE* f) { 115 return _fileno((FILE*)f); 116 } 117 118 void* sk_fmmap(FILE* f, size_t* length) { 119 int fileno = sk_fileno(f); 120 if (fileno < 0) { 121 return nullptr; 122 } 123 124 return sk_fdmmap(fileno, length); 125 } 126 127 //////////////////////////////////////////////////////////////////////////// 128 129 struct SkOSFileIterData { 130 SkOSFileIterData() : fHandle(0), fPath16(nullptr) { } 131 HANDLE fHandle; 132 uint16_t* fPath16; 133 }; 134 static_assert(sizeof(SkOSFileIterData) <= SkOSFile::Iter::kStorageSize, "not_enough_space"); 135 136 static uint16_t* concat_to_16(const char src[], const char suffix[]) { 137 size_t i, len = strlen(src); 138 size_t len2 = 3 + (suffix ? strlen(suffix) : 0); 139 uint16_t* dst = (uint16_t*)sk_malloc_throw((len + len2) * sizeof(uint16_t)); 140 141 for (i = 0; i < len; i++) { 142 dst[i] = src[i]; 143 } 144 145 if (i > 0 && dst[i-1] != '/') { 146 dst[i++] = '/'; 147 } 148 dst[i++] = '*'; 149 150 if (suffix) { 151 while (*suffix) { 152 dst[i++] = *suffix++; 153 } 154 } 155 dst[i] = 0; 156 SkASSERT(i + 1 <= len + len2); 157 158 return dst; 159 } 160 161 SkOSFile::Iter::Iter() { new (fSelf.get()) SkOSFileIterData; } 162 163 SkOSFile::Iter::Iter(const char path[], const char suffix[]) { 164 new (fSelf.get()) SkOSFileIterData; 165 this->reset(path, suffix); 166 } 167 168 SkOSFile::Iter::~Iter() { 169 SkOSFileIterData& self = *static_cast<SkOSFileIterData*>(fSelf.get()); 170 sk_free(self.fPath16); 171 if (self.fHandle) { 172 ::FindClose(self.fHandle); 173 } 174 self.~SkOSFileIterData(); 175 } 176 177 void SkOSFile::Iter::reset(const char path[], const char suffix[]) { 178 SkOSFileIterData& self = *static_cast<SkOSFileIterData*>(fSelf.get()); 179 if (self.fHandle) { 180 ::FindClose(self.fHandle); 181 self.fHandle = 0; 182 } 183 if (nullptr == path) { 184 path = ""; 185 } 186 187 sk_free(self.fPath16); 188 self.fPath16 = concat_to_16(path, suffix); 189 } 190 191 static bool is_magic_dir(const uint16_t dir[]) { 192 // return true for "." and ".." 193 return dir[0] == '.' && (dir[1] == 0 || (dir[1] == '.' && dir[2] == 0)); 194 } 195 196 static bool get_the_file(HANDLE handle, SkString* name, WIN32_FIND_DATAW* dataPtr, bool getDir) { 197 WIN32_FIND_DATAW data; 198 199 if (nullptr == dataPtr) { 200 if (::FindNextFileW(handle, &data)) 201 dataPtr = &data; 202 else 203 return false; 204 } 205 206 for (;;) { 207 if (getDir) { 208 if ((dataPtr->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && 209 !is_magic_dir((uint16_t*)dataPtr->cFileName)) 210 { 211 break; 212 } 213 } else { 214 if (!(dataPtr->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { 215 break; 216 } 217 } 218 if (!::FindNextFileW(handle, dataPtr)) { 219 return false; 220 } 221 } 222 // if we get here, we've found a file/dir 223 if (name) { 224 name->setUTF16((uint16_t*)dataPtr->cFileName); 225 } 226 return true; 227 } 228 229 bool SkOSFile::Iter::next(SkString* name, bool getDir) { 230 SkOSFileIterData& self = *static_cast<SkOSFileIterData*>(fSelf.get()); 231 WIN32_FIND_DATAW data; 232 WIN32_FIND_DATAW* dataPtr = nullptr; 233 234 if (self.fHandle == 0) { // our first time 235 if (self.fPath16 == nullptr || *self.fPath16 == 0) { // check for no path 236 return false; 237 } 238 239 self.fHandle = ::FindFirstFileW((LPCWSTR)self.fPath16, &data); 240 if (self.fHandle != 0 && self.fHandle != (HANDLE)~0) { 241 dataPtr = &data; 242 } 243 } 244 return self.fHandle != (HANDLE)~0 && get_the_file(self.fHandle, name, dataPtr, getDir); 245 } 246 247 #endif//defined(SK_BUILD_FOR_WIN32) 248