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 "SkOSFile.h"
9
10#include "SkTFitsIn.h"
11
12#include <io.h>
13#include <stdio.h>
14#include <sys/stat.h>
15
16typedef struct {
17    ULONGLONG fVolume;
18    ULONGLONG fLsbSize;
19    ULONGLONG fMsbSize;
20} SkFILEID;
21
22static bool sk_ino(SkFILE* f, SkFILEID* id) {
23    int fileno = _fileno((FILE*)f);
24    if (fileno < 0) {
25        return false;
26    }
27
28    HANDLE file = (HANDLE)_get_osfhandle(fileno);
29    if (INVALID_HANDLE_VALUE == file) {
30        return false;
31    }
32
33    //TODO: call GetFileInformationByHandleEx on Vista and later with FileIdInfo.
34    BY_HANDLE_FILE_INFORMATION info;
35    if (0 == GetFileInformationByHandle(file, &info)) {
36        return false;
37    }
38    id->fVolume = info.dwVolumeSerialNumber;
39    id->fLsbSize = info.nFileIndexLow + (((ULONGLONG)info.nFileIndexHigh) << 32);
40    id->fMsbSize = 0;
41
42    return true;
43}
44
45bool sk_fidentical(SkFILE* a, SkFILE* b) {
46    SkFILEID aID, bID;
47    return sk_ino(a, &aID) && sk_ino(b, &bID)
48           && aID.fLsbSize == bID.fLsbSize
49           && aID.fMsbSize == bID.fMsbSize
50           && aID.fVolume == bID.fVolume;
51}
52
53class SkAutoNullKernelHandle : SkNoncopyable {
54public:
55    SkAutoNullKernelHandle(const HANDLE handle) : fHandle(handle) { }
56    ~SkAutoNullKernelHandle() { CloseHandle(fHandle); }
57    operator HANDLE() const { return fHandle; }
58    bool isValid() const { return NULL != fHandle; }
59private:
60    HANDLE fHandle;
61};
62typedef SkAutoNullKernelHandle SkAutoWinMMap;
63
64void sk_fmunmap(const void* addr, size_t) {
65    UnmapViewOfFile(addr);
66}
67
68void* sk_fdmmap(int fileno, size_t* length) {
69    HANDLE file = (HANDLE)_get_osfhandle(fileno);
70    if (INVALID_HANDLE_VALUE == file) {
71        return NULL;
72    }
73
74    LARGE_INTEGER fileSize;
75    if (0 == GetFileSizeEx(file, &fileSize)) {
76        //TODO: use SK_TRACEHR(GetLastError(), "Could not get file size.") to report.
77        return NULL;
78    }
79    if (!SkTFitsIn<size_t>(fileSize.QuadPart)) {
80        return NULL;
81    }
82
83    SkAutoWinMMap mmap(CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL));
84    if (!mmap.isValid()) {
85        //TODO: use SK_TRACEHR(GetLastError(), "Could not create file mapping.") to report.
86        return NULL;
87    }
88
89    // Eventually call UnmapViewOfFile
90    void* addr = MapViewOfFile(mmap, FILE_MAP_READ, 0, 0, 0);
91    if (NULL == addr) {
92        //TODO: use SK_TRACEHR(GetLastError(), "Could not map view of file.") to report.
93        return NULL;
94    }
95
96    *length = static_cast<size_t>(fileSize.QuadPart);
97    return addr;
98}
99
100int sk_fileno(SkFILE* f) {
101    return _fileno((FILE*)f);
102}
103
104void* sk_fmmap(SkFILE* f, size_t* length) {
105    int fileno = sk_fileno(f);
106    if (fileno < 0) {
107        return NULL;
108    }
109
110    return sk_fdmmap(fileno, length);
111}
112