Home | History | Annotate | Download | only in ports
      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