@@ -416,7 +416,7 @@ int mingw_mkdir(const char *path, int mode)
416
416
int ret ;
417
417
wchar_t wpath [MAX_PATH ];
418
418
419
- if (!is_valid_win32_path (path )) {
419
+ if (!is_valid_win32_path (path , 0 )) {
420
420
errno = EINVAL ;
421
421
return -1 ;
422
422
}
@@ -513,21 +513,21 @@ int mingw_open (const char *filename, int oflags, ...)
513
513
mode = va_arg (args , int );
514
514
va_end (args );
515
515
516
- if (!is_valid_win32_path (filename )) {
516
+ if (!is_valid_win32_path (filename , ! create )) {
517
517
errno = create ? EINVAL : ENOENT ;
518
518
return -1 ;
519
519
}
520
520
521
- if (filename && !strcmp (filename , "/dev/null" ))
522
- filename = "nul" ;
523
-
524
521
if ((oflags & O_APPEND ) && !is_local_named_pipe_path (filename ))
525
522
open_fn = mingw_open_append ;
526
523
else
527
524
open_fn = _wopen ;
528
525
529
- if (xutftowcs_path (wfilename , filename ) < 0 )
526
+ if (filename && !strcmp (filename , "/dev/null" ))
527
+ wcscpy (wfilename , L"nul" );
528
+ else if (xutftowcs_path (wfilename , filename ) < 0 )
530
529
return -1 ;
530
+
531
531
fd = open_fn (wfilename , oflags , mode );
532
532
533
533
if (fd < 0 && (oflags & O_ACCMODE ) != O_RDONLY && errno == EACCES ) {
@@ -584,16 +584,18 @@ FILE *mingw_fopen (const char *filename, const char *otype)
584
584
int hide = needs_hiding (filename );
585
585
FILE * file ;
586
586
wchar_t wfilename [MAX_PATH ], wotype [4 ];
587
- if (!is_valid_win32_path (filename )) {
587
+ if (filename && !strcmp (filename , "/dev/null" ))
588
+ wcscpy (wfilename , L"nul" );
589
+ else if (!is_valid_win32_path (filename , 1 )) {
588
590
int create = otype && strchr (otype , 'w' );
589
591
errno = create ? EINVAL : ENOENT ;
590
592
return NULL ;
591
- }
592
- if (filename && !strcmp (filename , "/dev/null" ))
593
- filename = "nul" ;
594
- if (xutftowcs_path (wfilename , filename ) < 0 ||
595
- xutftowcs (wotype , otype , ARRAY_SIZE (wotype )) < 0 )
593
+ } else if (xutftowcs_path (wfilename , filename ) < 0 )
596
594
return NULL ;
595
+
596
+ if (xutftowcs (wotype , otype , ARRAY_SIZE (wotype )) < 0 )
597
+ return NULL ;
598
+
597
599
if (hide && !access (filename , F_OK ) && set_hidden_flag (wfilename , 0 )) {
598
600
error ("could not unhide %s" , filename );
599
601
return NULL ;
@@ -611,16 +613,18 @@ FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream)
611
613
int hide = needs_hiding (filename );
612
614
FILE * file ;
613
615
wchar_t wfilename [MAX_PATH ], wotype [4 ];
614
- if (!is_valid_win32_path (filename )) {
616
+ if (filename && !strcmp (filename , "/dev/null" ))
617
+ wcscpy (wfilename , L"nul" );
618
+ else if (!is_valid_win32_path (filename , 1 )) {
615
619
int create = otype && strchr (otype , 'w' );
616
620
errno = create ? EINVAL : ENOENT ;
617
621
return NULL ;
618
- }
619
- if (filename && !strcmp (filename , "/dev/null" ))
620
- filename = "nul" ;
621
- if (xutftowcs_path (wfilename , filename ) < 0 ||
622
- xutftowcs (wotype , otype , ARRAY_SIZE (wotype )) < 0 )
622
+ } else if (xutftowcs_path (wfilename , filename ) < 0 )
623
+ return NULL ;
624
+
625
+ if (xutftowcs (wotype , otype , ARRAY_SIZE (wotype )) < 0 )
623
626
return NULL ;
627
+
624
628
if (hide && !access (filename , F_OK ) && set_hidden_flag (wfilename , 0 )) {
625
629
error ("could not unhide %s" , filename );
626
630
return NULL ;
@@ -2741,14 +2745,16 @@ static void setup_windows_environment(void)
2741
2745
}
2742
2746
}
2743
2747
2744
- int is_valid_win32_path (const char * path )
2748
+ int is_valid_win32_path (const char * path , int allow_literal_nul )
2745
2749
{
2750
+ const char * p = path ;
2746
2751
int preceding_space_or_period = 0 , i = 0 , periods = 0 ;
2747
2752
2748
2753
if (!protect_ntfs )
2749
2754
return 1 ;
2750
2755
2751
2756
skip_dos_drive_prefix ((char * * )& path );
2757
+ goto segment_start ;
2752
2758
2753
2759
for (;;) {
2754
2760
char c = * (path ++ );
@@ -2763,7 +2769,83 @@ int is_valid_win32_path(const char *path)
2763
2769
return 1 ;
2764
2770
2765
2771
i = periods = preceding_space_or_period = 0 ;
2766
- continue ;
2772
+
2773
+ segment_start :
2774
+ switch (* path ) {
2775
+ case 'a' : case 'A' : /* AUX */
2776
+ if (((c = path [++ i ]) != 'u' && c != 'U' ) ||
2777
+ ((c = path [++ i ]) != 'x' && c != 'X' )) {
2778
+ not_a_reserved_name :
2779
+ path += i ;
2780
+ continue ;
2781
+ }
2782
+ break ;
2783
+ case 'c' : case 'C' : /* COM<N>, CON, CONIN$, CONOUT$ */
2784
+ if ((c = path [++ i ]) != 'o' && c != 'O' )
2785
+ goto not_a_reserved_name ;
2786
+ c = path [++ i ];
2787
+ if (c == 'm' || c == 'M' ) { /* COM<N> */
2788
+ if (!isdigit (path [++ i ]))
2789
+ goto not_a_reserved_name ;
2790
+ } else if (c == 'n' || c == 'N' ) { /* CON */
2791
+ c = path [i + 1 ];
2792
+ if ((c == 'i' || c == 'I' ) &&
2793
+ ((c = path [i + 2 ]) == 'n' ||
2794
+ c == 'N' ) &&
2795
+ path [i + 3 ] == '$' )
2796
+ i += 3 ; /* CONIN$ */
2797
+ else if ((c == 'o' || c == 'O' ) &&
2798
+ ((c = path [i + 2 ]) == 'u' ||
2799
+ c == 'U' ) &&
2800
+ ((c = path [i + 3 ]) == 't' ||
2801
+ c == 'T' ) &&
2802
+ path [i + 4 ] == '$' )
2803
+ i += 4 ; /* CONOUT$ */
2804
+ } else
2805
+ goto not_a_reserved_name ;
2806
+ break ;
2807
+ case 'l' : case 'L' : /* LPT<N> */
2808
+ if (((c = path [++ i ]) != 'p' && c != 'P' ) ||
2809
+ ((c = path [++ i ]) != 't' && c != 'T' ) ||
2810
+ !isdigit (path [++ i ]))
2811
+ goto not_a_reserved_name ;
2812
+ break ;
2813
+ case 'n' : case 'N' : /* NUL */
2814
+ if (((c = path [++ i ]) != 'u' && c != 'U' ) ||
2815
+ ((c = path [++ i ]) != 'l' && c != 'L' ) ||
2816
+ (allow_literal_nul &&
2817
+ !path [i + 1 ] && p == path ))
2818
+ goto not_a_reserved_name ;
2819
+ break ;
2820
+ case 'p' : case 'P' : /* PRN */
2821
+ if (((c = path [++ i ]) != 'r' && c != 'R' ) ||
2822
+ ((c = path [++ i ]) != 'n' && c != 'N' ))
2823
+ goto not_a_reserved_name ;
2824
+ break ;
2825
+ default :
2826
+ continue ;
2827
+ }
2828
+
2829
+ /*
2830
+ * So far, this looks like a reserved name. Let's see
2831
+ * whether it actually is one: trailing spaces, a file
2832
+ * extension, or an NTFS Alternate Data Stream do not
2833
+ * matter, the name is still reserved if any of those
2834
+ * follow immediately after the actual name.
2835
+ */
2836
+ i ++ ;
2837
+ if (path [i ] == ' ' ) {
2838
+ preceding_space_or_period = 1 ;
2839
+ while (path [++ i ] == ' ' )
2840
+ ; /* skip all spaces */
2841
+ }
2842
+
2843
+ c = path [i ];
2844
+ if (c && c != '.' && c != ':' && c != '/' && c != '\\' )
2845
+ goto not_a_reserved_name ;
2846
+
2847
+ /* contains reserved name */
2848
+ return 0 ;
2767
2849
case '.' :
2768
2850
periods ++ ;
2769
2851
/* fallthru */
0 commit comments