diff --git a/cmd/restic/cmd_diff.go b/cmd/restic/cmd_diff.go index 594e387e8..d1067b5ec 100644 --- a/cmd/restic/cmd_diff.go +++ b/cmd/restic/cmd_diff.go @@ -108,9 +108,9 @@ func (s *DiffStat) Add(node *restic.Node) { } switch node.Type { - case "file": + case restic.NodeTypeFile: s.Files++ - case "dir": + case restic.NodeTypeDir: s.Dirs++ default: s.Others++ @@ -124,7 +124,7 @@ func addBlobs(bs restic.BlobSet, node *restic.Node) { } switch node.Type { - case "file": + case restic.NodeTypeFile: for _, blob := range node.Content { h := restic.BlobHandle{ ID: blob, @@ -132,7 +132,7 @@ func addBlobs(bs restic.BlobSet, node *restic.Node) { } bs.Insert(h) } - case "dir": + case restic.NodeTypeDir: h := restic.BlobHandle{ ID: *node.Subtree, Type: restic.TreeBlob, @@ -184,14 +184,14 @@ func (c *Comparer) printDir(ctx context.Context, mode string, stats *DiffStat, b } name := path.Join(prefix, node.Name) - if node.Type == "dir" { + if node.Type == restic.NodeTypeDir { name += "/" } c.printChange(NewChange(name, mode)) stats.Add(node) addBlobs(blobs, node) - if node.Type == "dir" { + if node.Type == restic.NodeTypeDir { err := c.printDir(ctx, mode, stats, blobs, name, *node.Subtree) if err != nil && err != context.Canceled { Warnf("error: %v\n", err) @@ -216,7 +216,7 @@ func (c *Comparer) collectDir(ctx context.Context, blobs restic.BlobSet, id rest addBlobs(blobs, node) - if node.Type == "dir" { + if node.Type == restic.NodeTypeDir { err := c.collectDir(ctx, blobs, *node.Subtree) if err != nil && err != context.Canceled { Warnf("error: %v\n", err) @@ -284,12 +284,12 @@ func (c *Comparer) diffTree(ctx context.Context, stats *DiffStatsContainer, pref mod += "T" } - if node2.Type == "dir" { + if node2.Type == restic.NodeTypeDir { name += "/" } - if node1.Type == "file" && - node2.Type == "file" && + if node1.Type == restic.NodeTypeFile && + node2.Type == restic.NodeTypeFile && !reflect.DeepEqual(node1.Content, node2.Content) { mod += "M" stats.ChangedFiles++ @@ -311,7 +311,7 @@ func (c *Comparer) diffTree(ctx context.Context, stats *DiffStatsContainer, pref c.printChange(NewChange(name, mod)) } - if node1.Type == "dir" && node2.Type == "dir" { + if node1.Type == restic.NodeTypeDir && node2.Type == restic.NodeTypeDir { var err error if (*node1.Subtree).Equal(*node2.Subtree) { err = c.collectDir(ctx, stats.BlobsCommon, *node1.Subtree) @@ -324,13 +324,13 @@ func (c *Comparer) diffTree(ctx context.Context, stats *DiffStatsContainer, pref } case t1 && !t2: prefix := path.Join(prefix, name) - if node1.Type == "dir" { + if node1.Type == restic.NodeTypeDir { prefix += "/" } c.printChange(NewChange(prefix, "-")) stats.Removed.Add(node1) - if node1.Type == "dir" { + if node1.Type == restic.NodeTypeDir { err := c.printDir(ctx, "-", &stats.Removed, stats.BlobsBefore, prefix, *node1.Subtree) if err != nil && err != context.Canceled { Warnf("error: %v\n", err) @@ -338,13 +338,13 @@ func (c *Comparer) diffTree(ctx context.Context, stats *DiffStatsContainer, pref } case !t1 && t2: prefix := path.Join(prefix, name) - if node2.Type == "dir" { + if node2.Type == restic.NodeTypeDir { prefix += "/" } c.printChange(NewChange(prefix, "+")) stats.Added.Add(node2) - if node2.Type == "dir" { + if node2.Type == restic.NodeTypeDir { err := c.printDir(ctx, "+", &stats.Added, stats.BlobsAfter, prefix, *node2.Subtree) if err != nil && err != context.Canceled { Warnf("error: %v\n", err) diff --git a/cmd/restic/cmd_dump.go b/cmd/restic/cmd_dump.go index 7d6652e17..6b7f8d012 100644 --- a/cmd/restic/cmd_dump.go +++ b/cmd/restic/cmd_dump.go @@ -95,15 +95,15 @@ func printFromTree(ctx context.Context, tree *restic.Tree, repo restic.BlobLoade // first item it finds and dump that according to the switch case below. if node.Name == pathComponents[0] { switch { - case l == 1 && dump.IsFile(node): + case l == 1 && node.Type == restic.NodeTypeFile: return d.WriteNode(ctx, node) - case l > 1 && dump.IsDir(node): + case l > 1 && node.Type == restic.NodeTypeDir: subtree, err := restic.LoadTree(ctx, repo, *node.Subtree) if err != nil { return errors.Wrapf(err, "cannot load subtree for %q", item) } return printFromTree(ctx, subtree, repo, item, pathComponents[1:], d, canWriteArchiveFunc) - case dump.IsDir(node): + case node.Type == restic.NodeTypeDir: if err := canWriteArchiveFunc(); err != nil { return err } @@ -114,7 +114,7 @@ func printFromTree(ctx context.Context, tree *restic.Tree, repo restic.BlobLoade return d.DumpTree(ctx, subtree, item) case l > 1: return fmt.Errorf("%q should be a dir, but is a %q", item, node.Type) - case !dump.IsFile(node): + case node.Type != restic.NodeTypeFile: return fmt.Errorf("%q should be a file, but is a %q", item, node.Type) } } diff --git a/cmd/restic/cmd_find.go b/cmd/restic/cmd_find.go index cb5c0e5e0..92e88203f 100644 --- a/cmd/restic/cmd_find.go +++ b/cmd/restic/cmd_find.go @@ -298,7 +298,7 @@ func (f *Finder) findInSnapshot(ctx context.Context, sn *restic.Snapshot) error } var errIfNoMatch error - if node.Type == "dir" { + if node.Type == restic.NodeTypeDir { var childMayMatch bool for _, pat := range f.pat.pattern { mayMatch, err := filter.ChildMatch(pat, normalizedNodepath) @@ -357,7 +357,7 @@ func (f *Finder) findIDs(ctx context.Context, sn *restic.Snapshot) error { return nil } - if node.Type == "dir" && f.treeIDs != nil { + if node.Type == restic.NodeTypeDir && f.treeIDs != nil { treeID := node.Subtree found := false if _, ok := f.treeIDs[treeID.Str()]; ok { @@ -377,7 +377,7 @@ func (f *Finder) findIDs(ctx context.Context, sn *restic.Snapshot) error { } } - if node.Type == "file" && f.blobIDs != nil { + if node.Type == restic.NodeTypeFile && f.blobIDs != nil { for _, id := range node.Content { if ctx.Err() != nil { return ctx.Err() diff --git a/cmd/restic/cmd_ls.go b/cmd/restic/cmd_ls.go index 69e278103..2213d8e7a 100644 --- a/cmd/restic/cmd_ls.go +++ b/cmd/restic/cmd_ls.go @@ -137,7 +137,7 @@ func lsNodeJSON(enc *json.Encoder, path string, node *restic.Node) error { size uint64 // Target for Size pointer. }{ Name: node.Name, - Type: node.Type, + Type: string(node.Type), Path: path, UID: node.UID, GID: node.GID, @@ -153,7 +153,7 @@ func lsNodeJSON(enc *json.Encoder, path string, node *restic.Node) error { } // Always print size for regular files, even when empty, // but never for other types. - if node.Type == "file" { + if node.Type == restic.NodeTypeFile { n.Size = &n.size } @@ -208,7 +208,7 @@ func lsNcduNode(_ string, node *restic.Node) ([]byte, error) { Dev: node.DeviceID, Ino: node.Inode, NLink: node.Links, - NotReg: node.Type != "dir" && node.Type != "file", + NotReg: node.Type != restic.NodeTypeDir && node.Type != restic.NodeTypeFile, UID: node.UID, GID: node.GID, Mode: uint16(node.Mode & os.ModePerm), @@ -238,7 +238,7 @@ func (p *ncduLsPrinter) Node(path string, node *restic.Node, _ bool) { Warnf("JSON encode failed: %v\n", err) } - if node.Type == "dir" { + if node.Type == restic.NodeTypeDir { fmt.Fprintf(p.out, ",\n%s[\n%s%s", strings.Repeat(" ", p.depth), strings.Repeat(" ", p.depth+1), string(out)) p.depth++ } else { @@ -409,7 +409,7 @@ func runLs(ctx context.Context, opts LsOptions, gopts GlobalOptions, args []stri // otherwise, signal the walker to not walk recursively into any // subdirs - if node.Type == "dir" { + if node.Type == restic.NodeTypeDir { // immediately generate leaveDir if the directory is skipped if printedDir { printer.LeaveDir(nodepath) diff --git a/cmd/restic/cmd_ls_test.go b/cmd/restic/cmd_ls_test.go index a1fcd479b..b8b074242 100644 --- a/cmd/restic/cmd_ls_test.go +++ b/cmd/restic/cmd_ls_test.go @@ -23,7 +23,7 @@ var lsTestNodes = []lsTestNode{ path: "/bar/baz", Node: restic.Node{ Name: "baz", - Type: "file", + Type: restic.NodeTypeFile, Size: 12345, UID: 10000000, GID: 20000000, @@ -39,7 +39,7 @@ var lsTestNodes = []lsTestNode{ path: "/foo/empty", Node: restic.Node{ Name: "empty", - Type: "file", + Type: restic.NodeTypeFile, Size: 0, UID: 1001, GID: 1001, @@ -56,7 +56,7 @@ var lsTestNodes = []lsTestNode{ path: "/foo/link", Node: restic.Node{ Name: "link", - Type: "symlink", + Type: restic.NodeTypeSymlink, Mode: os.ModeSymlink | 0777, LinkTarget: "not printed", }, @@ -66,7 +66,7 @@ var lsTestNodes = []lsTestNode{ path: "/some/directory", Node: restic.Node{ Name: "directory", - Type: "dir", + Type: restic.NodeTypeDir, Mode: os.ModeDir | 0755, ModTime: time.Date(2020, 1, 2, 3, 4, 5, 0, time.UTC), AccessTime: time.Date(2021, 2, 3, 4, 5, 6, 7, time.UTC), @@ -79,7 +79,7 @@ var lsTestNodes = []lsTestNode{ path: "/some/sticky", Node: restic.Node{ Name: "sticky", - Type: "dir", + Type: restic.NodeTypeDir, Mode: os.ModeDir | 0755 | os.ModeSetuid | os.ModeSetgid | os.ModeSticky, }, }, @@ -139,19 +139,19 @@ func TestLsNcdu(t *testing.T) { Paths: []string{"/example"}, }) printer.Node("/directory", &restic.Node{ - Type: "dir", + Type: restic.NodeTypeDir, Name: "directory", ModTime: modTime, }, false) printer.Node("/directory/data", &restic.Node{ - Type: "file", + Type: restic.NodeTypeFile, Name: "data", Size: 42, ModTime: modTime, }, false) printer.LeaveDir("/directory") printer.Node("/file", &restic.Node{ - Type: "file", + Type: restic.NodeTypeFile, Name: "file", Size: 12345, ModTime: modTime, diff --git a/cmd/restic/cmd_recover.go b/cmd/restic/cmd_recover.go index a6ef59cc2..133f77978 100644 --- a/cmd/restic/cmd_recover.go +++ b/cmd/restic/cmd_recover.go @@ -88,7 +88,7 @@ func runRecover(ctx context.Context, gopts GlobalOptions) error { } for _, node := range tree.Nodes { - if node.Type == "dir" && node.Subtree != nil { + if node.Type == restic.NodeTypeDir && node.Subtree != nil { trees[*node.Subtree] = true } } @@ -128,7 +128,7 @@ func runRecover(ctx context.Context, gopts GlobalOptions) error { for id := range roots { var subtreeID = id node := restic.Node{ - Type: "dir", + Type: restic.NodeTypeDir, Name: id.Str(), Mode: 0755, Subtree: &subtreeID, diff --git a/cmd/restic/cmd_repair_snapshots.go b/cmd/restic/cmd_repair_snapshots.go index 385854312..46ba52dd4 100644 --- a/cmd/restic/cmd_repair_snapshots.go +++ b/cmd/restic/cmd_repair_snapshots.go @@ -92,7 +92,7 @@ func runRepairSnapshots(ctx context.Context, gopts GlobalOptions, opts RepairOpt // - files whose contents are not fully available (-> file will be modified) rewriter := walker.NewTreeRewriter(walker.RewriteOpts{ RewriteNode: func(node *restic.Node, path string) *restic.Node { - if node.Type != "file" { + if node.Type != restic.NodeTypeFile { return node } diff --git a/cmd/restic/cmd_stats.go b/cmd/restic/cmd_stats.go index dd51175d3..e0b60a29e 100644 --- a/cmd/restic/cmd_stats.go +++ b/cmd/restic/cmd_stats.go @@ -276,7 +276,7 @@ func statsWalkTree(repo restic.Loader, opts StatsOptions, stats *statsContainer, // will still be restored stats.TotalFileCount++ - if node.Links == 1 || node.Type == "dir" { + if node.Links == 1 || node.Type == restic.NodeTypeDir { stats.TotalSize += node.Size } else { // if hardlinks are present only count each deviceID+inode once diff --git a/cmd/restic/format.go b/cmd/restic/format.go index 063cd4e71..e7d178b4e 100644 --- a/cmd/restic/format.go +++ b/cmd/restic/format.go @@ -24,20 +24,20 @@ func formatNode(path string, n *restic.Node, long bool, human bool) string { } switch n.Type { - case "file": + case restic.NodeTypeFile: mode = 0 - case "dir": + case restic.NodeTypeDir: mode = os.ModeDir - case "symlink": + case restic.NodeTypeSymlink: mode = os.ModeSymlink target = fmt.Sprintf(" -> %v", n.LinkTarget) - case "dev": + case restic.NodeTypeDev: mode = os.ModeDevice - case "chardev": + case restic.NodeTypeCharDev: mode = os.ModeDevice | os.ModeCharDevice - case "fifo": + case restic.NodeTypeFifo: mode = os.ModeNamedPipe - case "socket": + case restic.NodeTypeSocket: mode = os.ModeSocket } diff --git a/cmd/restic/format_test.go b/cmd/restic/format_test.go index 689bd27a5..e232a200b 100644 --- a/cmd/restic/format_test.go +++ b/cmd/restic/format_test.go @@ -19,7 +19,7 @@ func TestFormatNode(t *testing.T) { testPath := "/test/path" node := restic.Node{ Name: "baz", - Type: "file", + Type: restic.NodeTypeFile, Size: 14680064, UID: 1000, GID: 2000, diff --git a/internal/archiver/archiver.go b/internal/archiver/archiver.go index a783f6c7f..0a0c18d28 100644 --- a/internal/archiver/archiver.go +++ b/internal/archiver/archiver.go @@ -232,7 +232,7 @@ func (arch *Archiver) trackItem(item string, previous, current *restic.Node, s I } switch current.Type { - case "dir": + case restic.NodeTypeDir: switch { case previous == nil: arch.summary.Dirs.New++ @@ -242,7 +242,7 @@ func (arch *Archiver) trackItem(item string, previous, current *restic.Node, s I arch.summary.Dirs.Changed++ } - case "file": + case restic.NodeTypeFile: switch { case previous == nil: arch.summary.Files.New++ @@ -261,7 +261,7 @@ func (arch *Archiver) nodeFromFileInfo(snPath, filename string, fi os.FileInfo, node.AccessTime = node.ModTime } if feature.Flag.Enabled(feature.DeviceIDForHardlinks) { - if node.Links == 1 || node.Type == "dir" { + if node.Links == 1 || node.Type == restic.NodeTypeDir { // the DeviceID is only necessary for hardlinked files // when using subvolumes or snapshots their deviceIDs tend to change which causes // restic to upload new tree blobs @@ -280,7 +280,7 @@ func (arch *Archiver) nodeFromFileInfo(snPath, filename string, fi os.FileInfo, // loadSubtree tries to load the subtree referenced by node. In case of an error, nil is returned. // If there is no node to load, then nil is returned without an error. func (arch *Archiver) loadSubtree(ctx context.Context, node *restic.Node) (*restic.Tree, error) { - if node == nil || node.Type != "dir" || node.Subtree == nil { + if node == nil || node.Type != restic.NodeTypeDir || node.Subtree == nil { return nil, nil } @@ -583,7 +583,7 @@ func fileChanged(fs fs.FS, fi os.FileInfo, node *restic.Node, ignoreFlags uint) switch { case node == nil: return true - case node.Type != "file": + case node.Type != restic.NodeTypeFile: // We're only called for regular files, so this is a type change. return true case uint64(fi.Size()) != node.Size: diff --git a/internal/archiver/archiver_test.go b/internal/archiver/archiver_test.go index 962fd5481..04d0b876b 100644 --- a/internal/archiver/archiver_test.go +++ b/internal/archiver/archiver_test.go @@ -730,7 +730,7 @@ func TestFilChangedSpecialCases(t *testing.T) { t.Run("type-change", func(t *testing.T) { fi := lstat(t, filename) node := nodeFromFI(t, filename, fi) - node.Type = "symlink" + node.Type = "restic.NodeTypeSymlink" if !fileChanged(&fs.Local{}, fi, node, 0) { t.Fatal("node with changed type detected as unchanged") } diff --git a/internal/archiver/file_saver.go b/internal/archiver/file_saver.go index fa19cab86..b9d07434a 100644 --- a/internal/archiver/file_saver.go +++ b/internal/archiver/file_saver.go @@ -163,7 +163,7 @@ func (s *fileSaver) saveFile(ctx context.Context, chnker *chunker.Chunker, snPat return } - if node.Type != "file" { + if node.Type != restic.NodeTypeFile { _ = f.Close() completeError(errors.Errorf("node type %q is wrong", node.Type)) return diff --git a/internal/archiver/testing.go b/internal/archiver/testing.go index 8bd854904..97bada644 100644 --- a/internal/archiver/testing.go +++ b/internal/archiver/testing.go @@ -289,7 +289,7 @@ func TestEnsureTree(ctx context.Context, t testing.TB, prefix string, repo resti switch e := entry.(type) { case TestDir: - if node.Type != "dir" { + if node.Type != restic.NodeTypeDir { t.Errorf("tree node %v has wrong type %q, want %q", nodePrefix, node.Type, "dir") return } @@ -301,13 +301,13 @@ func TestEnsureTree(ctx context.Context, t testing.TB, prefix string, repo resti TestEnsureTree(ctx, t, path.Join(prefix, node.Name), repo, *node.Subtree, e) case TestFile: - if node.Type != "file" { + if node.Type != restic.NodeTypeFile { t.Errorf("tree node %v has wrong type %q, want %q", nodePrefix, node.Type, "file") } TestEnsureFileContent(ctx, t, repo, nodePrefix, node, e) case TestSymlink: - if node.Type != "symlink" { - t.Errorf("tree node %v has wrong type %q, want %q", nodePrefix, node.Type, "file") + if node.Type != restic.NodeTypeSymlink { + t.Errorf("tree node %v has wrong type %q, want %q", nodePrefix, node.Type, "symlink") } if e.Target != node.LinkTarget { diff --git a/internal/checker/checker.go b/internal/checker/checker.go index 76bb15f63..12020891a 100644 --- a/internal/checker/checker.go +++ b/internal/checker/checker.go @@ -344,7 +344,7 @@ func (c *Checker) checkTree(id restic.ID, tree *restic.Tree) (errs []error) { for _, node := range tree.Nodes { switch node.Type { - case "file": + case restic.NodeTypeFile: if node.Content == nil { errs = append(errs, &Error{TreeID: id, Err: errors.Errorf("file %q has nil blob list", node.Name)}) } @@ -380,7 +380,7 @@ func (c *Checker) checkTree(id restic.ID, tree *restic.Tree) (errs []error) { c.blobRefs.Unlock() } - case "dir": + case restic.NodeTypeDir: if node.Subtree == nil { errs = append(errs, &Error{TreeID: id, Err: errors.Errorf("dir node %q has no subtree", node.Name)}) continue @@ -391,7 +391,7 @@ func (c *Checker) checkTree(id restic.ID, tree *restic.Tree) (errs []error) { continue } - case "symlink", "socket", "chardev", "dev", "fifo": + case restic.NodeTypeSymlink, restic.NodeTypeSocket, restic.NodeTypeCharDev, restic.NodeTypeDev, restic.NodeTypeFifo: // nothing to check default: diff --git a/internal/checker/checker_test.go b/internal/checker/checker_test.go index 5eaf550ba..0e2125bba 100644 --- a/internal/checker/checker_test.go +++ b/internal/checker/checker_test.go @@ -482,7 +482,7 @@ func TestCheckerBlobTypeConfusion(t *testing.T) { damagedNode := &restic.Node{ Name: "damaged", - Type: "file", + Type: restic.NodeTypeFile, Mode: 0644, Size: 42, Content: restic.IDs{restic.TestParseID("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")}, @@ -507,14 +507,14 @@ func TestCheckerBlobTypeConfusion(t *testing.T) { malNode := &restic.Node{ Name: "aaaaa", - Type: "file", + Type: restic.NodeTypeFile, Mode: 0644, Size: uint64(len(buf)), Content: restic.IDs{id}, } dirNode := &restic.Node{ Name: "bbbbb", - Type: "dir", + Type: restic.NodeTypeDir, Mode: 0755, Subtree: &id, } diff --git a/internal/dump/common.go b/internal/dump/common.go index 62145ba9c..4bc404fe0 100644 --- a/internal/dump/common.go +++ b/internal/dump/common.go @@ -67,7 +67,7 @@ func sendNodes(ctx context.Context, repo restic.BlobLoader, root *restic.Node, c } // If this is no directory we are finished - if !IsDir(root) { + if root.Type != restic.NodeTypeDir { return nil } @@ -81,7 +81,7 @@ func sendNodes(ctx context.Context, repo restic.BlobLoader, root *restic.Node, c node.Path = path.Join(root.Path, nodepath) - if !IsFile(node) && !IsDir(node) && !IsLink(node) { + if node.Type != restic.NodeTypeFile && node.Type != restic.NodeTypeDir && node.Type != restic.NodeTypeSymlink { return nil } @@ -176,18 +176,3 @@ func (d *Dumper) writeNode(ctx context.Context, w io.Writer, node *restic.Node) return wg.Wait() } - -// IsDir checks if the given node is a directory. -func IsDir(node *restic.Node) bool { - return node.Type == "dir" -} - -// IsLink checks if the given node as a link. -func IsLink(node *restic.Node) bool { - return node.Type == "symlink" -} - -// IsFile checks if the given node is a file. -func IsFile(node *restic.Node) bool { - return node.Type == "file" -} diff --git a/internal/dump/tar.go b/internal/dump/tar.go index e8f34deb1..c5933d4f8 100644 --- a/internal/dump/tar.go +++ b/internal/dump/tar.go @@ -79,16 +79,16 @@ func (d *Dumper) dumpNodeTar(ctx context.Context, node *restic.Node, w *tar.Writ header.Mode |= cISVTX } - if IsFile(node) { + if node.Type == restic.NodeTypeFile { header.Typeflag = tar.TypeReg } - if IsLink(node) { + if node.Type == restic.NodeTypeSymlink { header.Typeflag = tar.TypeSymlink header.Linkname = node.LinkTarget } - if IsDir(node) { + if node.Type == restic.NodeTypeDir { header.Typeflag = tar.TypeDir header.Name += "/" } diff --git a/internal/dump/tar_test.go b/internal/dump/tar_test.go index 3556e6aeb..0c97eae35 100644 --- a/internal/dump/tar_test.go +++ b/internal/dump/tar_test.go @@ -124,7 +124,7 @@ func TestFieldTooLong(t *testing.T) { node := restic.Node{ Name: "file_with_xattr", Path: "/file_with_xattr", - Type: "file", + Type: restic.NodeTypeFile, Mode: 0644, ExtendedAttributes: []restic.ExtendedAttribute{ { diff --git a/internal/dump/zip.go b/internal/dump/zip.go index e5ef5c95b..d32475770 100644 --- a/internal/dump/zip.go +++ b/internal/dump/zip.go @@ -40,7 +40,7 @@ func (d *Dumper) dumpNodeZip(ctx context.Context, node *restic.Node, zw *zip.Wri } header.SetMode(node.Mode) - if IsDir(node) { + if node.Type == restic.NodeTypeDir { header.Name += "/" } @@ -49,7 +49,7 @@ func (d *Dumper) dumpNodeZip(ctx context.Context, node *restic.Node, zw *zip.Wri return errors.Wrap(err, "ZipHeader") } - if IsLink(node) { + if node.Type == restic.NodeTypeSymlink { if _, err = w.Write([]byte(node.LinkTarget)); err != nil { return errors.Wrap(err, "Write") } diff --git a/internal/fs/file_windows.go b/internal/fs/file_windows.go index 50c7e9938..7a6d79f25 100644 --- a/internal/fs/file_windows.go +++ b/internal/fs/file_windows.go @@ -8,6 +8,7 @@ import ( "strings" "time" + "github.com/restic/restic/internal/restic" "golang.org/x/sys/windows" ) @@ -105,7 +106,7 @@ func ClearAttribute(path string, attribute uint32) error { } // OpenHandleForEA return a file handle for file or dir for setting/getting EAs -func OpenHandleForEA(nodeType, path string, writeAccess bool) (handle windows.Handle, err error) { +func OpenHandleForEA(nodeType restic.NodeType, path string, writeAccess bool) (handle windows.Handle, err error) { path = fixpath(path) fileAccess := windows.FILE_READ_EA if writeAccess { @@ -113,10 +114,10 @@ func OpenHandleForEA(nodeType, path string, writeAccess bool) (handle windows.Ha } switch nodeType { - case "file": + case restic.NodeTypeFile: utf16Path := windows.StringToUTF16Ptr(path) handle, err = windows.CreateFile(utf16Path, uint32(fileAccess), 0, nil, windows.OPEN_EXISTING, windows.FILE_ATTRIBUTE_NORMAL, 0) - case "dir": + case restic.NodeTypeDir: utf16Path := windows.StringToUTF16Ptr(path) handle, err = windows.CreateFile(utf16Path, uint32(fileAccess), 0, nil, windows.OPEN_EXISTING, windows.FILE_ATTRIBUTE_NORMAL|windows.FILE_FLAG_BACKUP_SEMANTICS, 0) default: diff --git a/internal/fs/node.go b/internal/fs/node.go index 9bd507ba5..e29011cc2 100644 --- a/internal/fs/node.go +++ b/internal/fs/node.go @@ -25,7 +25,7 @@ func NodeFromFileInfo(path string, fi os.FileInfo, ignoreXattrListError bool) (* } node.Type = nodeTypeFromFileInfo(fi) - if node.Type == "file" { + if node.Type == restic.NodeTypeFile { node.Size = uint64(fi.Size()) } @@ -33,27 +33,27 @@ func NodeFromFileInfo(path string, fi os.FileInfo, ignoreXattrListError bool) (* return node, err } -func nodeTypeFromFileInfo(fi os.FileInfo) string { +func nodeTypeFromFileInfo(fi os.FileInfo) restic.NodeType { switch fi.Mode() & os.ModeType { case 0: - return "file" + return restic.NodeTypeFile case os.ModeDir: - return "dir" + return restic.NodeTypeDir case os.ModeSymlink: - return "symlink" + return restic.NodeTypeSymlink case os.ModeDevice | os.ModeCharDevice: - return "chardev" + return restic.NodeTypeCharDev case os.ModeDevice: - return "dev" + return restic.NodeTypeDev case os.ModeNamedPipe: - return "fifo" + return restic.NodeTypeFifo case os.ModeSocket: - return "socket" + return restic.NodeTypeSocket case os.ModeIrregular: - return "irregular" + return restic.NodeTypeIrregular } - return "" + return restic.NodeTypeInvalid } func nodeFillExtra(node *restic.Node, path string, fi os.FileInfo, ignoreXattrListError bool) error { @@ -74,25 +74,25 @@ func nodeFillExtra(node *restic.Node, path string, fi os.FileInfo, ignoreXattrLi nodeFillUser(node, stat) switch node.Type { - case "file": + case restic.NodeTypeFile: node.Size = uint64(stat.size()) node.Links = uint64(stat.nlink()) - case "dir": - case "symlink": + case restic.NodeTypeDir: + case restic.NodeTypeSymlink: var err error node.LinkTarget, err = Readlink(path) node.Links = uint64(stat.nlink()) if err != nil { return errors.WithStack(err) } - case "dev": + case restic.NodeTypeDev: node.Device = uint64(stat.rdev()) node.Links = uint64(stat.nlink()) - case "chardev": + case restic.NodeTypeCharDev: node.Device = uint64(stat.rdev()) node.Links = uint64(stat.nlink()) - case "fifo": - case "socket": + case restic.NodeTypeFifo: + case restic.NodeTypeSocket: default: return errors.Errorf("unsupported file type %q", node.Type) } @@ -178,31 +178,31 @@ func NodeCreateAt(node *restic.Node, path string) error { debug.Log("create node %v at %v", node.Name, path) switch node.Type { - case "dir": + case restic.NodeTypeDir: if err := nodeCreateDirAt(node, path); err != nil { return err } - case "file": + case restic.NodeTypeFile: if err := nodeCreateFileAt(path); err != nil { return err } - case "symlink": + case restic.NodeTypeSymlink: if err := nodeCreateSymlinkAt(node, path); err != nil { return err } - case "dev": + case restic.NodeTypeDev: if err := nodeCreateDevAt(node, path); err != nil { return err } - case "chardev": + case restic.NodeTypeCharDev: if err := nodeCreateCharDevAt(node, path); err != nil { return err } - case "fifo": + case restic.NodeTypeFifo: if err := nodeCreateFifoAt(path); err != nil { return err } - case "socket": + case restic.NodeTypeSocket: return nil default: return errors.Errorf("filetype %q not implemented", node.Type) @@ -305,7 +305,7 @@ func nodeRestoreMetadata(node *restic.Node, path string, warn func(msg string)) // Moving RestoreTimestamps and restoreExtendedAttributes calls above as for readonly files in windows // calling Chmod below will no longer allow any modifications to be made on the file and the // calls above would fail. - if node.Type != "symlink" { + if node.Type != restic.NodeTypeSymlink { if err := Chmod(path, node.Mode); err != nil { if firsterr == nil { firsterr = errors.WithStack(err) @@ -322,7 +322,7 @@ func NodeRestoreTimestamps(node *restic.Node, path string) error { syscall.NsecToTimespec(node.ModTime.UnixNano()), } - if node.Type == "symlink" { + if node.Type == restic.NodeTypeSymlink { return nodeRestoreSymlinkTimestamps(path, utimes) } diff --git a/internal/fs/node_test.go b/internal/fs/node_test.go index e7f608352..2623513a8 100644 --- a/internal/fs/node_test.go +++ b/internal/fs/node_test.go @@ -79,7 +79,7 @@ func parseTime(s string) time.Time { var nodeTests = []restic.Node{ { Name: "testFile", - Type: "file", + Type: restic.NodeTypeFile, Content: restic.IDs{}, UID: uint32(os.Getuid()), GID: uint32(os.Getgid()), @@ -90,7 +90,7 @@ var nodeTests = []restic.Node{ }, { Name: "testSuidFile", - Type: "file", + Type: restic.NodeTypeFile, Content: restic.IDs{}, UID: uint32(os.Getuid()), GID: uint32(os.Getgid()), @@ -101,7 +101,7 @@ var nodeTests = []restic.Node{ }, { Name: "testSuidFile2", - Type: "file", + Type: restic.NodeTypeFile, Content: restic.IDs{}, UID: uint32(os.Getuid()), GID: uint32(os.Getgid()), @@ -112,7 +112,7 @@ var nodeTests = []restic.Node{ }, { Name: "testSticky", - Type: "file", + Type: restic.NodeTypeFile, Content: restic.IDs{}, UID: uint32(os.Getuid()), GID: uint32(os.Getgid()), @@ -123,7 +123,7 @@ var nodeTests = []restic.Node{ }, { Name: "testDir", - Type: "dir", + Type: restic.NodeTypeDir, Subtree: nil, UID: uint32(os.Getuid()), GID: uint32(os.Getgid()), @@ -134,7 +134,7 @@ var nodeTests = []restic.Node{ }, { Name: "testSymlink", - Type: "symlink", + Type: restic.NodeTypeSymlink, LinkTarget: "invalid", UID: uint32(os.Getuid()), GID: uint32(os.Getgid()), @@ -148,7 +148,7 @@ var nodeTests = []restic.Node{ // metadata, so we can test if CreateAt works with pre-existing files. { Name: "testFile", - Type: "file", + Type: restic.NodeTypeFile, Content: restic.IDs{}, UID: uint32(os.Getuid()), GID: uint32(os.Getgid()), @@ -159,7 +159,7 @@ var nodeTests = []restic.Node{ }, { Name: "testDir", - Type: "dir", + Type: restic.NodeTypeDir, Subtree: nil, UID: uint32(os.Getuid()), GID: uint32(os.Getgid()), @@ -170,7 +170,7 @@ var nodeTests = []restic.Node{ }, { Name: "testXattrFile", - Type: "file", + Type: restic.NodeTypeFile, Content: restic.IDs{}, UID: uint32(os.Getuid()), GID: uint32(os.Getgid()), @@ -184,7 +184,7 @@ var nodeTests = []restic.Node{ }, { Name: "testXattrDir", - Type: "dir", + Type: restic.NodeTypeDir, Subtree: nil, UID: uint32(os.Getuid()), GID: uint32(os.Getgid()), @@ -198,7 +198,7 @@ var nodeTests = []restic.Node{ }, { Name: "testXattrFileMacOSResourceFork", - Type: "file", + Type: restic.NodeTypeFile, Content: restic.IDs{}, UID: uint32(os.Getuid()), GID: uint32(os.Getgid()), @@ -268,7 +268,7 @@ func TestNodeRestoreAt(t *testing.T) { "%v: UID doesn't match (%v != %v)", test.Type, test.UID, n2.UID) rtest.Assert(t, test.GID == n2.GID, "%v: GID doesn't match (%v != %v)", test.Type, test.GID, n2.GID) - if test.Type != "symlink" { + if test.Type != restic.NodeTypeSymlink { // On OpenBSD only root can set sticky bit (see sticky(8)). if runtime.GOOS != "openbsd" && runtime.GOOS != "netbsd" && runtime.GOOS != "solaris" && test.Name == "testSticky" { rtest.Assert(t, test.Mode == n2.Mode, @@ -288,11 +288,11 @@ func TestNodeRestoreAt(t *testing.T) { } } -func AssertFsTimeEqual(t *testing.T, label string, nodeType string, t1 time.Time, t2 time.Time) { +func AssertFsTimeEqual(t *testing.T, label string, nodeType restic.NodeType, t1 time.Time, t2 time.Time) { var equal bool // Go currently doesn't support setting timestamps of symbolic links on darwin and bsd - if nodeType == "symlink" { + if nodeType == restic.NodeTypeSymlink { switch runtime.GOOS { case "darwin", "freebsd", "openbsd", "netbsd", "solaris": return diff --git a/internal/fs/node_unix_test.go b/internal/fs/node_unix_test.go index b505357f2..3658c8356 100644 --- a/internal/fs/node_unix_test.go +++ b/internal/fs/node_unix_test.go @@ -42,7 +42,7 @@ func checkFile(t testing.TB, stat *syscall.Stat_t, node *restic.Node) { t.Errorf("Dev does not match, want %v, got %v", stat.Dev, node.DeviceID) } - if node.Size != uint64(stat.Size) && node.Type != "symlink" { + if node.Size != uint64(stat.Size) && node.Type != restic.NodeTypeSymlink { t.Errorf("Size does not match, want %v, got %v", stat.Size, node.Size) } @@ -135,9 +135,9 @@ func TestNodeFromFileInfo(t *testing.T) { } switch node.Type { - case "file", "symlink": + case restic.NodeTypeFile, restic.NodeTypeSymlink: checkFile(t, s, node) - case "dev", "chardev": + case restic.NodeTypeDev, restic.NodeTypeCharDev: checkFile(t, s, node) checkDevice(t, s, node) default: diff --git a/internal/fs/node_windows.go b/internal/fs/node_windows.go index 90fa3462c..f2a2001e9 100644 --- a/internal/fs/node_windows.go +++ b/internal/fs/node_windows.go @@ -139,7 +139,7 @@ func closeFileHandle(fileHandle windows.Handle, path string) { // restoreExtendedAttributes handles restore of the Windows Extended Attributes to the specified path. // The Windows API requires setting of all the Extended Attributes in one call. -func restoreExtendedAttributes(nodeType, path string, eas []ExtendedAttribute) (err error) { +func restoreExtendedAttributes(nodeType restic.NodeType, path string, eas []ExtendedAttribute) (err error) { var fileHandle windows.Handle if fileHandle, err = OpenHandleForEA(nodeType, path, true); fileHandle == 0 { return nil @@ -386,7 +386,7 @@ func nodeFillGenericAttributes(node *restic.Node, path string, fi os.FileInfo, s } var sd *[]byte - if node.Type == "file" || node.Type == "dir" { + if node.Type == restic.NodeTypeFile || node.Type == restic.NodeTypeDir { // Check EA support and get security descriptor for file/dir only allowExtended, err = checkAndStoreEASupport(path) if err != nil { diff --git a/internal/fs/node_windows_test.go b/internal/fs/node_windows_test.go index 046c1984c..729ce2adb 100644 --- a/internal/fs/node_windows_test.go +++ b/internal/fs/node_windows_test.go @@ -24,14 +24,14 @@ func TestRestoreSecurityDescriptors(t *testing.T) { t.Parallel() tempDir := t.TempDir() for i, sd := range TestFileSDs { - testRestoreSecurityDescriptor(t, sd, tempDir, "file", fmt.Sprintf("testfile%d", i)) + testRestoreSecurityDescriptor(t, sd, tempDir, restic.NodeTypeFile, fmt.Sprintf("testfile%d", i)) } for i, sd := range TestDirSDs { - testRestoreSecurityDescriptor(t, sd, tempDir, "dir", fmt.Sprintf("testdir%d", i)) + testRestoreSecurityDescriptor(t, sd, tempDir, restic.NodeTypeDir, fmt.Sprintf("testdir%d", i)) } } -func testRestoreSecurityDescriptor(t *testing.T, sd string, tempDir, fileType, fileName string) { +func testRestoreSecurityDescriptor(t *testing.T, sd string, tempDir string, fileType restic.NodeType, fileName string) { // Decode the encoded string SD to get the security descriptor input in bytes. sdInputBytes, err := base64.StdEncoding.DecodeString(sd) test.OK(t, errors.Wrapf(err, "Error decoding SD for: %s", fileName)) @@ -56,7 +56,7 @@ func testRestoreSecurityDescriptor(t *testing.T, sd string, tempDir, fileType, f CompareSecurityDescriptors(t, testPath, *sdByteFromRestoredNode, *sdBytesFromRestoredPath) } -func getNode(name string, fileType string, genericAttributes map[restic.GenericAttributeType]json.RawMessage) restic.Node { +func getNode(name string, fileType restic.NodeType, genericAttributes map[restic.GenericAttributeType]json.RawMessage) restic.Node { return restic.Node{ Name: name, Type: fileType, @@ -113,7 +113,7 @@ func TestRestoreFileAttributes(t *testing.T) { expectedNodes := []restic.Node{ { Name: fmt.Sprintf("testfile%d", i), - Type: "file", + Type: restic.NodeTypeFile, Mode: 0655, ModTime: parseTime("2005-05-14 21:07:03.111"), AccessTime: parseTime("2005-05-14 21:07:04.222"), @@ -146,7 +146,7 @@ func TestRestoreFileAttributes(t *testing.T) { expectedNodes := []restic.Node{ { Name: fmt.Sprintf("testdirectory%d", i), - Type: "dir", + Type: restic.NodeTypeDir, Mode: 0755, ModTime: parseTime("2005-05-14 21:07:03.111"), AccessTime: parseTime("2005-05-14 21:07:04.222"), @@ -164,7 +164,7 @@ func runGenericAttributesTest(t *testing.T, tempDir string, genericAttributeName expectedNodes := []restic.Node{ { Name: "testfile", - Type: "file", + Type: restic.NodeTypeFile, Mode: 0644, ModTime: parseTime("2005-05-14 21:07:03.111"), AccessTime: parseTime("2005-05-14 21:07:04.222"), @@ -173,7 +173,7 @@ func runGenericAttributesTest(t *testing.T, tempDir string, genericAttributeName }, { Name: "testdirectory", - Type: "dir", + Type: restic.NodeTypeDir, Mode: 0755, ModTime: parseTime("2005-05-14 21:07:03.111"), AccessTime: parseTime("2005-05-14 21:07:04.222"), @@ -200,12 +200,12 @@ func restoreAndGetNode(t *testing.T, tempDir string, testNode *restic.Node, warn err := os.MkdirAll(filepath.Dir(testPath), testNode.Mode) test.OK(t, errors.Wrapf(err, "Failed to create parent directories for: %s", testPath)) - if testNode.Type == "file" { + if testNode.Type == restic.NodeTypeFile { testFile, err := os.Create(testPath) test.OK(t, errors.Wrapf(err, "Failed to create test file: %s", testPath)) testFile.Close() - } else if testNode.Type == "dir" { + } else if testNode.Type == restic.NodeTypeDir { err := os.Mkdir(testPath, testNode.Mode) test.OK(t, errors.Wrapf(err, "Failed to create test directory: %s", testPath)) @@ -242,7 +242,7 @@ func TestNewGenericAttributeType(t *testing.T) { expectedNodes := []restic.Node{ { Name: "testfile", - Type: "file", + Type: restic.NodeTypeFile, Mode: 0644, ModTime: parseTime("2005-05-14 21:07:03.111"), AccessTime: parseTime("2005-05-14 21:07:04.222"), @@ -251,7 +251,7 @@ func TestNewGenericAttributeType(t *testing.T) { }, { Name: "testdirectory", - Type: "dir", + Type: restic.NodeTypeDir, Mode: 0755, ModTime: parseTime("2005-05-14 21:07:03.111"), AccessTime: parseTime("2005-05-14 21:07:04.222"), @@ -274,7 +274,7 @@ func TestRestoreExtendedAttributes(t *testing.T) { expectedNodes := []restic.Node{ { Name: "testfile", - Type: "file", + Type: restic.NodeTypeFile, Mode: 0644, ModTime: parseTime("2005-05-14 21:07:03.111"), AccessTime: parseTime("2005-05-14 21:07:04.222"), @@ -285,7 +285,7 @@ func TestRestoreExtendedAttributes(t *testing.T) { }, { Name: "testdirectory", - Type: "dir", + Type: restic.NodeTypeDir, Mode: 0755, ModTime: parseTime("2005-05-14 21:07:03.111"), AccessTime: parseTime("2005-05-14 21:07:04.222"), @@ -301,9 +301,9 @@ func TestRestoreExtendedAttributes(t *testing.T) { var handle windows.Handle var err error utf16Path := windows.StringToUTF16Ptr(testPath) - if node.Type == "file" { + if node.Type == restic.NodeTypeFile { handle, err = windows.CreateFile(utf16Path, windows.FILE_READ_EA, 0, nil, windows.OPEN_EXISTING, windows.FILE_ATTRIBUTE_NORMAL, 0) - } else if node.Type == "dir" { + } else if node.Type == restic.NodeTypeDir { handle, err = windows.CreateFile(utf16Path, windows.FILE_READ_EA, 0, nil, windows.OPEN_EXISTING, windows.FILE_ATTRIBUTE_NORMAL|windows.FILE_FLAG_BACKUP_SEMANTICS, 0) } test.OK(t, errors.Wrapf(err, "Error opening file/directory for: %s", testPath)) diff --git a/internal/fs/node_xattr_all_test.go b/internal/fs/node_xattr_all_test.go index 39670d6e1..690302f70 100644 --- a/internal/fs/node_xattr_all_test.go +++ b/internal/fs/node_xattr_all_test.go @@ -23,13 +23,13 @@ func setAndVerifyXattr(t *testing.T, file string, attrs []restic.ExtendedAttribu } node := &restic.Node{ - Type: "file", + Type: restic.NodeTypeFile, ExtendedAttributes: attrs, } rtest.OK(t, nodeRestoreExtendedAttributes(node, file)) nodeActual := &restic.Node{ - Type: "file", + Type: restic.NodeTypeFile, } rtest.OK(t, nodeFillExtendedAttributes(nodeActual, file, false)) diff --git a/internal/fuse/dir.go b/internal/fuse/dir.go index fd030295b..62298cf24 100644 --- a/internal/fuse/dir.go +++ b/internal/fuse/dir.go @@ -59,7 +59,7 @@ func unwrapCtxCanceled(err error) error { // replaceSpecialNodes replaces nodes with name "." and "/" by their contents. // Otherwise, the node is returned. func replaceSpecialNodes(ctx context.Context, repo restic.BlobLoader, node *restic.Node) ([]*restic.Node, error) { - if node.Type != "dir" || node.Subtree == nil { + if node.Type != restic.NodeTypeDir || node.Subtree == nil { return []*restic.Node{node}, nil } @@ -147,7 +147,7 @@ func (d *dir) calcNumberOfLinks() uint32 { // of directories contained by d count := uint32(2) for _, node := range d.items { - if node.Type == "dir" { + if node.Type == restic.NodeTypeDir { count++ } } @@ -182,11 +182,11 @@ func (d *dir) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) { name := cleanupNodeName(node.Name) var typ fuse.DirentType switch node.Type { - case "dir": + case restic.NodeTypeDir: typ = fuse.DT_Dir - case "file": + case restic.NodeTypeFile: typ = fuse.DT_File - case "symlink": + case restic.NodeTypeSymlink: typ = fuse.DT_Link } @@ -215,13 +215,13 @@ func (d *dir) Lookup(ctx context.Context, name string) (fs.Node, error) { } inode := inodeFromNode(d.inode, node) switch node.Type { - case "dir": + case restic.NodeTypeDir: return newDir(d.root, inode, d.inode, node) - case "file": + case restic.NodeTypeFile: return newFile(d.root, inode, node) - case "symlink": + case restic.NodeTypeSymlink: return newLink(d.root, inode, node) - case "dev", "chardev", "fifo", "socket": + case restic.NodeTypeDev, restic.NodeTypeCharDev, restic.NodeTypeFifo, restic.NodeTypeSocket: return newOther(d.root, inode, node) default: debug.Log(" node %v has unknown type %v", name, node.Type) diff --git a/internal/fuse/fuse_test.go b/internal/fuse/fuse_test.go index aebcb1272..bbdfe6b3f 100644 --- a/internal/fuse/fuse_test.go +++ b/internal/fuse/fuse_test.go @@ -249,7 +249,7 @@ func TestBlocks(t *testing.T) { } func TestInodeFromNode(t *testing.T) { - node := &restic.Node{Name: "foo.txt", Type: "chardev", Links: 2} + node := &restic.Node{Name: "foo.txt", Type: restic.NodeTypeCharDev, Links: 2} ino1 := inodeFromNode(1, node) ino2 := inodeFromNode(2, node) rtest.Assert(t, ino1 == ino2, "inodes %d, %d of hard links differ", ino1, ino2) @@ -261,9 +261,9 @@ func TestInodeFromNode(t *testing.T) { // Regression test: in a path a/b/b, the grandchild should not get the // same inode as the grandparent. - a := &restic.Node{Name: "a", Type: "dir", Links: 2} - ab := &restic.Node{Name: "b", Type: "dir", Links: 2} - abb := &restic.Node{Name: "b", Type: "dir", Links: 2} + a := &restic.Node{Name: "a", Type: restic.NodeTypeDir, Links: 2} + ab := &restic.Node{Name: "b", Type: restic.NodeTypeDir, Links: 2} + abb := &restic.Node{Name: "b", Type: restic.NodeTypeDir, Links: 2} inoA := inodeFromNode(1, a) inoAb := inodeFromNode(inoA, ab) inoAbb := inodeFromNode(inoAb, abb) @@ -272,7 +272,7 @@ func TestInodeFromNode(t *testing.T) { } func TestLink(t *testing.T) { - node := &restic.Node{Name: "foo.txt", Type: "symlink", Links: 1, LinkTarget: "dst", ExtendedAttributes: []restic.ExtendedAttribute{ + node := &restic.Node{Name: "foo.txt", Type: restic.NodeTypeSymlink, Links: 1, LinkTarget: "dst", ExtendedAttributes: []restic.ExtendedAttribute{ {Name: "foo", Value: []byte("bar")}, }} @@ -305,11 +305,11 @@ func BenchmarkInode(b *testing.B) { }{ { name: "no_hard_links", - node: restic.Node{Name: "a somewhat long-ish filename.svg.bz2", Type: "fifo"}, + node: restic.Node{Name: "a somewhat long-ish filename.svg.bz2", Type: restic.NodeTypeFifo}, }, { name: "hard_link", - node: restic.Node{Name: "some other filename", Type: "file", Links: 2}, + node: restic.Node{Name: "some other filename", Type: restic.NodeTypeFile, Links: 2}, }, } { b.Run(sub.name, func(b *testing.B) { diff --git a/internal/fuse/inode.go b/internal/fuse/inode.go index 5e2ece4ac..88d5b8bb8 100644 --- a/internal/fuse/inode.go +++ b/internal/fuse/inode.go @@ -25,7 +25,7 @@ func inodeFromName(parent uint64, name string) uint64 { // inodeFromNode generates an inode number for a file within a snapshot. func inodeFromNode(parent uint64, node *restic.Node) (inode uint64) { - if node.Links > 1 && node.Type != "dir" { + if node.Links > 1 && node.Type != restic.NodeTypeDir { // If node has hard links, give them all the same inode, // irrespective of the parent. var buf [16]byte diff --git a/internal/restic/find.go b/internal/restic/find.go index d7b032bf8..f9b4e8bdf 100644 --- a/internal/restic/find.go +++ b/internal/restic/find.go @@ -46,7 +46,7 @@ func FindUsedBlobs(ctx context.Context, repo Loader, treeIDs IDs, blobs FindBlob lock.Lock() for _, node := range tree.Nodes { switch node.Type { - case "file": + case NodeTypeFile: for _, blob := range node.Content { blobs.Insert(BlobHandle{ID: blob, Type: DataBlob}) } diff --git a/internal/restic/node.go b/internal/restic/node.go index 8bf97e59c..c572996a5 100644 --- a/internal/restic/node.go +++ b/internal/restic/node.go @@ -67,10 +67,24 @@ func storeGenericAttributeType(attributeTypes ...GenericAttributeType) { } } +type NodeType string + +var ( + NodeTypeFile = NodeType("file") + NodeTypeDir = NodeType("dir") + NodeTypeSymlink = NodeType("symlink") + NodeTypeDev = NodeType("dev") + NodeTypeCharDev = NodeType("chardev") + NodeTypeFifo = NodeType("fifo") + NodeTypeSocket = NodeType("socket") + NodeTypeIrregular = NodeType("irregular") + NodeTypeInvalid = NodeType("") +) + // Node is a file, directory or other item in a backup. type Node struct { Name string `json:"name"` - Type string `json:"type"` + Type NodeType `json:"type"` Mode os.FileMode `json:"mode,omitempty"` ModTime time.Time `json:"mtime,omitempty"` AccessTime time.Time `json:"atime,omitempty"` @@ -110,19 +124,19 @@ func (n Nodes) Swap(i, j int) { n[i], n[j] = n[j], n[i] } func (node Node) String() string { var mode os.FileMode switch node.Type { - case "file": + case NodeTypeFile: mode = 0 - case "dir": + case NodeTypeDir: mode = os.ModeDir - case "symlink": + case NodeTypeSymlink: mode = os.ModeSymlink - case "dev": + case NodeTypeDev: mode = os.ModeDevice - case "chardev": + case NodeTypeCharDev: mode = os.ModeDevice | os.ModeCharDevice - case "fifo": + case NodeTypeFifo: mode = os.ModeNamedPipe - case "socket": + case NodeTypeSocket: mode = os.ModeSocket } diff --git a/internal/restic/testing.go b/internal/restic/testing.go index 8f86a7b2c..3e0563430 100644 --- a/internal/restic/testing.go +++ b/internal/restic/testing.go @@ -81,7 +81,7 @@ func (fs *fakeFileSystem) saveTree(ctx context.Context, seed int64, depth int) I node := &Node{ Name: fmt.Sprintf("dir-%v", treeSeed), - Type: "dir", + Type: NodeTypeDir, Mode: 0755, Subtree: &id, } @@ -95,7 +95,7 @@ func (fs *fakeFileSystem) saveTree(ctx context.Context, seed int64, depth int) I node := &Node{ Name: fmt.Sprintf("file-%v", fileSeed), - Type: "file", + Type: NodeTypeFile, Mode: 0644, Size: uint64(fileSize), } diff --git a/internal/restic/tree.go b/internal/restic/tree.go index 3c3e3ab56..c4125653b 100644 --- a/internal/restic/tree.go +++ b/internal/restic/tree.go @@ -96,7 +96,7 @@ func (t *Tree) Sort() { // Subtrees returns a slice of all subtree IDs of the tree. func (t *Tree) Subtrees() (trees IDs) { for _, node := range t.Nodes { - if node.Type == "dir" && node.Subtree != nil { + if node.Type == NodeTypeDir && node.Subtree != nil { trees = append(trees, *node.Subtree) } } @@ -208,7 +208,7 @@ func FindTreeDirectory(ctx context.Context, repo BlobLoader, id *ID, dir string) if node == nil { return nil, fmt.Errorf("path %s: not found", subfolder) } - if node.Type != "dir" || node.Subtree == nil { + if node.Type != NodeTypeDir || node.Subtree == nil { return nil, fmt.Errorf("path %s: not a directory", subfolder) } id = node.Subtree diff --git a/internal/restorer/restorer.go b/internal/restorer/restorer.go index 26b6f3474..f28cd0ba3 100644 --- a/internal/restorer/restorer.go +++ b/internal/restorer/restorer.go @@ -202,18 +202,18 @@ func (res *Restorer) traverseTreeInner(ctx context.Context, target, location str } // sockets cannot be restored - if node.Type == "socket" { + if node.Type == restic.NodeTypeSocket { continue } - selectedForRestore, childMayBeSelected := res.SelectFilter(nodeLocation, node.Type == "dir") + selectedForRestore, childMayBeSelected := res.SelectFilter(nodeLocation, node.Type == restic.NodeTypeDir) debug.Log("SelectFilter returned %v %v for %q", selectedForRestore, childMayBeSelected, nodeLocation) if selectedForRestore { hasRestored = true } - if node.Type == "dir" { + if node.Type == restic.NodeTypeDir { if node.Subtree == nil { return nil, hasRestored, errors.Errorf("Dir without subtree in tree %v", treeID.Str()) } @@ -377,7 +377,7 @@ func (res *Restorer) RestoreTo(ctx context.Context, dst string) (uint64, error) return err } - if node.Type != "file" { + if node.Type != restic.NodeTypeFile { res.opts.Progress.AddFile(0) return nil } @@ -433,7 +433,7 @@ func (res *Restorer) RestoreTo(ctx context.Context, dst string) (uint64, error) err = res.traverseTree(ctx, dst, *res.sn.Tree, treeVisitor{ visitNode: func(node *restic.Node, target, location string) error { debug.Log("second pass, visitNode: restore node %q", location) - if node.Type != "file" { + if node.Type != restic.NodeTypeFile { _, err := res.withOverwriteCheck(ctx, node, target, location, false, nil, func(_ bool, _ *fileState) error { return res.restoreNodeTo(node, target, location) }) @@ -547,7 +547,7 @@ func (res *Restorer) withOverwriteCheck(ctx context.Context, node *restic.Node, var matches *fileState updateMetadataOnly := false - if node.Type == "file" && !isHardlink { + if node.Type == restic.NodeTypeFile && !isHardlink { // if a file fails to verify, then matches is nil which results in restoring from scratch matches, buf, _ = res.verifyFile(ctx, target, node, false, res.opts.Overwrite == OverwriteIfChanged, buf) // skip files that are already correct completely @@ -616,7 +616,7 @@ func (res *Restorer) VerifyFiles(ctx context.Context, dst string, countRestoredF err := res.traverseTree(ctx, dst, *res.sn.Tree, treeVisitor{ visitNode: func(node *restic.Node, target, location string) error { - if node.Type != "file" { + if node.Type != restic.NodeTypeFile { return nil } if metadataOnly, ok := res.hasRestoredFile(location); !ok || metadataOnly { diff --git a/internal/restorer/restorer_test.go b/internal/restorer/restorer_test.go index 7d4895068..8844435ca 100644 --- a/internal/restorer/restorer_test.go +++ b/internal/restorer/restorer_test.go @@ -108,7 +108,7 @@ func saveDir(t testing.TB, repo restic.BlobSaver, nodes map[string]Node, inode u mode = 0644 } err := tree.Insert(&restic.Node{ - Type: "file", + Type: restic.NodeTypeFile, Mode: mode, ModTime: node.ModTime, Name: name, @@ -123,7 +123,7 @@ func saveDir(t testing.TB, repo restic.BlobSaver, nodes map[string]Node, inode u rtest.OK(t, err) case Symlink: err := tree.Insert(&restic.Node{ - Type: "symlink", + Type: restic.NodeTypeSymlink, Mode: os.ModeSymlink | 0o777, ModTime: node.ModTime, Name: name, @@ -143,7 +143,7 @@ func saveDir(t testing.TB, repo restic.BlobSaver, nodes map[string]Node, inode u } err := tree.Insert(&restic.Node{ - Type: "dir", + Type: restic.NodeTypeDir, Mode: mode, ModTime: node.ModTime, Name: name, diff --git a/internal/ui/backup/progress.go b/internal/ui/backup/progress.go index 1d494bf14..24640d71f 100644 --- a/internal/ui/backup/progress.go +++ b/internal/ui/backup/progress.go @@ -124,7 +124,7 @@ func (p *Progress) CompleteItem(item string, previous, current *restic.Node, s a } switch current.Type { - case "dir": + case restic.NodeTypeDir: p.mu.Lock() p.addProcessed(Counter{Dirs: 1}) p.mu.Unlock() @@ -138,7 +138,7 @@ func (p *Progress) CompleteItem(item string, previous, current *restic.Node, s a p.printer.CompleteItem("dir modified", item, s, d) } - case "file": + case restic.NodeTypeFile: p.mu.Lock() p.addProcessed(Counter{Files: 1}) delete(p.currentFiles, item) diff --git a/internal/ui/backup/progress_test.go b/internal/ui/backup/progress_test.go index 6b242a0f3..512fbab26 100644 --- a/internal/ui/backup/progress_test.go +++ b/internal/ui/backup/progress_test.go @@ -55,10 +55,10 @@ func TestProgress(t *testing.T) { prog.CompleteBlob(1024) // "dir unchanged" - node := restic.Node{Type: "dir"} + node := restic.Node{Type: restic.NodeTypeDir} prog.CompleteItem("foo", &node, &node, archiver.ItemStats{}, 0) // "file new" - node.Type = "file" + node.Type = restic.NodeTypeFile prog.CompleteItem("foo", nil, &node, archiver.ItemStats{}, 0) time.Sleep(10 * time.Millisecond) diff --git a/internal/walker/rewriter.go b/internal/walker/rewriter.go index 7e984ae25..968ef44f3 100644 --- a/internal/walker/rewriter.go +++ b/internal/walker/rewriter.go @@ -65,7 +65,7 @@ func NewSnapshotSizeRewriter(rewriteNode NodeRewriteFunc) (*TreeRewriter, QueryR t := NewTreeRewriter(RewriteOpts{ RewriteNode: func(node *restic.Node, path string) *restic.Node { node = rewriteNode(node, path) - if node != nil && node.Type == "file" { + if node != nil && node.Type == restic.NodeTypeFile { count++ size += node.Size } @@ -126,7 +126,7 @@ func (t *TreeRewriter) RewriteTree(ctx context.Context, repo BlobLoadSaver, node continue } - if node.Type != "dir" { + if node.Type != restic.NodeTypeDir { err = tb.AddNode(node) if err != nil { return restic.ID{}, err diff --git a/internal/walker/rewriter_test.go b/internal/walker/rewriter_test.go index f05e50f9b..58dd25cd0 100644 --- a/internal/walker/rewriter_test.go +++ b/internal/walker/rewriter_test.go @@ -110,7 +110,7 @@ func checkIncreaseNodeSize(increase uint64) checkRewriteFunc { return func(t testing.TB) (rewriter *TreeRewriter, final func(testing.TB)) { rewriter = NewTreeRewriter(RewriteOpts{ RewriteNode: func(node *restic.Node, path string) *restic.Node { - if node.Type == "file" { + if node.Type == restic.NodeTypeFile { node.Size += increase } return node @@ -329,7 +329,7 @@ func TestSnapshotSizeQuery(t *testing.T) { if path == "/bar" { return nil } - if node.Type == "file" { + if node.Type == restic.NodeTypeFile { node.Size += 21 } return node diff --git a/internal/walker/walker.go b/internal/walker/walker.go index 788ece1cf..8acfed2f2 100644 --- a/internal/walker/walker.go +++ b/internal/walker/walker.go @@ -63,11 +63,11 @@ func walk(ctx context.Context, repo restic.BlobLoader, prefix string, parentTree p := path.Join(prefix, node.Name) - if node.Type == "" { + if node.Type == restic.NodeTypeInvalid { return errors.Errorf("node type is empty for node %q", node.Name) } - if node.Type != "dir" { + if node.Type != restic.NodeTypeDir { err := visitor.ProcessNode(parentTreeID, p, node, nil) if err != nil { if err == ErrSkipNode { diff --git a/internal/walker/walker_test.go b/internal/walker/walker_test.go index 75f80e57f..fa377bb8f 100644 --- a/internal/walker/walker_test.go +++ b/internal/walker/walker_test.go @@ -38,7 +38,7 @@ func buildTreeMap(tree TestTree, m TreeMap) restic.ID { case TestFile: err := tb.AddNode(&restic.Node{ Name: name, - Type: "file", + Type: restic.NodeTypeFile, Size: elem.Size, }) if err != nil { @@ -49,7 +49,7 @@ func buildTreeMap(tree TestTree, m TreeMap) restic.ID { err := tb.AddNode(&restic.Node{ Name: name, Subtree: &id, - Type: "dir", + Type: restic.NodeTypeDir, }) if err != nil { panic(err)