golangのarchive/tarパッケージを使用すると、ファイルに含まれるハードリンクの数にアクセスできないようです。しかし、ディレクトリやファイルをtar'ingするとハードリンクを保存できるということをどこかで読んでいることを覚えています。ハードリンクを保存するTarアーカイブ
私はこれを行うのに役立ついくつかのパッケージがありますか?
golangのarchive/tarパッケージを使用すると、ファイルに含まれるハードリンクの数にアクセスできないようです。しかし、ディレクトリやファイルをtar'ingするとハードリンクを保存できるということをどこかで読んでいることを覚えています。ハードリンクを保存するTarアーカイブ
私はこれを行うのに役立ついくつかのパッケージがありますか?
tar
ハードリンクは保持されます。
ここではサンプルの3つのハード・リンクされたファイルとディレクトリおよび単一のリンクを持つ一つのファイルです:
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の上の基準を定める書類の束を指し、 BSD tar(これはlibarchive
に依存していますが、pax
など)は、POSIX拡張属性をサポートしていません。例えば、GNU tarはPOSIX拡張属性をサポートしていません。ハードリンク上のビットを引用する :
LNKTYPE
このフラグは は以前にアーカイブ、任意のタイプの別のファイルにリンクされたファイルを表します。そのようなファイルは、Unixでは、同じファイルと同じ番号の を持つ各ファイルによって識別されます。リンク先の名前は、リンク名フィールドの末尾にnullを指定して に指定されています。
そこで、hadrlinkは、その名前によって(既にアーカイブ)ファイルに先行するいくつか を指す特別なタイプ(「1」)のenrtyあります。
遊び場の例を作成しましょう。
私たちは、アーカイブエンコードBASE64:
foo% base64 <../foo.tar | xclip -selection clipboard
&hellip;及びthe codeを書きます。 アーカイブには、1つのディレクトリ、1つのファイル(タイプ '0')、別のファイル(タイプ '0')、2つのハードリンク(タイプ '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(名前付きパイプ)を含めることができるため
まあ、現実には、あなたがより良いシンボリックリンクとディレクトリ—以外排他的とレコードエントリすべてのタイプの だろう。
あなたは、そのヘッダのLinkname
フィールドを読むハードリンク(タイプarchive/tar.TypeReg
)、
2016年7月13日
の更新OPが実際に ソースファイルシステム上にハードリンクを管理する方法を知りたいと思ったとして、ここでの更新です。
実際にファイルを指定したディレクトリエントリは、「iノード」と呼ばれる特殊な ファイルシステムのメタデータブロックを指す:
チーフアイデアは、POSIXのセマンティクスを持つファイルシステム上にあることです。 inodeには、それを指し示すディレクトリエントリの番号 が含まれています。ハードリンクを作成する
は、実際には次のとおりです。
ln
の用語で—「リンク先」をファイルに新しいディレクトリエントリのポインティングを作成します。したがって、任意のファイルを一意に2つの整数の番号により識別される: ファイルが配置されているファイルシステム をホスト物理的装置を識別する「デバイス番号」、及びファイルのデータを識別するinode番号。
2つのファイルが同じ(デバイス、iノード)のペアを持つ場合、 は同じ内容を表します。あるいは、別の言葉で言えば、 はもう一方へのハードリンクです。
ので、ハードリンクを維持しながらtar
アーカイブにファイルを追加すると、このように動作します:
別のファイルを追加するときは、(デバイス、iノード)のペアとそのテーブル内の を調べてください。
一致するエントリが見つかった場合、そのファイルのデータはすでにストリームされています。 とハードリンクを追加する必要があります。
それ以外の場合は、手順(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システムで
、タイプ os.FileInfo
の値で呼び出さSys()
方法は何か他のものではなく、POSIX'y syscall.Stat_t
を返すことがあります。
Windowsでは、「ディスク」または「ドライブ」の異なる でホストされている複数のファイルシステムがあるとします。私はGoがそれをどのように処理するのか分かりません。 この場合、何らかの理由で「デバイス番号」をエミュレートする必要があったかもしれません。一方
、それはハードリンクを処理する方法を示しています。
uint64
を浪費:はまた、ルックアップテーブルを維持するために別のアプローチを使用する場合があります。したがって、地図の階層構造は分かりやすいことです。まず、デバイス番号を別のマップにマップし、inode番号をファイル名にマッピングします。
これが役に立ちます。
うわー私はこの多くのフィードバックを期待していませんでした!これらは本当に有用な点です。共有していただきありがとうございます:) – steve
私は実際にあなたの質問を何度か読んだことがあり、ソースファイルシステム上でハードリンクされたファイル*を見つける方法を尋ねたかったと思っています。 tarアーカイブにあるハードリンクされたファイルの数(私が答えた質問)。あなたは本当にあなたが尋ねたいと思っていたことを詳しく教えてください。 – kostix
Hey kostix、 実際には、tarアーカイブをストリーミングしている間にハードリンクの数を数える方法を尋ねることを意味しました。しかし、あなたの入力をありがとう! – steve
さて、私のコードをPoCの実装で更新しました。ハードリンク(ファイル/ディレクトリ名のモジュロ不完全な扱い)で私のテストディレクトリのために働きます。私は株式「タール」のように働くようにそれを調整する時間がありません、申し訳ありません。 – kostix