Skip to content

Commit

Permalink
Merge pull request #4611 from zmanda/windows-metadata-support
Browse files Browse the repository at this point in the history
Back up and restore windows metadata like created ts, file attribs like hidden, readonly, encrypted with a common extensible mechanism
  • Loading branch information
MichaelEischer committed Feb 23, 2024
2 parents c6311c1 + e8211cb commit b953dc8
Show file tree
Hide file tree
Showing 21 changed files with 1,435 additions and 108 deletions.
7 changes: 7 additions & 0 deletions changelog/unreleased/pull-4611
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Enhancement: Back up windows created time and file attributes like hidden flag

Restic did not back up windows-specific meta-data like created time and file attributes like hidden flag.
Restic now backs up file created time and file attributes like hidden, readonly and encrypted flag when backing up files and folders on windows.

https://github.com/restic/restic/pull/4611

1 change: 1 addition & 0 deletions cmd/restic/cmd_find.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ func (s *statefulOutput) PrintPatternJSON(path string, node *restic.Node) {
// Make the following attributes disappear
Name byte `json:"name,omitempty"`
ExtendedAttributes byte `json:"extended_attributes,omitempty"`
GenericAttributes byte `json:"generic_attributes,omitempty"`
Device byte `json:"device,omitempty"`
Content byte `json:"content,omitempty"`
Subtree byte `json:"subtree,omitempty"`
Expand Down
3 changes: 3 additions & 0 deletions cmd/restic/cmd_restore.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,9 @@ func runRestore(ctx context.Context, opts RestoreOptions, gopts GlobalOptions,
totalErrors++
return nil
}
res.Warn = func(message string) {
msg.E("Warning: %s\n", message)
}

excludePatterns := filter.ParsePatterns(opts.Exclude)
insensitiveExcludePatterns := filter.ParsePatterns(opts.InsensitiveExclude)
Expand Down
1 change: 0 additions & 1 deletion doc/040_backup.rst
Original file line number Diff line number Diff line change
Expand Up @@ -487,7 +487,6 @@ particular note are:
* File creation date on Unix platforms
* Inode flags on Unix platforms
* File ownership and ACLs on Windows
* The "hidden" flag on Windows

Reading data from a command
***************************
Expand Down
31 changes: 31 additions & 0 deletions internal/errors/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package errors

import (
stderrors "errors"
"fmt"

"github.com/pkg/errors"
)
Expand All @@ -22,12 +23,42 @@ var Wrap = errors.Wrap
// nil, Wrapf returns nil.
var Wrapf = errors.Wrapf

// WithStack annotates err with a stack trace at the point WithStack was called.
// If err is nil, WithStack returns nil.
var WithStack = errors.WithStack

// Go 1.13-style error handling.

// As finds the first error in err's tree that matches target, and if one is found,
// sets target to that error value and returns true. Otherwise, it returns false.
func As(err error, tgt interface{}) bool { return stderrors.As(err, tgt) }

// Is reports whether any error in err's tree matches target.
func Is(x, y error) bool { return stderrors.Is(x, y) }

// Unwrap returns the result of calling the Unwrap method on err, if err's type contains
// an Unwrap method returning error. Otherwise, Unwrap returns nil.
//
// Unwrap only calls a method of the form "Unwrap() error". In particular Unwrap does not
// unwrap errors returned by [Join].
func Unwrap(err error) error { return stderrors.Unwrap(err) }

// CombineErrors combines multiple errors into a single error.
func CombineErrors(errors ...error) error {
var combinedErrorMsg string

for _, err := range errors {
if err != nil {
if combinedErrorMsg != "" {
combinedErrorMsg += "; " // Separate error messages with a delimiter
}
combinedErrorMsg += err.Error()
}
}

if combinedErrorMsg == "" {
return nil // No errors, return nil
}

return fmt.Errorf("multiple errors occurred: [%s]", combinedErrorMsg)
}
14 changes: 14 additions & 0 deletions internal/fs/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,3 +124,17 @@ func RemoveIfExists(filename string) error {
func Chtimes(name string, atime time.Time, mtime time.Time) error {
return os.Chtimes(fixpath(name), atime, mtime)
}

// IsAccessDenied checks if the error is due to permission error.
func IsAccessDenied(err error) bool {
return os.IsPermission(err)
}

// ResetPermissions resets the permissions of the file at the specified path
func ResetPermissions(path string) error {
// Set the default file permissions
if err := os.Chmod(path, 0600); err != nil {
return err
}
return nil
}
26 changes: 26 additions & 0 deletions internal/fs/file_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,29 @@ func TempFile(dir, prefix string) (f *os.File, err error) {
func Chmod(name string, mode os.FileMode) error {
return os.Chmod(fixpath(name), mode)
}

// ClearSystem removes the system attribute from the file.
func ClearSystem(path string) error {
return ClearAttribute(path, windows.FILE_ATTRIBUTE_SYSTEM)
}

// ClearAttribute removes the specified attribute from the file.
func ClearAttribute(path string, attribute uint32) error {
ptr, err := windows.UTF16PtrFromString(path)
if err != nil {
return err
}
fileAttributes, err := windows.GetFileAttributes(ptr)
if err != nil {
return err
}
if fileAttributes&attribute != 0 {
// Clear the attribute
fileAttributes &= ^uint32(attribute)
err = windows.SetFileAttributes(ptr, fileAttributes)
if err != nil {
return err
}
}
return nil
}

0 comments on commit b953dc8

Please sign in to comment.