【问题标题】:why are some cygwin symlinks not visible from a cmd.exe session为什么某些 cygwin 符号链接在 cmd.exe 会话中不可见
【发布时间】:2020-12-23 03:39:27
【问题描述】:

总结:

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

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

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

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

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

Cygwin 创建的默认符号链接要么是特殊的重解析 在 Windows 10 上与 WSL 共享的点,或包含 魔术饼干后跟链接指向的路径。这 重解析点在 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 不可见,所以我猜想它们对任何其他窗口(即非 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。 (我们必须通过 /bin/awk 的 windows 可见版本)

$ 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 程序无法看到这些新符号链接的错误假设,由于这不正确,剩余的问题是:

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

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

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

除了在 CMD.EXE 中不可见之外,其他没什么特别的。

【问题讨论】:

  • awk 是一个带有System Windows 属性的普通文件,因此默认情况下是隐藏的。使用dir /A 显示隐藏文件。
  • 这是 cygwin 特定的符号链接。在 Windows 中,这只是一个包含 !&lt;symlink&gt;gawk.exe\0 的纯文本文件

标签: scala jvm cygwin symlink


【解决方案1】:

链接不可见的原因是因为它们的文件属性

S = System 在 DOS/Windows 设计的 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

【讨论】:

    【解决方案2】:

    Cygwin 比 NTFS 对符号链接的支持要古老得多。因此,Cygwin 有自己的符号链接实现,它本质上只是一个包含文本 !&lt;symlink&gt;gawk.exe 并以 ASCII NUL 字符结尾的文本文件。

    【讨论】:

    • 第一个字符实际上是一个感叹号:"!&lt;symlink&gt;gawk.exe"
    【解决方案3】:

    我使用 GoodSync 将安装 Cygwin 的卷同步到 NAS。这是由更改触发的,应该在后台工作。一段时间以来(我不能准确地说是什么时候),Cygwin 安装程序似乎默认创建 Windows 本地链接(在许多情况下,不是全部)。将系统变量 CYGWIN 设置为 winsymlinks:lnk 似乎没有帮助。在系统范围的 bash 配置文件中设置它也不能解决问题。

    但是,由于无法从 Windows 应用程序正确解析这些链接(链接 /etc/alternatives/2to3 指向 /usr/bin/2to3-3.8),因此从 GoodSync 读取它们将失败 - 除了它们无法备份之外。 GoodSync 中符号链接上的“忽略”选项没有达到预期的效果(也许它只尊重真正的符号链接,而不是重新解析点 - 我已经报告了这个错误)。

    因此,我的解决方案是注意此类错误,然后使用相关路径列表运行此脚本,以修复指向旧 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 中,也存在相同的问题 - 只是没有简单的解决方案。符号链接是 Windows 本地链接,如果它们指向 Unix 样式的路径,则无法读取。除了仅诉诸相对目标路径之外,没有其他表示方法。那些(可能)也有机会被 Windows 正确解释。

    从具有此类链接的文件系统创建基于文件的 1:1 备份仍将是一项挑战。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-01-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-22
      • 1970-01-01
      • 2013-09-10
      相关资源
      最近更新 更多