1 /*************************************************************************/
2 /*  dir_access_windows.cpp                                               */
3 /*************************************************************************/
4 /*                       This file is part of:                           */
5 /*                           GODOT ENGINE                                */
6 /*                      https://godotengine.org                          */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur.                 */
9 /* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md)    */
10 /*                                                                       */
11 /* Permission is hereby granted, free of charge, to any person obtaining */
12 /* a copy of this software and associated documentation files (the       */
13 /* "Software"), to deal in the Software without restriction, including   */
14 /* without limitation the rights to use, copy, modify, merge, publish,   */
15 /* distribute, sublicense, and/or sell copies of the Software, and to    */
16 /* permit persons to whom the Software is furnished to do so, subject to */
17 /* the following conditions:                                             */
18 /*                                                                       */
19 /* The above copyright notice and this permission notice shall be        */
20 /* included in all copies or substantial portions of the Software.       */
21 /*                                                                       */
22 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
23 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
24 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
25 /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
26 /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
27 /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
28 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
29 /*************************************************************************/
30 #if defined(WINDOWS_ENABLED)
31 
32 #include "dir_access_windows.h"
33 
34 #include "os/memory.h"
35 
36 #include "print_string.h"
37 #include <stdio.h>
38 #include <wchar.h>
39 #include <windows.h>
40 
41 /*
42 
43 [03:57] <reduz> yessopie, so i dont havemak to rely on unicows
44 [03:58] <yessopie> reduz- yeah, all of the functions fail, and then you can call GetLastError () which will return 120
45 [03:58] <drumstick> CategoryApl, hehe, what? :)
46 [03:59] <CategoryApl> didn't Verona lead to some trouble
47 [03:59] <yessopie> 120 = ERROR_CALL_NOT_IMPLEMENTED
48 [03:59] <yessopie> (you can use that constant if you include winerr.h)
49 [03:59] <CategoryApl> well answer with winning a compo
50 
51 [04:02] <yessopie> if ( SetCurrentDirectoryW ( L"." ) == FALSE && GetLastError () == ERROR_CALL_NOT_IMPLEMENTED ) { use ANSI }
52 */
53 
54 struct DirAccessWindowsPrivate {
55 
56 	HANDLE h; //handle for findfirstfile
57 	WIN32_FIND_DATA f;
58 	WIN32_FIND_DATAW fu; //unicode version
59 };
60 
61 // CreateFolderAsync
62 
list_dir_begin()63 bool DirAccessWindows::list_dir_begin() {
64 
65 	_cisdir = false;
66 	_cishidden = false;
67 
68 	list_dir_end();
69 	p->h = FindFirstFileExW((current_dir + "\\*").c_str(), FindExInfoStandard, &p->fu, FindExSearchNameMatch, NULL, 0);
70 
71 	return (p->h == INVALID_HANDLE_VALUE);
72 }
73 
get_next()74 String DirAccessWindows::get_next() {
75 
76 	if (p->h == INVALID_HANDLE_VALUE)
77 		return "";
78 
79 	_cisdir = (p->fu.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
80 	_cishidden = (p->fu.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN);
81 
82 	String name = p->fu.cFileName;
83 
84 	if (FindNextFileW(p->h, &p->fu) == 0) {
85 
86 		FindClose(p->h);
87 		p->h = INVALID_HANDLE_VALUE;
88 	}
89 
90 	return name;
91 }
92 
current_is_dir() const93 bool DirAccessWindows::current_is_dir() const {
94 
95 	return _cisdir;
96 }
97 
current_is_hidden() const98 bool DirAccessWindows::current_is_hidden() const {
99 
100 	return _cishidden;
101 }
102 
list_dir_end()103 void DirAccessWindows::list_dir_end() {
104 
105 	if (p->h != INVALID_HANDLE_VALUE) {
106 
107 		FindClose(p->h);
108 		p->h = INVALID_HANDLE_VALUE;
109 	}
110 }
get_drive_count()111 int DirAccessWindows::get_drive_count() {
112 
113 	return drive_count;
114 }
get_drive(int p_drive)115 String DirAccessWindows::get_drive(int p_drive) {
116 
117 	if (p_drive < 0 || p_drive >= drive_count)
118 		return "";
119 
120 	return String::chr(drives[p_drive]) + ":";
121 }
122 
change_dir(String p_dir)123 Error DirAccessWindows::change_dir(String p_dir) {
124 
125 	GLOBAL_LOCK_FUNCTION
126 
127 	p_dir = fix_path(p_dir);
128 
129 	wchar_t real_current_dir_name[2048];
130 	GetCurrentDirectoryW(2048, real_current_dir_name);
131 	String prev_dir = real_current_dir_name;
132 
133 	SetCurrentDirectoryW(current_dir.c_str());
134 	bool worked = (SetCurrentDirectoryW(p_dir.c_str()) != 0);
135 
136 	String base = _get_root_path();
137 	if (base != "") {
138 
139 		GetCurrentDirectoryW(2048, real_current_dir_name);
140 		String new_dir;
141 		new_dir = String(real_current_dir_name).replace("\\", "/");
142 		if (!new_dir.begins_with(base)) {
143 			worked = false;
144 		}
145 	}
146 
147 	if (worked) {
148 
149 		GetCurrentDirectoryW(2048, real_current_dir_name);
150 		current_dir = real_current_dir_name; // TODO, utf8 parser
151 		current_dir = current_dir.replace("\\", "/");
152 
153 	} //else {
154 
155 	SetCurrentDirectoryW(prev_dir.c_str());
156 	//}
157 
158 	return worked ? OK : ERR_INVALID_PARAMETER;
159 }
160 
make_dir(String p_dir)161 Error DirAccessWindows::make_dir(String p_dir) {
162 
163 	GLOBAL_LOCK_FUNCTION
164 
165 	if (p_dir.is_rel_path())
166 		p_dir = get_current_dir().plus_file(p_dir);
167 
168 	p_dir = fix_path(p_dir);
169 	p_dir = p_dir.replace("/", "\\");
170 
171 	bool success;
172 	int err;
173 
174 	p_dir = "\\\\?\\" + p_dir; //done according to
175 	// https://msdn.microsoft.com/en-us/library/windows/desktop/aa363855(v=vs.85).aspx
176 
177 	success = CreateDirectoryW(p_dir.c_str(), NULL);
178 	err = GetLastError();
179 
180 	if (success) {
181 		return OK;
182 	};
183 
184 	if (err == ERROR_ALREADY_EXISTS || err == ERROR_ACCESS_DENIED) {
185 		return ERR_ALREADY_EXISTS;
186 	};
187 
188 	return ERR_CANT_CREATE;
189 }
190 
get_current_dir()191 String DirAccessWindows::get_current_dir() {
192 
193 	String base = _get_root_path();
194 	if (base != "") {
195 
196 		String bd = current_dir.replace("\\", "/").replace_first(base, "");
197 		if (bd.begins_with("/"))
198 			return _get_root_string() + bd.substr(1, bd.length());
199 		else
200 			return _get_root_string() + bd;
201 
202 	} else {
203 	}
204 
205 	return current_dir;
206 }
207 
file_exists(String p_file)208 bool DirAccessWindows::file_exists(String p_file) {
209 
210 	GLOBAL_LOCK_FUNCTION
211 
212 	if (!p_file.is_abs_path())
213 		p_file = get_current_dir().plus_file(p_file);
214 
215 	p_file = fix_path(p_file);
216 
217 	//p_file.replace("/","\\");
218 
219 	//WIN32_FILE_ATTRIBUTE_DATA    fileInfo;
220 
221 	DWORD fileAttr;
222 
223 	fileAttr = GetFileAttributesW(p_file.c_str());
224 	if (INVALID_FILE_ATTRIBUTES == fileAttr)
225 		return false;
226 
227 	return !(fileAttr & FILE_ATTRIBUTE_DIRECTORY);
228 }
229 
dir_exists(String p_dir)230 bool DirAccessWindows::dir_exists(String p_dir) {
231 
232 	GLOBAL_LOCK_FUNCTION
233 
234 	if (p_dir.is_rel_path())
235 		p_dir = get_current_dir().plus_file(p_dir);
236 
237 	p_dir = fix_path(p_dir);
238 
239 	//p_dir.replace("/","\\");
240 
241 	//WIN32_FILE_ATTRIBUTE_DATA    fileInfo;
242 
243 	DWORD fileAttr;
244 
245 	fileAttr = GetFileAttributesW(p_dir.c_str());
246 	if (INVALID_FILE_ATTRIBUTES == fileAttr)
247 		return false;
248 	return (fileAttr & FILE_ATTRIBUTE_DIRECTORY);
249 }
250 
rename(String p_path,String p_new_path)251 Error DirAccessWindows::rename(String p_path, String p_new_path) {
252 
253 	if (p_path.is_rel_path())
254 		p_path = get_current_dir().plus_file(p_path);
255 
256 	p_path = fix_path(p_path);
257 
258 	if (p_new_path.is_rel_path())
259 		p_new_path = get_current_dir().plus_file(p_new_path);
260 
261 	p_new_path = fix_path(p_new_path);
262 
263 	if (file_exists(p_new_path)) {
264 		if (remove(p_new_path) != OK) {
265 			return FAILED;
266 		};
267 	};
268 
269 	return ::_wrename(p_path.c_str(), p_new_path.c_str()) == 0 ? OK : FAILED;
270 }
271 
remove(String p_path)272 Error DirAccessWindows::remove(String p_path) {
273 
274 	if (p_path.is_rel_path())
275 		p_path = get_current_dir().plus_file(p_path);
276 
277 	p_path = fix_path(p_path);
278 
279 	printf("erasing %s\n", p_path.utf8().get_data());
280 	//WIN32_FILE_ATTRIBUTE_DATA    fileInfo;
281 	//DWORD fileAttr = GetFileAttributesExW(p_path.c_str(), GetFileExInfoStandard, &fileInfo);
282 
283 	DWORD fileAttr;
284 
285 	fileAttr = GetFileAttributesW(p_path.c_str());
286 	if (INVALID_FILE_ATTRIBUTES == fileAttr)
287 		return FAILED;
288 	if ((fileAttr & FILE_ATTRIBUTE_DIRECTORY))
289 		return ::_wrmdir(p_path.c_str()) == 0 ? OK : FAILED;
290 	else
291 		return ::_wunlink(p_path.c_str()) == 0 ? OK : FAILED;
292 }
293 /*
294 
295 FileType DirAccessWindows::get_file_type(const String& p_file) const {
296 
297 
298 	wchar_t real_current_dir_name[2048];
299 	GetCurrentDirectoryW(2048,real_current_dir_name);
300 	String prev_dir=real_current_dir_name;
301 
302 	bool worked SetCurrentDirectoryW(current_dir.c_str());
303 
304 	DWORD attr;
305 	if (worked) {
306 
307 		WIN32_FILE_ATTRIBUTE_DATA    fileInfo;
308 		attr = GetFileAttributesExW(p_file.c_str(), GetFileExInfoStandard, &fileInfo);
309 
310 	}
311 
312 	SetCurrentDirectoryW(prev_dir.c_str());
313 
314 	if (!worked)
315 		return FILE_TYPE_NONE;
316 
317 
318 	return (attr&FILE_ATTRIBUTE_DIRECTORY)?FILE_TYPE_
319 }
320 */
get_space_left()321 size_t DirAccessWindows::get_space_left() {
322 
323 	uint64_t bytes = 0;
324 	if (!GetDiskFreeSpaceEx(NULL, (PULARGE_INTEGER)&bytes, NULL, NULL))
325 		return 0;
326 
327 	//this is either 0 or a value in bytes.
328 	return (size_t)bytes;
329 }
330 
DirAccessWindows()331 DirAccessWindows::DirAccessWindows() {
332 
333 	p = memnew(DirAccessWindowsPrivate);
334 	p->h = INVALID_HANDLE_VALUE;
335 	current_dir = ".";
336 
337 	drive_count = 0;
338 
339 #ifdef WINRT_ENABLED
340 	Windows::Storage::StorageFolder ^ install_folder = Windows::ApplicationModel::Package::Current->InstalledLocation;
341 	change_dir(install_folder->Path->Data());
342 
343 #else
344 
345 	DWORD mask = GetLogicalDrives();
346 
347 	for (int i = 0; i < MAX_DRIVES; i++) {
348 
349 		if (mask & (1 << i)) { //DRIVE EXISTS
350 
351 			drives[drive_count] = 'a' + i;
352 			drive_count++;
353 		}
354 	}
355 
356 	change_dir(".");
357 #endif
358 }
359 
~DirAccessWindows()360 DirAccessWindows::~DirAccessWindows() {
361 
362 	memdelete(p);
363 }
364 
365 #endif //windows DirAccess support
366