file-map.hpp 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. #pragma once
  2. #include <nall/file.hpp>
  3. #include <nall/stdint.hpp>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #if defined(PLATFORM_WINDOWS)
  7. #include <nall/windows/utf8.hpp>
  8. #else
  9. #include <fcntl.h>
  10. #include <unistd.h>
  11. #include <sys/mman.h>
  12. #include <sys/stat.h>
  13. #include <sys/types.h>
  14. #endif
  15. #if !defined(MAP_NORESERVE)
  16. //not supported on FreeBSD; flag removed in 11.0
  17. #define MAP_NORESERVE 0
  18. #endif
  19. namespace nall {
  20. struct file_map {
  21. struct mode { enum : uint { read, write, modify, append }; };
  22. file_map(const file_map&) = delete;
  23. auto operator=(const file_map&) = delete;
  24. file_map() = default;
  25. file_map(file_map&& source) { operator=(move(source)); }
  26. file_map(const string& filename, uint mode) { open(filename, mode); }
  27. ~file_map() { close(); }
  28. explicit operator bool() const { return _open; }
  29. auto size() const -> uint64_t { return _size; }
  30. auto data() -> uint8_t* { return _data; }
  31. auto data() const -> const uint8_t* { return _data; }
  32. //auto operator=(file_map&& source) -> file_map&;
  33. //auto open(const string& filename, uint mode) -> bool;
  34. //auto close() -> void;
  35. private:
  36. bool _open = false; //zero-byte files return _data = nullptr, _size = 0
  37. uint8_t* _data = nullptr;
  38. uint64_t _size = 0;
  39. #if defined(API_WINDOWS)
  40. HANDLE _file = INVALID_HANDLE_VALUE;
  41. HANDLE _map = INVALID_HANDLE_VALUE;
  42. public:
  43. auto operator=(file_map&& source) -> file_map& {
  44. _open = source._open;
  45. _data = source._data;
  46. _size = source._size;
  47. _file = source._file;
  48. _map = source._map;
  49. source._open = false;
  50. source._data = nullptr;
  51. source._size = 0;
  52. source._file = INVALID_HANDLE_VALUE;
  53. source._map = INVALID_HANDLE_VALUE;
  54. return *this;
  55. }
  56. auto open(const string& filename, uint mode_) -> bool {
  57. close();
  58. if(file::exists(filename) && file::size(filename) == 0) return _open = true;
  59. int desiredAccess, creationDisposition, protection, mapAccess;
  60. switch(mode_) {
  61. default: return false;
  62. case mode::read:
  63. desiredAccess = GENERIC_READ;
  64. creationDisposition = OPEN_EXISTING;
  65. protection = PAGE_READONLY;
  66. mapAccess = FILE_MAP_READ;
  67. break;
  68. case mode::write:
  69. //write access requires read access
  70. desiredAccess = GENERIC_WRITE;
  71. creationDisposition = CREATE_ALWAYS;
  72. protection = PAGE_READWRITE;
  73. mapAccess = FILE_MAP_ALL_ACCESS;
  74. break;
  75. case mode::modify:
  76. desiredAccess = GENERIC_READ | GENERIC_WRITE;
  77. creationDisposition = OPEN_EXISTING;
  78. protection = PAGE_READWRITE;
  79. mapAccess = FILE_MAP_ALL_ACCESS;
  80. break;
  81. case mode::append:
  82. desiredAccess = GENERIC_READ | GENERIC_WRITE;
  83. creationDisposition = CREATE_NEW;
  84. protection = PAGE_READWRITE;
  85. mapAccess = FILE_MAP_ALL_ACCESS;
  86. break;
  87. }
  88. _file = CreateFileW(utf16_t(filename), desiredAccess, FILE_SHARE_READ, nullptr,
  89. creationDisposition, FILE_ATTRIBUTE_NORMAL, nullptr);
  90. if(_file == INVALID_HANDLE_VALUE) return false;
  91. _size = GetFileSize(_file, nullptr);
  92. _map = CreateFileMapping(_file, nullptr, protection, 0, _size, nullptr);
  93. if(_map == INVALID_HANDLE_VALUE) {
  94. CloseHandle(_file);
  95. _file = INVALID_HANDLE_VALUE;
  96. return false;
  97. }
  98. _data = (uint8_t*)MapViewOfFile(_map, mapAccess, 0, 0, _size);
  99. return _open = true;
  100. }
  101. auto close() -> void {
  102. if(_data) {
  103. UnmapViewOfFile(_data);
  104. _data = nullptr;
  105. }
  106. if(_map != INVALID_HANDLE_VALUE) {
  107. CloseHandle(_map);
  108. _map = INVALID_HANDLE_VALUE;
  109. }
  110. if(_file != INVALID_HANDLE_VALUE) {
  111. CloseHandle(_file);
  112. _file = INVALID_HANDLE_VALUE;
  113. }
  114. _open = false;
  115. }
  116. #else
  117. int _fd = -1;
  118. public:
  119. auto operator=(file_map&& source) -> file_map& {
  120. _open = source._open;
  121. _data = source._data;
  122. _size = source._size;
  123. _fd = source._fd;
  124. source._open = false;
  125. source._data = nullptr;
  126. source._size = 0;
  127. source._fd = -1;
  128. return *this;
  129. }
  130. auto open(const string& filename, uint mode_) -> bool {
  131. close();
  132. if(file::exists(filename) && file::size(filename) == 0) return _open = true;
  133. int openFlags = 0;
  134. int mmapFlags = 0;
  135. switch(mode_) {
  136. default: return false;
  137. case mode::read:
  138. openFlags = O_RDONLY;
  139. mmapFlags = PROT_READ;
  140. break;
  141. case mode::write:
  142. openFlags = O_RDWR | O_CREAT; //mmap() requires read access
  143. mmapFlags = PROT_WRITE;
  144. break;
  145. case mode::modify:
  146. openFlags = O_RDWR;
  147. mmapFlags = PROT_READ | PROT_WRITE;
  148. break;
  149. case mode::append:
  150. openFlags = O_RDWR | O_CREAT;
  151. mmapFlags = PROT_READ | PROT_WRITE;
  152. break;
  153. }
  154. _fd = ::open(filename, openFlags, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
  155. if(_fd < 0) return false;
  156. struct stat _stat;
  157. fstat(_fd, &_stat);
  158. _size = _stat.st_size;
  159. _data = (uint8_t*)mmap(nullptr, _size, mmapFlags, MAP_SHARED | MAP_NORESERVE, _fd, 0);
  160. if(_data == MAP_FAILED) {
  161. _data = nullptr;
  162. ::close(_fd);
  163. _fd = -1;
  164. return false;
  165. }
  166. return _open = true;
  167. }
  168. auto close() -> void {
  169. if(_data) {
  170. munmap(_data, _size);
  171. _data = nullptr;
  172. }
  173. if(_fd >= 0) {
  174. ::close(_fd);
  175. _fd = -1;
  176. }
  177. _open = false;
  178. }
  179. #endif
  180. };
  181. }