Bug #9648
closedDir.glob('../*') shows unexpected result in a symbolic linked directory on Windows
Description
Dir.glob('../*')
shows unexpected result if current directory is a symbolic linked directory on Windows.
This issue seems to be introduced by r44802.
The following is a test case.
C:\foo>mklink /D bar V:\
symbolic link created for bar <<===>> V:\
C:\foo>cd bar
C:\foo\bar>ruby -ve "p Dir.glob('../*')"
ruby 1.9.3p392 (2013-02-22) [i386-mingw32]
["../a", "../bar"]
C:\foo\bar>\rubyinstaller\sandbox\ruby21_build\miniruby.exe -ve "p Dir.glob('../*')"
ruby 2.2.0dev (2014-02-04 trunk 45356) [x64-mingw32]
[]
C:\foo\bar>dir ..
Volume in drive C is OS
Volume Serial Number is 6629-B36B
Directory of C:\foo
2014/03/17 18:58 <DIR> .
2014/03/17 18:58 <DIR> ..
2014/03/17 18:45 6 a
2014/03/17 18:58 <SYMLINKD> bar [V:\]
1 File(s) 6 bytes
3 Dir(s) 81,915,052,032 bytes free
Updated by nobu (Nobuyoshi Nakada) over 10 years ago
- Status changed from Open to Feedback
Is there any files at V:/
?
Updated by usa (Usaku NAKAMURA) over 10 years ago
- Backport changed from 2.0.0: UNKNOWN, 2.1: UNKNOWN to 2.0.0: DONTNEED, 2.1: DONTNEED
I've tested on 1.9.3-p545, 2.0.0-p451, 2.1.1 and found they are ok.
This problem is only with trunk.
Updated by nobu (Nobuyoshi Nakada) over 10 years ago
Usaku NAKAMURA wrote:
I've tested on 1.9.3-p545, 2.0.0-p451, 2.1.1 and found they are ok.
‘OK’ means it globs as if it is a real directory but not a symlink?
This problem is only with trunk.
It doesn’t glob anything, neither the parent of the symlink, or the target?
Updated by usa (Usaku NAKAMURA) over 10 years ago
Hi,
In message "[ruby-core:62170] [ruby-trunk - Bug #9648] Dir.glob('../*') shows unexpected result in a symbolic linked directory on Windows"
on Apr.26,2014 16:22:34, nobu@ruby-lang.org wrote:
'ok' means it globs as if it is a real directory but not a symlink?
It's too difficult for me to say it in English.
C:\foo に V:\ へのsymlinkである bar (つまり C:\foo\bar) を作り、
そこに chdir した後で Dir.glob('../*') するわけですが、結果は
期待通り C:\foo の中身(V:\ でなく)を返します。
This problem is only with trunk.
It doesn't glob anything, neither the parent of the symlink, or the target?
何も返しません。なお、targetである V:\ にはparentが存在しないことは
留意すべき事項かもしれません。
ちなみに、targetを適当なディレクトリ V:\baz に変更して実行すると、
なぜかtrunkでも正しい結果(C:\fooの中身)を返します。
Regards,¶
U.Nakamura usa@garbagecollect.jp
Updated by h.shirosaki (Hiroshi Shirosaki) about 10 years ago
Nobuyoshi Nakada wrote:
Is there any files at
V:/
?
Yes, there are some files and directories at V:/
.
If no files and directories exist at V:/
, the result is same.
Updated by h.shirosaki (Hiroshi Shirosaki) about 10 years ago
- Status changed from Feedback to Assigned
- Assignee set to nobu (Nobuyoshi Nakada)
If current directory is C:\foo\bar (linked to V:), READDIR
of '.' (i.e. FindFirstFile(".\\*", &d)
) globs linked directory (V:/), but the result doesn't have '..'.
So we cannot trace parent directory.
Skipping READDIR
usage for this case solves the bug.
diff --git a/dir.c b/dir.c
index f456e8b..91a8495 100644
--- a/dir.c
+++ b/dir.c
@@ -1397,6 +1397,14 @@ glob_helper(
if (exist == NO || isdir == NO) return 0;
+ if (!(magical || recursive) && (FNM_SYSCASE && plain)) {
+ /* READDIR will not return '..' at a directory which is symbolic linked to
+ a root directory on Windows. We don't use READDIR to get '..'. */
+ struct glob_pattern *p = *beg;
+ if (p && strcmp(p->str, "..") == 0)
+ goto literally;
+ }
+
if (magical || recursive || ((FNM_SYSCASE || HAVE_HFS) && plain)) {
struct dirent *dp;
DIR *dirp;
Updated by nobu (Nobuyoshi Nakada) about 10 years ago
Hiroshi Shirosaki wrote:
If current directory is C:\foo\bar (linked to V:),
READDIR
of '.' (i.e.FindFirstFile(".\\*", &d)
) globs linked directory (V:/), but the result doesn't have '..'.
So we cannot trace parent directory.
In that case, what should it return?
- ignores it and globs as if it were not a symlink
- matches nothing, since there is no parent directory of a root directory
- treat the parent directory same as the root directory, like unixen systems
Skipping
READDIR
usage for this case solves the bug.
I'm not sure what is a "bug" yet.
+ if (!(magical || recursive) && (FNM_SYSCASE && plain)) {
This "super-root" issue is not common to all case-insensitive systems,
but seems a DOSISH centric probably.
Updated by usa (Usaku NAKAMURA) about 10 years ago
Nobuyoshi Nakada wrote:
In that case, what should it return?
- ignores it and globs as if it were not a symlink
- matches nothing, since there is no parent directory of a root directory
- treat the parent directory same as the root directory, like unixen systems
First I think it should returns the directory that the symlink exists (maybe 1 ?),
but now I think it should be 3.
Skipping
READDIR
usage for this case solves the bug.I'm not sure what is a "bug" yet.
I've not tested the patch yet, but I think there are some bugs now.
-
glob
should return the root itself for the parent of the root, like unixen. -
glob
should return the parent of the symlinked directory instead of the parent of the symlink, like unixen, too.
Updated by h.shirosaki (Hiroshi Shirosaki) about 10 years ago
Usaku NAKAMURA wrote:
Nobuyoshi Nakada wrote:
In that case, what should it return?
- ignores it and globs as if it were not a symlink
- matches nothing, since there is no parent directory of a root directory
- treat the parent directory same as the root directory, like unixen systems
First I think it should returns the directory that the symlink exists (maybe 1 ?),
but now I think it should be 3.
I thought 1. is spec on Windows because old version ruby, dir
command and FindFirstFile
behavior is same.
I agree to change behavior unixen systems.
Updated by nobu (Nobuyoshi Nakada) about 10 years ago
Unfortunately, it seems to need tools more than expected to deal with symbolic links on Windows.
So I'll fix only the empty result for the meantime.
Updated by nobu (Nobuyoshi Nakada) about 10 years ago
- Status changed from Assigned to Closed
- % Done changed from 0 to 100
Applied in changeset r45965.
dir.c: match plain names as-is
- dir.c (
glob_pattern_type
): separate names with alphabet but no
magical from plain. - dir.c (
glob_helper
): match plain names as-is to treat super-root
same as the root. [ruby-core:61552] [Bug #9648]