35
35
36
36
#include " core/config/project_settings.h"
37
37
#include " core/os/memory.h"
38
+ #include " core/os/os.h"
38
39
#include " core/string/print_string.h"
39
40
40
41
#include < stdio.h>
@@ -69,9 +70,17 @@ struct DirAccessWindowsPrivate {
69
70
};
70
71
71
72
String DirAccessWindows::fix_path (const String &p_path) const {
72
- String r_path = DirAccess::fix_path (p_path);
73
- if (r_path.is_absolute_path () && !r_path.is_network_share_path () && r_path.length () > MAX_PATH) {
74
- r_path = " \\\\ ?\\ " + r_path.replace (" /" , " \\ " );
73
+ String r_path = DirAccess::fix_path (p_path.trim_prefix (R"( \\?\)" ).replace (" \\ " , " /" ));
74
+
75
+ if (r_path.is_relative_path ()) {
76
+ r_path = current_dir.trim_prefix (R"( \\?\)" ).replace (" \\ " , " /" ).path_join (r_path);
77
+ } else if (r_path == " ." ) {
78
+ r_path = current_dir.trim_prefix (R"( \\?\)" ).replace (" \\ " , " /" );
79
+ }
80
+ r_path = r_path.simplify_path ();
81
+ r_path = r_path.replace (" /" , " \\ " );
82
+ if (!r_path.is_network_share_path () && !r_path.begins_with (R"( \\?\)" )) {
83
+ r_path = R"( \\?\)" + r_path;
75
84
}
76
85
return r_path;
77
86
}
@@ -140,28 +149,33 @@ String DirAccessWindows::get_drive(int p_drive) {
140
149
Error DirAccessWindows::change_dir (String p_dir) {
141
150
GLOBAL_LOCK_FUNCTION
142
151
143
- p_dir = fix_path (p_dir);
152
+ String dir = fix_path (p_dir);
144
153
145
- WCHAR real_current_dir_name[2048 ];
146
- GetCurrentDirectoryW (2048 , real_current_dir_name);
147
- String prev_dir = String::utf16 ((const char16_t *)real_current_dir_name);
154
+ Char16String real_current_dir_name;
155
+ size_t str_len = GetCurrentDirectoryW (0 , nullptr );
156
+ real_current_dir_name.resize (str_len + 1 );
157
+ GetCurrentDirectoryW (real_current_dir_name.size (), (LPWSTR)real_current_dir_name.ptrw ());
158
+ String prev_dir = String::utf16 ((const char16_t *)real_current_dir_name.get_data ());
148
159
149
160
SetCurrentDirectoryW ((LPCWSTR)(current_dir.utf16 ().get_data ()));
150
- bool worked = (SetCurrentDirectoryW ((LPCWSTR)(p_dir .utf16 ().get_data ())) != 0 );
161
+ bool worked = (SetCurrentDirectoryW ((LPCWSTR)(dir .utf16 ().get_data ())) != 0 );
151
162
152
163
String base = _get_root_path ();
153
164
if (!base.is_empty ()) {
154
- GetCurrentDirectoryW (2048 , real_current_dir_name);
155
- String new_dir = String::utf16 ((const char16_t *)real_current_dir_name).replace (" \\ " , " /" );
165
+ str_len = GetCurrentDirectoryW (0 , nullptr );
166
+ real_current_dir_name.resize (str_len + 1 );
167
+ GetCurrentDirectoryW (real_current_dir_name.size (), (LPWSTR)real_current_dir_name.ptrw ());
168
+ String new_dir = String::utf16 ((const char16_t *)real_current_dir_name.get_data ()).trim_prefix (R"( \\?\)" ).replace (" \\ " , " /" );
156
169
if (!new_dir.begins_with (base)) {
157
170
worked = false ;
158
171
}
159
172
}
160
173
161
174
if (worked) {
162
- GetCurrentDirectoryW (2048 , real_current_dir_name);
163
- current_dir = String::utf16 ((const char16_t *)real_current_dir_name);
164
- current_dir = current_dir.replace (" \\ " , " /" );
175
+ str_len = GetCurrentDirectoryW (0 , nullptr );
176
+ real_current_dir_name.resize (str_len + 1 );
177
+ GetCurrentDirectoryW (real_current_dir_name.size (), (LPWSTR)real_current_dir_name.ptrw ());
178
+ current_dir = String::utf16 ((const char16_t *)real_current_dir_name.get_data ());
165
179
}
166
180
167
181
SetCurrentDirectoryW ((LPCWSTR)(prev_dir.utf16 ().get_data ()));
@@ -172,25 +186,19 @@ Error DirAccessWindows::change_dir(String p_dir) {
172
186
Error DirAccessWindows::make_dir (String p_dir) {
173
187
GLOBAL_LOCK_FUNCTION
174
188
175
- p_dir = fix_path (p_dir);
176
- if (p_dir.is_relative_path ()) {
177
- p_dir = current_dir.path_join (p_dir);
178
- p_dir = fix_path (p_dir);
179
- }
180
-
181
189
if (FileAccessWindows::is_path_invalid (p_dir)) {
182
190
#ifdef DEBUG_ENABLED
183
191
WARN_PRINT (" The path :" + p_dir + " is a reserved Windows system pipe, so it can't be used for creating directories." );
184
192
#endif
185
193
return ERR_INVALID_PARAMETER;
186
194
}
187
195
188
- p_dir = p_dir. simplify_path (). replace ( " / " , " \\ " );
196
+ String dir = fix_path (p_dir );
189
197
190
198
bool success;
191
199
int err;
192
200
193
- success = CreateDirectoryW ((LPCWSTR)(p_dir .utf16 ().get_data ()), nullptr );
201
+ success = CreateDirectoryW ((LPCWSTR)(dir .utf16 ().get_data ()), nullptr );
194
202
err = GetLastError ();
195
203
196
204
if (success) {
@@ -205,9 +213,10 @@ Error DirAccessWindows::make_dir(String p_dir) {
205
213
}
206
214
207
215
String DirAccessWindows::get_current_dir (bool p_include_drive) const {
216
+ String cdir = current_dir.trim_prefix (R"( \\?\)" ).replace (" \\ " , " /" );
208
217
String base = _get_root_path ();
209
218
if (!base.is_empty ()) {
210
- String bd = current_dir. replace ( " \\ " , " / " ) .replace_first (base, " " );
219
+ String bd = cdir .replace_first (base, " " );
211
220
if (bd.begins_with (" /" )) {
212
221
return _get_root_string () + bd.substr (1 , bd.length ());
213
222
} else {
@@ -216,30 +225,25 @@ String DirAccessWindows::get_current_dir(bool p_include_drive) const {
216
225
}
217
226
218
227
if (p_include_drive) {
219
- return current_dir ;
228
+ return cdir ;
220
229
} else {
221
230
if (_get_root_string ().is_empty ()) {
222
- int pos = current_dir .find (" :" );
231
+ int pos = cdir .find (" :" );
223
232
if (pos != -1 ) {
224
- return current_dir .substr (pos + 1 );
233
+ return cdir .substr (pos + 1 );
225
234
}
226
235
}
227
- return current_dir ;
236
+ return cdir ;
228
237
}
229
238
}
230
239
231
240
bool DirAccessWindows::file_exists (String p_file) {
232
241
GLOBAL_LOCK_FUNCTION
233
242
234
- if (!p_file.is_absolute_path ()) {
235
- p_file = get_current_dir ().path_join (p_file);
236
- }
237
-
238
- p_file = fix_path (p_file);
243
+ String file = fix_path (p_file);
239
244
240
245
DWORD fileAttr;
241
-
242
- fileAttr = GetFileAttributesW ((LPCWSTR)(p_file.utf16 ().get_data ()));
246
+ fileAttr = GetFileAttributesW ((LPCWSTR)(file.utf16 ().get_data ()));
243
247
if (INVALID_FILE_ATTRIBUTES == fileAttr) {
244
248
return false ;
245
249
}
@@ -250,81 +254,74 @@ bool DirAccessWindows::file_exists(String p_file) {
250
254
bool DirAccessWindows::dir_exists (String p_dir) {
251
255
GLOBAL_LOCK_FUNCTION
252
256
253
- if (p_dir.is_relative_path ()) {
254
- p_dir = get_current_dir ().path_join (p_dir);
255
- }
256
-
257
- p_dir = fix_path (p_dir);
257
+ String dir = fix_path (p_dir);
258
258
259
259
DWORD fileAttr;
260
- fileAttr = GetFileAttributesW ((LPCWSTR)(p_dir .utf16 ().get_data ()));
260
+ fileAttr = GetFileAttributesW ((LPCWSTR)(dir .utf16 ().get_data ()));
261
261
if (INVALID_FILE_ATTRIBUTES == fileAttr) {
262
262
return false ;
263
263
}
264
264
return (fileAttr & FILE_ATTRIBUTE_DIRECTORY);
265
265
}
266
266
267
267
Error DirAccessWindows::rename (String p_path, String p_new_path) {
268
- if (p_path.is_relative_path ()) {
269
- p_path = get_current_dir ().path_join (p_path);
270
- }
271
-
272
- p_path = fix_path (p_path);
273
-
274
- if (p_new_path.is_relative_path ()) {
275
- p_new_path = get_current_dir ().path_join (p_new_path);
276
- }
277
-
278
- p_new_path = fix_path (p_new_path);
268
+ String path = fix_path (p_path);
269
+ String new_path = fix_path (p_new_path);
279
270
280
271
// If we're only changing file name case we need to do a little juggling
281
- if (p_path .to_lower () == p_new_path .to_lower ()) {
282
- if (dir_exists (p_path )) {
272
+ if (path .to_lower () == new_path .to_lower ()) {
273
+ if (dir_exists (path )) {
283
274
// The path is a dir; just rename
284
- return :: _wrename ((LPCWSTR)(p_path .utf16 ().get_data ()), (LPCWSTR)(p_new_path .utf16 ().get_data ())) = = 0 ? OK : FAILED;
275
+ return MoveFileW ((LPCWSTR)(path .utf16 ().get_data ()), (LPCWSTR)(new_path .utf16 ().get_data ())) ! = 0 ? OK : FAILED;
285
276
}
286
277
// The path is a file; juggle
287
- WCHAR tmpfile [MAX_PATH];
288
-
289
- if (!GetTempFileNameW ((LPCWSTR)(fix_path (get_current_dir ()).utf16 ().get_data ()), nullptr , 0 , tmpfile )) {
290
- return FAILED;
278
+ // Note: do not use GetTempFileNameW, it's not long path aware!
279
+ Char16String tmpfile_utf16;
280
+ uint64_t id = OS::get_singleton ()->get_ticks_usec ();
281
+ while (true ) {
282
+ tmpfile_utf16 = (path + itos (id++) + " .tmp" ).utf16 ();
283
+ HANDLE handle = CreateFileW ((LPCWSTR)tmpfile_utf16.get_data (), GENERIC_WRITE, 0 , NULL , CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
284
+ if (handle != INVALID_HANDLE_VALUE) {
285
+ CloseHandle (handle);
286
+ break ;
287
+ }
288
+ if (GetLastError () != ERROR_FILE_EXISTS && GetLastError () != ERROR_SHARING_VIOLATION) {
289
+ return FAILED;
290
+ }
291
291
}
292
292
293
- if (!::ReplaceFileW (tmpfile , (LPCWSTR)(p_path .utf16 ().get_data ()), nullptr , 0 , nullptr , nullptr )) {
294
- DeleteFileW (tmpfile );
293
+ if (!::ReplaceFileW ((LPCWSTR)tmpfile_utf16. get_data () , (LPCWSTR)(path .utf16 ().get_data ()), nullptr , 0 , nullptr , nullptr )) {
294
+ DeleteFileW ((LPCWSTR)tmpfile_utf16. get_data () );
295
295
return FAILED;
296
296
}
297
297
298
- return :: _wrename ( tmpfile , (LPCWSTR)(p_new_path .utf16 ().get_data ())) = = 0 ? OK : FAILED;
298
+ return MoveFileW ((LPCWSTR)tmpfile_utf16. get_data () , (LPCWSTR)(new_path .utf16 ().get_data ())) ! = 0 ? OK : FAILED;
299
299
300
300
} else {
301
- if (file_exists (p_new_path )) {
302
- if (remove (p_new_path ) != OK) {
301
+ if (file_exists (new_path )) {
302
+ if (remove (new_path ) != OK) {
303
303
return FAILED;
304
304
}
305
305
}
306
306
307
- return :: _wrename ((LPCWSTR)(p_path .utf16 ().get_data ()), (LPCWSTR)(p_new_path.utf16 ().get_data ())) = = 0 ? OK : FAILED;
307
+ return MoveFileW ((LPCWSTR)(path .utf16 ().get_data ()), (LPCWSTR)(p_new_path.utf16 ().get_data ())) ! = 0 ? OK : FAILED;
308
308
}
309
309
}
310
310
311
311
Error DirAccessWindows::remove (String p_path) {
312
- if (p_path.is_relative_path ()) {
313
- p_path = get_current_dir ().path_join (p_path);
314
- }
315
-
316
- p_path = fix_path (p_path);
312
+ String path = fix_path (p_path);
313
+ const Char16String &path_utf16 = path.utf16 ();
317
314
318
315
DWORD fileAttr;
319
316
320
- fileAttr = GetFileAttributesW ((LPCWSTR)(p_path. utf16 () .get_data ()));
317
+ fileAttr = GetFileAttributesW ((LPCWSTR)(path_utf16 .get_data ()));
321
318
if (INVALID_FILE_ATTRIBUTES == fileAttr) {
322
319
return FAILED;
323
320
}
324
321
if ((fileAttr & FILE_ATTRIBUTE_DIRECTORY)) {
325
- return :: _wrmdir ((LPCWSTR)(p_path. utf16 (). get_data ())) = = 0 ? OK : FAILED;
322
+ return RemoveDirectoryW ((LPCWSTR)(path_utf16. get_data ())) ! = 0 ? OK : FAILED;
326
323
} else {
327
- return :: _wunlink ((LPCWSTR)(p_path. utf16 (). get_data ())) = = 0 ? OK : FAILED;
324
+ return DeleteFileW ((LPCWSTR)(path_utf16. get_data ())) ! = 0 ? OK : FAILED;
328
325
}
329
326
}
330
327
@@ -339,16 +336,16 @@ uint64_t DirAccessWindows::get_space_left() {
339
336
}
340
337
341
338
String DirAccessWindows::get_filesystem_type () const {
342
- String path = fix_path (const_cast <DirAccessWindows *>(this )->get_current_dir ());
343
-
344
- int unit_end = path.find (" :" );
345
- ERR_FAIL_COND_V (unit_end == -1 , String ());
346
- String unit = path.substr (0 , unit_end + 1 ) + " \\ " ;
339
+ String path = current_dir.trim_prefix (R"( \\?\)" );
347
340
348
341
if (path.is_network_share_path ()) {
349
342
return " Network Share" ;
350
343
}
351
344
345
+ int unit_end = path.find (" :" );
346
+ ERR_FAIL_COND_V (unit_end == -1 , String ());
347
+ String unit = path.substr (0 , unit_end + 1 ) + " \\ " ;
348
+
352
349
WCHAR szVolumeName[100 ];
353
350
WCHAR szFileSystemName[10 ];
354
351
DWORD dwSerialNumber = 0 ;
@@ -370,11 +367,7 @@ String DirAccessWindows::get_filesystem_type() const {
370
367
}
371
368
372
369
bool DirAccessWindows::is_case_sensitive (const String &p_path) const {
373
- String f = p_path;
374
- if (!f.is_absolute_path ()) {
375
- f = get_current_dir ().path_join (f);
376
- }
377
- f = fix_path (f);
370
+ String f = fix_path (p_path);
378
371
379
372
HANDLE h_file = ::CreateFileW ((LPCWSTR)(f.utf16 ().get_data ()), 0 ,
380
373
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
@@ -397,12 +390,7 @@ bool DirAccessWindows::is_case_sensitive(const String &p_path) const {
397
390
}
398
391
399
392
bool DirAccessWindows::is_link (String p_file) {
400
- String f = p_file;
401
-
402
- if (!f.is_absolute_path ()) {
403
- f = get_current_dir ().path_join (f);
404
- }
405
- f = fix_path (f);
393
+ String f = fix_path (p_file);
406
394
407
395
DWORD attr = GetFileAttributesW ((LPCWSTR)(f.utf16 ().get_data ()));
408
396
if (attr == INVALID_FILE_ATTRIBUTES) {
@@ -413,12 +401,7 @@ bool DirAccessWindows::is_link(String p_file) {
413
401
}
414
402
415
403
String DirAccessWindows::read_link (String p_file) {
416
- String f = p_file;
417
-
418
- if (!f.is_absolute_path ()) {
419
- f = get_current_dir ().path_join (f);
420
- }
421
- f = fix_path (f);
404
+ String f = fix_path (p_file);
422
405
423
406
HANDLE hfile = CreateFileW ((LPCWSTR)(f.utf16 ().get_data ()), GENERIC_READ, FILE_SHARE_READ, nullptr , OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr );
424
407
if (hfile == INVALID_HANDLE_VALUE) {
@@ -434,22 +417,18 @@ String DirAccessWindows::read_link(String p_file) {
434
417
GetFinalPathNameByHandleW (hfile, (LPWSTR)cs.ptrw (), ret, VOLUME_NAME_DOS | FILE_NAME_NORMALIZED);
435
418
CloseHandle (hfile);
436
419
437
- return String::utf16 ((const char16_t *)cs.ptr (), ret).trim_prefix (R"( \\?\)" );
420
+ return String::utf16 ((const char16_t *)cs.ptr (), ret).trim_prefix (R"( \\?\)" ). replace ( " \\ " , " / " ) ;
438
421
}
439
422
440
423
Error DirAccessWindows::create_link (String p_source, String p_target) {
441
- if (p_target.is_relative_path ()) {
442
- p_target = get_current_dir ().path_join (p_target);
443
- }
424
+ String source = fix_path (p_source);
425
+ String target = fix_path (p_target);
444
426
445
- p_source = fix_path (p_source);
446
- p_target = fix_path (p_target);
447
-
448
- DWORD file_attr = GetFileAttributesW ((LPCWSTR)(p_source.utf16 ().get_data ()));
427
+ DWORD file_attr = GetFileAttributesW ((LPCWSTR)(source.utf16 ().get_data ()));
449
428
bool is_dir = (file_attr & FILE_ATTRIBUTE_DIRECTORY);
450
429
451
430
DWORD flags = ((is_dir) ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0 ) | SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE;
452
- if (CreateSymbolicLinkW ((LPCWSTR)p_target .utf16 ().get_data (), (LPCWSTR)p_source .utf16 ().get_data (), flags) != 0 ) {
431
+ if (CreateSymbolicLinkW ((LPCWSTR)target .utf16 ().get_data (), (LPCWSTR)source .utf16 ().get_data (), flags) != 0 ) {
453
432
return OK;
454
433
} else {
455
434
return FAILED;
@@ -459,7 +438,12 @@ Error DirAccessWindows::create_link(String p_source, String p_target) {
459
438
DirAccessWindows::DirAccessWindows () {
460
439
p = memnew (DirAccessWindowsPrivate);
461
440
p->h = INVALID_HANDLE_VALUE;
462
- current_dir = " ." ;
441
+
442
+ Char16String real_current_dir_name;
443
+ size_t str_len = GetCurrentDirectoryW (0 , nullptr );
444
+ real_current_dir_name.resize (str_len + 1 );
445
+ GetCurrentDirectoryW (real_current_dir_name.size (), (LPWSTR)real_current_dir_name.ptrw ());
446
+ current_dir = String::utf16 ((const char16_t *)real_current_dir_name.get_data ());
463
447
464
448
DWORD mask = GetLogicalDrives ();
465
449
0 commit comments