@@ -1967,14 +1967,28 @@ open_special(const WCHAR *path, DWORD access, DWORD flags)
19671967
19681968static const WCHAR namespace_prefix [] = {L'\\' , L'\\' , L'?' , L'\\' };
19691969
1970- enum {FINAL_PATH_MAX = PATH_MAX + numberof (namespace_prefix )};
1970+ /* License: Ruby's */
1971+ /* returns 0 on failure, otherwise stores tha path in `*pathptr` and
1972+ * returns the length of that path. The path must be freed. */
1973+ static DWORD
1974+ get_handle_pathname (HANDLE fh , WCHAR * * pathptr , DWORD add )
1975+ {
1976+ DWORD len = GetFinalPathNameByHandleW (fh , NULL , 0 , 0 );
1977+ if (!len ) return 0 ;
1978+ WCHAR * path = malloc ((len + add + 1 ) * sizeof (WCHAR ));
1979+ if (!(* pathptr = path )) return 0 ;
1980+ len = GetFinalPathNameByHandleW (fh , path , len + 1 , 0 );
1981+ if (!len ) free (path );
1982+ return len ;
1983+ }
19711984
19721985/* License: Artistic or GPL */
19731986static HANDLE
19741987open_dir_handle (const WCHAR * filename , WIN32_FIND_DATAW * fd )
19751988{
19761989 HANDLE fh ;
1977- WCHAR fullname [FINAL_PATH_MAX + rb_strlen_lit ("\\*" )];
1990+ int wildcard_len = rb_strlen_lit ("\\*" );
1991+ WCHAR * fullname = 0 ;
19781992 WCHAR * p ;
19791993 int len = 0 ;
19801994
@@ -1984,21 +1998,18 @@ open_dir_handle(const WCHAR *filename, WIN32_FIND_DATAW *fd)
19841998
19851999 fh = open_special (filename , 0 , 0 );
19862000 if (fh != INVALID_HANDLE_VALUE ) {
1987- len = GetFinalPathNameByHandleW (fh , fullname , FINAL_PATH_MAX , 0 );
2001+ len = get_handle_pathname (fh , & fullname , wildcard_len );
19882002 CloseHandle (fh );
1989- if (len >= FINAL_PATH_MAX ) {
1990- errno = ENAMETOOLONG ;
1991- return INVALID_HANDLE_VALUE ;
1992- }
19932003 }
19942004 if (!len ) {
19952005 len = lstrlenW (filename );
1996- if (len >= PATH_MAX ) {
1997- errno = ENAMETOOLONG ;
1998- return INVALID_HANDLE_VALUE ;
1999- }
2006+ fullname = malloc ((len + wildcard_len + 1 ) * sizeof (WCHAR ));
2007+ if (!fullname ) return INVALID_HANDLE_VALUE ;
20002008 MEMCPY (fullname , filename , WCHAR , len );
20012009 }
2010+ else {
2011+ RUBY_ASSERT (fullname );
2012+ }
20022013 p = & fullname [len - 1 ];
20032014 if (!(isdirsep (* p ) || * p == L':' )) * ++ p = L'\\' ;
20042015 * ++ p = L'*' ;
@@ -2011,6 +2022,7 @@ open_dir_handle(const WCHAR *filename, WIN32_FIND_DATAW *fd)
20112022 if (fh == INVALID_HANDLE_VALUE ) {
20122023 errno = map_errno (GetLastError ());
20132024 }
2025+ free (fullname );
20142026 return fh ;
20152027}
20162028
@@ -5697,7 +5709,6 @@ check_valid_dir(const WCHAR *path)
56975709 WIN32_FIND_DATAW fd ;
56985710 HANDLE fh ;
56995711 WCHAR full [PATH_MAX ];
5700- WCHAR * dmy ;
57015712 WCHAR * p , * q ;
57025713
57035714 /* GetFileAttributes() determines "..." as directory. */
@@ -5713,12 +5724,20 @@ check_valid_dir(const WCHAR *path)
57135724
57145725 /* if the specified path is the root of a drive and the drive is empty, */
57155726 /* FindFirstFile() returns INVALID_HANDLE_VALUE. */
5716- if (!GetFullPathNameW (path , sizeof (full ) / sizeof (WCHAR ), full , & dmy )) {
5727+ DWORD len = GetFullPathNameW (path , numberof (full ), full , NULL );
5728+ if (len >= numberof (full )) {
5729+ WCHAR * fullpath = malloc (len * sizeof (WCHAR ));
5730+ if (!fullpath ) return -1 ;
5731+ len = GetFullPathNameW (path , len , fullpath , NULL );
5732+ if (len == 3 ) MEMCPY (full , fullpath , WCHAR , len + 1 );
5733+ free (fullpath );
5734+ }
5735+ if (!len ) {
57175736 errno = map_errno (GetLastError ());
57185737 return -1 ;
57195738 }
5720- if (full [1 ] == L':' && ! full [ 3 ] && GetDriveTypeW (full ) != DRIVE_NO_ROOT_DIR )
5721- return 0 ;
5739+ if (len == 3 && full [1 ] == L':' && GetDriveTypeW (full ) != DRIVE_NO_ROOT_DIR )
5740+ return 0 ; /* x:\ only */
57225741
57235742 fh = open_dir_handle (path , & fd );
57245743 if (fh == INVALID_HANDLE_VALUE )
@@ -5757,8 +5776,11 @@ stat_by_find(const WCHAR *path, struct stati128 *st)
57575776static int
57585777path_drive (const WCHAR * path )
57595778{
5760- return (iswalpha (path [0 ]) && path [1 ] == L':' ) ?
5761- towupper (path [0 ]) - L'A' : _getdrive () - 1 ;
5779+ if (path [0 ] && path [1 ] == L':' ) {
5780+ if (iswalpha (path [0 ])) return towupper (path [0 ]) - L'A' ;
5781+ return (int )path [0 ];
5782+ }
5783+ return _getdrive () - 1 ;
57625784}
57635785
57645786/* License: Ruby's */
@@ -5767,7 +5789,7 @@ winnt_stat(const WCHAR *path, struct stati128 *st, BOOL lstat)
57675789{
57685790 DWORD flags = lstat ? FILE_FLAG_OPEN_REPARSE_POINT : 0 ;
57695791 HANDLE f ;
5770- WCHAR finalname [ PATH_MAX ] ;
5792+ WCHAR * finalname = 0 ;
57715793 int open_error ;
57725794
57735795 memset (st , 0 , sizeof (* st ));
@@ -5788,7 +5810,6 @@ winnt_stat(const WCHAR *path, struct stati128 *st, BOOL lstat)
57885810 }
57895811 if (f != INVALID_HANDLE_VALUE ) {
57905812 DWORD attr = stati128_handle (f , st );
5791- const DWORD len = GetFinalPathNameByHandleW (f , finalname , numberof (finalname ), 0 );
57925813 unsigned mode = 0 ;
57935814 switch (GetFileType (f )) {
57945815 case FILE_TYPE_CHAR :
@@ -5798,6 +5819,9 @@ winnt_stat(const WCHAR *path, struct stati128 *st, BOOL lstat)
57985819 mode = S_IFIFO ;
57995820 break ;
58005821 default :
5822+ if (attr & FILE_ATTRIBUTE_DIRECTORY ) {
5823+ if (check_valid_dir (path )) return -1 ;
5824+ }
58015825 if (attr & FILE_ATTRIBUTE_REPARSE_POINT ) {
58025826 FILE_ATTRIBUTE_TAG_INFO attr_info ;
58035827 DWORD e ;
@@ -5818,13 +5842,10 @@ winnt_stat(const WCHAR *path, struct stati128 *st, BOOL lstat)
58185842 }
58195843 }
58205844 }
5845+ const DWORD len = get_handle_pathname (f , & finalname , 0 );
58215846 CloseHandle (f );
5822- if (attr & FILE_ATTRIBUTE_DIRECTORY ) {
5823- if (check_valid_dir (path )) return -1 ;
5824- }
58255847 st -> st_mode = fileattr_to_unixmode (attr , path , mode );
58265848 if (len ) {
5827- finalname [min (len , numberof (finalname )- 1 )] = L'\0' ;
58285849 path = finalname ;
58295850 if (wcsncmp (path , namespace_prefix , numberof (namespace_prefix )) == 0 )
58305851 path += numberof (namespace_prefix );
@@ -5841,6 +5862,7 @@ winnt_stat(const WCHAR *path, struct stati128 *st, BOOL lstat)
58415862 }
58425863
58435864 st -> st_dev = st -> st_rdev = path_drive (path );
5865+ if (finalname ) free (finalname );
58445866
58455867 return 0 ;
58465868}
0 commit comments