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
53template <typename HandleType, HandleType InvalidValue, BOOL (WINAPI * Close)(HandleType)>
54class SkAutoTHandle : SkNoncopyable {
55public:
56    SkAutoTHandle(HandleType handle) : fHandle(handle) { }
57    ~SkAutoTHandle() { Close(fHandle); }
58    operator HandleType() { return fHandle; }
59    bool isValid() { return InvalidValue != fHandle; }
60private:
61    HandleType fHandle;
62};
63typedef SkAutoTHandle<HANDLE, INVALID_HANDLE_VALUE, CloseHandle> SkAutoWinFile;
64typedef SkAutoTHandle<HANDLE, NULL, CloseHandle> SkAutoWinMMap;
65
66void sk_fmunmap(const void* addr, size_t) {
67    UnmapViewOfFile(addr);
68}
69
70void* sk_fdmmap(int fileno, size_t* length) {
71    HANDLE file = (HANDLE)_get_osfhandle(fileno);
72    if (INVALID_HANDLE_VALUE == file) {
73        return NULL;
74    }
75
76    LARGE_INTEGER fileSize;
77    if (0 == GetFileSizeEx(file, &fileSize)) {
78        //TODO: use SK_TRACEHR(GetLastError(), "Could not get file size.") to report.
79        return NULL;
80    }
81    if (!SkTFitsIn<size_t>(fileSize.QuadPart)) {
82        return NULL;
83    }
84
85    SkAutoWinMMap mmap(CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL));
86    if (!mmap.isValid()) {
87        //TODO: use SK_TRACEHR(GetLastError(), "Could not create file mapping.") to report.
88        return NULL;
89    }
90
91    // Eventually call UnmapViewOfFile
92    void* addr = MapViewOfFile(mmap, FILE_MAP_READ, 0, 0, 0);
93    if (NULL == addr) {
94        //TODO: use SK_TRACEHR(GetLastError(), "Could not map view of file.") to report.
95        return NULL;
96    }
97
98    *length = static_cast<size_t>(fileSize.QuadPart);
99    return addr;
100}
101
102int sk_fileno(SkFILE* f) {
103    return _fileno((FILE*)f);
104}
105
106void* sk_fmmap(SkFILE* f, size_t* length) {
107    int fileno = sk_fileno(f);
108    if (fileno < 0) {
109        return NULL;
110    }
111
112    return sk_fdmmap(fileno, length);
113}
114