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