Add unit test for EvalSymlinks.
Arvados-DCO-1.1-Signed-off-by: Peter Amstutz <pamstutz@veritasgenetics.com>
return
}
- var tgt string
if info.Mode()&os.ModeSymlink == 0 {
// Not a symlink, nothing to do.
return
// Remember symlink for cleanup later
links = append(links, path)
- tgt, err = os.Readlink(path)
+ var readlinktgt string
+ readlinktgt, err = os.Readlink(path)
+ tgt := readlinktgt
if err != nil {
return
}
// directory, otherwise it is an error.
if !strings.HasPrefix(tgt, runner.HostOutputDir+"/") {
err = fmt.Errorf("Output directory symlink %q points to invalid location %q, must point to mount or output directory.",
- path[len(runner.HostOutputDir):], tgt)
+ path[len(runner.HostOutputDir):], readlinktgt)
return
}
// Update symlink to host FS
- os.Remove(path)
- os.Symlink(tgt, path)
+ err = os.Remove(path)
+ if err != nil {
+ err = fmt.Errorf("Error removing symlink %q: %v", path, err)
+ return
+ }
+
+ err = os.Symlink(tgt, path)
+ if err != nil {
+ err = fmt.Errorf("Error updating symlink %q: %v", path, err)
+ return
+ }
// Target is within the output directory, so loop and check if
// it is also a symlink.
if err != nil {
// Regular directory
- var symlinksToRemove []string
+ symlinksToRemove := make(map[string]bool)
var m string
var srm []string
// Find symlinks to arv-mounted files & dirs.
return err
}
m, srm, err = runner.EvalSymlinks(path, binds)
- symlinksToRemove = append(symlinksToRemove, srm...)
+ for _, r := range srm {
+ symlinksToRemove[r] = true
+ }
if err == nil {
manifestText = manifestText + m
}
return err
})
- for _, l := range symlinksToRemove {
- os.Remove(l)
+ for l, _ := range symlinksToRemove {
+ err2 := os.Remove(l)
+ if err2 != nil {
+ if err == nil {
+ err = fmt.Errorf("Error removing symlink %q: %v", err2)
+ } else {
+ err = fmt.Errorf("%v\nError removing symlink %q: %v",
+ err, err2)
+ }
+ }
}
if err != nil {
return fmt.Errorf("While checking output symlinks: %v", err)
c.Check(err, IsNil)
c.Check(string(jsondata), Equals, `{"number":123456789123456789}`)
}
+
+func (s *TestSuite) TestEvalSymlinks(c *C) {
+ cr := NewContainerRunner(&ArvTestClient{callraw: true}, &KeepTestClient{}, nil, "zzzzz-zzzzz-zzzzzzzzzzzzzzz")
+
+ realTemp, err := ioutil.TempDir("", "crunchrun_test-")
+ c.Assert(err, IsNil)
+ defer os.RemoveAll(realTemp)
+
+ cr.HostOutputDir = realTemp
+
+ // Absolute path outside output dir
+ os.Symlink("/etc/passwd", realTemp+"/p1")
+
+ // Relative outside output dir
+ os.Symlink("../..", realTemp+"/p2")
+
+ // Circular references
+ os.Symlink("p4", realTemp+"/p3")
+ os.Symlink("p5", realTemp+"/p4")
+ os.Symlink("p3", realTemp+"/p5")
+
+ symlinksToRemove := make(map[string]bool)
+ for _, v := range []string{"p1", "p2", "p3", "p4", "p5"} {
+ var srm []string
+ _, srm, err = cr.EvalSymlinks(realTemp+"/"+v, []string{})
+ c.Assert(err, NotNil)
+ for _, r := range srm {
+ symlinksToRemove[r] = true
+ }
+ }
+ c.Assert(len(symlinksToRemove), Equals, 5)
+
+ c.Assert(map[string]bool{realTemp + "/" + "p1": true,
+ realTemp + "/" + "p2": true,
+ realTemp + "/" + "p3": true,
+ realTemp + "/" + "p4": true,
+ realTemp + "/" + "p5": true}, DeepEquals, symlinksToRemove)
+}
if err != nil {
return fmt.Errorf("stat symlink %q target %q: %s", path, targetPath, err)
}
- if targetInfo.Mode()&os.ModeDir != 0 {
+ if targetInfo.IsDir() {
// Symlinks to directories don't get walked, so do it
// here. We've previously checked that they stay in
// the output directory and don't result in an endless