@@ -404,7 +404,7 @@ int mingw_mkdir(const char *path, int mode)
404
404
int ret ;
405
405
wchar_t wpath [MAX_PATH ];
406
406
407
- if (!is_valid_win32_path (path )) {
407
+ if (!is_valid_win32_path (path , 0 )) {
408
408
errno = EINVAL ;
409
409
return -1 ;
410
410
}
@@ -490,21 +490,21 @@ int mingw_open (const char *filename, int oflags, ...)
490
490
mode = va_arg (args , int );
491
491
va_end (args );
492
492
493
- if (!is_valid_win32_path (filename )) {
493
+ if (!is_valid_win32_path (filename , ! create )) {
494
494
errno = create ? EINVAL : ENOENT ;
495
495
return -1 ;
496
496
}
497
497
498
- if (filename && !strcmp (filename , "/dev/null" ))
499
- filename = "nul" ;
500
-
501
498
if ((oflags & O_APPEND ) && !is_local_named_pipe_path (filename ))
502
499
open_fn = mingw_open_append ;
503
500
else
504
501
open_fn = _wopen ;
505
502
506
- if (xutftowcs_path (wfilename , filename ) < 0 )
503
+ if (filename && !strcmp (filename , "/dev/null" ))
504
+ wcscpy (wfilename , L"nul" );
505
+ else if (xutftowcs_path (wfilename , filename ) < 0 )
507
506
return -1 ;
507
+
508
508
fd = open_fn (wfilename , oflags , mode );
509
509
510
510
if (fd < 0 && (oflags & O_ACCMODE ) != O_RDONLY && errno == EACCES ) {
@@ -561,16 +561,18 @@ FILE *mingw_fopen (const char *filename, const char *otype)
561
561
int hide = needs_hiding (filename );
562
562
FILE * file ;
563
563
wchar_t wfilename [MAX_PATH ], wotype [4 ];
564
- if (!is_valid_win32_path (filename )) {
564
+ if (filename && !strcmp (filename , "/dev/null" ))
565
+ wcscpy (wfilename , L"nul" );
566
+ else if (!is_valid_win32_path (filename , 1 )) {
565
567
int create = otype && strchr (otype , 'w' );
566
568
errno = create ? EINVAL : ENOENT ;
567
569
return NULL ;
568
- }
569
- if (filename && !strcmp (filename , "/dev/null" ))
570
- filename = "nul" ;
571
- if (xutftowcs_path (wfilename , filename ) < 0 ||
572
- xutftowcs (wotype , otype , ARRAY_SIZE (wotype )) < 0 )
570
+ } else if (xutftowcs_path (wfilename , filename ) < 0 )
573
571
return NULL ;
572
+
573
+ if (xutftowcs (wotype , otype , ARRAY_SIZE (wotype )) < 0 )
574
+ return NULL ;
575
+
574
576
if (hide && !access (filename , F_OK ) && set_hidden_flag (wfilename , 0 )) {
575
577
error ("could not unhide %s" , filename );
576
578
return NULL ;
@@ -588,16 +590,18 @@ FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream)
588
590
int hide = needs_hiding (filename );
589
591
FILE * file ;
590
592
wchar_t wfilename [MAX_PATH ], wotype [4 ];
591
- if (!is_valid_win32_path (filename )) {
593
+ if (filename && !strcmp (filename , "/dev/null" ))
594
+ wcscpy (wfilename , L"nul" );
595
+ else if (!is_valid_win32_path (filename , 1 )) {
592
596
int create = otype && strchr (otype , 'w' );
593
597
errno = create ? EINVAL : ENOENT ;
594
598
return NULL ;
595
- }
596
- if (filename && !strcmp (filename , "/dev/null" ))
597
- filename = "nul" ;
598
- if (xutftowcs_path (wfilename , filename ) < 0 ||
599
- xutftowcs (wotype , otype , ARRAY_SIZE (wotype )) < 0 )
599
+ } else if (xutftowcs_path (wfilename , filename ) < 0 )
600
+ return NULL ;
601
+
602
+ if (xutftowcs (wotype , otype , ARRAY_SIZE (wotype )) < 0 )
600
603
return NULL ;
604
+
601
605
if (hide && !access (filename , F_OK ) && set_hidden_flag (wfilename , 0 )) {
602
606
error ("could not unhide %s" , filename );
603
607
return NULL ;
@@ -2529,14 +2533,16 @@ static void setup_windows_environment(void)
2529
2533
}
2530
2534
}
2531
2535
2532
- int is_valid_win32_path (const char * path )
2536
+ int is_valid_win32_path (const char * path , int allow_literal_nul )
2533
2537
{
2538
+ const char * p = path ;
2534
2539
int preceding_space_or_period = 0 , i = 0 , periods = 0 ;
2535
2540
2536
2541
if (!protect_ntfs )
2537
2542
return 1 ;
2538
2543
2539
2544
skip_dos_drive_prefix ((char * * )& path );
2545
+ goto segment_start ;
2540
2546
2541
2547
for (;;) {
2542
2548
char c = * (path ++ );
@@ -2551,7 +2557,83 @@ int is_valid_win32_path(const char *path)
2551
2557
return 1 ;
2552
2558
2553
2559
i = periods = preceding_space_or_period = 0 ;
2554
- continue ;
2560
+
2561
+ segment_start :
2562
+ switch (* path ) {
2563
+ case 'a' : case 'A' : /* AUX */
2564
+ if (((c = path [++ i ]) != 'u' && c != 'U' ) ||
2565
+ ((c = path [++ i ]) != 'x' && c != 'X' )) {
2566
+ not_a_reserved_name :
2567
+ path += i ;
2568
+ continue ;
2569
+ }
2570
+ break ;
2571
+ case 'c' : case 'C' : /* COM<N>, CON, CONIN$, CONOUT$ */
2572
+ if ((c = path [++ i ]) != 'o' && c != 'O' )
2573
+ goto not_a_reserved_name ;
2574
+ c = path [++ i ];
2575
+ if (c == 'm' || c == 'M' ) { /* COM<N> */
2576
+ if (!isdigit (path [++ i ]))
2577
+ goto not_a_reserved_name ;
2578
+ } else if (c == 'n' || c == 'N' ) { /* CON */
2579
+ c = path [i + 1 ];
2580
+ if ((c == 'i' || c == 'I' ) &&
2581
+ ((c = path [i + 2 ]) == 'n' ||
2582
+ c == 'N' ) &&
2583
+ path [i + 3 ] == '$' )
2584
+ i += 3 ; /* CONIN$ */
2585
+ else if ((c == 'o' || c == 'O' ) &&
2586
+ ((c = path [i + 2 ]) == 'u' ||
2587
+ c == 'U' ) &&
2588
+ ((c = path [i + 3 ]) == 't' ||
2589
+ c == 'T' ) &&
2590
+ path [i + 4 ] == '$' )
2591
+ i += 4 ; /* CONOUT$ */
2592
+ } else
2593
+ goto not_a_reserved_name ;
2594
+ break ;
2595
+ case 'l' : case 'L' : /* LPT<N> */
2596
+ if (((c = path [++ i ]) != 'p' && c != 'P' ) ||
2597
+ ((c = path [++ i ]) != 't' && c != 'T' ) ||
2598
+ !isdigit (path [++ i ]))
2599
+ goto not_a_reserved_name ;
2600
+ break ;
2601
+ case 'n' : case 'N' : /* NUL */
2602
+ if (((c = path [++ i ]) != 'u' && c != 'U' ) ||
2603
+ ((c = path [++ i ]) != 'l' && c != 'L' ) ||
2604
+ (allow_literal_nul &&
2605
+ !path [i + 1 ] && p == path ))
2606
+ goto not_a_reserved_name ;
2607
+ break ;
2608
+ case 'p' : case 'P' : /* PRN */
2609
+ if (((c = path [++ i ]) != 'r' && c != 'R' ) ||
2610
+ ((c = path [++ i ]) != 'n' && c != 'N' ))
2611
+ goto not_a_reserved_name ;
2612
+ break ;
2613
+ default :
2614
+ continue ;
2615
+ }
2616
+
2617
+ /*
2618
+ * So far, this looks like a reserved name. Let's see
2619
+ * whether it actually is one: trailing spaces, a file
2620
+ * extension, or an NTFS Alternate Data Stream do not
2621
+ * matter, the name is still reserved if any of those
2622
+ * follow immediately after the actual name.
2623
+ */
2624
+ i ++ ;
2625
+ if (path [i ] == ' ' ) {
2626
+ preceding_space_or_period = 1 ;
2627
+ while (path [++ i ] == ' ' )
2628
+ ; /* skip all spaces */
2629
+ }
2630
+
2631
+ c = path [i ];
2632
+ if (c && c != '.' && c != ':' && c != '/' && c != '\\' )
2633
+ goto not_a_reserved_name ;
2634
+
2635
+ /* contains reserved name */
2636
+ return 0 ;
2555
2637
case '.' :
2556
2638
periods ++ ;
2557
2639
/* fallthru */
0 commit comments