为什么某些 cygwin 符号链接在 cmd.exe 会话中不可见
why are some cygwin symlinks not visible from a cmd.exe session
总结:
在最近(2020年9月)版本的64位cygwin中,/bin/
和/lib
目录下的symlinks有令人费解的特征,似乎不同于任何其他各种记录的 symlinks。问题是:
为什么它们对 CMD.EXE 隐藏,但在其他地方可见,不像
其他符号link 类型
是否可以创建具有相同功能的符号link?如果可以,怎么做?
TL;DR
请参阅@matzeri 的回答:SYSTEM 属性在 /bin/awk
上设置,使其对 CMD.EXE 会话不可见。
/bin
和 /lib
下面的 symlinks 似乎是此处描述的两种“默认 cygwin symlinks”之一:
The default symlinks created by Cygwin are either special reparse
points shared with WSL on Windows 10, or plain files containing a
magic cookie followed by the path to which the link points. The
reparse point is used on NTFS, the plain file on almost any other
filesystem.
see symbolic links
但是,/bin
以下的所有 symlink 都设置了 SYSTEM 属性,而 /lib
以下的大部分 symlink 都没有。我不知道我是如何在 NTFS 上用 magic cookie 创建一个 symlink。
下面是问题的长版
cygwin下有多种symlink。其他问题解释了它们的历史,描述了它们的差异,并展示了如何创建它们等。例如:
check the difference of symlink type in cygwin
下面是 windows 上关于 symlink 的一些历史和问题的讨论:
Symlinks on the mounted Windows directories are not compatible with native
如前所述,有快捷方式、连接点和 symlinks,所有这些都可以从 CMD.EXE 会话中看到,如图所示。
但是,在我的64位cygwin安装下,还有一种我找不到任何解释。其中一些出现在 /bin
、/lib
以及其他地方。将它们与其他 3 个区分开来的主要特征是它们在 CMD.EXE 会话中不可见。
举个例子:
如果我尝试从 /bin 目录通过 CMD.EXE 列出 'awk',该文件似乎不存在:
$ cd /bin
$ cmd.exe /c dir awk
Volume in drive C is opt
Volume Serial Number is D0C8-EA58
Directory of C:\cygwin64\bin
File Not Found
这是 ls
的样子:
$ ls -l awk
lrwxrwxrwx 1 philwalk None 8 May 14 12:26 awk -> gawk.exe
但根据我的经验,大多数 symlink 都可以从 CMD.EXE 会话中看到。让我们创建一个 symlink 用于测试:
$ CYGWIN=winsymlinks:nativestrict # make sure we don't create an old-style symlink
$ ln -s `which ls.exe` ls-link
$ cmd.exe /c dir ls-link
Volume in drive C is opt
Volume Serial Number is D0C8-EA58
Directory of C:\opt\ue
2020-09-03 13:12 <SYMLINK> ls-link [C:\cygwin64\bin\ls.exe]
1 File(s) 0 bytes
0 Dir(s) 295,290,556,416 bytes free
这说明CMD.EXE可以看到这种类型的symlink。
似乎所有 symlink 都可以像这样取消引用:
$ cygpath -w `which awk`
C:\cygwin64\bin\gawk.exe
那么基于 windows 的程序可以解引用它们吗?它能看到它们吗?因为它们对 CMD.EXE 不可见,我猜想它们对任何其他 windows(即非 cygwin)程序都不可见。
这是一个 scala 脚本,deref.sc
,将测试这些问题:
#!/usr/bin/env scala
import java.nio.file._
for( posixPath <- args ){
val cyg = cygpath(posixPath)
val windows = Paths.get(posixPath)
val exists = Files.exists(windows)
printf("file path [%s]\n",posixPath )
printf("cygpath [%s]\n",cyg)
printf("windows [%s]\n",windows)
if( exists ){
printf("exists [%s] # visible to jvm-based programs\n",exists)
} else {
printf("exists [%s] # NOT visible to jvm-based programs\n",exists)
}
val realpath = if( exists ){
if( Files.isSymbolicLink(windows) ){
Files.readSymbolicLink(windows)
} else {
windows.toRealPath()
}
}
printf("real windows [%s]\n",realpath)
printf("\n")
}
def cygpath(posixPath:String) = {
import scala.sys.process._
Seq("cygpath.exe","-m",posixPath).lazyLines_!.mkString("")
}
这是应用于 /bin/awk 和 ./ls-link 的 deref.sc 的输出。
(我们必须通过windows-可见版本的/bin/awk)
$ deref.sc ls-link
cygpath [ls-link]
windows [.\ls-link]
exists [true] # visible to jvm-based programs
real windows [C:\cygwin64\bin\ls.exe]
$ cd /bin
$ deref.sc awk
file path [awk]
cygpath [C:/cygwin64/bin/gawk.exe]
windows [awk]
exists [true] # visible to jvm-based programs
real windows [C:\cygwin64\bin\awk]
所以这表明,虽然有些windows程序(比如CMD.EXE)看不到c:/cygwin64/bin/awk,但是其他的(比如基于jvm的程序)可以!
我最初的问题是基于 windows 程序无法看到这些新符号 link 的错误假设,由于这是不正确的,所以剩下的问题是:
这些新符号是什么link,它们是如何创建的?它们真的不同,还是这可能是权限的副作用? 运行 CMD.EXE 作为管理员似乎没有什么区别。
我验证了 c:/cygwin64/bin/awk
也可以从 WSL 会话中看到,尽管这并不奇怪,因为 jvm 可以看到它们。
更新:虽然 /bin/awk
对我们的程序可见,但 java.nio.file.Files.isSymbolicLink()
并未将其视为符号 link。它的内容由字符串 "!<symlink>gawk.exe"
组成,因此它似乎是 symlinks 的早期 cygwin 实现,在 windows 提供本机 symlinks 之前。
除了在 CMD.EXE.
中不可见外,它没什么特别的
Cygwin 比 NTFS 对符号链接的支持要老得多。因此,Cygwin 有自己的符号链接实现,它本质上只是一个包含文本 !<symlink>gawk.exe
并以 ASCII NUL
字符终止的文本文件。
链接不可见的原因是它们的文件属性
根据 DOS/Windows 设计,S = System
在 CMD 中不可见,
来自 CMD,对不起德语,我们有:
$ cmd
Microsoft Windows [Version 10.0.19041.450]
(c) 2020 Microsoft Corporation. Alle Rechte vorbehalten.
D:\cygwin64\bin>attrib zipinfo
S D:\cygwin64\bin\zipinfo
D:\cygwin64\bin>dir zipinfo
Datenträger in Laufwerk D: ist DATA
Volumeseriennummer: D603-FB6E
Verzeichnis von D:\cygwin64\bin
Datei nicht gefunden
D:\cygwin64\bin>dir /A:S zipinfo
Datenträger in Laufwerk D: ist DATA
Volumeseriennummer: D603-FB6E
Verzeichnis von D:\cygwin64\bin
19.06.2018 22:17 16 zipinfo
1 Datei(en), 16 Bytes
0 Verzeichnis(se), 542.542.495.744 Bytes frei
我使用 GoodSync 将安装 Cygwin 的卷同步到 NAS。这是由更改触发的,应该在后台运行。一段时间以来(我不能准确地说什么时候),Cygwin 安装程序似乎默认创建 Windows 本机 links(在许多情况下,不是全部)。将系统变量 CYGWIN
设置为 winsymlinks:lnk
似乎没有帮助。在系统范围 bash 配置文件中进行设置也无法解决问题。
但是,由于无法从 Windows 应用程序正确解析这些 link(link /etc/alternatives/2to3
指向 /usr/bin/2to3-3.8
),请阅读它们来自 GoodSync 的文件将失败 - 除了无法备份它们之外。 GoodSync 中符号 links 上的选项“忽略”没有达到预期的效果(也许它只尊重真正的符号 links,而不是重新分析点 - 我已经报告过那个错误)。
所以,我的解决方案是注意此类错误,然后 运行 此脚本包含涉及的路径列表,以将 link 修复回旧的 Cygwin 风格的 .lnk 文件.
#! /bin/bash
CYGWIN=winsymlinks:lnk; export CYGWIN
for file in $* ; do
if [ -L "$file" ] ; then
t="`readlink $file`"
echo "$file: symbolic link -> $t"
if [ -L "$file.lnk" ] ; then
echo " already ok"
else
rm "$file"
ln -s "$t" "$file"
echo " fixed"
fi
else
echo "$file: not a link"
fi
done
exit 0
对于初始扫描,我 运行 对整个 Cygwin 安装进行了 find / -type l -print
扫描,过滤掉了存在同名 .lnk 文件的路径,并修复了其余路径。
在 WSL 中,存在相同的问题 - 除了没有简单的解决方案。符号 links 是 Windows 原生 links,如果它们指向 Unix 风格的路径则无法读取。除了仅求助于相对目标路径之外,没有其他表示法。这些(可能)也有机会被 Windows.
正确解释
从具有此类 link 的文件系统创建基于文件的 1:1 备份仍然是一个挑战。
总结:
在最近(2020年9月)版本的64位cygwin中,/bin/
和/lib
目录下的symlinks有令人费解的特征,似乎不同于任何其他各种记录的 symlinks。问题是:
为什么它们对 CMD.EXE 隐藏,但在其他地方可见,不像 其他符号link 类型
是否可以创建具有相同功能的符号link?如果可以,怎么做?
TL;DR
请参阅@matzeri 的回答:SYSTEM 属性在 /bin/awk
上设置,使其对 CMD.EXE 会话不可见。
/bin
和 /lib
下面的 symlinks 似乎是此处描述的两种“默认 cygwin symlinks”之一:
The default symlinks created by Cygwin are either special reparse points shared with WSL on Windows 10, or plain files containing a magic cookie followed by the path to which the link points. The reparse point is used on NTFS, the plain file on almost any other filesystem. see symbolic links
但是,/bin
以下的所有 symlink 都设置了 SYSTEM 属性,而 /lib
以下的大部分 symlink 都没有。我不知道我是如何在 NTFS 上用 magic cookie 创建一个 symlink。
下面是问题的长版
cygwin下有多种symlink。其他问题解释了它们的历史,描述了它们的差异,并展示了如何创建它们等。例如:
check the difference of symlink type in cygwin
下面是 windows 上关于 symlink 的一些历史和问题的讨论:
Symlinks on the mounted Windows directories are not compatible with native
如前所述,有快捷方式、连接点和 symlinks,所有这些都可以从 CMD.EXE 会话中看到,如图所示。
但是,在我的64位cygwin安装下,还有一种我找不到任何解释。其中一些出现在 /bin
、/lib
以及其他地方。将它们与其他 3 个区分开来的主要特征是它们在 CMD.EXE 会话中不可见。
举个例子: 如果我尝试从 /bin 目录通过 CMD.EXE 列出 'awk',该文件似乎不存在:
$ cd /bin
$ cmd.exe /c dir awk
Volume in drive C is opt
Volume Serial Number is D0C8-EA58
Directory of C:\cygwin64\bin
File Not Found
这是 ls
的样子:
$ ls -l awk
lrwxrwxrwx 1 philwalk None 8 May 14 12:26 awk -> gawk.exe
但根据我的经验,大多数 symlink 都可以从 CMD.EXE 会话中看到。让我们创建一个 symlink 用于测试:
$ CYGWIN=winsymlinks:nativestrict # make sure we don't create an old-style symlink
$ ln -s `which ls.exe` ls-link
$ cmd.exe /c dir ls-link
Volume in drive C is opt
Volume Serial Number is D0C8-EA58
Directory of C:\opt\ue
2020-09-03 13:12 <SYMLINK> ls-link [C:\cygwin64\bin\ls.exe]
1 File(s) 0 bytes
0 Dir(s) 295,290,556,416 bytes free
这说明CMD.EXE可以看到这种类型的symlink。
似乎所有 symlink 都可以像这样取消引用:
$ cygpath -w `which awk`
C:\cygwin64\bin\gawk.exe
那么基于 windows 的程序可以解引用它们吗?它能看到它们吗?因为它们对 CMD.EXE 不可见,我猜想它们对任何其他 windows(即非 cygwin)程序都不可见。
这是一个 scala 脚本,deref.sc
,将测试这些问题:
#!/usr/bin/env scala
import java.nio.file._
for( posixPath <- args ){
val cyg = cygpath(posixPath)
val windows = Paths.get(posixPath)
val exists = Files.exists(windows)
printf("file path [%s]\n",posixPath )
printf("cygpath [%s]\n",cyg)
printf("windows [%s]\n",windows)
if( exists ){
printf("exists [%s] # visible to jvm-based programs\n",exists)
} else {
printf("exists [%s] # NOT visible to jvm-based programs\n",exists)
}
val realpath = if( exists ){
if( Files.isSymbolicLink(windows) ){
Files.readSymbolicLink(windows)
} else {
windows.toRealPath()
}
}
printf("real windows [%s]\n",realpath)
printf("\n")
}
def cygpath(posixPath:String) = {
import scala.sys.process._
Seq("cygpath.exe","-m",posixPath).lazyLines_!.mkString("")
}
这是应用于 /bin/awk 和 ./ls-link 的 deref.sc 的输出。 (我们必须通过windows-可见版本的/bin/awk)
$ deref.sc ls-link
cygpath [ls-link]
windows [.\ls-link]
exists [true] # visible to jvm-based programs
real windows [C:\cygwin64\bin\ls.exe]
$ cd /bin
$ deref.sc awk
file path [awk]
cygpath [C:/cygwin64/bin/gawk.exe]
windows [awk]
exists [true] # visible to jvm-based programs
real windows [C:\cygwin64\bin\awk]
所以这表明,虽然有些windows程序(比如CMD.EXE)看不到c:/cygwin64/bin/awk,但是其他的(比如基于jvm的程序)可以!
我最初的问题是基于 windows 程序无法看到这些新符号 link 的错误假设,由于这是不正确的,所以剩下的问题是:
这些新符号是什么link,它们是如何创建的?它们真的不同,还是这可能是权限的副作用? 运行 CMD.EXE 作为管理员似乎没有什么区别。
我验证了 c:/cygwin64/bin/awk
也可以从 WSL 会话中看到,尽管这并不奇怪,因为 jvm 可以看到它们。
更新:虽然 /bin/awk
对我们的程序可见,但 java.nio.file.Files.isSymbolicLink()
并未将其视为符号 link。它的内容由字符串 "!<symlink>gawk.exe"
组成,因此它似乎是 symlinks 的早期 cygwin 实现,在 windows 提供本机 symlinks 之前。
除了在 CMD.EXE.
中不可见外,它没什么特别的Cygwin 比 NTFS 对符号链接的支持要老得多。因此,Cygwin 有自己的符号链接实现,它本质上只是一个包含文本 !<symlink>gawk.exe
并以 ASCII NUL
字符终止的文本文件。
链接不可见的原因是它们的文件属性
根据 DOS/Windows 设计,S = System
在 CMD 中不可见,
来自 CMD,对不起德语,我们有:
$ cmd
Microsoft Windows [Version 10.0.19041.450]
(c) 2020 Microsoft Corporation. Alle Rechte vorbehalten.
D:\cygwin64\bin>attrib zipinfo
S D:\cygwin64\bin\zipinfo
D:\cygwin64\bin>dir zipinfo
Datenträger in Laufwerk D: ist DATA
Volumeseriennummer: D603-FB6E
Verzeichnis von D:\cygwin64\bin
Datei nicht gefunden
D:\cygwin64\bin>dir /A:S zipinfo
Datenträger in Laufwerk D: ist DATA
Volumeseriennummer: D603-FB6E
Verzeichnis von D:\cygwin64\bin
19.06.2018 22:17 16 zipinfo
1 Datei(en), 16 Bytes
0 Verzeichnis(se), 542.542.495.744 Bytes frei
我使用 GoodSync 将安装 Cygwin 的卷同步到 NAS。这是由更改触发的,应该在后台运行。一段时间以来(我不能准确地说什么时候),Cygwin 安装程序似乎默认创建 Windows 本机 links(在许多情况下,不是全部)。将系统变量 CYGWIN
设置为 winsymlinks:lnk
似乎没有帮助。在系统范围 bash 配置文件中进行设置也无法解决问题。
但是,由于无法从 Windows 应用程序正确解析这些 link(link /etc/alternatives/2to3
指向 /usr/bin/2to3-3.8
),请阅读它们来自 GoodSync 的文件将失败 - 除了无法备份它们之外。 GoodSync 中符号 links 上的选项“忽略”没有达到预期的效果(也许它只尊重真正的符号 links,而不是重新分析点 - 我已经报告过那个错误)。
所以,我的解决方案是注意此类错误,然后 运行 此脚本包含涉及的路径列表,以将 link 修复回旧的 Cygwin 风格的 .lnk 文件.
#! /bin/bash
CYGWIN=winsymlinks:lnk; export CYGWIN
for file in $* ; do
if [ -L "$file" ] ; then
t="`readlink $file`"
echo "$file: symbolic link -> $t"
if [ -L "$file.lnk" ] ; then
echo " already ok"
else
rm "$file"
ln -s "$t" "$file"
echo " fixed"
fi
else
echo "$file: not a link"
fi
done
exit 0
对于初始扫描,我 运行 对整个 Cygwin 安装进行了 find / -type l -print
扫描,过滤掉了存在同名 .lnk 文件的路径,并修复了其余路径。
在 WSL 中,存在相同的问题 - 除了没有简单的解决方案。符号 links 是 Windows 原生 links,如果它们指向 Unix 风格的路径则无法读取。除了仅求助于相对目标路径之外,没有其他表示法。这些(可能)也有机会被 Windows.
正确解释从具有此类 link 的文件系统创建基于文件的 1:1 备份仍然是一个挑战。