@@ -393,7 +393,7 @@ int mingw_mkdir(const char *path, int mode)
393
393
int ret ;
394
394
wchar_t wpath [MAX_PATH ];
395
395
396
- if (!is_valid_win32_path (path )) {
396
+ if (!is_valid_win32_path (path , 0 )) {
397
397
errno = EINVAL ;
398
398
return -1 ;
399
399
}
@@ -479,7 +479,7 @@ int mingw_open (const char *filename, int oflags, ...)
479
479
mode = va_arg (args , int );
480
480
va_end (args );
481
481
482
- if (!is_valid_win32_path (filename )) {
482
+ if (!is_valid_win32_path (filename , ! create )) {
483
483
errno = create ? EINVAL : ENOENT ;
484
484
return -1 ;
485
485
}
@@ -550,14 +550,13 @@ FILE *mingw_fopen (const char *filename, const char *otype)
550
550
int hide = needs_hiding (filename );
551
551
FILE * file ;
552
552
wchar_t wfilename [MAX_PATH ], wotype [4 ];
553
- if (!is_valid_win32_path (filename )) {
553
+ if (filename && !strcmp (filename , "/dev/null" ))
554
+ wcscpy (wfilename , L"nul" );
555
+ else if (!is_valid_win32_path (filename , 1 )) {
554
556
int create = otype && strchr (otype , 'w' );
555
557
errno = create ? EINVAL : ENOENT ;
556
558
return NULL ;
557
- }
558
- if (filename && !strcmp (filename , "/dev/null" ))
559
- wcscpy (wfilename , L"nul" );
560
- else if (xutftowcs_path (wfilename , filename ) < 0 )
559
+ } else if (xutftowcs_path (wfilename , filename ) < 0 )
561
560
return NULL ;
562
561
563
562
if (xutftowcs (wotype , otype , ARRAY_SIZE (wotype )) < 0 )
@@ -580,14 +579,13 @@ FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream)
580
579
int hide = needs_hiding (filename );
581
580
FILE * file ;
582
581
wchar_t wfilename [MAX_PATH ], wotype [4 ];
583
- if (!is_valid_win32_path (filename )) {
582
+ if (filename && !strcmp (filename , "/dev/null" ))
583
+ wcscpy (wfilename , L"nul" );
584
+ else if (!is_valid_win32_path (filename , 1 )) {
584
585
int create = otype && strchr (otype , 'w' );
585
586
errno = create ? EINVAL : ENOENT ;
586
587
return NULL ;
587
- }
588
- if (filename && !strcmp (filename , "/dev/null" ))
589
- wcscpy (wfilename , L"nul" );
590
- else if (xutftowcs_path (wfilename , filename ) < 0 )
588
+ } else if (xutftowcs_path (wfilename , filename ) < 0 )
591
589
return NULL ;
592
590
593
591
if (xutftowcs (wotype , otype , ARRAY_SIZE (wotype )) < 0 )
@@ -2412,14 +2410,16 @@ static void setup_windows_environment(void)
2412
2410
}
2413
2411
}
2414
2412
2415
- int is_valid_win32_path (const char * path )
2413
+ int is_valid_win32_path (const char * path , int allow_literal_nul )
2416
2414
{
2415
+ const char * p = path ;
2417
2416
int preceding_space_or_period = 0 , i = 0 , periods = 0 ;
2418
2417
2419
2418
if (!protect_ntfs )
2420
2419
return 1 ;
2421
2420
2422
2421
skip_dos_drive_prefix ((char * * )& path );
2422
+ goto segment_start ;
2423
2423
2424
2424
for (;;) {
2425
2425
char c = * (path ++ );
@@ -2434,7 +2434,83 @@ int is_valid_win32_path(const char *path)
2434
2434
return 1 ;
2435
2435
2436
2436
i = periods = preceding_space_or_period = 0 ;
2437
- continue ;
2437
+
2438
+ segment_start :
2439
+ switch (* path ) {
2440
+ case 'a' : case 'A' : /* AUX */
2441
+ if (((c = path [++ i ]) != 'u' && c != 'U' ) ||
2442
+ ((c = path [++ i ]) != 'x' && c != 'X' )) {
2443
+ not_a_reserved_name :
2444
+ path += i ;
2445
+ continue ;
2446
+ }
2447
+ break ;
2448
+ case 'c' : case 'C' : /* COM<N>, CON, CONIN$, CONOUT$ */
2449
+ if ((c = path [++ i ]) != 'o' && c != 'O' )
2450
+ goto not_a_reserved_name ;
2451
+ c = path [++ i ];
2452
+ if (c == 'm' || c == 'M' ) { /* COM<N> */
2453
+ if (!isdigit (path [++ i ]))
2454
+ goto not_a_reserved_name ;
2455
+ } else if (c == 'n' || c == 'N' ) { /* CON */
2456
+ c = path [i + 1 ];
2457
+ if ((c == 'i' || c == 'I' ) &&
2458
+ ((c = path [i + 2 ]) == 'n' ||
2459
+ c == 'N' ) &&
2460
+ path [i + 3 ] == '$' )
2461
+ i += 3 ; /* CONIN$ */
2462
+ else if ((c == 'o' || c == 'O' ) &&
2463
+ ((c = path [i + 2 ]) == 'u' ||
2464
+ c == 'U' ) &&
2465
+ ((c = path [i + 3 ]) == 't' ||
2466
+ c == 'T' ) &&
2467
+ path [i + 4 ] == '$' )
2468
+ i += 4 ; /* CONOUT$ */
2469
+ } else
2470
+ goto not_a_reserved_name ;
2471
+ break ;
2472
+ case 'l' : case 'L' : /* LPT<N> */
2473
+ if (((c = path [++ i ]) != 'p' && c != 'P' ) ||
2474
+ ((c = path [++ i ]) != 't' && c != 'T' ) ||
2475
+ !isdigit (path [++ i ]))
2476
+ goto not_a_reserved_name ;
2477
+ break ;
2478
+ case 'n' : case 'N' : /* NUL */
2479
+ if (((c = path [++ i ]) != 'u' && c != 'U' ) ||
2480
+ ((c = path [++ i ]) != 'l' && c != 'L' ) ||
2481
+ (allow_literal_nul &&
2482
+ !path [i + 1 ] && p == path ))
2483
+ goto not_a_reserved_name ;
2484
+ break ;
2485
+ case 'p' : case 'P' : /* PRN */
2486
+ if (((c = path [++ i ]) != 'r' && c != 'R' ) ||
2487
+ ((c = path [++ i ]) != 'n' && c != 'N' ))
2488
+ goto not_a_reserved_name ;
2489
+ break ;
2490
+ default :
2491
+ continue ;
2492
+ }
2493
+
2494
+ /*
2495
+ * So far, this looks like a reserved name. Let's see
2496
+ * whether it actually is one: trailing spaces, a file
2497
+ * extension, or an NTFS Alternate Data Stream do not
2498
+ * matter, the name is still reserved if any of those
2499
+ * follow immediately after the actual name.
2500
+ */
2501
+ i ++ ;
2502
+ if (path [i ] == ' ' ) {
2503
+ preceding_space_or_period = 1 ;
2504
+ while (path [++ i ] == ' ' )
2505
+ ; /* skip all spaces */
2506
+ }
2507
+
2508
+ c = path [i ];
2509
+ if (c && c != '.' && c != ':' && c != '/' && c != '\\' )
2510
+ goto not_a_reserved_name ;
2511
+
2512
+ /* contains reserved name */
2513
+ return 0 ;
2438
2514
case '.' :
2439
2515
periods ++ ;
2440
2516
/* fallthru */
0 commit comments