如何在Go中检查文件是否为 硬 链接? os.FileMode
只有符号链接模式,而不是硬链接。
我有一个想法,遗憾的是不起作用:
package main
func main() {
filename := os.Args[1]
var hardlink bool
link, _ := os.Readlink(filename)
fi, _ := os.Stat(filename)
mode := string(fi.Mode().String()[0])
if link != "" && mode != "L" {
hardlink = true
}
fmt.Printf("%v is hard link? %v\n", filename, hardlink)
}
这个^不起作用,因为os.Readlink
只读取符号链接,而不读取硬链接。
我找到了一个有点相关的答案:
Counting hard links to a file in Go
但是这个答案显示了如何找到文件硬链接的数字,而不是 文件本身是否是硬链接。
我猜测该答案中使用的syscall包,或者更好的是,sys包有一种方法来测试文件是否是硬链接。有谁知道这样做? (我无法理解这些软件包,因为它们的级别很低。)
我应该补充我想查看这个的原因。我正在尝试创建一个函数来创建目录[使用filepath.Walk()
]的tar存档。在此函数中,当我为文件创建*tar.Header
时,我将值设置为*tar.Header.Typeflag
例如,如果fi
是文件的*os.FileInfo
变量而hdr
是该文件的*tar.Header
变量放在新的tar存档中,它看起来像这样:
if fi.Mode().IsDir() {
hdr.Typeflag = tar.TypeDir
}
在tar包中,硬链接和常规文件的模式不同,TypeLink
和TypeReg
,但os中的情况并非如此包。因此,运行此设置不会设置正确的Typeflag
:
hdr.Mode = int64(fi.Mode())
答案 0 :(得分:5)
术语“硬链接”有点用词不当。文件在大多数文件系统中的工作方式是给定文件(由路径标识的东西,如/foo
)实际上只是指向称为“inode”的结构的指针。 Inode是磁盘上实际表示文件内容和元数据的结构。当文件是另一个文件的“硬链接”时,它只意味着它们都指向同一个inode。系统将跟踪指向给定inode的文件数,并确保在删除指向它的所有文件之前不删除inode。
因此,问题“这个文件是一个硬链接”并不是真的有意义。 有意义的问题是“这两个文件是否相互硬链接”,或者更确切地说,“这两个文件是指向同一个inode的指针”。如果您想在Go中回答该问题,您只需os.SameFile。
答案 1 :(得分:3)
从Docker的源代码示例中得出结论:
https://github.com/docker/docker/blob/master/pkg/archive/archive.go
https://github.com/docker/docker/blob/master/pkg/archive/archive_unix.go
package main
import (
"errors"
"fmt"
"log"
"os"
"syscall"
)
func main() {
filename := os.Args[1]
// 'os.Lstat()' reads the link itself.
// 'os.Stat()' would read the link's target.
fi, err := os.Lstat(filename)
if err != nil {
log.Fatal(err)
}
// https://github.com/docker/docker/blob/master/pkg/archive/archive_unix.go
// in 'func setHeaderForSpecialDevice()'
s, ok := fi.Sys().(*syscall.Stat_t)
if !ok {
err = errors.New("cannot convert stat value to syscall.Stat_t")
log.Fatal(err)
}
// The index number of this file's inode:
inode := uint64(s.Ino)
// Total number of files/hardlinks connected to this file's inode:
nlink := uint32(s.Nlink)
// True if the file is a symlink.
if fi.Mode()&os.ModeSymlink != 0 {
link, err := os.Readlink(fi.Name())
if err != nil {
log.Fatal(err)
}
fmt.Printf("%v is a symlink to %v on inode %v.\n", filename, link, inode)
os.Exit(0)
}
// Otherwise, for hardlinks:
fmt.Printf("The inode for %v, %v, has %v hardlinks.\n", filename, inode, nlink)
if nlink > 1 {
fmt.Printf("Inode %v has %v other hardlinks besides %v.\n", inode, nlink, filename)
} else {
fmt.Printf("%v is the only hardlink to inode %v.\n", filename, inode)
}
}
答案 2 :(得分:1)
文件是指向inode的硬链接,您可以拥有多个指向inode的硬链接,文件系统也无法区分它们。如果有两个文件指向磁盘上的同一inode并删除一个文件仍然存在。只有删除了所有指向inode的链接后,文件系统才会回收空间。
您可以使用ls -i
来确定索引,并使用stats <path to file>
计算出文件系统中inode的链接数量。