@@ -135,6 +135,16 @@ const char * System::GetCWD()
135
135
*/
136
136
}
137
137
138
+ static inline int Mkdir2 (const char *utf8)
139
+ {
140
+ #ifdef _MSC_VER
141
+ const std::wstring unc = System::ConvertToUNC (utf8);
142
+ return _wmkdir (unc.c_str ());
143
+ #else
144
+ return Mkdir (utf8);
145
+ #endif
146
+ }
147
+
138
148
bool System::MakeDirectory (const char *path)
139
149
{
140
150
if ( !path || !*path )
@@ -156,7 +166,7 @@ bool System::MakeDirectory(const char *path)
156
166
while (ok && (pos = dir.find (' /' , pos)) != std::string::npos)
157
167
{
158
168
topdir = dir.substr (0 , pos+1 );
159
- ok = ok && (System::FileIsDirectory (topdir.c_str ()) || 0 == Mkdir (topdir.c_str ()));
169
+ ok = ok && (System::FileIsDirectory (topdir.c_str ()) || 0 == Mkdir2 (topdir.c_str ()));
160
170
pos++;
161
171
}
162
172
if ( !ok ) return false ;
@@ -168,7 +178,7 @@ bool System::MakeDirectory(const char *path)
168
178
{
169
179
topdir = dir;
170
180
}
171
- if (Mkdir (topdir.c_str ()) != 0 )
181
+ if (Mkdir2 (topdir.c_str ()) != 0 )
172
182
{
173
183
// There is a bug in the Borland Run time library which makes MKDIR
174
184
// return EACCES when it should return EEXISTS
@@ -189,13 +199,15 @@ bool System::MakeDirectory(const char *path)
189
199
// return true if the file exists
190
200
bool System::FileExists (const char * filename)
191
201
{
192
- #ifdef _MSC_VER
193
- # define access _access
194
- #endif
195
202
#ifndef R_OK
196
203
# define R_OK 04
197
204
#endif
205
+ #ifdef _MSC_VER
206
+ const std::wstring unc = System::ConvertToUNC (filename);
207
+ if (_waccess (unc.c_str (), R_OK) != 0 )
208
+ #else
198
209
if ( access (filename, R_OK) != 0 )
210
+ #endif
199
211
{
200
212
return false ;
201
213
}
@@ -208,8 +220,14 @@ bool System::FileExists(const char* filename)
208
220
209
221
bool System::FileIsDirectory (const char * name)
210
222
{
223
+ #ifdef _MSC_VER
224
+ struct _stat64i32 fs;
225
+ const std::wstring wname = System::ConvertToUNC (name);
226
+ if (_wstat (wname.c_str (), &fs) == 0 )
227
+ #else
211
228
struct stat fs;
212
229
if (stat (name, &fs) == 0 )
230
+ #endif
213
231
{
214
232
#if _WIN32
215
233
return ((fs.st_mode & _S_IFDIR) != 0 );
@@ -366,6 +384,83 @@ bool System::DeleteDirectory(const char *source)
366
384
#define PATH_MAX 4096
367
385
#endif
368
386
387
+ #ifdef _MSC_VER
388
+ namespace {
389
+ static inline std::wstring ToUtf16 (std::string const &str) {
390
+ std::wstring ret;
391
+ int len = MultiByteToWideChar (CP_UTF8, 0 , str.c_str (), (int )str.length (),
392
+ nullptr , 0 );
393
+ if (len > 0 ) {
394
+ ret.resize (len);
395
+ MultiByteToWideChar (CP_UTF8, 0 , str.c_str (), (int )str.length (), &ret[0 ],
396
+ len);
397
+ }
398
+ return ret;
399
+ }
400
+ // http://arsenmk.blogspot.com/2015/12/handling-long-paths-on-windows.html
401
+ static inline bool ComputeFullPath (std::wstring const &in,
402
+ std::wstring &out) {
403
+ // consider an input fileName of type PCWSTR (const wchar_t*)
404
+ const wchar_t *fileName = in.c_str ();
405
+ DWORD requiredBufferLength =
406
+ GetFullPathNameW (fileName, 0 , nullptr , nullptr );
407
+
408
+ if (0 == requiredBufferLength) // means failure
409
+ {
410
+ return false ;
411
+ }
412
+
413
+ out.resize (requiredBufferLength);
414
+ wchar_t *buffer = &out[0 ];
415
+
416
+ DWORD result =
417
+ GetFullPathNameW (fileName, requiredBufferLength, buffer, nullptr );
418
+
419
+ if (0 == result) {
420
+ return false ;
421
+ }
422
+
423
+ // buffer now contains the full path name of fileName, use it.
424
+ return true ;
425
+ }
426
+
427
+ static inline std::wstring HandleMaxPath (std::wstring const &in) {
428
+ if (in.size () >= MAX_PATH) {
429
+ std::wstring out;
430
+ bool ret = ComputeFullPath (in, out);
431
+ if (!ret) return in;
432
+ if (out.size () < 4 ) return in;
433
+ if (out[0 ] == ' \\ ' && out[1 ] == ' \\ ' && out[2 ] == ' ?' ) {
434
+ // nothing to do
435
+ } else if (out[0 ] == ' \\ ' && out[1 ] == ' \\ ' && out[2 ] != ' ?' ) {
436
+ // server path
437
+ const std::wstring prefix = LR"( \\?\UNC\)" ;
438
+ out = prefix + (out.c_str () + 2 );
439
+ } else {
440
+ // regular C:\ style path:
441
+ assert (out[1 ] == ' :' );
442
+ const std::wstring prefix = LR"( \\?\)" ;
443
+ out = prefix + out.c_str ();
444
+ }
445
+ return out;
446
+ }
447
+ return in;
448
+ }
449
+ } // namespace
450
+ #endif
451
+
452
+ std::wstring System::ConvertToUNC (const char *utf8path)
453
+ {
454
+ #ifdef _MSC_VER
455
+ const std::wstring uft16path = ToUtf16 (utf8path);
456
+ const std::wstring uncpath = HandleMaxPath (uft16path);
457
+ return uncpath;
458
+ #else
459
+ (void )utf8path;
460
+ return std::wstring ();
461
+ #endif
462
+ }
463
+
369
464
// return size of file; also returns zero if no file exists
370
465
size_t System::FileSize (const char * filename)
371
466
{
0 commit comments