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