检查文件是否为硬文件link
Check whether a file is a hard link
在 Go 中如何检查一个文件是否是 hard link? os.FileMode
只有 symlinks 的模式,没有 hard links 的模式。
我有一个不幸的想法行不通:
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
只读取 symlinks,而不是硬 links。
我找到了一个有点的相关答案:
Counting hard links to a file in Go
但是这个答案显示了如何找到一个文件的 number 个硬 link,而不是 whether 一个文件本身是一个 hard link.
我猜 syscall package used in that answer or, better yet, the sys 包有一种方法可以测试文件是否是硬文件 link。有谁知道这样做? (我很难理解这些包,因为它们太低级了。)
编辑
我应该补充一下我想检查这个的原因。我正在尝试制作一个函数来创建目录的 tar 存档 [使用 filepath.Walk()
]。在此函数中,当我为文件创建 *tar.Header
时,我将值设置为 *tar.Header.Typeflag
.
例如,如果 fi
是文件的 *os.FileInfo
变量,而 hdr
是该文件在新 tar 存档中的位置的 *tar.Header
变量,它看起来像这样:
if fi.Mode().IsDir() {
hdr.Typeflag = tar.TypeDir
}
在 tar package, the modes for hard links and regular files are distinct, TypeLink
and TypeReg
, but this isn't the case in the os 包中。所以 运行 这不会设置正确的 Typeflag
:
hdr.Mode = int64(fi.Mode())
文件是到inode的硬链接,你可以有多个到inode的硬链接,文件系统不会区分它们。如果您有两个文件指向磁盘上的同一个 inode 并删除一个文件将仍然存在。 Space 仅在删除所有到 inode 的链接后才由文件系统回收。
您可以使用 ls -i
来确定索引,并使用 stats <path to file>
计算出您的文件系统中有多少个 inode 链接。
"hard link" 一词用词不当。文件在大多数文件系统中的工作方式是给定文件(由路径标识的东西,如 /foo
)实际上只是指向称为 "inode." 的结构的指针 Inode 是磁盘上的结构实际上表示文件的内容和元数据。当一个文件是另一个文件的 "hard link" 时,这只是意味着它们都指向同一个 inode。系统将跟踪指向给定 inode 的文件数,并确保在所有指向它的文件都被删除之前不要删除 inode。
因此,"is this file a hard link"这个问题其实没有任何意义。 有意义的是这个问题,"are these two files hard links to each other," 或者更准确地说,"are these two files pointers to the same inode." 如果你想在 Go 中回答这个问题,你只需要 os.SameFile.
从 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)
}
}
在 Go 中如何检查一个文件是否是 hard link? os.FileMode
只有 symlinks 的模式,没有 hard links 的模式。
我有一个不幸的想法行不通:
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
只读取 symlinks,而不是硬 links。
我找到了一个有点的相关答案:
Counting hard links to a file in Go
但是这个答案显示了如何找到一个文件的 number 个硬 link,而不是 whether 一个文件本身是一个 hard link.
我猜 syscall package used in that answer or, better yet, the sys 包有一种方法可以测试文件是否是硬文件 link。有谁知道这样做? (我很难理解这些包,因为它们太低级了。)
编辑
我应该补充一下我想检查这个的原因。我正在尝试制作一个函数来创建目录的 tar 存档 [使用 filepath.Walk()
]。在此函数中,当我为文件创建 *tar.Header
时,我将值设置为 *tar.Header.Typeflag
.
例如,如果 fi
是文件的 *os.FileInfo
变量,而 hdr
是该文件在新 tar 存档中的位置的 *tar.Header
变量,它看起来像这样:
if fi.Mode().IsDir() {
hdr.Typeflag = tar.TypeDir
}
在 tar package, the modes for hard links and regular files are distinct, TypeLink
and TypeReg
, but this isn't the case in the os 包中。所以 运行 这不会设置正确的 Typeflag
:
hdr.Mode = int64(fi.Mode())
文件是到inode的硬链接,你可以有多个到inode的硬链接,文件系统不会区分它们。如果您有两个文件指向磁盘上的同一个 inode 并删除一个文件将仍然存在。 Space 仅在删除所有到 inode 的链接后才由文件系统回收。
您可以使用 ls -i
来确定索引,并使用 stats <path to file>
计算出您的文件系统中有多少个 inode 链接。
"hard link" 一词用词不当。文件在大多数文件系统中的工作方式是给定文件(由路径标识的东西,如 /foo
)实际上只是指向称为 "inode." 的结构的指针 Inode 是磁盘上的结构实际上表示文件的内容和元数据。当一个文件是另一个文件的 "hard link" 时,这只是意味着它们都指向同一个 inode。系统将跟踪指向给定 inode 的文件数,并确保在所有指向它的文件都被删除之前不要删除 inode。
因此,"is this file a hard link"这个问题其实没有任何意义。 有意义的是这个问题,"are these two files hard links to each other," 或者更准确地说,"are these two files pointers to the same inode." 如果你想在 Go 中回答这个问题,你只需要 os.SameFile.
从 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)
}
}