ReadFileFlags on linux minor fix

Add ignoring EINTR to syscall, set O_NOATIME on open, ignore
ENOTTY error (unsupported ioctl) to avoid massive spam for
non-exceptional failure on nonsupporting file systems
This commit is contained in:
2023-10-06 15:26:48 -05:00
parent bede63f33f
commit 09637c69bc
2 changed files with 37 additions and 16 deletions

View File

@@ -1,13 +1,13 @@
# Dupluxe
A Duplicacy derivative with improved support for preserving state on UNIX like systems. Produces snapshots compatible with Duplicacy.
An experimental Duplicacy derivative with improved support for preserving state on UNIX like systems. Produces snapshots compatible with Duplicacy.
NOTE: This project/repository is not affiliated with nor endorsed by Duplicacy, Acrosync or their associated rights holders. It is developed and distributed in accordance with the associated LICENSE. Commercial use may require purchase of a license from Acrosync.
NOTE: This project/repository is not affiliated with nor endorsed by Duplicacy, Acrosync or their associated rights holders. This project is open source but is not free/libre software. It is developed and distributed in accordance with the associated LICENSE. Commercial use may require purchase of a license from Acrosync, please contact them if you have any doubts.
## Added Features
* Support for hard links. Hard links are tracked during local file listing. All linked entries will reuse the same chunk data, so this can give a time and space saving benefit as hard-linked files only need to be packed once. Hard links are supported to everything (regular files, symlinks, special files) except directories.
* File flags, that is chflags(1) on BSD/Darwin, and ioctl_iflags(2) on Linux. The primary use case is to preserve iflags used by btrfs for no-COW and compression.
* Special files (character/block devices, FIFOs, and sockets) are preserved along with associated metadata.
* Optional File flags, that is chflags(1) on BSD/Darwin, and ioctl_iflags(2) on Linux. The primary use case is to preserve iflags used by btrfs for no-COW and compression.
* Optional Special files (character/block devices, FIFOs, and sockets) are preserved along with associated metadata.
## Assorted Changes
* The S3 backend uses the newer ListObjectsV2 interface originally because of a bug with some providers with the old, obsolete interface, but now because this API is considerably faster on a number of providers tested.

View File

@@ -33,9 +33,6 @@ const (
linux_FS_NOCOW_FL = 0x00800000 /* Do not cow file */
linux_FS_PROJINHERIT_FL = 0x20000000 /* Create with parents projid */
linux_FS_IOC_GETFLAGS uintptr = 0x80086601
linux_FS_IOC_SETFLAGS uintptr = 0x40086602
linuxIocFlagsFileEarly = linux_FS_SECRM_FL | linux_FS_UNRM_FL | linux_FS_COMPR_FL | linux_FS_NODUMP_FL | linux_FS_NOATIME_FL | linux_FS_NOCOMP_FL | linux_FS_JOURNAL_DATA_FL | linux_FS_NOTAIL_FL | linux_FS_NOCOW_FL
linuxIocFlagsDirEarly = linux_FS_TOPDIR_FL | linux_FS_PROJINHERIT_FL
linuxIocFlagsLate = linux_FS_SYNC_FL | linux_FS_IMMUTABLE_FL | linux_FS_APPEND_FL | linux_FS_DIRSYNC_FL
@@ -43,13 +40,32 @@ const (
linuxFileFlagsKey = "\x00lf"
)
var (
errENOTTY error = unix.ENOTTY
)
func ignoringEINTR(fn func() error) (err error) {
for {
err = fn()
if err != unix.EINTR {
break
}
}
return err
}
func ioctl(f *os.File, request uintptr, attrp *uint32) error {
return ignoringEINTR(func() error {
argp := uintptr(unsafe.Pointer(attrp))
if _, _, errno := unix.Syscall(unix.SYS_IOCTL, f.Fd(), request, argp); errno != 0 {
return os.NewSyscallError("ioctl", errno)
}
_, _, errno := unix.Syscall(unix.SYS_IOCTL, f.Fd(), request, argp)
if errno == 0 {
return nil
} else if errno == unix.ENOTTY {
return errENOTTY
}
return errno
})
}
func (entry *Entry) ReadAttributes(fullPath string, fi os.FileInfo) error {
@@ -75,20 +91,25 @@ func (entry *Entry) ReadAttributes(fullPath string, fi os.FileInfo) error {
}
func (entry *Entry) ReadFileFlags(fullPath string, fileInfo os.FileInfo) error {
// the linux file flags interface is quite depressing. The half assed attempt at statx
// doesn't even cover the flags we're interested in
if !(entry.IsFile() || entry.IsDir()) {
return nil
}
f, err := os.OpenFile(fullPath, os.O_RDONLY|unix.O_NOFOLLOW, 0)
f, err := os.OpenFile(fullPath, os.O_RDONLY|unix.O_NOATIME|unix.O_NOFOLLOW, 0)
if err != nil {
return err
}
var flags uint32
err = ioctl(f, linux_FS_IOC_GETFLAGS, &flags)
err = ioctl(f, unix.FS_IOC_GETFLAGS, &flags)
f.Close()
if err != nil {
if err == unix.ENOTTY {
return nil
}
return err
}
@@ -154,7 +175,7 @@ func (entry *Entry) RestoreEarlyDirFlags(fullPath string, mask uint32) error {
if err != nil {
return err
}
err = ioctl(f, linux_FS_IOC_SETFLAGS, &flags)
err = ioctl(f, unix.FS_IOC_SETFLAGS, &flags)
f.Close()
if err != nil {
return fmt.Errorf("Set flags 0x%.8x failed: %w", flags, err)
@@ -174,7 +195,7 @@ func (entry *Entry) RestoreEarlyFileFlags(f *os.File, mask uint32) error {
}
if flags != 0 {
err := ioctl(f, linux_FS_IOC_SETFLAGS, &flags)
err := ioctl(f, unix.FS_IOC_SETFLAGS, &flags)
if err != nil {
return fmt.Errorf("Set flags 0x%.8x failed: %w", flags, err)
}