mirror of
https://github.com/ruby/ruby.git
synced 2025-08-15 13:39:04 +02:00
[Bug #21177] Win32: Allow longer path name
This commit is contained in:
parent
e51411ff1f
commit
3278e3b6f3
Notes:
git
2025-03-11 16:20:38 +00:00
2 changed files with 58 additions and 23 deletions
|
@ -641,6 +641,19 @@ class TestDir < Test::Unit::TestCase
|
|||
assert_equal("C:/ruby/homepath", Dir.home)
|
||||
end;
|
||||
end
|
||||
|
||||
def test_children_long_name
|
||||
Dir.mktmpdir do |dirname|
|
||||
longest_possible_component = "b" * 255
|
||||
long_path = File.join(dirname, longest_possible_component)
|
||||
Dir.mkdir(long_path)
|
||||
File.write("#{long_path}/c", "")
|
||||
assert_equal(%w[c], Dir.children(long_path))
|
||||
ensure
|
||||
File.unlink("#{long_path}/c")
|
||||
Dir.rmdir(long_path)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_home
|
||||
|
|
|
@ -1967,14 +1967,28 @@ open_special(const WCHAR *path, DWORD access, DWORD flags)
|
|||
|
||||
static const WCHAR namespace_prefix[] = {L'\\', L'\\', L'?', L'\\'};
|
||||
|
||||
enum {FINAL_PATH_MAX = PATH_MAX + numberof(namespace_prefix)};
|
||||
/* License: Ruby's */
|
||||
/* returns 0 on failure, otherwise stores tha path in `*pathptr` and
|
||||
* returns the length of that path. The path must be freed. */
|
||||
static DWORD
|
||||
get_handle_pathname(HANDLE fh, WCHAR **pathptr, DWORD add)
|
||||
{
|
||||
DWORD len = GetFinalPathNameByHandleW(fh, NULL, 0, 0);
|
||||
if (!len) return 0;
|
||||
WCHAR *path = malloc((len + add + 1) * sizeof(WCHAR));
|
||||
if (!(*pathptr = path)) return 0;
|
||||
len = GetFinalPathNameByHandleW(fh, path, len + 1, 0);
|
||||
if (!len) free(path);
|
||||
return len;
|
||||
}
|
||||
|
||||
/* License: Artistic or GPL */
|
||||
static HANDLE
|
||||
open_dir_handle(const WCHAR *filename, WIN32_FIND_DATAW *fd)
|
||||
{
|
||||
HANDLE fh;
|
||||
WCHAR fullname[FINAL_PATH_MAX + rb_strlen_lit("\\*")];
|
||||
int wildcard_len = rb_strlen_lit("\\*");
|
||||
WCHAR *fullname = 0;
|
||||
WCHAR *p;
|
||||
int len = 0;
|
||||
|
||||
|
@ -1984,21 +1998,18 @@ open_dir_handle(const WCHAR *filename, WIN32_FIND_DATAW *fd)
|
|||
|
||||
fh = open_special(filename, 0, 0);
|
||||
if (fh != INVALID_HANDLE_VALUE) {
|
||||
len = GetFinalPathNameByHandleW(fh, fullname, FINAL_PATH_MAX, 0);
|
||||
len = get_handle_pathname(fh, &fullname, wildcard_len);
|
||||
CloseHandle(fh);
|
||||
if (len >= FINAL_PATH_MAX) {
|
||||
errno = ENAMETOOLONG;
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
}
|
||||
if (!len) {
|
||||
len = lstrlenW(filename);
|
||||
if (len >= PATH_MAX) {
|
||||
errno = ENAMETOOLONG;
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
fullname = malloc((len + wildcard_len + 1) * sizeof(WCHAR));
|
||||
if (!fullname) return INVALID_HANDLE_VALUE;
|
||||
MEMCPY(fullname, filename, WCHAR, len);
|
||||
}
|
||||
else {
|
||||
RUBY_ASSERT(fullname);
|
||||
}
|
||||
p = &fullname[len-1];
|
||||
if (!(isdirsep(*p) || *p == L':')) *++p = L'\\';
|
||||
*++p = L'*';
|
||||
|
@ -2011,6 +2022,7 @@ open_dir_handle(const WCHAR *filename, WIN32_FIND_DATAW *fd)
|
|||
if (fh == INVALID_HANDLE_VALUE) {
|
||||
errno = map_errno(GetLastError());
|
||||
}
|
||||
free(fullname);
|
||||
return fh;
|
||||
}
|
||||
|
||||
|
@ -5697,7 +5709,6 @@ check_valid_dir(const WCHAR *path)
|
|||
WIN32_FIND_DATAW fd;
|
||||
HANDLE fh;
|
||||
WCHAR full[PATH_MAX];
|
||||
WCHAR *dmy;
|
||||
WCHAR *p, *q;
|
||||
|
||||
/* GetFileAttributes() determines "..." as directory. */
|
||||
|
@ -5713,12 +5724,20 @@ check_valid_dir(const WCHAR *path)
|
|||
|
||||
/* if the specified path is the root of a drive and the drive is empty, */
|
||||
/* FindFirstFile() returns INVALID_HANDLE_VALUE. */
|
||||
if (!GetFullPathNameW(path, sizeof(full) / sizeof(WCHAR), full, &dmy)) {
|
||||
DWORD len = GetFullPathNameW(path, numberof(full), full, NULL);
|
||||
if (len >= numberof(full)) {
|
||||
WCHAR *fullpath = malloc(len * sizeof(WCHAR));
|
||||
if (!fullpath) return -1;
|
||||
len = GetFullPathNameW(path, len, fullpath, NULL);
|
||||
if (len == 3) MEMCPY(full, fullpath, WCHAR, len+1);
|
||||
free(fullpath);
|
||||
}
|
||||
if (!len) {
|
||||
errno = map_errno(GetLastError());
|
||||
return -1;
|
||||
}
|
||||
if (full[1] == L':' && !full[3] && GetDriveTypeW(full) != DRIVE_NO_ROOT_DIR)
|
||||
return 0;
|
||||
if (len == 3 && full[1] == L':' && GetDriveTypeW(full) != DRIVE_NO_ROOT_DIR)
|
||||
return 0; /* x:\ only */
|
||||
|
||||
fh = open_dir_handle(path, &fd);
|
||||
if (fh == INVALID_HANDLE_VALUE)
|
||||
|
@ -5757,8 +5776,11 @@ stat_by_find(const WCHAR *path, struct stati128 *st)
|
|||
static int
|
||||
path_drive(const WCHAR *path)
|
||||
{
|
||||
return (iswalpha(path[0]) && path[1] == L':') ?
|
||||
towupper(path[0]) - L'A' : _getdrive() - 1;
|
||||
if (path[0] && path[1] == L':') {
|
||||
if (iswalpha(path[0])) return towupper(path[0]) - L'A';
|
||||
return (int)path[0];
|
||||
}
|
||||
return _getdrive() - 1;
|
||||
}
|
||||
|
||||
/* License: Ruby's */
|
||||
|
@ -5767,7 +5789,7 @@ winnt_stat(const WCHAR *path, struct stati128 *st, BOOL lstat)
|
|||
{
|
||||
DWORD flags = lstat ? FILE_FLAG_OPEN_REPARSE_POINT : 0;
|
||||
HANDLE f;
|
||||
WCHAR finalname[PATH_MAX];
|
||||
WCHAR *finalname = 0;
|
||||
int open_error;
|
||||
|
||||
memset(st, 0, sizeof(*st));
|
||||
|
@ -5788,7 +5810,6 @@ winnt_stat(const WCHAR *path, struct stati128 *st, BOOL lstat)
|
|||
}
|
||||
if (f != INVALID_HANDLE_VALUE) {
|
||||
DWORD attr = stati128_handle(f, st);
|
||||
const DWORD len = GetFinalPathNameByHandleW(f, finalname, numberof(finalname), 0);
|
||||
unsigned mode = 0;
|
||||
switch (GetFileType(f)) {
|
||||
case FILE_TYPE_CHAR:
|
||||
|
@ -5798,6 +5819,9 @@ winnt_stat(const WCHAR *path, struct stati128 *st, BOOL lstat)
|
|||
mode = S_IFIFO;
|
||||
break;
|
||||
default:
|
||||
if (attr & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
if (check_valid_dir(path)) return -1;
|
||||
}
|
||||
if (attr & FILE_ATTRIBUTE_REPARSE_POINT) {
|
||||
FILE_ATTRIBUTE_TAG_INFO attr_info;
|
||||
DWORD e;
|
||||
|
@ -5818,13 +5842,10 @@ winnt_stat(const WCHAR *path, struct stati128 *st, BOOL lstat)
|
|||
}
|
||||
}
|
||||
}
|
||||
const DWORD len = get_handle_pathname(f, &finalname, 0);
|
||||
CloseHandle(f);
|
||||
if (attr & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
if (check_valid_dir(path)) return -1;
|
||||
}
|
||||
st->st_mode = fileattr_to_unixmode(attr, path, mode);
|
||||
if (len) {
|
||||
finalname[min(len, numberof(finalname)-1)] = L'\0';
|
||||
path = finalname;
|
||||
if (wcsncmp(path, namespace_prefix, numberof(namespace_prefix)) == 0)
|
||||
path += numberof(namespace_prefix);
|
||||
|
@ -5841,6 +5862,7 @@ winnt_stat(const WCHAR *path, struct stati128 *st, BOOL lstat)
|
|||
}
|
||||
|
||||
st->st_dev = st->st_rdev = path_drive(path);
|
||||
if (finalname) free(finalname);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue