SkOSFile_win.cpp revision f5cc5b140c1c00c536e02b5cfbe158bb2d5c2c15
16cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com/*
26cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com * Copyright 2013 Google Inc.
36cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com *
46cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com * Use of this source code is governed by a BSD-style license that can be
56cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com * found in the LICENSE file.
66cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com */
76cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com
86cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com#include "SkOSFile.h"
96cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com
10f5cc5b140c1c00c536e02b5cfbe158bb2d5c2c15bungeman@google.com#include "SkTFitsIn.h"
1111c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com
126cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com#include <io.h>
136cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com#include <stdio.h>
146cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com#include <sys/stat.h>
156cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com
166cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.comtypedef struct {
176cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    ULONGLONG fVolume;
186cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    ULONGLONG fLsbSize;
196cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    ULONGLONG fMsbSize;
206cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com} SkFILEID;
216cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com
226cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.comstatic bool sk_ino(SkFILE* f, SkFILEID* id) {
236cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    int fileno = _fileno((FILE*)f);
246cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    if (fileno < 0) {
256cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com        return false;
266cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    }
276cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com
286cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    HANDLE file = (HANDLE)_get_osfhandle(fileno);
296cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    if (INVALID_HANDLE_VALUE == file) {
306cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com        return false;
316cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    }
326cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com
336cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    //TODO: call GetFileInformationByHandleEx on Vista and later with FileIdInfo.
346cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    BY_HANDLE_FILE_INFORMATION info;
356cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    if (0 == GetFileInformationByHandle(file, &info)) {
366cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com        return false;
376cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    }
386cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    id->fVolume = info.dwVolumeSerialNumber;
396cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    id->fLsbSize = info.nFileIndexLow + (((ULONGLONG)info.nFileIndexHigh) << 32);
406cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    id->fMsbSize = 0;
416cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com
426cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    return true;
436cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com}
446cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com
456cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.combool sk_fidentical(SkFILE* a, SkFILE* b) {
466cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    SkFILEID aID, bID;
476cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    return sk_ino(a, &aID) && sk_ino(b, &bID)
486cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com           && aID.fLsbSize == bID.fLsbSize
496cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com           && aID.fMsbSize == bID.fMsbSize
506cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com           && aID.fVolume == bID.fVolume;
516cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com}
526cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com
536cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.comtemplate <typename HandleType, HandleType InvalidValue, BOOL (WINAPI * Close)(HandleType)>
546cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.comclass SkAutoTHandle : SkNoncopyable {
556cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.compublic:
566cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    SkAutoTHandle(HandleType handle) : fHandle(handle) { }
576cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    ~SkAutoTHandle() { Close(fHandle); }
586cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    operator HandleType() { return fHandle; }
596cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    bool isValid() { return InvalidValue != fHandle; }
606cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.comprivate:
616cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    HandleType fHandle;
626cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com};
636cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.comtypedef SkAutoTHandle<HANDLE, INVALID_HANDLE_VALUE, CloseHandle> SkAutoWinFile;
646cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.comtypedef SkAutoTHandle<HANDLE, NULL, CloseHandle> SkAutoWinMMap;
656cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com
666cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.comvoid sk_fmunmap(const void* addr, size_t) {
676cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    UnmapViewOfFile(addr);
686cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com}
696cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com
7011c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.comvoid* sk_fdmmap(int fileno, size_t* length) {
7111c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com    HANDLE file = (HANDLE)_get_osfhandle(fileno);
7211c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com    if (INVALID_HANDLE_VALUE == file) {
736cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com        return NULL;
746cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    }
756cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com
7611c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com    LARGE_INTEGER fileSize;
7711c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com    if (0 == GetFileSizeEx(file, &fileSize)) {
7811c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com        //TODO: use SK_TRACEHR(GetLastError(), "Could not get file size.") to report.
796cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com        return NULL;
806cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    }
8111c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com    if (!SkTFitsIn<size_t>(fileSize.QuadPart)) {
826cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com        return NULL;
836cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    }
846cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com
856cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    SkAutoWinMMap mmap(CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL));
866cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    if (!mmap.isValid()) {
876cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com        //TODO: use SK_TRACEHR(GetLastError(), "Could not create file mapping.") to report.
886cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com        return NULL;
896cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    }
906cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com
916cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    // Eventually call UnmapViewOfFile
926cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    void* addr = MapViewOfFile(mmap, FILE_MAP_READ, 0, 0, 0);
936cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    if (NULL == addr) {
946cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com        //TODO: use SK_TRACEHR(GetLastError(), "Could not map view of file.") to report.
956cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com        return NULL;
966cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    }
976cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com
9811c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com    *length = static_cast<size_t>(fileSize.QuadPart);
996cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    return addr;
1006cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com}
10111c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com
10211c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.comint sk_fileno(SkFILE* f) {
10311c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com    return _fileno((FILE*)f);
10411c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com}
10511c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com
10611c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.comvoid* sk_fmmap(SkFILE* f, size_t* length) {
10711c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com    int fileno = sk_fileno(f);
10811c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com    if (fileno < 0) {
10911c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com        return NULL;
11011c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com    }
11111c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com
11211c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com    return sk_fdmmap(fileno, length);
11311c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com}
114