Skip to content

Commit

Permalink
Ignore invalid symlinks when computing Merkle tree (bazelbuild#134)
Browse files Browse the repository at this point in the history
When given an output directory containing an invalid symlink (i.e., a
symlink pointing to a non-existent file), the SDK fails to compute
Merkle tree because of Stat failure. This change makes the SDK ignore
it.

Tested by both using this version of re-client and added unit-tests.
  • Loading branch information
gkousik authored Mar 31, 2020
1 parent 24a03e3 commit d833149
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 4 deletions.
18 changes: 15 additions & 3 deletions go/pkg/filemetadata/filemetadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,35 @@ type Metadata struct {

// FileError is the error returned by the Compute function.
type FileError struct {
IsDirectory bool
IsNotFound bool
Err error
IsDirectory bool
IsNotFound bool
IsInvalidSymlink bool
Err error
}

// Error returns the error message.
func (e *FileError) Error() string {
return e.Err.Error()
}

func isSymlink(filename string) (bool, error) {
file, err := os.Lstat(filename)
if err != nil {
return false, err
}
return file.Mode()&os.ModeSymlink != 0, nil
}

// Compute computes a Metadata from a given file path.
// If an error is returned, it will be of type *FileError.
func Compute(filename string) *Metadata {
md := &Metadata{Digest: digest.Empty}
file, err := os.Stat(filename)
if err != nil {
fe := &FileError{Err: err}
if s, err := isSymlink(filename); err == nil && s {
fe.IsInvalidSymlink = true
}
if os.IsNotExist(err) {
fe.IsNotFound = true
}
Expand Down
9 changes: 8 additions & 1 deletion go/pkg/tree/tree.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,14 @@ func loadFiles(execRoot string, excl []*command.InputExclusion, path string, fs
meta := cache.Get(absPath)
t := command.FileInputType
if meta.Err != nil {
if e, ok := meta.Err.(*filemetadata.FileError); !ok || !e.IsDirectory {
e, ok := meta.Err.(*filemetadata.FileError)
if !ok {
return meta.Err
}
if e.IsInvalidSymlink {
return nil
}
if !e.IsDirectory {
return meta.Err
}
t = command.DirectoryInputType
Expand Down
26 changes: 26 additions & 0 deletions go/pkg/tree/tree_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,32 @@ func TestComputeMerkleTree(t *testing.T) {
TotalInputBytes: 2*fooDg.Size + fooDirDg.Size,
},
},
{
desc: "File invalid symlink",
input: []*inputPath{
{path: "fooDir/foo", fileContents: fooBlob, isExecutable: true},
{path: "foo", isSymlink: true, symlinkTarget: "fooDir/foo"},
{path: "bar", isSymlink: true, symlinkTarget: "fooDir/bar"},
},
spec: &command.InputSpec{
Inputs: []string{"fooDir", "foo"},
},
rootDir: &repb.Directory{
Directories: []*repb.DirectoryNode{{Name: "fooDir", Digest: fooDirDgPb}},
Files: []*repb.FileNode{{Name: "foo", Digest: fooDgPb, IsExecutable: true}},
},
additionalBlobs: [][]byte{fooBlob, fooDirBlob},
wantCacheCalls: map[string]int{
"fooDir": 1,
"fooDir/foo": 1,
"foo": 1,
},
wantStats: &Stats{
InputDirectories: 2,
InputFiles: 2,
TotalInputBytes: 2*fooDg.Size + fooDirDg.Size,
},
},
{
desc: "Directory absolute symlink",
input: []*inputPath{
Expand Down

0 comments on commit d833149

Please sign in to comment.