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
538e13a159f3a54f761ab80b16377015e5a9077411commit-bot@chromium.orgclass SkAutoNullKernelHandle : SkNoncopyable {
546cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.compublic:
558e13a159f3a54f761ab80b16377015e5a9077411commit-bot@chromium.org    SkAutoNullKernelHandle(const HANDLE handle) : fHandle(handle) { }
568e13a159f3a54f761ab80b16377015e5a9077411commit-bot@chromium.org    ~SkAutoNullKernelHandle() { CloseHandle(fHandle); }
578e13a159f3a54f761ab80b16377015e5a9077411commit-bot@chromium.org    operator HANDLE() const { return fHandle; }
588e13a159f3a54f761ab80b16377015e5a9077411commit-bot@chromium.org    bool isValid() const { return NULL != fHandle; }
596cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.comprivate:
608e13a159f3a54f761ab80b16377015e5a9077411commit-bot@chromium.org    HANDLE fHandle;
616cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com};
628e13a159f3a54f761ab80b16377015e5a9077411commit-bot@chromium.orgtypedef SkAutoNullKernelHandle SkAutoWinMMap;
636cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com
646cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.comvoid sk_fmunmap(const void* addr, size_t) {
656cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    UnmapViewOfFile(addr);
666cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com}
676cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com
6811c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.comvoid* sk_fdmmap(int fileno, size_t* length) {
6911c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com    HANDLE file = (HANDLE)_get_osfhandle(fileno);
7011c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com    if (INVALID_HANDLE_VALUE == file) {
716cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com        return NULL;
726cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    }
736cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com
7411c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com    LARGE_INTEGER fileSize;
7511c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com    if (0 == GetFileSizeEx(file, &fileSize)) {
7611c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com        //TODO: use SK_TRACEHR(GetLastError(), "Could not get file size.") to report.
776cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com        return NULL;
786cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    }
7911c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com    if (!SkTFitsIn<size_t>(fileSize.QuadPart)) {
806cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com        return NULL;
816cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    }
826cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com
836cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    SkAutoWinMMap mmap(CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL));
846cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    if (!mmap.isValid()) {
856cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com        //TODO: use SK_TRACEHR(GetLastError(), "Could not create file mapping.") to report.
866cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com        return NULL;
876cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    }
886cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com
896cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    // Eventually call UnmapViewOfFile
906cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    void* addr = MapViewOfFile(mmap, FILE_MAP_READ, 0, 0, 0);
916cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    if (NULL == addr) {
926cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com        //TODO: use SK_TRACEHR(GetLastError(), "Could not map view of file.") to report.
936cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com        return NULL;
946cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    }
956cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com
9611c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com    *length = static_cast<size_t>(fileSize.QuadPart);
976cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    return addr;
986cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com}
9911c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com
10011c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.comint sk_fileno(SkFILE* f) {
10111c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com    return _fileno((FILE*)f);
10211c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com}
10311c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com
10411c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.comvoid* sk_fmmap(SkFILE* f, size_t* length) {
10511c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com    int fileno = sk_fileno(f);
10611c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com    if (fileno < 0) {
10711c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com        return NULL;
10811c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com    }
10911c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com
11011c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com    return sk_fdmmap(fileno, length);
11111c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com}
112