回答
tar
会保留硬链接。
这里的三个硬链接的文件,一个文件,一个环节一个样品目录:
foo% vdir .
total 16
-rw-r--r-- 3 kostix kostix 5 Jul 12 19:37 bar.txt
-rw-r--r-- 3 kostix kostix 5 Jul 12 19:37 foo.txt
-rw-r--r-- 3 kostix kostix 5 Jul 12 19:37 test.txt
-rw-r--r-- 1 kostix kostix 9 Jul 12 19:49 xyzzy.txt
现在我们将其归档使用GNU tar
并验证它确实增加了链接 (因为我们没有传递给它--hard-dereferece
命令行选项):
foo% tar -cf ../foo.tar .
foo% tar -tvf ../foo.tar
drwxr-xr-x kostix/kostix 0 2016-07-12 19:49 ./
-rw-r--r-- kostix/kostix 9 2016-07-12 19:49 ./xyzzy.txt
-rw-r--r-- kostix/kostix 5 2016-07-12 19:37 ./bar.txt
hrw-r--r-- kostix/kostix 0 2016-07-12 19:37 ./test.txt link to ./bar.txt
hrw-r--r-- kostix/kostix 0 2016-07-12 19:37 ./foo.txt link to ./bar.txt
的archive/tar
文档是指一束限定在tar
ARCHI标准文献(不幸的是,没有一个标准:例如,GNU tar不支持POSIX扩展属性,而BSD tar(依赖于libarchive
),而pax
也是如此。 举的硬链接其位:
LNKTYPE
此标志表示链接到另一个文件的文件任何类型的, 先前存档。这些文件在Unix中由每个具有相同设备和inode编号的文件标识。链接名称在 链接名称字段中指定,其后缀为空。
因此,一个hadrlink是指一些 前述(已归档)通过其名称的文件的特殊类型(“1”)的enrty。
所以我们来创建一个游乐场的例子。
我们的base64编码我们的档案:
foo% base64 <../foo.tar | xclip -selection clipboard
&hellip;而写the code。 档案包含一个单一目录,一个文件(类型'0'),另一个文件(类型'0'),后面跟着两个硬链接(类型'1')。
从操场示例的输出:
Archive entry '5': ./
Archive entry '0': ./xyzzy.txt
Archive entry '0': ./bar.txt
Archive entry '1': ./test.txt link to ./bar.txt
Archive entry '1': ./foo.txt link to ./bar.txt
所以你的链接计数代码应该:
扫描整个档案记录,通过记录。
记住任何常规文件(类型
archive/tar.TypeReg
或键入archive/tar.TypeRegA
)已经处理过的,并具有与其相关联的计数器,从1开始。那么,在现实中,你最好是独家和记录条目各类 除了符号链接和目录—因为焦油 档案文件可以包含字符和块设备节点和FIFO(命名管道)。
当你遇到一个硬链接(类型
archive/tar.TypeReg
),- 阅读它的头的
Linkname
领域。 - 查看“已见”文件的列表,并增加与该名称匹配的条目的计数器 。在2016年7月13日
- 阅读它的头的
更新作为OP其实是想知道如何在 源文件系统管理的硬链接,这里的更新。
的主要想法是,与POSIX语义文件系统:
目录项指定一个文件实际上指向称为“索引节点”的特殊 文件系统元数据块。 inode包含指向它的目录条目数 。
创建硬链接实际上只是:
- 创建新目录条目指向的inode原始(源)的 在
ln
条款文件—“链接目标”。 - 递增该inode中的链接计数器。
- 创建新目录条目指向的inode原始(源)的 在
因此,任何文件被唯一地标识由两个整数: “设备号”标识主机文件系统 在其上的文件的位置,并且节点号码识别该文件的数据的物理设备。
接下来,如果两个文件具有相同的(设备,inode)对,则它们表示相同的内容。或者,如果我们换一种说法,其中一个 是另一个的硬链接。
因此,将文件添加至tar
存档,同时保留硬链接的工作原理是这样的:
已经添加了一个文件,它的(设备,索引节点)对保存一些查找表。
当添加另一个文件时,找出它的(设备,inode)对,然后在该表中查找它。
如果找到匹配项,则表明文件的数据已经传输,我们应该添加一个硬链接。
否则,表现如步骤(1)。
所以这里的代码:
package main
import (
"archive/tar"
"io"
"log"
"os"
"path/filepath"
"syscall"
)
type devino struct {
Dev uint64
Ino uint64
}
func main() {
log.SetFlags(0)
if len(os.Args) != 2 {
log.Fatalf("Usage: %s DIR\n", os.Args[0])
}
seen := make(map[devino]string)
tw := tar.NewWriter(os.Stdout)
err := filepath.Walk(os.Args[1],
func(fn string, fi os.FileInfo, we error) (err error) {
if we != nil {
log.Fatal("Error processing directory", we)
}
hdr, err := tar.FileInfoHeader(fi, "")
if err != nil {
return
}
if fi.IsDir() {
err = tw.WriteHeader(hdr)
return
}
st := fi.Sys().(*syscall.Stat_t)
di := devino{
Dev: st.Dev,
Ino: st.Ino,
}
orig, ok := seen[di]
if ok {
hdr.Typeflag = tar.TypeLink
hdr.Linkname = orig
hdr.Size = 0
err = tw.WriteHeader(hdr)
return
}
fd, err := os.Open(fn)
if err != nil {
return
}
err = tw.WriteHeader(hdr)
if err != nil {
return
}
_, err = io.Copy(tw, fd)
fd.Close() // Ignoring error for a file opened R/O
if err == nil {
seen[di] = fi.Name()
}
return err
})
if err != nil {
log.Fatal(err)
}
err = tw.Close()
if err != nil {
log.Fatal(err)
}
return
}
请注意,这是相当跛:
它不适当地文件和目录名的交易。
它并不试图用正确的符号链接和FIFO, 工作,并跳过Unix域套接字等
它假定它工作在一个POSIX环境。
在非POSIX系统中,
Sys()
方法呼吁os.FileInfo
类型的值可能会返回别的东西,而不是POSIX'ysyscall.Stat_t
。假设在Windows上有多个由不同的 “磁盘”或“驱动器”托管的文件系统。我不知道Go如何处理它。 也许在这种情况下,必须以某种方式模拟“设备号”。
在另一方面,它显示了如何处理硬链接:
- 将头结构的“链接名称”字段。
- 将标题的“大小”字段重置为0(因为没有数据会跟随)。
您可能还需要使用其他方法来维持查找表:如果你的大多数文件都预计将位于同一个物理文件系统,每个条目为每个条目的设备编号浪费的uint64
。因此,地图层次结构可能是一个明智的做法:首先将设备编号映射到将inode编号映射到文件名的另一个映射。
希望这会有所帮助。
哇我不期待这么多的反馈!这些是一些真正有用的观点,谢谢分享:) – steve
- 1. tar文件归档不
- 2. 保存归档的文档文件夹
- 3. 测试文件中tar归档
- 4. 递归硬链接
- 5. Autotools - tar这看起来不像一个tar归档文件
- 6. 提取链接描述归档文件
- 7. 如何使用Perl的Archive :: Tar保存tar档案文件中的setuid位?
- 8. 列表的多个.tar归档文件的文件
- 9. 提取存储在tar归档文件中的以前版本的文件
- 10. Golang:将文件追加到现有的tar归档文件
- 11. 删除从tar归档文件中提取的文件
- 12. 排除从tar归档文件目录中有.tarignore文件
- 13. 如何使用compress/gzip和archive/tar创建压缩的tar归档文件?
- 14. 使用php提取空目录的tar归档文件PharData
- 15. 将tar文件归档到Perl中的其他位置
- 16. 链接到文档附件的链接
- 17. GCC链接 - 指定存档文件
- 18. 截断的tar归档错误
- 19. 码头加载和保存:归档/ tar:无效的焦点标题
- 20. tar仅列出归档文件而不是目录
- 21. tar命令无法找到文件归档
- 22. Ruby:创建一个Gzipped Tar归档文件
- 23. 擦除文件后保持硬链接连接
- 24. “归档” CSV到存档文件夹
- 25. 在Ruby中,如何将tar归档流直接提取到文件系统?
- 26. 链接硬件库
- 27. 使用python递归创建硬链接
- 28. 隐藏符号链接文件夹到硬链接文件夹
- 29. 如何将文件追加到Java中的.tar归档文件中?
- 30. 如何创建不会展开到子文件夹的tar归档文件?
其实我已经重新阅读你的问题好几次,现在扶着想到你居然要问如何找到硬链接的文件*在源文件系统*当它们被添加到压缩文件,而不是怎么算的在tar档案中的硬连接文件的数量(我回答的问题)。你能否详细说明你想问什么? – kostix
嘿kostix, 我其实的意思是问如何计算硬链接的数量,同时流式存档。尽管感谢您的输入! – steve
好的,用PoC实现更新我的代码。适用于我的硬链接的测试目录(对文件/目录名的模数处理不完整);我没有时间调整它,像股票'焦油'工作,对不起。 – kostix