diff --git a/keywords.go b/keywords.go index 280ef3b..db19f2f 100644 --- a/keywords.go +++ b/keywords.go @@ -55,6 +55,12 @@ var ( "sha384digest": hasherKeywordFunc("sha384digest", sha512.New384), // A synonym for `sha384` "sha512": hasherKeywordFunc("sha512", sha512.New), // The SHA512 message digest of the file "sha512digest": hasherKeywordFunc("sha512digest", sha512.New), // A synonym for `sha512` + + // This is not an upstreamed keyword, but a needed attribute for file validation. + // The pattern for this keyword key is prefixed by "xattr." followed by the extended attribute "namespace.key". + // The keyword value is the SHA1 digest of the extended attribute's value. + // In this way, the order of the keys does not matter, and the contents of the value is not revealed. + "xattr": xattrKeywordFunc, } ) diff --git a/keywords_linux.go b/keywords_linux.go index a52b369..fd59f7f 100644 --- a/keywords_linux.go +++ b/keywords_linux.go @@ -3,10 +3,14 @@ package mtree import ( + "crypto/sha1" "fmt" "os" "os/user" + "strings" "syscall" + + "./xattr" ) var ( @@ -30,4 +34,20 @@ var ( stat := info.Sys().(*syscall.Stat_t) return fmt.Sprintf("nlink=%d", stat.Nlink), nil } + xattrKeywordFunc = func(path string, info os.FileInfo) (string, error) { + xlist, err := xattr.List(path) + if err != nil { + return "", err + } + klist := make([]string, len(xlist)) + for i := range xlist { + data, err := xattr.Get(path, xlist[i]) + if err != nil { + return "", err + } + println(string(data)) + klist[i] = fmt.Sprintf("xattr.%s=%x", xlist[i], sha1.Sum(data)) + } + return strings.Join(klist, " "), nil + } ) diff --git a/keywords_unsupported.go b/keywords_unsupported.go index 88b92a5..ba61845 100644 --- a/keywords_unsupported.go +++ b/keywords_unsupported.go @@ -17,4 +17,7 @@ var ( nlinkKeywordFunc = func(path string, info os.FileInfo) (string, error) { return "", nil } + xattrKeywordFunc = func(path string, info os.FileInfo) (string, error) { + return "", nil + } ) diff --git a/walk.go b/walk.go index cbfd583..1964d27 100644 --- a/walk.go +++ b/walk.go @@ -15,6 +15,8 @@ type ExcludeFunc func(path string, info os.FileInfo) bool // need a more linear walk, which this can not ensure. func Walk(root string, exlcudes []ExcludeFunc, keywords []string) (*DirectoryHierarchy, error) { dh := DirectoryHierarchy{} + count := 0 + // TODO insert signature and metadata comments first err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error { if err != nil { return err @@ -27,6 +29,7 @@ func Walk(root string, exlcudes []ExcludeFunc, keywords []string) (*DirectoryHie e := Entry{} //e.Name = filepath.Base(path) e.Name = path + e.Pos = count for _, keyword := range keywords { if str, err := KeywordFuncs[keyword](path, info); err == nil && str != "" { e.Keywords = append(e.Keywords, str) @@ -34,8 +37,8 @@ func Walk(root string, exlcudes []ExcludeFunc, keywords []string) (*DirectoryHie return err } } - // XXX dh.Entries = append(dh.Entries, e) + count++ return nil }) return &dh, err diff --git a/walk_test.go b/walk_test.go index 9a60e51..7d3f59f 100644 --- a/walk_test.go +++ b/walk_test.go @@ -6,7 +6,7 @@ import ( ) func TestWalk(t *testing.T) { - dh, err := Walk(".", nil, append(DefaultKeywords, "cksum", "md5", "rmd160digest", "sha1", "sha256", "sha512")) + dh, err := Walk(".", nil, append(DefaultKeywords, "xattr")) if err != nil { t.Fatal(err) }