File: filehash.go

package info (click to toggle)
singularity-container 4.1.5%2Bds4-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 43,876 kB
  • sloc: asm: 14,840; sh: 3,190; ansic: 1,751; awk: 414; makefile: 413; python: 99
file content (102 lines) | stat: -rw-r--r-- 2,327 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
package contenthash

import (
	"archive/tar"
	"crypto/sha256"
	"hash"
	"os"
	"path/filepath"
	"time"

	fstypes "github.com/tonistiigi/fsutil/types"
)

// NewFileHash returns new hash that is used for the builder cache keys
func NewFileHash(path string, fi os.FileInfo) (hash.Hash, error) {
	var link string
	if fi.Mode()&os.ModeSymlink != 0 {
		var err error
		link, err = os.Readlink(path)
		if err != nil {
			return nil, err
		}
	}

	stat := &fstypes.Stat{
		Mode:     uint32(fi.Mode()),
		Size_:    fi.Size(),
		ModTime:  fi.ModTime().UnixNano(),
		Linkname: link,
	}

	if fi.Mode()&os.ModeSymlink != 0 {
		stat.Mode = stat.Mode | 0777
	}

	if err := setUnixOpt(path, fi, stat); err != nil {
		return nil, err
	}
	return NewFromStat(stat)
}

func NewFromStat(stat *fstypes.Stat) (hash.Hash, error) {
	// Clear the socket bit since archive/tar.FileInfoHeader does not handle it
	stat.Mode &^= uint32(os.ModeSocket)

	fi := &statInfo{stat}
	hdr, err := tar.FileInfoHeader(fi, stat.Linkname)
	if err != nil {
		return nil, err
	}
	hdr.Name = "" // note: empty name is different from current has in docker build. Name is added on recursive directory scan instead
	hdr.Devmajor = stat.Devmajor
	hdr.Devminor = stat.Devminor
	hdr.Uid = int(stat.Uid)
	hdr.Gid = int(stat.Gid)

	if len(stat.Xattrs) > 0 {
		hdr.PAXRecords = make(map[string]string, len(stat.Xattrs))
		for k, v := range stat.Xattrs {
			hdr.PAXRecords["SCHILY.xattr."+k] = string(v)
		}
	}
	// fmt.Printf("hdr: %#v\n", hdr)
	tsh := &tarsumHash{hdr: hdr, Hash: sha256.New()}
	tsh.Reset() // initialize header
	return tsh, nil
}

type tarsumHash struct {
	hash.Hash
	hdr *tar.Header
}

// Reset resets the Hash to its initial state.
func (tsh *tarsumHash) Reset() {
	// comply with hash.Hash and reset to the state hash had before any writes
	tsh.Hash.Reset()
	WriteV1TarsumHeaders(tsh.hdr, tsh.Hash)
}

type statInfo struct {
	*fstypes.Stat
}

func (s *statInfo) Name() string {
	return filepath.Base(s.Stat.Path)
}
func (s *statInfo) Size() int64 {
	return s.Stat.Size_
}
func (s *statInfo) Mode() os.FileMode {
	return os.FileMode(s.Stat.Mode)
}
func (s *statInfo) ModTime() time.Time {
	return time.Unix(s.Stat.ModTime/1e9, s.Stat.ModTime%1e9)
}
func (s *statInfo) IsDir() bool {
	return s.Mode().IsDir()
}
func (s *statInfo) Sys() interface{} {
	return s.Stat
}