Golang:检查文件是否是硬链接?

Gre*_*n23 1 attributes file hardlink go

如何检查文件是否是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)
}
Run Code Online (Sandbox Code Playgroud)

这^不起作用,因为os.Readlink只读符号链接,而不是硬链接.

我发现了一个有点相关的答案:
计数硬链接在Go文件
,但这个答案显示了如何找到的硬链接到一个文件,而不是是否一个文件本身的硬链接.

我猜这个答案中使用的系统调用包,或者更好的是,sys包有一种方法来测试文件是否是硬链接.有谁知道这样做?(我很难理解这些包,因为它们太低了.)

编辑

我应该补充我想检查这个的原因.我正在尝试创建一个函数来创建目录[using filepath.Walk()] 的tar存档.在此函数中,当我*tar.Header为文件创建时,我将值设置为*tar.Header.Typeflag.
例如,if fi是文件的*os.FileInfo变量,并且hdr是该*tar.Header文件在新tar存档中的位置的变量,它看起来像这样:

if fi.Mode().IsDir() {
    hdr.Typeflag = tar.TypeDir
}
Run Code Online (Sandbox Code Playgroud)

焦油包,硬链接和普通文件的方式是不同的,TypeLink并且TypeReg,但这不是在的情况下OS包.所以运行它不会设置正确Typeflag:

hdr.Mode = int64(fi.Mode())
Run Code Online (Sandbox Code Playgroud)

Gre*_*n23 6

从 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)
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 顺便说一句,您通常不应该只保存/使用/引用文件 inode 编号;如果不引用设备(例如保存/使用/引用`s.Dev`、`s.Ino`),它就毫无意义。特别是对于像遍历文件树的归档工具之类的东西,它可能会跨越设备/文件系统边界,并且需要将不同的 inode 与具有相同 inode 编号的不同设备区分开来(例如,通过使用 `s.Dev, s. Ino` 作为地图/设置键)。 (2认同)

jos*_*hlf 5

"硬链接"这个词有点用词不当.文件在大多数文件系统中的工作方式是给定文件(由路径标识的东西/foo)实际上只是指向称为"inode"的结构的指针.Inode是磁盘上实际表示文件内容和元数据的结构.当文件是另一个文件的"硬链接"时,它只意味着它们都指向同一个inode.系统将跟踪指向给定inode的文件数,并确保在删除指向它的所有文件之前不删除inode.

因此,问题"这个文件是一个硬链接"并不真正有意义.什么没有意义的问题,"是这两个文件的硬链接给对方,"或者更准确的说,"是这两个文件指向相同的inode." 如果你想在Go中回答这个问题,你只需要os.SameFile.