forked from TrueCloudLab/restic
restic: prepare extraction of fs code from Node
This commit is contained in:
parent
3e0c081bed
commit
5644079707
15 changed files with 108 additions and 112 deletions
|
@ -142,7 +142,7 @@ func TestSetGetFileEA(t *testing.T) {
|
||||||
testFilePath, testFile := setupTestFile(t)
|
testFilePath, testFile := setupTestFile(t)
|
||||||
testEAs := generateTestEAs(t, 3, testFilePath)
|
testEAs := generateTestEAs(t, 3, testFilePath)
|
||||||
fileHandle := openFile(t, testFilePath, windows.FILE_ATTRIBUTE_NORMAL)
|
fileHandle := openFile(t, testFilePath, windows.FILE_ATTRIBUTE_NORMAL)
|
||||||
defer closeFileHandle(t, testFilePath, testFile, fileHandle)
|
defer testCloseFileHandle(t, testFilePath, testFile, fileHandle)
|
||||||
|
|
||||||
testSetGetEA(t, testFilePath, fileHandle, testEAs)
|
testSetGetEA(t, testFilePath, fileHandle, testEAs)
|
||||||
}
|
}
|
||||||
|
@ -154,7 +154,7 @@ func TestSetGetFolderEA(t *testing.T) {
|
||||||
|
|
||||||
testEAs := generateTestEAs(t, 3, testFolderPath)
|
testEAs := generateTestEAs(t, 3, testFolderPath)
|
||||||
fileHandle := openFile(t, testFolderPath, windows.FILE_ATTRIBUTE_NORMAL|windows.FILE_FLAG_BACKUP_SEMANTICS)
|
fileHandle := openFile(t, testFolderPath, windows.FILE_ATTRIBUTE_NORMAL|windows.FILE_FLAG_BACKUP_SEMANTICS)
|
||||||
defer closeFileHandle(t, testFolderPath, nil, fileHandle)
|
defer testCloseFileHandle(t, testFolderPath, nil, fileHandle)
|
||||||
|
|
||||||
testSetGetEA(t, testFolderPath, fileHandle, testEAs)
|
testSetGetEA(t, testFolderPath, fileHandle, testEAs)
|
||||||
}
|
}
|
||||||
|
@ -212,7 +212,7 @@ func openFile(t *testing.T, path string, attributes uint32) windows.Handle {
|
||||||
return fileHandle
|
return fileHandle
|
||||||
}
|
}
|
||||||
|
|
||||||
func closeFileHandle(t *testing.T, testfilePath string, testFile *os.File, handle windows.Handle) {
|
func testCloseFileHandle(t *testing.T, testfilePath string, testFile *os.File, handle windows.Handle) {
|
||||||
if testFile != nil {
|
if testFile != nil {
|
||||||
err := testFile.Close()
|
err := testFile.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -150,7 +150,7 @@ func NodeFromFileInfo(path string, fi os.FileInfo, ignoreXattrListError bool) (*
|
||||||
node.Size = uint64(fi.Size())
|
node.Size = uint64(fi.Size())
|
||||||
}
|
}
|
||||||
|
|
||||||
err := node.fillExtra(path, fi, ignoreXattrListError)
|
err := nodeFillExtra(node, path, fi, ignoreXattrListError)
|
||||||
return node, err
|
return node, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,33 +187,33 @@ func (node Node) GetExtendedAttribute(a string) []byte {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateAt creates the node at the given path but does NOT restore node meta data.
|
// NodeCreateAt creates the node at the given path but does NOT restore node meta data.
|
||||||
func (node *Node) CreateAt(ctx context.Context, path string, repo BlobLoader) error {
|
func NodeCreateAt(ctx context.Context, node *Node, path string, repo BlobLoader) error {
|
||||||
debug.Log("create node %v at %v", node.Name, path)
|
debug.Log("create node %v at %v", node.Name, path)
|
||||||
|
|
||||||
switch node.Type {
|
switch node.Type {
|
||||||
case "dir":
|
case "dir":
|
||||||
if err := node.createDirAt(path); err != nil {
|
if err := nodeCreateDirAt(node, path); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
case "file":
|
case "file":
|
||||||
if err := node.createFileAt(ctx, path, repo); err != nil {
|
if err := nodeCreateFileAt(ctx, node, path, repo); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
case "symlink":
|
case "symlink":
|
||||||
if err := node.createSymlinkAt(path); err != nil {
|
if err := nodeCreateSymlinkAt(node, path); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
case "dev":
|
case "dev":
|
||||||
if err := node.createDevAt(path); err != nil {
|
if err := nodeCreateDevAt(node, path); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
case "chardev":
|
case "chardev":
|
||||||
if err := node.createCharDevAt(path); err != nil {
|
if err := nodeCreateCharDevAt(node, path); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
case "fifo":
|
case "fifo":
|
||||||
if err := node.createFifoAt(path); err != nil {
|
if err := nodeCreateFifoAt(path); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
case "socket":
|
case "socket":
|
||||||
|
@ -225,9 +225,9 @@ func (node *Node) CreateAt(ctx context.Context, path string, repo BlobLoader) er
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// RestoreMetadata restores node metadata
|
// NodeRestoreMetadata restores node metadata
|
||||||
func (node Node) RestoreMetadata(path string, warn func(msg string)) error {
|
func NodeRestoreMetadata(node *Node, path string, warn func(msg string)) error {
|
||||||
err := node.restoreMetadata(path, warn)
|
err := nodeRestoreMetadata(node, path, warn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// It is common to have permission errors for folders like /home
|
// It is common to have permission errors for folders like /home
|
||||||
// unless you're running as root, so ignore those.
|
// unless you're running as root, so ignore those.
|
||||||
|
@ -242,28 +242,28 @@ func (node Node) RestoreMetadata(path string, warn func(msg string)) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (node Node) restoreMetadata(path string, warn func(msg string)) error {
|
func nodeRestoreMetadata(node *Node, path string, warn func(msg string)) error {
|
||||||
var firsterr error
|
var firsterr error
|
||||||
|
|
||||||
if err := lchown(path, int(node.UID), int(node.GID)); err != nil {
|
if err := lchown(path, int(node.UID), int(node.GID)); err != nil {
|
||||||
firsterr = errors.WithStack(err)
|
firsterr = errors.WithStack(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := node.restoreExtendedAttributes(path); err != nil {
|
if err := nodeRestoreExtendedAttributes(node, path); err != nil {
|
||||||
debug.Log("error restoring extended attributes for %v: %v", path, err)
|
debug.Log("error restoring extended attributes for %v: %v", path, err)
|
||||||
if firsterr == nil {
|
if firsterr == nil {
|
||||||
firsterr = err
|
firsterr = err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := node.restoreGenericAttributes(path, warn); err != nil {
|
if err := nodeRestoreGenericAttributes(node, path, warn); err != nil {
|
||||||
debug.Log("error restoring generic attributes for %v: %v", path, err)
|
debug.Log("error restoring generic attributes for %v: %v", path, err)
|
||||||
if firsterr == nil {
|
if firsterr == nil {
|
||||||
firsterr = err
|
firsterr = err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := node.RestoreTimestamps(path); err != nil {
|
if err := NodeRestoreTimestamps(node, path); err != nil {
|
||||||
debug.Log("error restoring timestamps for %v: %v", path, err)
|
debug.Log("error restoring timestamps for %v: %v", path, err)
|
||||||
if firsterr == nil {
|
if firsterr == nil {
|
||||||
firsterr = err
|
firsterr = err
|
||||||
|
@ -284,14 +284,14 @@ func (node Node) restoreMetadata(path string, warn func(msg string)) error {
|
||||||
return firsterr
|
return firsterr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (node Node) RestoreTimestamps(path string) error {
|
func NodeRestoreTimestamps(node *Node, path string) error {
|
||||||
var utimes = [...]syscall.Timespec{
|
var utimes = [...]syscall.Timespec{
|
||||||
syscall.NsecToTimespec(node.AccessTime.UnixNano()),
|
syscall.NsecToTimespec(node.AccessTime.UnixNano()),
|
||||||
syscall.NsecToTimespec(node.ModTime.UnixNano()),
|
syscall.NsecToTimespec(node.ModTime.UnixNano()),
|
||||||
}
|
}
|
||||||
|
|
||||||
if node.Type == "symlink" {
|
if node.Type == "symlink" {
|
||||||
return node.restoreSymlinkTimestamps(path, utimes)
|
return nodeRestoreSymlinkTimestamps(path, utimes)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := syscall.UtimesNano(path, utimes[:]); err != nil {
|
if err := syscall.UtimesNano(path, utimes[:]); err != nil {
|
||||||
|
@ -301,7 +301,7 @@ func (node Node) RestoreTimestamps(path string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (node Node) createDirAt(path string) error {
|
func nodeCreateDirAt(node *Node, path string) error {
|
||||||
err := fs.Mkdir(path, node.Mode)
|
err := fs.Mkdir(path, node.Mode)
|
||||||
if err != nil && !os.IsExist(err) {
|
if err != nil && !os.IsExist(err) {
|
||||||
return errors.WithStack(err)
|
return errors.WithStack(err)
|
||||||
|
@ -310,13 +310,13 @@ func (node Node) createDirAt(path string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (node Node) createFileAt(ctx context.Context, path string, repo BlobLoader) error {
|
func nodeCreateFileAt(ctx context.Context, node *Node, path string, repo BlobLoader) error {
|
||||||
f, err := fs.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0600)
|
f, err := fs.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0600)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.WithStack(err)
|
return errors.WithStack(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = node.writeNodeContent(ctx, repo, f)
|
err = nodeWriteNodeContent(ctx, node, repo, f)
|
||||||
closeErr := f.Close()
|
closeErr := f.Close()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -330,7 +330,7 @@ func (node Node) createFileAt(ctx context.Context, path string, repo BlobLoader)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (node Node) writeNodeContent(ctx context.Context, repo BlobLoader, f *os.File) error {
|
func nodeWriteNodeContent(ctx context.Context, node *Node, repo BlobLoader, f *os.File) error {
|
||||||
var buf []byte
|
var buf []byte
|
||||||
for _, id := range node.Content {
|
for _, id := range node.Content {
|
||||||
buf, err := repo.LoadBlob(ctx, DataBlob, id, buf)
|
buf, err := repo.LoadBlob(ctx, DataBlob, id, buf)
|
||||||
|
@ -347,7 +347,7 @@ func (node Node) writeNodeContent(ctx context.Context, repo BlobLoader, f *os.Fi
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (node Node) createSymlinkAt(path string) error {
|
func nodeCreateSymlinkAt(node *Node, path string) error {
|
||||||
if err := fs.Symlink(node.LinkTarget, path); err != nil {
|
if err := fs.Symlink(node.LinkTarget, path); err != nil {
|
||||||
return errors.WithStack(err)
|
return errors.WithStack(err)
|
||||||
}
|
}
|
||||||
|
@ -355,15 +355,15 @@ func (node Node) createSymlinkAt(path string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (node *Node) createDevAt(path string) error {
|
func nodeCreateDevAt(node *Node, path string) error {
|
||||||
return mknod(path, syscall.S_IFBLK|0600, node.Device)
|
return mknod(path, syscall.S_IFBLK|0600, node.Device)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (node *Node) createCharDevAt(path string) error {
|
func nodeCreateCharDevAt(node *Node, path string) error {
|
||||||
return mknod(path, syscall.S_IFCHR|0600, node.Device)
|
return mknod(path, syscall.S_IFCHR|0600, node.Device)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (node *Node) createFifoAt(path string) error {
|
func nodeCreateFifoAt(path string) error {
|
||||||
return mkfifo(path, 0600)
|
return mkfifo(path, 0600)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -601,7 +601,7 @@ func deepEqual(map1, map2 map[GenericAttributeType]json.RawMessage) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (node *Node) fillUser(stat *statT) {
|
func nodeFillUser(node *Node, stat *statT) {
|
||||||
uid, gid := stat.uid(), stat.gid()
|
uid, gid := stat.uid(), stat.gid()
|
||||||
node.UID, node.GID = uid, gid
|
node.UID, node.GID = uid, gid
|
||||||
node.User = lookupUsername(uid)
|
node.User = lookupUsername(uid)
|
||||||
|
@ -662,7 +662,7 @@ func lookupGroup(gid uint32) string {
|
||||||
return group
|
return group
|
||||||
}
|
}
|
||||||
|
|
||||||
func (node *Node) fillExtra(path string, fi os.FileInfo, ignoreXattrListError bool) error {
|
func nodeFillExtra(node *Node, path string, fi os.FileInfo, ignoreXattrListError bool) error {
|
||||||
stat, ok := toStatT(fi.Sys())
|
stat, ok := toStatT(fi.Sys())
|
||||||
if !ok {
|
if !ok {
|
||||||
// fill minimal info with current values for uid, gid
|
// fill minimal info with current values for uid, gid
|
||||||
|
@ -675,9 +675,9 @@ func (node *Node) fillExtra(path string, fi os.FileInfo, ignoreXattrListError bo
|
||||||
node.Inode = uint64(stat.ino())
|
node.Inode = uint64(stat.ino())
|
||||||
node.DeviceID = uint64(stat.dev())
|
node.DeviceID = uint64(stat.dev())
|
||||||
|
|
||||||
node.fillTimes(stat)
|
nodeFillTimes(node, stat)
|
||||||
|
|
||||||
node.fillUser(stat)
|
nodeFillUser(node, stat)
|
||||||
|
|
||||||
switch node.Type {
|
switch node.Type {
|
||||||
case "file":
|
case "file":
|
||||||
|
@ -703,10 +703,10 @@ func (node *Node) fillExtra(path string, fi os.FileInfo, ignoreXattrListError bo
|
||||||
return errors.Errorf("unsupported file type %q", node.Type)
|
return errors.Errorf("unsupported file type %q", node.Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
allowExtended, err := node.fillGenericAttributes(path, fi, stat)
|
allowExtended, err := nodeFillGenericAttributes(node, path, fi, stat)
|
||||||
if allowExtended {
|
if allowExtended {
|
||||||
// Skip processing ExtendedAttributes if allowExtended is false.
|
// Skip processing ExtendedAttributes if allowExtended is false.
|
||||||
err = errors.CombineErrors(err, node.fillExtendedAttributes(path, ignoreXattrListError))
|
err = errors.CombineErrors(err, nodeFillExtendedAttributes(node, path, ignoreXattrListError))
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -715,7 +715,7 @@ func mkfifo(path string, mode uint32) (err error) {
|
||||||
return mknod(path, mode|syscall.S_IFIFO, 0)
|
return mknod(path, mode|syscall.S_IFIFO, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (node *Node) fillTimes(stat *statT) {
|
func nodeFillTimes(node *Node, stat *statT) {
|
||||||
ctim := stat.ctim()
|
ctim := stat.ctim()
|
||||||
atim := stat.atim()
|
atim := stat.atim()
|
||||||
node.ChangeTime = time.Unix(ctim.Unix())
|
node.ChangeTime = time.Unix(ctim.Unix())
|
||||||
|
@ -746,11 +746,11 @@ func handleUnknownGenericAttributeFound(genericAttributeType GenericAttributeTyp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// handleAllUnknownGenericAttributesFound performs validations for all generic attributes in the node.
|
// HandleAllUnknownGenericAttributesFound performs validations for all generic attributes of a node.
|
||||||
// This is not used on windows currently because windows has handling for generic attributes.
|
// This is not used on windows currently because windows has handling for generic attributes.
|
||||||
// nolint:unused
|
// nolint:unused
|
||||||
func (node Node) handleAllUnknownGenericAttributesFound(warn func(msg string)) error {
|
func HandleAllUnknownGenericAttributesFound(attributes map[GenericAttributeType]json.RawMessage, warn func(msg string)) error {
|
||||||
for name := range node.GenericAttributes {
|
for name := range attributes {
|
||||||
handleUnknownGenericAttributeFound(name, warn)
|
handleUnknownGenericAttributeFound(name, warn)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -770,9 +770,8 @@ func checkGenericAttributeNameNotHandledAndPut(value GenericAttributeType) bool
|
||||||
// The functions below are common helper functions which can be used for generic attributes support
|
// The functions below are common helper functions which can be used for generic attributes support
|
||||||
// across different OS.
|
// across different OS.
|
||||||
|
|
||||||
// genericAttributesToOSAttrs gets the os specific attribute from the generic attribute using reflection
|
// GenericAttributesToOSAttrs gets the os specific attribute from the generic attribute using reflection
|
||||||
// nolint:unused
|
func GenericAttributesToOSAttrs(attrs map[GenericAttributeType]json.RawMessage, attributeType reflect.Type, attributeValuePtr *reflect.Value, keyPrefix string) (unknownAttribs []GenericAttributeType, err error) {
|
||||||
func genericAttributesToOSAttrs(attrs map[GenericAttributeType]json.RawMessage, attributeType reflect.Type, attributeValuePtr *reflect.Value, keyPrefix string) (unknownAttribs []GenericAttributeType, err error) {
|
|
||||||
attributeValue := *attributeValuePtr
|
attributeValue := *attributeValuePtr
|
||||||
|
|
||||||
for key, rawMsg := range attrs {
|
for key, rawMsg := range attrs {
|
||||||
|
@ -796,20 +795,17 @@ func genericAttributesToOSAttrs(attrs map[GenericAttributeType]json.RawMessage,
|
||||||
}
|
}
|
||||||
|
|
||||||
// getFQKey gets the fully qualified key for the field
|
// getFQKey gets the fully qualified key for the field
|
||||||
// nolint:unused
|
|
||||||
func getFQKey(field reflect.StructField, keyPrefix string) GenericAttributeType {
|
func getFQKey(field reflect.StructField, keyPrefix string) GenericAttributeType {
|
||||||
return GenericAttributeType(fmt.Sprintf("%s.%s", keyPrefix, field.Tag.Get("generic")))
|
return GenericAttributeType(fmt.Sprintf("%s.%s", keyPrefix, field.Tag.Get("generic")))
|
||||||
}
|
}
|
||||||
|
|
||||||
// getFQKeyByIndex gets the fully qualified key for the field index
|
// getFQKeyByIndex gets the fully qualified key for the field index
|
||||||
// nolint:unused
|
|
||||||
func getFQKeyByIndex(attributeType reflect.Type, index int, keyPrefix string) GenericAttributeType {
|
func getFQKeyByIndex(attributeType reflect.Type, index int, keyPrefix string) GenericAttributeType {
|
||||||
return getFQKey(attributeType.Field(index), keyPrefix)
|
return getFQKey(attributeType.Field(index), keyPrefix)
|
||||||
}
|
}
|
||||||
|
|
||||||
// osAttrsToGenericAttributes gets the generic attribute from the os specific attribute using reflection
|
// OSAttrsToGenericAttributes gets the generic attribute from the os specific attribute using reflection
|
||||||
// nolint:unused
|
func OSAttrsToGenericAttributes(attributeType reflect.Type, attributeValuePtr *reflect.Value, keyPrefix string) (attrs map[GenericAttributeType]json.RawMessage, err error) {
|
||||||
func osAttrsToGenericAttributes(attributeType reflect.Type, attributeValuePtr *reflect.Value, keyPrefix string) (attrs map[GenericAttributeType]json.RawMessage, err error) {
|
|
||||||
attributeValue := *attributeValuePtr
|
attributeValue := *attributeValuePtr
|
||||||
attrs = make(map[GenericAttributeType]json.RawMessage)
|
attrs = make(map[GenericAttributeType]json.RawMessage)
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
"syscall"
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (node Node) restoreSymlinkTimestamps(_ string, _ [2]syscall.Timespec) error {
|
func nodeRestoreSymlinkTimestamps(_ string, _ [2]syscall.Timespec) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,13 +23,13 @@ func (s statT) atim() syscall.Timespec { return toTimespec(s.Atim) }
|
||||||
func (s statT) mtim() syscall.Timespec { return toTimespec(s.Mtim) }
|
func (s statT) mtim() syscall.Timespec { return toTimespec(s.Mtim) }
|
||||||
func (s statT) ctim() syscall.Timespec { return toTimespec(s.Ctim) }
|
func (s statT) ctim() syscall.Timespec { return toTimespec(s.Ctim) }
|
||||||
|
|
||||||
// restoreExtendedAttributes is a no-op on AIX.
|
// nodeRestoreExtendedAttributes is a no-op on AIX.
|
||||||
func (node Node) restoreExtendedAttributes(_ string) error {
|
func nodeRestoreExtendedAttributes(_ *Node, _ string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// fillExtendedAttributes is a no-op on AIX.
|
// nodeFillExtendedAttributes is a no-op on AIX.
|
||||||
func (node *Node) fillExtendedAttributes(_ string, _ bool) error {
|
func nodeFillExtendedAttributes(_ *Node, _ string, _ bool) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,12 +38,12 @@ func IsListxattrPermissionError(_ error) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// restoreGenericAttributes is no-op on AIX.
|
// nodeRestoreGenericAttributes is no-op on AIX.
|
||||||
func (node *Node) restoreGenericAttributes(_ string, warn func(msg string)) error {
|
func nodeRestoreGenericAttributes(node *Node, _ string, warn func(msg string)) error {
|
||||||
return node.handleAllUnknownGenericAttributesFound(warn)
|
return HandleAllUnknownGenericAttributesFound(node.GenericAttributes, warn)
|
||||||
}
|
}
|
||||||
|
|
||||||
// fillGenericAttributes is a no-op on AIX.
|
// nodeFillGenericAttributes is a no-op on AIX.
|
||||||
func (node *Node) fillGenericAttributes(_ string, _ os.FileInfo, _ *statT) (allowExtended bool, err error) {
|
func nodeFillGenericAttributes(_ *Node, _ string, _ os.FileInfo, _ *statT) (allowExtended bool, err error) {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ package restic
|
||||||
|
|
||||||
import "syscall"
|
import "syscall"
|
||||||
|
|
||||||
func (node Node) restoreSymlinkTimestamps(path string, utimes [2]syscall.Timespec) error {
|
func nodeRestoreSymlinkTimestamps(path string, utimes [2]syscall.Timespec) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ package restic
|
||||||
|
|
||||||
import "syscall"
|
import "syscall"
|
||||||
|
|
||||||
func (node Node) restoreSymlinkTimestamps(path string, utimes [2]syscall.Timespec) error {
|
func nodeRestoreSymlinkTimestamps(path string, utimes [2]syscall.Timespec) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ import (
|
||||||
"github.com/restic/restic/internal/fs"
|
"github.com/restic/restic/internal/fs"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (node Node) restoreSymlinkTimestamps(path string, utimes [2]syscall.Timespec) error {
|
func nodeRestoreSymlinkTimestamps(path string, utimes [2]syscall.Timespec) error {
|
||||||
dir, err := fs.Open(filepath.Dir(path))
|
dir, err := fs.Open(filepath.Dir(path))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.WithStack(err)
|
return errors.WithStack(err)
|
||||||
|
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"syscall"
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (node Node) restoreSymlinkTimestamps(_ string, _ [2]syscall.Timespec) error {
|
func nodeRestoreSymlinkTimestamps(_ string, _ [2]syscall.Timespec) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,13 +13,13 @@ func (s statT) atim() syscall.Timespec { return s.Atimespec }
|
||||||
func (s statT) mtim() syscall.Timespec { return s.Mtimespec }
|
func (s statT) mtim() syscall.Timespec { return s.Mtimespec }
|
||||||
func (s statT) ctim() syscall.Timespec { return s.Ctimespec }
|
func (s statT) ctim() syscall.Timespec { return s.Ctimespec }
|
||||||
|
|
||||||
// restoreExtendedAttributes is a no-op on netbsd.
|
// nodeRestoreExtendedAttributes is a no-op on netbsd.
|
||||||
func (node Node) restoreExtendedAttributes(_ string) error {
|
func nodeRestoreExtendedAttributes(_ *Node, _ string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// fillExtendedAttributes is a no-op on netbsd.
|
// nodeFillExtendedAttributes is a no-op on netbsd.
|
||||||
func (node *Node) fillExtendedAttributes(_ string, _ bool) error {
|
func nodeFillExtendedAttributes(_ *Node, _ string, _ bool) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,12 +28,12 @@ func IsListxattrPermissionError(_ error) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// restoreGenericAttributes is no-op on netbsd.
|
// nodeRestoreGenericAttributes is no-op on netbsd.
|
||||||
func (node *Node) restoreGenericAttributes(_ string, warn func(msg string)) error {
|
func nodeRestoreGenericAttributes(node *Node, _ string, warn func(msg string)) error {
|
||||||
return node.handleAllUnknownGenericAttributesFound(warn)
|
return HandleAllUnknownGenericAttributesFound(node.GenericAttributes, warn)
|
||||||
}
|
}
|
||||||
|
|
||||||
// fillGenericAttributes is a no-op on netbsd.
|
// nodeFillGenericAttributes is a no-op on netbsd.
|
||||||
func (node *Node) fillGenericAttributes(_ string, _ os.FileInfo, _ *statT) (allowExtended bool, err error) {
|
func nodeFillGenericAttributes(_ *Node, _ string, _ os.FileInfo, _ *statT) (allowExtended bool, err error) {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"syscall"
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (node Node) restoreSymlinkTimestamps(_ string, _ [2]syscall.Timespec) error {
|
func nodeRestoreSymlinkTimestamps(_ string, _ [2]syscall.Timespec) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,13 +13,13 @@ func (s statT) atim() syscall.Timespec { return s.Atim }
|
||||||
func (s statT) mtim() syscall.Timespec { return s.Mtim }
|
func (s statT) mtim() syscall.Timespec { return s.Mtim }
|
||||||
func (s statT) ctim() syscall.Timespec { return s.Ctim }
|
func (s statT) ctim() syscall.Timespec { return s.Ctim }
|
||||||
|
|
||||||
// restoreExtendedAttributes is a no-op on openbsd.
|
// nodeRestoreExtendedAttributes is a no-op on openbsd.
|
||||||
func (node Node) restoreExtendedAttributes(_ string) error {
|
func nodeRestoreExtendedAttributes(_ *Node, _ string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// fillExtendedAttributes is a no-op on openbsd.
|
// nodeFillExtendedAttributes is a no-op on openbsd.
|
||||||
func (node *Node) fillExtendedAttributes(_ string, _ bool) error {
|
func nodeFillExtendedAttributes(_ *Node, _ string, _ bool) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,12 +28,12 @@ func IsListxattrPermissionError(_ error) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// restoreGenericAttributes is no-op on openbsd.
|
// nodeRestoreGenericAttributes is no-op on openbsd.
|
||||||
func (node *Node) restoreGenericAttributes(_ string, warn func(msg string)) error {
|
func nodeRestoreGenericAttributes(node *Node, _ string, warn func(msg string)) error {
|
||||||
return node.handleAllUnknownGenericAttributesFound(warn)
|
return HandleAllUnknownGenericAttributesFound(node.GenericAttributes, warn)
|
||||||
}
|
}
|
||||||
|
|
||||||
// fillGenericAttributes is a no-op on openbsd.
|
// fillGenericAttributes is a no-op on openbsd.
|
||||||
func (node *Node) fillGenericAttributes(_ string, _ os.FileInfo, _ *statT) (allowExtended bool, err error) {
|
func nodeFillGenericAttributes(_ *Node, _ string, _ os.FileInfo, _ *statT) (allowExtended bool, err error) {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ package restic
|
||||||
|
|
||||||
import "syscall"
|
import "syscall"
|
||||||
|
|
||||||
func (node Node) restoreSymlinkTimestamps(path string, utimes [2]syscall.Timespec) error {
|
func nodeRestoreSymlinkTimestamps(path string, utimes [2]syscall.Timespec) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -245,8 +245,8 @@ func TestNodeRestoreAt(t *testing.T) {
|
||||||
} else {
|
} else {
|
||||||
nodePath = filepath.Join(tempdir, test.Name)
|
nodePath = filepath.Join(tempdir, test.Name)
|
||||||
}
|
}
|
||||||
rtest.OK(t, test.CreateAt(context.TODO(), nodePath, nil))
|
rtest.OK(t, NodeCreateAt(context.TODO(), &test, nodePath, nil))
|
||||||
rtest.OK(t, test.RestoreMetadata(nodePath, func(msg string) { rtest.OK(t, fmt.Errorf("Warning triggered for path: %s: %s", nodePath, msg)) }))
|
rtest.OK(t, NodeRestoreMetadata(&test, nodePath, func(msg string) { rtest.OK(t, fmt.Errorf("Warning triggered for path: %s: %s", nodePath, msg)) }))
|
||||||
|
|
||||||
fi, err := os.Lstat(nodePath)
|
fi, err := os.Lstat(nodePath)
|
||||||
rtest.OK(t, err)
|
rtest.OK(t, err)
|
||||||
|
@ -402,10 +402,10 @@ func TestSymlinkSerializationFormat(t *testing.T) {
|
||||||
func TestNodeRestoreMetadataError(t *testing.T) {
|
func TestNodeRestoreMetadataError(t *testing.T) {
|
||||||
tempdir := t.TempDir()
|
tempdir := t.TempDir()
|
||||||
|
|
||||||
node := nodeTests[0]
|
node := &nodeTests[0]
|
||||||
nodePath := filepath.Join(tempdir, node.Name)
|
nodePath := filepath.Join(tempdir, node.Name)
|
||||||
|
|
||||||
// This will fail because the target file does not exist
|
// This will fail because the target file does not exist
|
||||||
err := node.RestoreMetadata(nodePath, func(msg string) { rtest.OK(t, fmt.Errorf("Warning triggered for path: %s: %s", nodePath, msg)) })
|
err := NodeRestoreMetadata(node, nodePath, func(msg string) { rtest.OK(t, fmt.Errorf("Warning triggered for path: %s: %s", nodePath, msg)) })
|
||||||
test.Assert(t, errors.Is(err, os.ErrNotExist), "failed for an unexpected reason")
|
test.Assert(t, errors.Is(err, os.ErrNotExist), "failed for an unexpected reason")
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,7 @@ func lchown(_ string, _ int, _ int) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// restoreSymlinkTimestamps restores timestamps for symlinks
|
// restoreSymlinkTimestamps restores timestamps for symlinks
|
||||||
func (node Node) restoreSymlinkTimestamps(path string, utimes [2]syscall.Timespec) error {
|
func nodeRestoreSymlinkTimestamps(path string, utimes [2]syscall.Timespec) error {
|
||||||
// tweaked version of UtimesNano from go/src/syscall/syscall_windows.go
|
// tweaked version of UtimesNano from go/src/syscall/syscall_windows.go
|
||||||
pathp, e := syscall.UTF16PtrFromString(path)
|
pathp, e := syscall.UTF16PtrFromString(path)
|
||||||
if e != nil {
|
if e != nil {
|
||||||
|
@ -82,7 +82,7 @@ func (node Node) restoreSymlinkTimestamps(path string, utimes [2]syscall.Timespe
|
||||||
}
|
}
|
||||||
|
|
||||||
// restore extended attributes for windows
|
// restore extended attributes for windows
|
||||||
func (node Node) restoreExtendedAttributes(path string) (err error) {
|
func nodeRestoreExtendedAttributes(node *Node, path string) (err error) {
|
||||||
count := len(node.ExtendedAttributes)
|
count := len(node.ExtendedAttributes)
|
||||||
if count > 0 {
|
if count > 0 {
|
||||||
eas := make([]fs.ExtendedAttribute, count)
|
eas := make([]fs.ExtendedAttribute, count)
|
||||||
|
@ -97,7 +97,7 @@ func (node Node) restoreExtendedAttributes(path string) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// fill extended attributes in the node. This also includes the Generic attributes for windows.
|
// fill extended attributes in the node. This also includes the Generic attributes for windows.
|
||||||
func (node *Node) fillExtendedAttributes(path string, _ bool) (err error) {
|
func nodeFillExtendedAttributes(node *Node, path string, _ bool) (err error) {
|
||||||
var fileHandle windows.Handle
|
var fileHandle windows.Handle
|
||||||
if fileHandle, err = fs.OpenHandleForEA(node.Type, path, false); fileHandle == 0 {
|
if fileHandle, err = fs.OpenHandleForEA(node.Type, path, false); fileHandle == 0 {
|
||||||
return nil
|
return nil
|
||||||
|
@ -210,7 +210,7 @@ func (s statT) ctim() syscall.Timespec {
|
||||||
}
|
}
|
||||||
|
|
||||||
// restoreGenericAttributes restores generic attributes for Windows
|
// restoreGenericAttributes restores generic attributes for Windows
|
||||||
func (node Node) restoreGenericAttributes(path string, warn func(msg string)) (err error) {
|
func nodeRestoreGenericAttributes(node *Node, path string, warn func(msg string)) (err error) {
|
||||||
if len(node.GenericAttributes) == 0 {
|
if len(node.GenericAttributes) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -242,7 +242,7 @@ func (node Node) restoreGenericAttributes(path string, warn func(msg string)) (e
|
||||||
// genericAttributesToWindowsAttrs converts the generic attributes map to a WindowsAttributes and also returns a string of unknown attributes that it could not convert.
|
// genericAttributesToWindowsAttrs converts the generic attributes map to a WindowsAttributes and also returns a string of unknown attributes that it could not convert.
|
||||||
func genericAttributesToWindowsAttrs(attrs map[GenericAttributeType]json.RawMessage) (windowsAttributes WindowsAttributes, unknownAttribs []GenericAttributeType, err error) {
|
func genericAttributesToWindowsAttrs(attrs map[GenericAttributeType]json.RawMessage) (windowsAttributes WindowsAttributes, unknownAttribs []GenericAttributeType, err error) {
|
||||||
waValue := reflect.ValueOf(&windowsAttributes).Elem()
|
waValue := reflect.ValueOf(&windowsAttributes).Elem()
|
||||||
unknownAttribs, err = genericAttributesToOSAttrs(attrs, reflect.TypeOf(windowsAttributes), &waValue, "windows")
|
unknownAttribs, err = GenericAttributesToOSAttrs(attrs, reflect.TypeOf(windowsAttributes), &waValue, "windows")
|
||||||
return windowsAttributes, unknownAttribs, err
|
return windowsAttributes, unknownAttribs, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -361,11 +361,11 @@ func decryptFile(pathPointer *uint16) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// fillGenericAttributes fills in the generic attributes for windows like File Attributes,
|
// nodeFillGenericAttributes fills in the generic attributes for windows like File Attributes,
|
||||||
// Created time and Security Descriptors.
|
// Created time and Security Descriptors.
|
||||||
// It also checks if the volume supports extended attributes and stores the result in a map
|
// It also checks if the volume supports extended attributes and stores the result in a map
|
||||||
// so that it does not have to be checked again for subsequent calls for paths in the same volume.
|
// so that it does not have to be checked again for subsequent calls for paths in the same volume.
|
||||||
func (node *Node) fillGenericAttributes(path string, fi os.FileInfo, stat *statT) (allowExtended bool, err error) {
|
func nodeFillGenericAttributes(node *Node, path string, fi os.FileInfo, stat *statT) (allowExtended bool, err error) {
|
||||||
if strings.Contains(filepath.Base(path), ":") {
|
if strings.Contains(filepath.Base(path), ":") {
|
||||||
// Do not process for Alternate Data Streams in Windows
|
// Do not process for Alternate Data Streams in Windows
|
||||||
// Also do not allow processing of extended attributes for ADS.
|
// Also do not allow processing of extended attributes for ADS.
|
||||||
|
@ -499,7 +499,7 @@ func prepareVolumeName(path string) (volumeName string, err error) {
|
||||||
func WindowsAttrsToGenericAttributes(windowsAttributes WindowsAttributes) (attrs map[GenericAttributeType]json.RawMessage, err error) {
|
func WindowsAttrsToGenericAttributes(windowsAttributes WindowsAttributes) (attrs map[GenericAttributeType]json.RawMessage, err error) {
|
||||||
// Get the value of the WindowsAttributes
|
// Get the value of the WindowsAttributes
|
||||||
windowsAttributesValue := reflect.ValueOf(windowsAttributes)
|
windowsAttributesValue := reflect.ValueOf(windowsAttributes)
|
||||||
return osAttrsToGenericAttributes(reflect.TypeOf(windowsAttributes), &windowsAttributesValue, runtime.GOOS)
|
return OSAttrsToGenericAttributes(reflect.TypeOf(windowsAttributes), &windowsAttributesValue, runtime.GOOS)
|
||||||
}
|
}
|
||||||
|
|
||||||
// getCreationTime gets the value for the WindowsAttribute CreationTime in a windows specific time format.
|
// getCreationTime gets the value for the WindowsAttribute CreationTime in a windows specific time format.
|
||||||
|
|
|
@ -42,7 +42,7 @@ func testRestoreSecurityDescriptor(t *testing.T, sd string, tempDir, fileType, f
|
||||||
expectedNode := getNode(fileName, fileType, genericAttributes)
|
expectedNode := getNode(fileName, fileType, genericAttributes)
|
||||||
|
|
||||||
// Restore the file/dir and restore the meta data including the security descriptors.
|
// Restore the file/dir and restore the meta data including the security descriptors.
|
||||||
testPath, node := restoreAndGetNode(t, tempDir, expectedNode, false)
|
testPath, node := restoreAndGetNode(t, tempDir, &expectedNode, false)
|
||||||
// Get the security descriptor from the node constructed from the file info of the restored path.
|
// Get the security descriptor from the node constructed from the file info of the restored path.
|
||||||
sdByteFromRestoredNode := getWindowsAttr(t, testPath, node).SecurityDescriptor
|
sdByteFromRestoredNode := getWindowsAttr(t, testPath, node).SecurityDescriptor
|
||||||
|
|
||||||
|
@ -186,7 +186,7 @@ func runGenericAttributesTest(t *testing.T, tempDir string, genericAttributeName
|
||||||
func runGenericAttributesTestForNodes(t *testing.T, expectedNodes []Node, tempDir string, genericAttr GenericAttributeType, genericAttributeExpected WindowsAttributes, warningExpected bool) {
|
func runGenericAttributesTestForNodes(t *testing.T, expectedNodes []Node, tempDir string, genericAttr GenericAttributeType, genericAttributeExpected WindowsAttributes, warningExpected bool) {
|
||||||
|
|
||||||
for _, testNode := range expectedNodes {
|
for _, testNode := range expectedNodes {
|
||||||
testPath, node := restoreAndGetNode(t, tempDir, testNode, warningExpected)
|
testPath, node := restoreAndGetNode(t, tempDir, &testNode, warningExpected)
|
||||||
rawMessage := node.GenericAttributes[genericAttr]
|
rawMessage := node.GenericAttributes[genericAttr]
|
||||||
genericAttrsExpected, err := WindowsAttrsToGenericAttributes(genericAttributeExpected)
|
genericAttrsExpected, err := WindowsAttrsToGenericAttributes(genericAttributeExpected)
|
||||||
test.OK(t, err)
|
test.OK(t, err)
|
||||||
|
@ -195,7 +195,7 @@ func runGenericAttributesTestForNodes(t *testing.T, expectedNodes []Node, tempDi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func restoreAndGetNode(t *testing.T, tempDir string, testNode Node, warningExpected bool) (string, *Node) {
|
func restoreAndGetNode(t *testing.T, tempDir string, testNode *Node, warningExpected bool) (string, *Node) {
|
||||||
testPath := filepath.Join(tempDir, "001", testNode.Name)
|
testPath := filepath.Join(tempDir, "001", testNode.Name)
|
||||||
err := os.MkdirAll(filepath.Dir(testPath), testNode.Mode)
|
err := os.MkdirAll(filepath.Dir(testPath), testNode.Mode)
|
||||||
test.OK(t, errors.Wrapf(err, "Failed to create parent directories for: %s", testPath))
|
test.OK(t, errors.Wrapf(err, "Failed to create parent directories for: %s", testPath))
|
||||||
|
@ -211,7 +211,7 @@ func restoreAndGetNode(t *testing.T, tempDir string, testNode Node, warningExpec
|
||||||
test.OK(t, errors.Wrapf(err, "Failed to create test directory: %s", testPath))
|
test.OK(t, errors.Wrapf(err, "Failed to create test directory: %s", testPath))
|
||||||
}
|
}
|
||||||
|
|
||||||
err = testNode.RestoreMetadata(testPath, func(msg string) {
|
err = NodeRestoreMetadata(testNode, testPath, func(msg string) {
|
||||||
if warningExpected {
|
if warningExpected {
|
||||||
test.Assert(t, warningExpected, "Warning triggered as expected: %s", msg)
|
test.Assert(t, warningExpected, "Warning triggered as expected: %s", msg)
|
||||||
} else {
|
} else {
|
||||||
|
@ -260,7 +260,7 @@ func TestNewGenericAttributeType(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, testNode := range expectedNodes {
|
for _, testNode := range expectedNodes {
|
||||||
testPath, node := restoreAndGetNode(t, tempDir, testNode, true)
|
testPath, node := restoreAndGetNode(t, tempDir, &testNode, true)
|
||||||
_, ua, err := genericAttributesToWindowsAttrs(node.GenericAttributes)
|
_, ua, err := genericAttributesToWindowsAttrs(node.GenericAttributes)
|
||||||
test.OK(t, err)
|
test.OK(t, err)
|
||||||
// Since this GenericAttribute is unknown to this version of the software, it will not get set on the file.
|
// Since this GenericAttribute is unknown to this version of the software, it will not get set on the file.
|
||||||
|
@ -296,7 +296,7 @@ func TestRestoreExtendedAttributes(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, testNode := range expectedNodes {
|
for _, testNode := range expectedNodes {
|
||||||
testPath, node := restoreAndGetNode(t, tempDir, testNode, false)
|
testPath, node := restoreAndGetNode(t, tempDir, &testNode, false)
|
||||||
|
|
||||||
var handle windows.Handle
|
var handle windows.Handle
|
||||||
var err error
|
var err error
|
||||||
|
|
|
@ -64,17 +64,17 @@ func handleXattrErr(err error) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// restoreGenericAttributes is no-op.
|
// nodeRestoreGenericAttributes is no-op.
|
||||||
func (node *Node) restoreGenericAttributes(_ string, warn func(msg string)) error {
|
func nodeRestoreGenericAttributes(node *Node, _ string, warn func(msg string)) error {
|
||||||
return node.handleAllUnknownGenericAttributesFound(warn)
|
return HandleAllUnknownGenericAttributesFound(node.GenericAttributes, warn)
|
||||||
}
|
}
|
||||||
|
|
||||||
// fillGenericAttributes is a no-op.
|
// nodeFillGenericAttributes is a no-op.
|
||||||
func (node *Node) fillGenericAttributes(_ string, _ os.FileInfo, _ *statT) (allowExtended bool, err error) {
|
func nodeFillGenericAttributes(_ *Node, _ string, _ os.FileInfo, _ *statT) (allowExtended bool, err error) {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (node Node) restoreExtendedAttributes(path string) error {
|
func nodeRestoreExtendedAttributes(node *Node, path string) error {
|
||||||
expectedAttrs := map[string]struct{}{}
|
expectedAttrs := map[string]struct{}{}
|
||||||
for _, attr := range node.ExtendedAttributes {
|
for _, attr := range node.ExtendedAttributes {
|
||||||
err := setxattr(path, attr.Name, attr.Value)
|
err := setxattr(path, attr.Name, attr.Value)
|
||||||
|
@ -101,7 +101,7 @@ func (node Node) restoreExtendedAttributes(path string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (node *Node) fillExtendedAttributes(path string, ignoreListError bool) error {
|
func nodeFillExtendedAttributes(node *Node, path string, ignoreListError bool) error {
|
||||||
xattrs, err := listxattr(path)
|
xattrs, err := listxattr(path)
|
||||||
debug.Log("fillExtendedAttributes(%v) %v %v", path, xattrs, err)
|
debug.Log("fillExtendedAttributes(%v) %v %v", path, xattrs, err)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -21,18 +21,18 @@ func setAndVerifyXattr(t *testing.T, file string, attrs []ExtendedAttribute) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
node := Node{
|
node := &Node{
|
||||||
Type: "file",
|
Type: "file",
|
||||||
ExtendedAttributes: attrs,
|
ExtendedAttributes: attrs,
|
||||||
}
|
}
|
||||||
rtest.OK(t, node.restoreExtendedAttributes(file))
|
rtest.OK(t, nodeRestoreExtendedAttributes(node, file))
|
||||||
|
|
||||||
nodeActual := Node{
|
nodeActual := &Node{
|
||||||
Type: "file",
|
Type: "file",
|
||||||
}
|
}
|
||||||
rtest.OK(t, nodeActual.fillExtendedAttributes(file, false))
|
rtest.OK(t, nodeFillExtendedAttributes(nodeActual, file, false))
|
||||||
|
|
||||||
rtest.Assert(t, nodeActual.sameExtendedAttributes(node), "xattr mismatch got %v expected %v", nodeActual.ExtendedAttributes, node.ExtendedAttributes)
|
rtest.Assert(t, nodeActual.Equals(*node), "xattr mismatch got %v expected %v", nodeActual.ExtendedAttributes, node.ExtendedAttributes)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestOverwriteXattr(t *testing.T) {
|
func TestOverwriteXattr(t *testing.T) {
|
||||||
|
|
|
@ -272,7 +272,7 @@ func (res *Restorer) restoreNodeTo(ctx context.Context, node *restic.Node, targe
|
||||||
return errors.Wrap(err, "RemoveNode")
|
return errors.Wrap(err, "RemoveNode")
|
||||||
}
|
}
|
||||||
|
|
||||||
err := node.CreateAt(ctx, target, res.repo)
|
err := restic.NodeCreateAt(ctx, node, target, res.repo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
debug.Log("node.CreateAt(%s) error %v", target, err)
|
debug.Log("node.CreateAt(%s) error %v", target, err)
|
||||||
return err
|
return err
|
||||||
|
@ -288,7 +288,7 @@ func (res *Restorer) restoreNodeMetadataTo(node *restic.Node, target, location s
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
debug.Log("restoreNodeMetadata %v %v %v", node.Name, target, location)
|
debug.Log("restoreNodeMetadata %v %v %v", node.Name, target, location)
|
||||||
err := node.RestoreMetadata(target, res.Warn)
|
err := restic.NodeRestoreMetadata(node, target, res.Warn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
debug.Log("node.RestoreMetadata(%s) error %v", target, err)
|
debug.Log("node.RestoreMetadata(%s) error %v", target, err)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue