我想用Go覆盖一个符号链接,但我找不到怎么做。
如果我尝试创建符号链接并且它已经存在,则会返回错误。
我的代码:
err := os.Symlink(filePath, symlinkPath)
if err != nil {
fmt.Println(err)
}
我想必须删除符号链接,然后重新创建。是对的吗?如果是这样,我该如何取消链接符号链接?
答案 0 :(得分:5)
只需检查符号链接是否存在并在创建新符号之前将其删除
if _, err := os.Lstat(symlinkPath); err == nil {
os.Remove(symlinkPath)
}
答案 1 :(得分:2)
请注意,@ Vadyus的答案在运行lstat时隐藏了实际的文件系统错误。例如,如果磁盘损坏并且Lstat发生故障,您仍将运行os.Remove并忽略其错误(“ DANGEROUS”,除非您想调试几个小时才能看到)。
以下代码片段可正确检查文件是否存在以及其他错误:
if _, err := os.Lstat(symlinkPath); err == nil {
if err := os.Remove(symlinkPath); err != nil {
return fmt.Errorf("failed to unlink: %+v", err)
}
} else if os.IsNotExist(err) {
return fmt.Errorf("failed to check symlink: %+v", err)
}
答案 2 :(得分:0)
这里的其他答案是正确的...但是有两个小问题:
更原子的方法是创建一个临时符号链接,然后将其重命名为原始符号链接:
symlinkPathTmp := symlinkPath + ".tmp"
if err := os.Remove(symlinkPathTmp); err != nil && !os.IsNotExist(err) {
return err
}
if err := os.Symlink(filePath, symlinkPathTmp); err != nil {
return err
}
if err := os.Rename(symlinkPathTmp, symlinkPath); err != nil {
return err
}
在删除临时链接与重新创建临时链接之间仍然存在一个小小的竞争,但是这不会冒使主要链接处于不一致状态的风险。 理想地,我们可以通过使用临时链接的临时名称来解决此问题,但是Go的TempFile总是创建一个新文件,因此它并不是那么有用。 (您也许可以调用TempFile,然后删除文件名并重新使用该名称,这样做会比较冒险,但更安全,然后附加一个常量.tmp
后缀。)
尽管如此,即使在种族竞赛中,您仍然会获得原子性,任何中断都不会导致链接丢失。
请注意,这取决于Posix的行为,可能在Windows上不起作用(为什么您仍要在Windows上使用符号链接?),但这是许多需要原子符号链接替换的macOS / Linux工具共享的技术。