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