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