mirror of
https://github.com/jkl1337/duplicacy.git
synced 2026-01-06 21:54:38 -06:00
Compare commits
1 Commits
96e7c93a2c
...
wip-chattr
| Author | SHA1 | Date | |
|---|---|---|---|
| ad677702ba |
@@ -703,19 +703,8 @@ func (manager *BackupManager) Restore(top string, revision int, inPlace bool, qu
|
|||||||
var localEntry *Entry
|
var localEntry *Entry
|
||||||
localListingOK := true
|
localListingOK := true
|
||||||
|
|
||||||
type hardLinkEntry struct {
|
|
||||||
entry *Entry
|
|
||||||
willDownload bool
|
|
||||||
}
|
|
||||||
var hardLinkTable []hardLinkEntry
|
|
||||||
var hardLinks []*Entry
|
|
||||||
|
|
||||||
for remoteEntry := range remoteListingChannel {
|
for remoteEntry := range remoteListingChannel {
|
||||||
|
|
||||||
if remoteEntry.IsHardlinkRoot() {
|
|
||||||
hardLinkTable = append(hardLinkTable, hardLinkEntry{remoteEntry, false})
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(patterns) > 0 && !MatchPath(remoteEntry.Path, patterns) {
|
if len(patterns) > 0 && !MatchPath(remoteEntry.Path, patterns) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -753,7 +742,8 @@ func (manager *BackupManager) Restore(top string, revision int, inPlace bool, qu
|
|||||||
|
|
||||||
fullPath := joinPath(top, remoteEntry.Path)
|
fullPath := joinPath(top, remoteEntry.Path)
|
||||||
if remoteEntry.IsLink() {
|
if remoteEntry.IsLink() {
|
||||||
if stat, _ := os.Lstat(fullPath); stat != nil {
|
stat, err := os.Lstat(fullPath)
|
||||||
|
if stat != nil {
|
||||||
if stat.Mode()&os.ModeSymlink != 0 {
|
if stat.Mode()&os.ModeSymlink != 0 {
|
||||||
isRegular, link, err := Readlink(fullPath)
|
isRegular, link, err := Readlink(fullPath)
|
||||||
if err == nil && link == remoteEntry.Link && !isRegular {
|
if err == nil && link == remoteEntry.Link && !isRegular {
|
||||||
@@ -762,16 +752,11 @@ func (manager *BackupManager) Restore(top string, revision int, inPlace bool, qu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !overwrite {
|
|
||||||
LOG_WERROR(allowFailures, "DOWNLOAD_OVERWRITE",
|
|
||||||
"File %s already exists. Please specify the -overwrite option to overwrite", remoteEntry.Path)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
os.Remove(fullPath)
|
os.Remove(fullPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := os.Symlink(remoteEntry.Link, fullPath); err != nil {
|
err = os.Symlink(remoteEntry.Link, fullPath)
|
||||||
|
if err != nil {
|
||||||
LOG_ERROR("RESTORE_SYMLINK", "Can't create symlink %s: %v", remoteEntry.Path, err)
|
LOG_ERROR("RESTORE_SYMLINK", "Can't create symlink %s: %v", remoteEntry.Path, err)
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
@@ -797,37 +782,7 @@ func (manager *BackupManager) Restore(top string, revision int, inPlace bool, qu
|
|||||||
}
|
}
|
||||||
remoteEntry.RestoreEarlyDirFlags(fullPath)
|
remoteEntry.RestoreEarlyDirFlags(fullPath)
|
||||||
directoryEntries = append(directoryEntries, remoteEntry)
|
directoryEntries = append(directoryEntries, remoteEntry)
|
||||||
} else if remoteEntry.IsSpecial() {
|
|
||||||
if stat, _ := os.Lstat(fullPath); stat != nil {
|
|
||||||
if !overwrite {
|
|
||||||
LOG_WERROR(allowFailures, "DOWNLOAD_OVERWRITE",
|
|
||||||
"File %s already exists. Please specify the -overwrite option to overwrite", remoteEntry.Path)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
os.Remove(fullPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := remoteEntry.RestoreSpecial(fullPath); err != nil {
|
|
||||||
LOG_ERROR("RESTORE_SPECIAL", "Unable to restore special file %s: %v", remoteEntry.Path, err)
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
remoteEntry.RestoreMetadata(fullPath, nil, setOwner)
|
|
||||||
} else {
|
} else {
|
||||||
if remoteEntry.IsHardlinkRoot() {
|
|
||||||
hardLinkTable[len(hardLinkTable)-1] = hardLinkEntry{remoteEntry, true}
|
|
||||||
} else if remoteEntry.IsHardlinkedFrom() {
|
|
||||||
i, err := strconv.ParseUint(remoteEntry.Link, 16, 64)
|
|
||||||
if err != nil {
|
|
||||||
LOG_ERROR("RESTORE_HARDLINK", "Decode error in hardlink entry, expected hex int, got %s", remoteEntry.Link)
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
if !hardLinkTable[i].willDownload {
|
|
||||||
hardLinkTable[i] = hardLinkEntry{remoteEntry, true}
|
|
||||||
} else {
|
|
||||||
hardLinks = append(hardLinks, remoteEntry)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// We can't download files here since fileEntries needs to be sorted
|
// We can't download files here since fileEntries needs to be sorted
|
||||||
fileEntries = append(fileEntries, remoteEntry)
|
fileEntries = append(fileEntries, remoteEntry)
|
||||||
totalFileSize += remoteEntry.Size
|
totalFileSize += remoteEntry.Size
|
||||||
@@ -947,17 +902,6 @@ func (manager *BackupManager) Restore(top string, revision int, inPlace bool, qu
|
|||||||
file.RestoreMetadata(fullPath, nil, setOwner)
|
file.RestoreMetadata(fullPath, nil, setOwner)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, linkEntry := range hardLinks {
|
|
||||||
i, _ := strconv.ParseUint(linkEntry.Link, 16, 64)
|
|
||||||
sourcePath := joinPath(top, hardLinkTable[i].entry.Path)
|
|
||||||
fullPath := joinPath(top, linkEntry.Path)
|
|
||||||
LOG_INFO("RESTORE_HARDLINK", "Hard linking %s to %s", fullPath, sourcePath)
|
|
||||||
if err := os.Link(sourcePath, fullPath); err != nil {
|
|
||||||
LOG_ERROR("RESTORE_HARDLINK", "Failed to create hard link %s to %s", fullPath, sourcePath)
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if deleteMode && len(patterns) == 0 {
|
if deleteMode && len(patterns) == 0 {
|
||||||
// Reverse the order to make sure directories are empty before being deleted
|
// Reverse the order to make sure directories are empty before being deleted
|
||||||
for i := range extraFiles {
|
for i := range extraFiles {
|
||||||
@@ -1109,13 +1053,8 @@ func (manager *BackupManager) UploadSnapshot(chunkOperator *ChunkOperator, top s
|
|||||||
|
|
||||||
lastEndChunk := 0
|
lastEndChunk := 0
|
||||||
|
|
||||||
type hardLinkEntry struct {
|
|
||||||
entry *Entry
|
|
||||||
startChunk int
|
|
||||||
}
|
|
||||||
var hardLinkTable []hardLinkEntry
|
|
||||||
|
|
||||||
uploadEntryInfoFunc := func(entry *Entry) error {
|
uploadEntryInfoFunc := func(entry *Entry) error {
|
||||||
|
|
||||||
if entry.IsFile() && entry.Size > 0 {
|
if entry.IsFile() && entry.Size > 0 {
|
||||||
delta := entry.StartChunk - len(chunkHashes) + 1
|
delta := entry.StartChunk - len(chunkHashes) + 1
|
||||||
if entry.StartChunk != lastChunk {
|
if entry.StartChunk != lastChunk {
|
||||||
@@ -1133,38 +1072,10 @@ func (manager *BackupManager) UploadSnapshot(chunkOperator *ChunkOperator, top s
|
|||||||
entry.StartChunk -= delta
|
entry.StartChunk -= delta
|
||||||
entry.EndChunk -= delta
|
entry.EndChunk -= delta
|
||||||
|
|
||||||
if entry.IsHardlinkRoot() {
|
|
||||||
LOG_DEBUG("SNAPSHOT_UPLOAD", "Hard link root %s %v %v", entry.Path, entry.StartChunk, entry.EndChunk)
|
|
||||||
hardLinkTable = append(hardLinkTable, hardLinkEntry{entry, entry.StartChunk})
|
|
||||||
}
|
|
||||||
|
|
||||||
delta = entry.EndChunk - entry.StartChunk
|
delta = entry.EndChunk - entry.StartChunk
|
||||||
entry.StartChunk -= lastEndChunk
|
entry.StartChunk -= lastEndChunk
|
||||||
lastEndChunk = entry.EndChunk
|
lastEndChunk = entry.EndChunk
|
||||||
entry.EndChunk = delta
|
entry.EndChunk = delta
|
||||||
} else if entry.IsHardlinkedFrom() {
|
|
||||||
i, err := strconv.ParseUint(entry.Link, 16, 64)
|
|
||||||
if err != nil {
|
|
||||||
LOG_ERROR("SNAPSHOT_UPLOAD", "Decode error in hardlink entry, expected hex int, got %s", entry.Link)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
targetEntry := hardLinkTable[i].entry
|
|
||||||
var startChunk, endChunk int
|
|
||||||
|
|
||||||
if targetEntry.Size > 0 {
|
|
||||||
startChunk = hardLinkTable[i].startChunk - lastEndChunk
|
|
||||||
endChunk = targetEntry.EndChunk
|
|
||||||
}
|
|
||||||
entry = entry.HardLinkTo(targetEntry, startChunk, endChunk)
|
|
||||||
|
|
||||||
if targetEntry.Size > 0 {
|
|
||||||
lastEndChunk = hardLinkTable[i].startChunk + endChunk
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_DEBUG("SNAPSHOT_UPLOAD", "Uploading cloned hardlink for %s to %s (%v %v)", entry.Path, targetEntry.Path, startChunk, endChunk)
|
|
||||||
} else if entry.IsHardlinkRoot() {
|
|
||||||
hardLinkTable = append(hardLinkTable, hardLinkEntry{entry, 0})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer.Reset()
|
buffer.Reset()
|
||||||
|
|||||||
@@ -4,8 +4,6 @@
|
|||||||
package duplicacy
|
package duplicacy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"crypto/sha256"
|
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -17,10 +15,12 @@ import (
|
|||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
|
||||||
"time"
|
"time"
|
||||||
|
"bytes"
|
||||||
|
"crypto/sha256"
|
||||||
|
|
||||||
"github.com/vmihailenco/msgpack"
|
"github.com/vmihailenco/msgpack"
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// This is the hidden directory in the repository for storing various files.
|
// This is the hidden directory in the repository for storing various files.
|
||||||
@@ -119,27 +119,6 @@ func (entry *Entry) Copy() *Entry {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (entry *Entry) HardLinkTo(target *Entry, startChunk int, endChunk int) *Entry {
|
|
||||||
return &Entry{
|
|
||||||
Path: entry.Path,
|
|
||||||
Size: target.Size,
|
|
||||||
Time: target.Time,
|
|
||||||
Mode: target.Mode,
|
|
||||||
Link: entry.Link,
|
|
||||||
Hash: target.Hash,
|
|
||||||
|
|
||||||
UID: target.UID,
|
|
||||||
GID: target.GID,
|
|
||||||
|
|
||||||
StartChunk: startChunk,
|
|
||||||
StartOffset: target.StartOffset,
|
|
||||||
EndChunk: endChunk,
|
|
||||||
EndOffset: target.EndOffset,
|
|
||||||
|
|
||||||
Attributes: target.Attributes,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateEntryFromJSON creates an entry from a json description.
|
// CreateEntryFromJSON creates an entry from a json description.
|
||||||
func (entry *Entry) UnmarshalJSON(description []byte) (err error) {
|
func (entry *Entry) UnmarshalJSON(description []byte) (err error) {
|
||||||
|
|
||||||
@@ -509,22 +488,10 @@ func (entry *Entry) IsLink() bool {
|
|||||||
return entry.Mode&uint32(os.ModeSymlink) != 0
|
return entry.Mode&uint32(os.ModeSymlink) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (entry *Entry) IsSpecial() bool {
|
|
||||||
return entry.Mode&uint32(os.ModeNamedPipe|os.ModeDevice|os.ModeCharDevice) != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) IsComplete() bool {
|
func (entry *Entry) IsComplete() bool {
|
||||||
return entry.Size >= 0
|
return entry.Size >= 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (entry *Entry) IsHardlinkedFrom() bool {
|
|
||||||
return entry.IsFile() && len(entry.Link) > 0 && entry.Link != "/"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) IsHardlinkRoot() bool {
|
|
||||||
return entry.IsFile() && entry.Link == "/"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) GetPermissions() os.FileMode {
|
func (entry *Entry) GetPermissions() os.FileMode {
|
||||||
return os.FileMode(entry.Mode) & fileModeMask
|
return os.FileMode(entry.Mode) & fileModeMask
|
||||||
}
|
}
|
||||||
@@ -727,27 +694,10 @@ func (files FileInfoCompare) Less(i, j int) bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type listEntryLinkKey struct {
|
|
||||||
dev uint64
|
|
||||||
ino uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
type ListingState struct {
|
|
||||||
linkIndex int
|
|
||||||
linkTable map[listEntryLinkKey]int // map unique inode details to initially found path
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewListingState() *ListingState {
|
|
||||||
return &ListingState{
|
|
||||||
linkTable: make(map[listEntryLinkKey]int),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListEntries returns a list of entries representing file and subdirectories under the directory 'path'. Entry paths
|
// ListEntries returns a list of entries representing file and subdirectories under the directory 'path'. Entry paths
|
||||||
// are normalized as relative to 'top'. 'patterns' are used to exclude or include certain files.
|
// are normalized as relative to 'top'. 'patterns' are used to exclude or include certain files.
|
||||||
func ListEntries(top string, path string, patterns []string, nobackupFile string, excludeByAttribute bool,
|
func ListEntries(top string, path string, patterns []string, nobackupFile string, excludeByAttribute bool, listingChannel chan *Entry) (directoryList []*Entry,
|
||||||
listingState *ListingState,
|
skippedFiles []string, err error) {
|
||||||
listingChannel chan *Entry) (directoryList []*Entry, skippedFiles []string, err error) {
|
|
||||||
|
|
||||||
LOG_DEBUG("LIST_ENTRIES", "Listing %s", path)
|
LOG_DEBUG("LIST_ENTRIES", "Listing %s", path)
|
||||||
|
|
||||||
@@ -819,33 +769,6 @@ func ListEntries(top string, path string, patterns []string, nobackupFile string
|
|||||||
}
|
}
|
||||||
entry = newEntry
|
entry = newEntry
|
||||||
}
|
}
|
||||||
} else if entry.Mode & uint32(os.ModeSocket) != 0 {
|
|
||||||
// no reason to issue a warning for what should always be a transient file anyways
|
|
||||||
continue
|
|
||||||
} else if entry.IsSpecial() {
|
|
||||||
if !entry.ReadSpecial(f) {
|
|
||||||
LOG_WARN("LIST_DEV", "Failed to save device node %s", entry.Path)
|
|
||||||
skippedFiles = append(skippedFiles, entry.Path)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var linkKey *listEntryLinkKey
|
|
||||||
|
|
||||||
if stat, ok := f.Sys().(*syscall.Stat_t); entry.IsFile() && ok && stat != nil && stat.Nlink > 1 {
|
|
||||||
k := listEntryLinkKey{dev: uint64(stat.Dev), ino: uint64(stat.Ino)}
|
|
||||||
if linkIndex, seen := listingState.linkTable[k]; seen {
|
|
||||||
if linkIndex == -1 {
|
|
||||||
LOG_DEBUG("LIST_EXCLUDE", "%s is excluded by attribute (hardlink)", entry.Path)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
entry.Size = 0
|
|
||||||
entry.Link = strconv.FormatInt(int64(linkIndex), 16)
|
|
||||||
} else {
|
|
||||||
entry.Link = "/"
|
|
||||||
listingState.linkTable[k] = -1
|
|
||||||
linkKey = &k
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
entry.ReadAttributes(top)
|
entry.ReadAttributes(top)
|
||||||
@@ -855,9 +778,10 @@ func ListEntries(top string, path string, patterns []string, nobackupFile string
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if linkKey != nil {
|
if f.Mode()&(os.ModeNamedPipe|os.ModeSocket|os.ModeDevice) != 0 {
|
||||||
listingState.linkTable[*linkKey] = listingState.linkIndex
|
LOG_WARN("LIST_SKIP", "Skipped non-regular file %s", entry.Path)
|
||||||
listingState.linkIndex++
|
skippedFiles = append(skippedFiles, entry.Path)
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if entry.IsDir() {
|
if entry.IsDir() {
|
||||||
|
|||||||
@@ -111,12 +111,12 @@ func (entryList *EntryList)createOnDiskFile() error {
|
|||||||
// Add an entry to the entry list
|
// Add an entry to the entry list
|
||||||
func (entryList *EntryList)AddEntry(entry *Entry) error {
|
func (entryList *EntryList)AddEntry(entry *Entry) error {
|
||||||
|
|
||||||
if entry.IsFile() {
|
if !entry.IsDir() && !entry.IsLink() {
|
||||||
entryList.NumberOfEntries++
|
entryList.NumberOfEntries++
|
||||||
}
|
}
|
||||||
|
|
||||||
if !entry.IsComplete() {
|
if !entry.IsComplete() {
|
||||||
if !entry.IsFile() {
|
if entry.IsDir() || entry.IsLink() {
|
||||||
entry.Size = 0
|
entry.Size = 0
|
||||||
} else {
|
} else {
|
||||||
modifiedEntry := ModifiedEntry {
|
modifiedEntry := ModifiedEntry {
|
||||||
|
|||||||
@@ -68,7 +68,6 @@ func (snapshot *Snapshot) ListLocalFiles(top string, nobackupFile string,
|
|||||||
skippedDirectories *[]string, skippedFiles *[]string) {
|
skippedDirectories *[]string, skippedFiles *[]string) {
|
||||||
|
|
||||||
var patterns []string
|
var patterns []string
|
||||||
listingState := NewListingState()
|
|
||||||
|
|
||||||
if filtersFile == "" {
|
if filtersFile == "" {
|
||||||
filtersFile = joinPath(GetDuplicacyPreferencePath(), "filters")
|
filtersFile = joinPath(GetDuplicacyPreferencePath(), "filters")
|
||||||
@@ -82,7 +81,7 @@ func (snapshot *Snapshot) ListLocalFiles(top string, nobackupFile string,
|
|||||||
|
|
||||||
directory := directories[len(directories)-1]
|
directory := directories[len(directories)-1]
|
||||||
directories = directories[:len(directories)-1]
|
directories = directories[:len(directories)-1]
|
||||||
subdirectories, skipped, err := ListEntries(top, directory.Path, patterns, nobackupFile, excludeByAttribute, listingState, listingChannel)
|
subdirectories, skipped, err := ListEntries(top, directory.Path, patterns, nobackupFile, excludeByAttribute, listingChannel)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if directory.Path == "" {
|
if directory.Path == "" {
|
||||||
LOG_ERROR("LIST_FAILURE", "Failed to list the repository root: %v", err)
|
LOG_ERROR("LIST_FAILURE", "Failed to list the repository root: %v", err)
|
||||||
|
|||||||
@@ -48,9 +48,6 @@ func ioctl(f *os.File, request uintptr, attrp *uint32) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (entry *Entry) ReadFileFlags(f *os.File) error {
|
func (entry *Entry) ReadFileFlags(f *os.File) error {
|
||||||
if entry.IsSpecial() {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
var flags uint32
|
var flags uint32
|
||||||
if err := ioctl(f, linux_FS_IOC_GETFLAGS, &flags); err != nil {
|
if err := ioctl(f, linux_FS_IOC_GETFLAGS, &flags); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ func SetOwner(fullPath string, entry *Entry, fileInfo *os.FileInfo) bool {
|
|||||||
|
|
||||||
func (entry *Entry) ReadAttributes(top string) {
|
func (entry *Entry) ReadAttributes(top string) {
|
||||||
fullPath := filepath.Join(top, entry.Path)
|
fullPath := filepath.Join(top, entry.Path)
|
||||||
f, err := os.OpenFile(fullPath, os.O_RDONLY|syscall.O_NOFOLLOW|syscall.O_NONBLOCK, 0)
|
f, err := os.OpenFile(fullPath, os.O_RDONLY|syscall.O_NOFOLLOW, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -101,37 +101,6 @@ func (entry *Entry) SetAttributesToFile(fullPath string) {
|
|||||||
f.Close()
|
f.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (entry *Entry) ReadSpecial(fileInfo os.FileInfo) bool {
|
|
||||||
if fileInfo.Mode() & (os.ModeDevice | os.ModeCharDevice) == 0 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
stat, ok := fileInfo.Sys().(*syscall.Stat_t)
|
|
||||||
if !ok || stat == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
entry.Size = 0
|
|
||||||
rdev := uint64(stat.Rdev)
|
|
||||||
entry.StartChunk = int(rdev & 0xFFFFFFFF)
|
|
||||||
entry.StartOffset = int(rdev >> 32)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) RestoreSpecial(fullPath string) error {
|
|
||||||
if entry.Mode & uint32(os.ModeDevice | os.ModeCharDevice) != 0 {
|
|
||||||
mode := entry.Mode & uint32(fileModeMask)
|
|
||||||
if entry.Mode & uint32(os.ModeCharDevice) != 0 {
|
|
||||||
mode |= syscall.S_IFCHR
|
|
||||||
} else {
|
|
||||||
mode |= syscall.S_IFBLK
|
|
||||||
}
|
|
||||||
rdev := uint64(entry.StartChunk) | uint64(entry.StartOffset) << 32
|
|
||||||
return syscall.Mknod(fullPath, mode, int(rdev))
|
|
||||||
} else if entry.Mode & uint32(os.ModeNamedPipe) != 0 {
|
|
||||||
return syscall.Mkfifo(fullPath, uint32(entry.Mode))
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func joinPath(components ...string) string {
|
func joinPath(components ...string) string {
|
||||||
return path.Join(components...)
|
return path.Join(components...)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -117,14 +117,6 @@ func (entry *Entry) SetAttributesToFile(fullPath string) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (entry *Entry) ReadDeviceNode(fileInfo os.FileInfo) bool {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) RestoreSpecial(fullPath string) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func joinPath(components ...string) string {
|
func joinPath(components ...string) string {
|
||||||
|
|
||||||
combinedPath := `\\?\` + filepath.Join(components...)
|
combinedPath := `\\?\` + filepath.Join(components...)
|
||||||
|
|||||||
Reference in New Issue
Block a user