| 
									
										
										
										
											2024-08-26 23:03:25 +02:00
										 |  |  | package fs | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2024-11-11 21:37:28 +01:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2024-08-26 23:03:25 +02:00
										 |  |  | 	"os" | 
					
						
							|  |  |  | 	"os/user" | 
					
						
							|  |  |  | 	"strconv" | 
					
						
							|  |  |  | 	"sync" | 
					
						
							|  |  |  | 	"syscall" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/restic/restic/internal/debug" | 
					
						
							|  |  |  | 	"github.com/restic/restic/internal/errors" | 
					
						
							|  |  |  | 	"github.com/restic/restic/internal/restic" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-28 10:58:07 +02:00
										 |  |  | // nodeFromFileInfo returns a new node from the given path and FileInfo. It | 
					
						
							| 
									
										
										
										
											2024-08-26 23:03:25 +02:00
										 |  |  | // returns the first error that is encountered, together with a node. | 
					
						
							| 
									
										
										
										
											2024-11-03 16:01:59 +01:00
										 |  |  | func nodeFromFileInfo(path string, fi *ExtendedFileInfo, ignoreXattrListError bool) (*restic.Node, error) { | 
					
						
							| 
									
										
										
										
											2024-11-30 16:58:04 +01:00
										 |  |  | 	node := buildBasicNode(path, fi) | 
					
						
							| 
									
										
										
										
											2024-08-28 10:58:07 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-03 16:01:59 +01:00
										 |  |  | 	if err := nodeFillExtendedStat(node, path, fi); err != nil { | 
					
						
							| 
									
										
										
										
											2024-08-28 10:58:07 +02:00
										 |  |  | 		return node, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-03 16:01:59 +01:00
										 |  |  | 	err := nodeFillGenericAttributes(node, path, fi) | 
					
						
							| 
									
										
										
										
											2024-11-02 22:45:48 +01:00
										 |  |  | 	err = errors.Join(err, nodeFillExtendedAttributes(node, path, ignoreXattrListError)) | 
					
						
							| 
									
										
										
										
											2024-08-28 10:58:07 +02:00
										 |  |  | 	return node, err | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-30 16:58:04 +01:00
										 |  |  | func buildBasicNode(path string, fi *ExtendedFileInfo) *restic.Node { | 
					
						
							| 
									
										
										
										
											2024-08-26 23:03:25 +02:00
										 |  |  | 	mask := os.ModePerm | os.ModeType | os.ModeSetuid | os.ModeSetgid | os.ModeSticky | 
					
						
							|  |  |  | 	node := &restic.Node{ | 
					
						
							|  |  |  | 		Path:    path, | 
					
						
							| 
									
										
										
										
											2024-11-30 16:58:04 +01:00
										 |  |  | 		Name:    fi.Name, | 
					
						
							|  |  |  | 		Mode:    fi.Mode & mask, | 
					
						
							|  |  |  | 		ModTime: fi.ModTime, | 
					
						
							| 
									
										
										
										
											2024-08-26 23:03:25 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-30 16:58:04 +01:00
										 |  |  | 	node.Type = nodeTypeFromFileInfo(fi.Mode) | 
					
						
							| 
									
										
										
										
											2024-07-09 19:51:44 +02:00
										 |  |  | 	if node.Type == restic.NodeTypeFile { | 
					
						
							| 
									
										
										
										
											2024-11-30 16:58:04 +01:00
										 |  |  | 		node.Size = uint64(fi.Size) | 
					
						
							| 
									
										
										
										
											2024-08-26 23:03:25 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-08-28 10:58:07 +02:00
										 |  |  | 	return node | 
					
						
							| 
									
										
										
										
											2024-08-26 23:03:25 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-03 16:01:59 +01:00
										 |  |  | func nodeTypeFromFileInfo(mode os.FileMode) restic.NodeType { | 
					
						
							|  |  |  | 	switch mode & os.ModeType { | 
					
						
							| 
									
										
										
										
											2024-08-26 23:03:25 +02:00
										 |  |  | 	case 0: | 
					
						
							| 
									
										
										
										
											2024-07-09 19:51:44 +02:00
										 |  |  | 		return restic.NodeTypeFile | 
					
						
							| 
									
										
										
										
											2024-08-26 23:03:25 +02:00
										 |  |  | 	case os.ModeDir: | 
					
						
							| 
									
										
										
										
											2024-07-09 19:51:44 +02:00
										 |  |  | 		return restic.NodeTypeDir | 
					
						
							| 
									
										
										
										
											2024-08-26 23:03:25 +02:00
										 |  |  | 	case os.ModeSymlink: | 
					
						
							| 
									
										
										
										
											2024-07-09 19:51:44 +02:00
										 |  |  | 		return restic.NodeTypeSymlink | 
					
						
							| 
									
										
										
										
											2024-08-26 23:03:25 +02:00
										 |  |  | 	case os.ModeDevice | os.ModeCharDevice: | 
					
						
							| 
									
										
										
										
											2024-07-09 19:51:44 +02:00
										 |  |  | 		return restic.NodeTypeCharDev | 
					
						
							| 
									
										
										
										
											2024-08-26 23:03:25 +02:00
										 |  |  | 	case os.ModeDevice: | 
					
						
							| 
									
										
										
										
											2024-07-09 19:51:44 +02:00
										 |  |  | 		return restic.NodeTypeDev | 
					
						
							| 
									
										
										
										
											2024-08-26 23:03:25 +02:00
										 |  |  | 	case os.ModeNamedPipe: | 
					
						
							| 
									
										
										
										
											2024-07-09 19:51:44 +02:00
										 |  |  | 		return restic.NodeTypeFifo | 
					
						
							| 
									
										
										
										
											2024-08-26 23:03:25 +02:00
										 |  |  | 	case os.ModeSocket: | 
					
						
							| 
									
										
										
										
											2024-07-09 19:51:44 +02:00
										 |  |  | 		return restic.NodeTypeSocket | 
					
						
							| 
									
										
										
										
											2024-08-26 23:03:25 +02:00
										 |  |  | 	case os.ModeIrregular: | 
					
						
							| 
									
										
										
										
											2024-07-09 19:51:44 +02:00
										 |  |  | 		return restic.NodeTypeIrregular | 
					
						
							| 
									
										
										
										
											2024-08-26 23:03:25 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-09 19:51:44 +02:00
										 |  |  | 	return restic.NodeTypeInvalid | 
					
						
							| 
									
										
										
										
											2024-08-26 23:03:25 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-28 10:58:07 +02:00
										 |  |  | func nodeFillExtendedStat(node *restic.Node, path string, stat *ExtendedFileInfo) error { | 
					
						
							| 
									
										
										
										
											2024-08-24 23:43:45 +02:00
										 |  |  | 	node.Inode = stat.Inode | 
					
						
							|  |  |  | 	node.DeviceID = stat.DeviceID | 
					
						
							|  |  |  | 	node.ChangeTime = stat.ChangeTime | 
					
						
							|  |  |  | 	node.AccessTime = stat.AccessTime | 
					
						
							| 
									
										
										
										
											2024-08-26 23:03:25 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-24 23:43:45 +02:00
										 |  |  | 	node.UID = stat.UID | 
					
						
							|  |  |  | 	node.GID = stat.GID | 
					
						
							|  |  |  | 	node.User = lookupUsername(stat.UID) | 
					
						
							|  |  |  | 	node.Group = lookupGroup(stat.GID) | 
					
						
							| 
									
										
										
										
											2024-08-26 23:03:25 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	switch node.Type { | 
					
						
							| 
									
										
										
										
											2024-07-09 19:51:44 +02:00
										 |  |  | 	case restic.NodeTypeFile: | 
					
						
							| 
									
										
										
										
											2024-08-24 23:43:45 +02:00
										 |  |  | 		node.Size = uint64(stat.Size) | 
					
						
							|  |  |  | 		node.Links = stat.Links | 
					
						
							| 
									
										
										
										
											2024-07-09 19:51:44 +02:00
										 |  |  | 	case restic.NodeTypeDir: | 
					
						
							|  |  |  | 	case restic.NodeTypeSymlink: | 
					
						
							| 
									
										
										
										
											2024-08-26 23:03:25 +02:00
										 |  |  | 		var err error | 
					
						
							| 
									
										
										
										
											2024-07-21 15:58:41 +02:00
										 |  |  | 		node.LinkTarget, err = os.Readlink(fixpath(path)) | 
					
						
							| 
									
										
										
										
											2024-08-24 23:43:45 +02:00
										 |  |  | 		node.Links = stat.Links | 
					
						
							| 
									
										
										
										
											2024-08-26 23:03:25 +02:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return errors.WithStack(err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-07-09 19:51:44 +02:00
										 |  |  | 	case restic.NodeTypeDev: | 
					
						
							| 
									
										
										
										
											2024-08-24 23:43:45 +02:00
										 |  |  | 		node.Device = stat.Device | 
					
						
							|  |  |  | 		node.Links = stat.Links | 
					
						
							| 
									
										
										
										
											2024-07-09 19:51:44 +02:00
										 |  |  | 	case restic.NodeTypeCharDev: | 
					
						
							| 
									
										
										
										
											2024-08-24 23:43:45 +02:00
										 |  |  | 		node.Device = stat.Device | 
					
						
							|  |  |  | 		node.Links = stat.Links | 
					
						
							| 
									
										
										
										
											2024-07-09 19:51:44 +02:00
										 |  |  | 	case restic.NodeTypeFifo: | 
					
						
							|  |  |  | 	case restic.NodeTypeSocket: | 
					
						
							| 
									
										
										
										
											2024-08-26 23:03:25 +02:00
										 |  |  | 	default: | 
					
						
							|  |  |  | 		return errors.Errorf("unsupported file type %q", node.Type) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-08-28 10:58:07 +02:00
										 |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2024-08-26 23:03:25 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var ( | 
					
						
							|  |  |  | 	uidLookupCache      = make(map[uint32]string) | 
					
						
							|  |  |  | 	uidLookupCacheMutex = sync.RWMutex{} | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Cached user name lookup by uid. Returns "" when no name can be found. | 
					
						
							|  |  |  | func lookupUsername(uid uint32) string { | 
					
						
							|  |  |  | 	uidLookupCacheMutex.RLock() | 
					
						
							|  |  |  | 	username, ok := uidLookupCache[uid] | 
					
						
							|  |  |  | 	uidLookupCacheMutex.RUnlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if ok { | 
					
						
							|  |  |  | 		return username | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	u, err := user.LookupId(strconv.Itoa(int(uid))) | 
					
						
							|  |  |  | 	if err == nil { | 
					
						
							|  |  |  | 		username = u.Username | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	uidLookupCacheMutex.Lock() | 
					
						
							|  |  |  | 	uidLookupCache[uid] = username | 
					
						
							|  |  |  | 	uidLookupCacheMutex.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return username | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var ( | 
					
						
							|  |  |  | 	gidLookupCache      = make(map[uint32]string) | 
					
						
							|  |  |  | 	gidLookupCacheMutex = sync.RWMutex{} | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Cached group name lookup by gid. Returns "" when no name can be found. | 
					
						
							|  |  |  | func lookupGroup(gid uint32) string { | 
					
						
							|  |  |  | 	gidLookupCacheMutex.RLock() | 
					
						
							|  |  |  | 	group, ok := gidLookupCache[gid] | 
					
						
							|  |  |  | 	gidLookupCacheMutex.RUnlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if ok { | 
					
						
							|  |  |  | 		return group | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	g, err := user.LookupGroupId(strconv.Itoa(int(gid))) | 
					
						
							|  |  |  | 	if err == nil { | 
					
						
							|  |  |  | 		group = g.Name | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	gidLookupCacheMutex.Lock() | 
					
						
							|  |  |  | 	gidLookupCache[gid] = group | 
					
						
							|  |  |  | 	gidLookupCacheMutex.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return group | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // NodeCreateAt creates the node at the given path but does NOT restore node meta data. | 
					
						
							| 
									
										
										
										
											2024-10-03 21:36:48 +02:00
										 |  |  | func NodeCreateAt(node *restic.Node, path string) (err error) { | 
					
						
							| 
									
										
										
										
											2024-08-26 23:03:25 +02:00
										 |  |  | 	debug.Log("create node %v at %v", node.Name, path) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch node.Type { | 
					
						
							| 
									
										
										
										
											2024-07-09 19:51:44 +02:00
										 |  |  | 	case restic.NodeTypeDir: | 
					
						
							| 
									
										
										
										
											2024-10-03 21:36:48 +02:00
										 |  |  | 		err = nodeCreateDirAt(node, path) | 
					
						
							| 
									
										
										
										
											2024-07-09 19:51:44 +02:00
										 |  |  | 	case restic.NodeTypeFile: | 
					
						
							| 
									
										
										
										
											2024-10-03 21:36:48 +02:00
										 |  |  | 		err = nodeCreateFileAt(path) | 
					
						
							| 
									
										
										
										
											2024-07-09 19:51:44 +02:00
										 |  |  | 	case restic.NodeTypeSymlink: | 
					
						
							| 
									
										
										
										
											2024-10-03 21:36:48 +02:00
										 |  |  | 		err = nodeCreateSymlinkAt(node, path) | 
					
						
							| 
									
										
										
										
											2024-07-09 19:51:44 +02:00
										 |  |  | 	case restic.NodeTypeDev: | 
					
						
							| 
									
										
										
										
											2024-10-03 21:36:48 +02:00
										 |  |  | 		err = nodeCreateDevAt(node, path) | 
					
						
							| 
									
										
										
										
											2024-07-09 19:51:44 +02:00
										 |  |  | 	case restic.NodeTypeCharDev: | 
					
						
							| 
									
										
										
										
											2024-10-03 21:36:48 +02:00
										 |  |  | 		err = nodeCreateCharDevAt(node, path) | 
					
						
							| 
									
										
										
										
											2024-07-09 19:51:44 +02:00
										 |  |  | 	case restic.NodeTypeFifo: | 
					
						
							| 
									
										
										
										
											2024-10-03 21:36:48 +02:00
										 |  |  | 		err = nodeCreateFifoAt(path) | 
					
						
							| 
									
										
										
										
											2024-07-09 19:51:44 +02:00
										 |  |  | 	case restic.NodeTypeSocket: | 
					
						
							| 
									
										
										
										
											2024-10-03 21:36:48 +02:00
										 |  |  | 		err = nil | 
					
						
							| 
									
										
										
										
											2024-08-26 23:03:25 +02:00
										 |  |  | 	default: | 
					
						
							| 
									
										
										
										
											2024-10-03 21:36:48 +02:00
										 |  |  | 		err = errors.Errorf("filetype %q not implemented", node.Type) | 
					
						
							| 
									
										
										
										
											2024-08-26 23:03:25 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-10-03 21:36:48 +02:00
										 |  |  | 	return err | 
					
						
							| 
									
										
										
										
											2024-08-26 23:03:25 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func nodeCreateDirAt(node *restic.Node, path string) error { | 
					
						
							| 
									
										
										
										
											2024-07-21 15:58:41 +02:00
										 |  |  | 	err := os.Mkdir(fixpath(path), node.Mode) | 
					
						
							| 
									
										
										
										
											2024-08-26 23:03:25 +02:00
										 |  |  | 	if err != nil && !os.IsExist(err) { | 
					
						
							|  |  |  | 		return errors.WithStack(err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func nodeCreateFileAt(path string) error { | 
					
						
							|  |  |  | 	f, err := OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0600) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return errors.WithStack(err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if err := f.Close(); err != nil { | 
					
						
							|  |  |  | 		return errors.WithStack(err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func nodeCreateSymlinkAt(node *restic.Node, path string) error { | 
					
						
							| 
									
										
										
										
											2024-07-21 15:58:41 +02:00
										 |  |  | 	if err := os.Symlink(node.LinkTarget, fixpath(path)); err != nil { | 
					
						
							| 
									
										
										
										
											2024-08-26 23:03:25 +02:00
										 |  |  | 		return errors.WithStack(err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func nodeCreateDevAt(node *restic.Node, path string) error { | 
					
						
							|  |  |  | 	return mknod(path, syscall.S_IFBLK|0600, node.Device) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func nodeCreateCharDevAt(node *restic.Node, path string) error { | 
					
						
							|  |  |  | 	return mknod(path, syscall.S_IFCHR|0600, node.Device) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func nodeCreateFifoAt(path string) error { | 
					
						
							|  |  |  | 	return mkfifo(path, 0600) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func mkfifo(path string, mode uint32) (err error) { | 
					
						
							|  |  |  | 	return mknod(path, mode|syscall.S_IFIFO, 0) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // NodeRestoreMetadata restores node metadata | 
					
						
							|  |  |  | func NodeRestoreMetadata(node *restic.Node, path string, warn func(msg string)) error { | 
					
						
							|  |  |  | 	err := nodeRestoreMetadata(node, path, warn) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		// It is common to have permission errors for folders like /home | 
					
						
							|  |  |  | 		// unless you're running as root, so ignore those. | 
					
						
							|  |  |  | 		if os.Geteuid() > 0 && errors.Is(err, os.ErrPermission) { | 
					
						
							|  |  |  | 			debug.Log("not running as root, ignoring permission error for %v: %v", | 
					
						
							|  |  |  | 				path, err) | 
					
						
							|  |  |  | 			return nil | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		debug.Log("restoreMetadata(%s) error %v", path, err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return err | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func nodeRestoreMetadata(node *restic.Node, path string, warn func(msg string)) error { | 
					
						
							|  |  |  | 	var firsterr error | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if err := lchown(path, int(node.UID), int(node.GID)); err != nil { | 
					
						
							|  |  |  | 		firsterr = errors.WithStack(err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if err := nodeRestoreExtendedAttributes(node, path); err != nil { | 
					
						
							|  |  |  | 		debug.Log("error restoring extended attributes for %v: %v", path, err) | 
					
						
							|  |  |  | 		if firsterr == nil { | 
					
						
							|  |  |  | 			firsterr = err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if err := nodeRestoreGenericAttributes(node, path, warn); err != nil { | 
					
						
							|  |  |  | 		debug.Log("error restoring generic attributes for %v: %v", path, err) | 
					
						
							|  |  |  | 		if firsterr == nil { | 
					
						
							|  |  |  | 			firsterr = err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-27 15:34:53 +02:00
										 |  |  | 	if err := nodeRestoreTimestamps(node, path); err != nil { | 
					
						
							| 
									
										
										
										
											2024-08-26 23:03:25 +02:00
										 |  |  | 		debug.Log("error restoring timestamps for %v: %v", path, err) | 
					
						
							|  |  |  | 		if firsterr == nil { | 
					
						
							|  |  |  | 			firsterr = err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 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. | 
					
						
							| 
									
										
										
										
											2024-07-09 19:51:44 +02:00
										 |  |  | 	if node.Type != restic.NodeTypeSymlink { | 
					
						
							| 
									
										
										
										
											2024-07-21 16:00:47 +02:00
										 |  |  | 		if err := chmod(path, node.Mode); err != nil { | 
					
						
							| 
									
										
										
										
											2024-08-26 23:03:25 +02:00
										 |  |  | 			if firsterr == nil { | 
					
						
							|  |  |  | 				firsterr = errors.WithStack(err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return firsterr | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-27 15:34:53 +02:00
										 |  |  | func nodeRestoreTimestamps(node *restic.Node, path string) error { | 
					
						
							| 
									
										
										
										
											2024-10-04 10:06:18 +02:00
										 |  |  | 	atime := node.AccessTime.UnixNano() | 
					
						
							|  |  |  | 	mtime := node.ModTime.UnixNano() | 
					
						
							| 
									
										
										
										
											2024-08-26 23:03:25 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-10-04 10:06:18 +02:00
										 |  |  | 	if err := utimesNano(fixpath(path), atime, mtime, node.Type); err != nil { | 
					
						
							| 
									
										
										
										
											2024-11-11 21:37:28 +01:00
										 |  |  | 		return fmt.Errorf("failed to restore timestamp of %q: %w", path, err) | 
					
						
							| 
									
										
										
										
											2024-08-26 23:03:25 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } |