diff options
-rw-r--r-- | TODO.md | 2 | ||||
-rw-r--r-- | repo.go | 62 | ||||
-rw-r--r-- | repo_test.go | 11 |
3 files changed, 47 insertions, 28 deletions
@@ -50,7 +50,7 @@ priority 2 I stored it in the _files_ file so that we don't need to read the chunks to get the content of a symlinked file and because it does not seem to add a lot of weight to this file (after compression). -- [ ] store and restore symlinks relatively if it was relative in source +- [x] store and restore symlinks relatively if it was relative in source directory. - [ ] add quick progress bar to CLI - [ ] `list` command to list versions @@ -194,7 +194,11 @@ func (r *Repo) Restore(destination string) { dir := filepath.Dir(filePath) os.MkdirAll(dir, 0775) // TODO: handle errors if file.Link != "" { - err := os.Symlink(filepath.Join(destination, file.Link), filePath) + link := file.Link + if filepath.IsAbs(link) { + filepath.Join(destination, file.Link) + } + err := os.Symlink(link, filePath) if err != nil { logger.Errorf("restored symlink ", err) } @@ -236,30 +240,15 @@ func listFiles(path string) []File { if i.IsDir() { return nil } - var link string - var size = i.Size() + var file = File{Path: p, Size: i.Size()} if i.Mode()&fs.ModeSymlink != 0 { - target, err := filepath.EvalSymlinks(p) + file, err = cleanSymlink(path, p, i) if err != nil { - logger.Warning(err) - return nil - } - if !strings.HasPrefix(target, path) { - logger.Warningf("skipping external symlink %s -> %s", p, target) - return nil - } - size = 0 - link, err = filepath.Rel(path, target) - if err != nil { - logger.Warning(err) - return nil - } - if link == "" { - logger.Warningf("skipping empty symlink %s", p) + logger.Warning("skipping symlink ", err) return nil } } - files = append(files, File{p, size, link}) + files = append(files, file) return nil }) if err != nil { @@ -268,6 +257,39 @@ func listFiles(path string) []File { return files } +func cleanSymlink(root string, p string, i fs.FileInfo) (f File, err error) { + dir := filepath.Dir(p) + target, err := os.Readlink(p) + if err != nil { + return + } + isAbs := filepath.IsAbs(target) + cleaned := target + if !isAbs { + cleaned = filepath.Join(dir, cleaned) + } + cleaned = filepath.Clean(cleaned) + if !strings.HasPrefix(cleaned, root) { + err = fmt.Errorf("external %s -> %s", p, cleaned) + return + } + if isAbs { + f.Link, err = utils.Unprefix(cleaned, root) + } else { + f.Link, err = filepath.Rel(dir, filepath.Join(dir, target)) + } + if err != nil { + return + } + if f.Link == "" { + err = fmt.Errorf("empty %s", p) + return + } + f.Path = p + f.Size = 0 + return f, nil +} + func unprefixFiles(files []File, prefix string) (ret []File) { var err error ret = make([]File, len(files)) diff --git a/repo_test.go b/repo_test.go index 5a0abea..fda61f5 100644 --- a/repo_test.go +++ b/repo_test.go @@ -203,19 +203,16 @@ func TestSymlinks(t *testing.T) { } files := listFiles(tmpDir) fmt.Println(files) - testutils.AssertLen(t, 2, files, "Files") + testutils.AssertLen(t, 3, files, "Files") if files[0].Link != "" { - t.Error("linkexisting should not be a link, actual:", files[0].Link) + t.Error("existing should not be a link, actual:", files[0].Link) } - if files[1].Link != "existing" { - t.Error("linkexisting should point to 'existing', actual:", files[1].Link) + if files[1].Link != "/existing" { + t.Error("linkexisting should point to '/existing', actual:", files[1].Link) } if !strings.Contains(output.String(), "linkexternal") { t.Errorf("log should contain a warning for linkexternal, actual %q", &output) } - if !strings.Contains(output.String(), "notexisting") { - t.Errorf("log should contain a warning for notexisting, actual %q", &output) - } } func TestLoadChunks(t *testing.T) { |