为什么从cmd.exe会话中看不到某些cygwin符号链接

问题描述

摘要:

在最新版本(2020年9月)的64位cygwin中,/bin//lib目录中的符号链接具有令人费解的功能,并且似乎与所记录的其他各个版本有所不同符号链接。问题是:

  1. 为什么它们对CMD.EXE隐藏,但在其他地方可见,不像 其他符号链接类型

  2. 是否可以创建具有相同功能的符号链接?如果可以,怎么办?

TL; DR 请参阅@matzeri的答案:SYSTEM属性设置为/bin/awk,使其对CMD.EXE会话不可见。

/bin/lib下的符号链接似乎是此处所述的两种“默认cygwin符号链接”之一:

Cygwin创建的默认符号链接是特殊解析的 Windows 10上与WSL共享的点,或包含 魔术cookie,然后是链接指向的路径。的 重解析点用于NTFS,几乎所有其他文件都使用纯文件 文件系统。 参见symbolic links

但是,/bin下的所有符号链接均已设置SYSTEM属性,而/lib下的大多数符号链接均未设置。我不知道如何在NTFS上使用魔术cookie创建符号链接。

下面是问题的长版

cygwin下有多种类型的符号链接。其他问题可以解释它们的历史,描述它们的差异以及显示如何创建它们,等等。例如:

check the difference of symlink type in cygwin

这里是有关Windows符号链接的一些历史和问题的讨论:

Symlinks on the mounted Windows directories are not compatible with native

如前所述,有一些快捷方式,连接点和符号链接,所有这些都可以从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

但是,根据我的经验,大多数符号链接在CMD.EXE会话中可见。让我们创建一个用于测试的符号链接:

$ 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可以看到这种符号链接。

似乎所有符号链接都可以像这样被取消引用:

$ 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("")
}

这是deref.sc的输出,应用于/ bin / awk和./ls-link。 (我们必须传递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,但其他Windows程序(例如基于jvm的程序)可以看到!

我最初的问题是基于一个错误的假设,即Windows程序无法看到这些新的符号链接,并且由于这是不正确的,因此剩余的问题是:

这些新的符号链接是什么,如何创建?它们真的不同吗,或者这可能是权限的副作用?以管理员身份运行CMD.EXE似乎没有任何作用。

我验证了c:/cygwin64/bin/awk在WSL会话中也是可见的,尽管考虑到jvm可以看到它们,这并不奇怪。

更新:似乎/bin/awk虽然对我们的程序可见,但java.nio.file.Files.isSymbolicLink()并不将其视为符号链接。它的内容由字符串"!<symlink>gawk.exe"组成,因此在Windows提供本机符号链接之前,它似乎是符号链接的早期cygwin实现。

除了从CMD.EXE中不可见之外,其他都没有。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)