3 回答
TA贡献2021条经验 获得超8个赞
只需检查符号链接是否存在并在创建新链接之前将其删除
if _, err := os.Lstat(symlinkPath); err == nil {
os.Remove(symlinkPath)
}
TA贡献1859条经验 获得超6个赞
这里的其他答案是正确的......但有两个小问题:
有一个微小的数据竞争,新的符号链接将在此处之前但在删除之后的其他地方创建,使其处于潜在的不一致状态。
如果程序在创建符号链接之前死亡/崩溃,但在删除前一个符号链接之后,它可能会再次使事情处于不一致的状态。
处理这个问题的更原子的方法是创建一个临时符号链接,然后将其重命名为原始符号链接:
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 工具共享的技术。
TA贡献1868条经验 获得超4个赞
请注意,@Vadyus 的答案在运行 lstat 时隐藏了实际的文件系统错误。例如,如果您的磁盘损坏并且 Lstat 失败,您仍然会运行 os.Remove 并忽略它的错误(危险,除非您喜欢调试几个小时)。
以下片段正确检查文件是否存在和其他错误:
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)
}
- 3 回答
- 0 关注
- 155 浏览
添加回答
举报