SkOSFile_win.cpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  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. #include "include/core/SkTypes.h"
  8. #if defined(SK_BUILD_FOR_WIN)
  9. #include "include/private/SkMalloc.h"
  10. #include "include/private/SkNoncopyable.h"
  11. #include "include/private/SkTFitsIn.h"
  12. #include "src/core/SkLeanWindows.h"
  13. #include "src/core/SkOSFile.h"
  14. #include "src/core/SkStringUtils.h"
  15. #include <io.h>
  16. #include <new>
  17. #include <stdio.h>
  18. #include <sys/stat.h>
  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. typedef struct {
  30. ULONGLONG fVolume;
  31. ULONGLONG fLsbSize;
  32. ULONGLONG fMsbSize;
  33. } SkFILEID;
  34. static bool sk_ino(FILE* f, SkFILEID* id) {
  35. int fileno = _fileno((FILE*)f);
  36. if (fileno < 0) {
  37. return false;
  38. }
  39. HANDLE file = (HANDLE)_get_osfhandle(fileno);
  40. if (INVALID_HANDLE_VALUE == file) {
  41. return false;
  42. }
  43. //TODO: call GetFileInformationByHandleEx on Vista and later with FileIdInfo.
  44. BY_HANDLE_FILE_INFORMATION info;
  45. if (0 == GetFileInformationByHandle(file, &info)) {
  46. return false;
  47. }
  48. id->fVolume = info.dwVolumeSerialNumber;
  49. id->fLsbSize = info.nFileIndexLow + (((ULONGLONG)info.nFileIndexHigh) << 32);
  50. id->fMsbSize = 0;
  51. return true;
  52. }
  53. bool sk_fidentical(FILE* a, FILE* b) {
  54. SkFILEID aID, bID;
  55. return sk_ino(a, &aID) && sk_ino(b, &bID)
  56. && aID.fLsbSize == bID.fLsbSize
  57. && aID.fMsbSize == bID.fMsbSize
  58. && aID.fVolume == bID.fVolume;
  59. }
  60. class SkAutoNullKernelHandle : SkNoncopyable {
  61. public:
  62. SkAutoNullKernelHandle(const HANDLE handle) : fHandle(handle) { }
  63. ~SkAutoNullKernelHandle() { CloseHandle(fHandle); }
  64. operator HANDLE() const { return fHandle; }
  65. bool isValid() const { return SkToBool(fHandle); }
  66. private:
  67. HANDLE fHandle;
  68. };
  69. typedef SkAutoNullKernelHandle SkAutoWinMMap;
  70. void sk_fmunmap(const void* addr, size_t) {
  71. UnmapViewOfFile(addr);
  72. }
  73. void* sk_fdmmap(int fileno, size_t* length) {
  74. HANDLE file = (HANDLE)_get_osfhandle(fileno);
  75. if (INVALID_HANDLE_VALUE == file) {
  76. return nullptr;
  77. }
  78. LARGE_INTEGER fileSize;
  79. if (0 == GetFileSizeEx(file, &fileSize)) {
  80. //TODO: use SK_TRACEHR(GetLastError(), "Could not get file size.") to report.
  81. return nullptr;
  82. }
  83. if (!SkTFitsIn<size_t>(fileSize.QuadPart)) {
  84. return nullptr;
  85. }
  86. SkAutoWinMMap mmap(CreateFileMapping(file, nullptr, PAGE_READONLY, 0, 0, nullptr));
  87. if (!mmap.isValid()) {
  88. //TODO: use SK_TRACEHR(GetLastError(), "Could not create file mapping.") to report.
  89. return nullptr;
  90. }
  91. // Eventually call UnmapViewOfFile
  92. void* addr = MapViewOfFile(mmap, FILE_MAP_READ, 0, 0, 0);
  93. if (nullptr == addr) {
  94. //TODO: use SK_TRACEHR(GetLastError(), "Could not map view of file.") to report.
  95. return nullptr;
  96. }
  97. *length = static_cast<size_t>(fileSize.QuadPart);
  98. return addr;
  99. }
  100. int sk_fileno(FILE* f) {
  101. return _fileno((FILE*)f);
  102. }
  103. void* sk_fmmap(FILE* f, size_t* length) {
  104. int fileno = sk_fileno(f);
  105. if (fileno < 0) {
  106. return nullptr;
  107. }
  108. return sk_fdmmap(fileno, length);
  109. }
  110. size_t sk_qread(FILE* file, void* buffer, size_t count, size_t offset) {
  111. int fileno = sk_fileno(file);
  112. HANDLE fileHandle = (HANDLE)_get_osfhandle(fileno);
  113. if (INVALID_HANDLE_VALUE == file) {
  114. return SIZE_MAX;
  115. }
  116. OVERLAPPED overlapped;
  117. memset(&overlapped, 0, sizeof(overlapped));
  118. ULARGE_INTEGER winOffset;
  119. winOffset.QuadPart = offset;
  120. overlapped.Offset = winOffset.LowPart;
  121. overlapped.OffsetHigh = winOffset.HighPart;
  122. if (!SkTFitsIn<DWORD>(count)) {
  123. count = std::numeric_limits<DWORD>::max();
  124. }
  125. DWORD bytesRead;
  126. if (ReadFile(fileHandle, buffer, static_cast<DWORD>(count), &bytesRead, &overlapped)) {
  127. return bytesRead;
  128. }
  129. if (GetLastError() == ERROR_HANDLE_EOF) {
  130. return 0;
  131. }
  132. return SIZE_MAX;
  133. }
  134. ////////////////////////////////////////////////////////////////////////////
  135. struct SkOSFileIterData {
  136. SkOSFileIterData() : fHandle(0), fPath16(nullptr) { }
  137. HANDLE fHandle;
  138. uint16_t* fPath16;
  139. };
  140. static_assert(sizeof(SkOSFileIterData) <= SkOSFile::Iter::kStorageSize, "not_enough_space");
  141. static uint16_t* concat_to_16(const char src[], const char suffix[]) {
  142. size_t i, len = strlen(src);
  143. size_t len2 = 3 + (suffix ? strlen(suffix) : 0);
  144. uint16_t* dst = (uint16_t*)sk_malloc_throw((len + len2) * sizeof(uint16_t));
  145. for (i = 0; i < len; i++) {
  146. dst[i] = src[i];
  147. }
  148. if (i > 0 && dst[i-1] != '/') {
  149. dst[i++] = '/';
  150. }
  151. dst[i++] = '*';
  152. if (suffix) {
  153. while (*suffix) {
  154. dst[i++] = *suffix++;
  155. }
  156. }
  157. dst[i] = 0;
  158. SkASSERT(i + 1 <= len + len2);
  159. return dst;
  160. }
  161. SkOSFile::Iter::Iter() { new (fSelf.get()) SkOSFileIterData; }
  162. SkOSFile::Iter::Iter(const char path[], const char suffix[]) {
  163. new (fSelf.get()) SkOSFileIterData;
  164. this->reset(path, suffix);
  165. }
  166. SkOSFile::Iter::~Iter() {
  167. SkOSFileIterData& self = *static_cast<SkOSFileIterData*>(fSelf.get());
  168. sk_free(self.fPath16);
  169. if (self.fHandle) {
  170. ::FindClose(self.fHandle);
  171. }
  172. self.~SkOSFileIterData();
  173. }
  174. void SkOSFile::Iter::reset(const char path[], const char suffix[]) {
  175. SkOSFileIterData& self = *static_cast<SkOSFileIterData*>(fSelf.get());
  176. if (self.fHandle) {
  177. ::FindClose(self.fHandle);
  178. self.fHandle = 0;
  179. }
  180. if (nullptr == path) {
  181. path = "";
  182. }
  183. sk_free(self.fPath16);
  184. self.fPath16 = concat_to_16(path, suffix);
  185. }
  186. static bool is_magic_dir(const uint16_t dir[]) {
  187. // return true for "." and ".."
  188. return dir[0] == '.' && (dir[1] == 0 || (dir[1] == '.' && dir[2] == 0));
  189. }
  190. static bool get_the_file(HANDLE handle, SkString* name, WIN32_FIND_DATAW* dataPtr, bool getDir) {
  191. WIN32_FIND_DATAW data;
  192. if (nullptr == dataPtr) {
  193. if (::FindNextFileW(handle, &data))
  194. dataPtr = &data;
  195. else
  196. return false;
  197. }
  198. for (;;) {
  199. if (getDir) {
  200. if ((dataPtr->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
  201. !is_magic_dir((uint16_t*)dataPtr->cFileName))
  202. {
  203. break;
  204. }
  205. } else {
  206. if (!(dataPtr->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
  207. break;
  208. }
  209. }
  210. if (!::FindNextFileW(handle, dataPtr)) {
  211. return false;
  212. }
  213. }
  214. // if we get here, we've found a file/dir
  215. if (name) {
  216. const uint16_t* utf16name = (const uint16_t*)dataPtr->cFileName;
  217. const uint16_t* ptr = utf16name;
  218. while (*ptr != 0) { ++ptr; }
  219. *name = SkStringFromUTF16(utf16name, ptr - utf16name);
  220. }
  221. return true;
  222. }
  223. bool SkOSFile::Iter::next(SkString* name, bool getDir) {
  224. SkOSFileIterData& self = *static_cast<SkOSFileIterData*>(fSelf.get());
  225. WIN32_FIND_DATAW data;
  226. WIN32_FIND_DATAW* dataPtr = nullptr;
  227. if (self.fHandle == 0) { // our first time
  228. if (self.fPath16 == nullptr || *self.fPath16 == 0) { // check for no path
  229. return false;
  230. }
  231. self.fHandle = ::FindFirstFileW((LPCWSTR)self.fPath16, &data);
  232. if (self.fHandle != 0 && self.fHandle != (HANDLE)~0) {
  233. dataPtr = &data;
  234. }
  235. }
  236. return self.fHandle != (HANDLE)~0 && get_the_file(self.fHandle, name, dataPtr, getDir);
  237. }
  238. #endif//defined(SK_BUILD_FOR_WIN)