1 #include <string>
2 #include <cstdlib>
3 #include <sys/types.h>
4 #include <sys/stat.h>
5 #include "xr_file_system_win32.h"
6 #include "xr_string_utils.h"
7
8 using namespace xray_re;
9
create_folder(const char * path) const10 bool xr_file_system::create_folder(const char* path) const
11 {
12 if (read_only()) {
13 dbg("fs_ro: creating folder %s", path);
14 return true;
15 }
16 return CreateDirectoryA(path, NULL) != 0 ||
17 GetLastError() == ERROR_ALREADY_EXISTS;
18 }
19
create_path(const char * path) const20 bool xr_file_system::create_path(const char* path) const
21 {
22 if (read_only()) {
23 dbg("fs_ro: creating path %s", path);
24 return true;
25 }
26 char* temp = _strdup(path);
27 bool done = false;
28 for (char* p = temp; *p != 0; ++p) {
29 if (*p != '\\')
30 continue;
31 *p = 0;
32 DWORD attrs = GetFileAttributesA(temp);
33 if (attrs == INVALID_FILE_ATTRIBUTES) {
34 if (CreateDirectoryA(temp, NULL) == 0 &&
35 GetLastError() != ERROR_ALREADY_EXISTS) {
36 goto out;
37 }
38 } else if ((attrs & FILE_ATTRIBUTE_DIRECTORY) == 0) {
39 goto out;
40 }
41 *p = '\\';
42 }
43 done = CreateDirectoryA(temp, NULL) != 0 || GetLastError() == ERROR_ALREADY_EXISTS;
44 out:
45 free(temp);
46 return done;
47 }
48
split_path(const char * path,std::string * folder,std::string * name,std::string * extension)49 void xr_file_system::split_path(const char* path, std::string* folder,
50 std::string* name, std::string* extension)
51 {
52 char _drive[_MAX_DRIVE];
53 char _dir[_MAX_DIR];
54 char _name[_MAX_FNAME];
55 char _extension[_MAX_EXT];
56 #if defined(_MSC_VER) && _MSC_VER >= 1400
57 errno_t err = _splitpath_s(path,
58 _drive, sizeof(_drive),
59 _dir, sizeof(_dir),
60 _name, sizeof(_name),
61 _extension, sizeof(_extension));
62 xr_assert(!err);
63 #else
64 _splitpath(path, _drive, _dir, _name, _extension);
65 #endif
66 if (folder) {
67 folder->assign(_drive);
68 folder->append(_dir);
69 xr_strlwr(*folder);
70 }
71 if (name) {
72 name->assign(_name);
73 xr_strlwr(*name);
74 }
75 if (extension) {
76 extension->assign(_extension);
77 xr_strlwr(*extension);
78 }
79 }
80
folder_exist(const char * path)81 bool xr_file_system::folder_exist(const char* path)
82 {
83 DWORD attrs = GetFileAttributesA(path);
84 if (attrs == INVALID_FILE_ATTRIBUTES || (attrs & FILE_ATTRIBUTE_DIRECTORY) == 0)
85 return false;
86 return true;
87 }
88
file_exist(const char * path)89 bool xr_file_system::file_exist(const char* path)
90 {
91 DWORD attrs = GetFileAttributesA(path);
92 if (attrs == INVALID_FILE_ATTRIBUTES || (attrs & FILE_ATTRIBUTE_DIRECTORY) != 0)
93 return false;
94 return true;
95 }
96
file_length(const char * path)97 size_t xr_file_system::file_length(const char* path)
98 {
99 HANDLE h = CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, NULL,
100 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
101 if (h == INVALID_HANDLE_VALUE)
102 return 0;
103 size_t length = 0;
104 LARGE_INTEGER size64;
105 if (GetFileSizeEx(h, &size64) && size64.HighPart == 0)
106 length = size64.LowPart;
107 CloseHandle(h);
108 return length;
109 }
110
file_age(const char * path)111 uint32_t xr_file_system::file_age(const char* path)
112 {
113 #if 1
114 #ifdef _MSC_VER
115 struct _stat32 st;
116 if (_stat32(path, &st) == 0)
117 #else
118 struct _stat st;
119 if (_stat(path, &st) == 0)
120 #endif
121 return uint32_t(st.st_mtime);
122 return 0;
123 #else
124 union temp_time {
125 FILETIME ft;
126 uint64_t nsec;
127 };
128 HANDLE h = CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, NULL,
129 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
130 if (h == INVALID_HANDLE_VALUE)
131 return 0;
132 uint32_t age = 0;
133 temp_time time;
134 if (GetFileTime(h, NULL, NULL, &time.ft) != FALSE) {
135 SYSTEMTIME st1970;
136 st1970.wYear = 1970;
137 st1970.wMonth = 1;
138 st1970.wDayOfWeek = 0;
139 st1970.wDay = 1;
140 st1970.wHour = 0;
141 st1970.wMinute = 0;
142 st1970.wSecond = 0;
143 st1970.wMilliseconds = 0;
144 temp_time time1970;
145 SystemTimeToFileTime(&st1970, &time1970.ft);
146 age = uint32_t((time.nsec - time1970.nsec) / 10000000ul);
147 }
148 CloseHandle(h);
149 return age;
150 #endif
151 }
152
copy_file(const char * src_path,const char * tgt_path) const153 bool xr_file_system::copy_file(const char* src_path, const char* tgt_path) const
154 {
155 if (read_only()) {
156 dbg("fs_ro: copying %s to %s", src_path, tgt_path);
157 return true;
158 }
159 return CopyFileA(src_path, tgt_path, FALSE) != FALSE;
160 }
161
r_open(const char * path) const162 xr_reader* xr_file_system::r_open(const char* path) const
163 {
164 HANDLE h = CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, NULL,
165 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
166 if (h == INVALID_HANDLE_VALUE)
167 return 0;
168
169 LARGE_INTEGER size64;
170 if (!GetFileSizeEx(h, &size64) || size64.HighPart != 0) {
171 CloseHandle(h);
172 return 0;
173 }
174 DWORD len = size64.LowPart;
175
176 SYSTEM_INFO si;
177 GetSystemInfo(&si);
178
179 xr_reader* r = 0;
180
181 LPVOID data;
182 if (len < si.dwAllocationGranularity) {
183 DWORD read;
184 PBYTE data = (PBYTE)malloc(len);
185 if (data != NULL) {
186 if (ReadFile(h, data, len, &read, NULL) && read == len) {
187 r = new xr_temp_reader(data, len);
188 } else {
189 free(data);
190 }
191 }
192 CloseHandle(h);
193 return r;
194 }
195
196 HANDLE h_mmap = CreateFileMapping(h, NULL, PAGE_READONLY, 0, len, NULL);
197 if (h_mmap == NULL) {
198 CloseHandle(h);
199 return 0;
200 }
201
202 data = MapViewOfFile(h_mmap, FILE_MAP_READ, 0, 0, len);
203 if (data != NULL) {
204 r = new xr_mmap_reader_win32(h, h_mmap, data, len);
205 if (r)
206 return r;
207 UnmapViewOfFile(data);
208 }
209
210 CloseHandle(h_mmap);
211 CloseHandle(h);
212
213 return 0;
214 }
215
w_open(const char * path,bool ignore_ro) const216 xr_writer* xr_file_system::w_open(const char* path, bool ignore_ro) const
217 {
218 if (!ignore_ro && read_only()) {
219 dbg("fs_ro: writing %s", path);
220 return new xr_fake_writer();
221 }
222
223 HANDLE h = CreateFileA(path, GENERIC_WRITE, FILE_SHARE_READ, NULL,
224 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
225 //assert(h != INVALID_HANDLE_VALUE);
226 if (h == INVALID_HANDLE_VALUE) {
227 if(GetLastError() == ERROR_PATH_NOT_FOUND) {
228 std::string folder;
229 split_path(path, &folder);
230 if (!create_path(folder))
231 return 0;
232 return w_open(path, ignore_ro);
233 }
234 else
235 return 0;
236 }
237 xr_writer* w = new xr_file_writer_win32(h);
238 if (w == 0)
239 CloseHandle(h);
240 return w;
241 }
242
xr_mmap_reader_win32()243 xr_mmap_reader_win32::xr_mmap_reader_win32(): m_h(INVALID_HANDLE_VALUE), m_h_mmap(INVALID_HANDLE_VALUE) {}
244
xr_mmap_reader_win32(HANDLE h,HANDLE h_mmap,const void * data,size_t size)245 xr_mmap_reader_win32::xr_mmap_reader_win32(HANDLE h, HANDLE h_mmap, const void* data, size_t size):
246 m_h(h), m_h_mmap(h_mmap)
247 {
248 m_next = m_p = m_data = static_cast<const uint8_t*>(data);
249 m_end = m_data + size;
250 }
251
~xr_mmap_reader_win32()252 xr_mmap_reader_win32::~xr_mmap_reader_win32()
253 {
254 assert(m_data != 0);
255 assert(m_h_mmap != INVALID_HANDLE_VALUE);
256 assert(m_h != INVALID_HANDLE_VALUE);
257 UnmapViewOfFile(const_cast<uint8_t*>(m_data));
258 CloseHandle(m_h_mmap);
259 CloseHandle(m_h);
260 }
261
xr_file_writer_win32()262 xr_file_writer_win32::xr_file_writer_win32(): m_h(INVALID_HANDLE_VALUE) {}
263
xr_file_writer_win32(HANDLE h)264 xr_file_writer_win32::xr_file_writer_win32(HANDLE h): m_h(h) {}
265
~xr_file_writer_win32()266 xr_file_writer_win32::~xr_file_writer_win32()
267 {
268 CloseHandle(m_h);
269 }
270
w_raw(const void * data,size_t size)271 void xr_file_writer_win32::w_raw(const void* data, size_t size)
272 {
273 DWORD written;
274 BOOL ok = WriteFile(m_h, data, DWORD(size & MAXDWORD), &written, NULL);
275 xr_assert(ok && size == written);
276 }
277
seek(size_t pos)278 void xr_file_writer_win32::seek(size_t pos)
279 {
280 DWORD new_pos = SetFilePointer(m_h, LONG(pos & MAXLONG), NULL, FILE_BEGIN);
281 xr_assert(pos == new_pos);
282 }
283
tell()284 size_t xr_file_writer_win32::tell()
285 {
286 return SetFilePointer(m_h, 0, NULL, FILE_CURRENT);
287 }
288