chore: remove tracking inode change time (#10579)
Signed-off-by: Jakob Borg <jakob@kastelo.net>
This commit is contained in:
@@ -1786,7 +1786,6 @@ func fileIntfJSONMap(f protocol.FileInfo) map[string]interface{} {
|
||||
"version": jsonVersionVector(f.FileVersion()),
|
||||
"localFlags": f.FileLocalFlags(),
|
||||
"platform": f.PlatformData(),
|
||||
"inodeChange": f.InodeChangeTime(),
|
||||
"blocksHash": f.FileBlocksHash(),
|
||||
"previousBlocksHash": f.PreviousBlocksHash,
|
||||
}
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
// Copyright (C) 2022 The Syncthing Authors.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
// You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
//go:build darwin || freebsd || netbsd
|
||||
// +build darwin freebsd netbsd
|
||||
|
||||
package fs
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (fi basicFileInfo) InodeChangeTime() time.Time {
|
||||
if sys, ok := fi.Sys().(*syscall.Stat_t); ok {
|
||||
return time.Unix(0, sys.Ctimespec.Nano())
|
||||
}
|
||||
return time.Time{}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
// Copyright (C) 2022 The Syncthing Authors.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
// You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
//go:build aix || dragonfly || linux || openbsd || solaris || illumos
|
||||
// +build aix dragonfly linux openbsd solaris illumos
|
||||
|
||||
package fs
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/syncthing/syncthing/lib/build"
|
||||
)
|
||||
|
||||
func (fi basicFileInfo) InodeChangeTime() time.Time {
|
||||
// On Android, mtime and inode-change-time fluctuate, which can cause
|
||||
// conflicts even when nothing has been modified on the device itself.
|
||||
// Ref: https://forum.syncthing.net/t/keep-getting-conflicts-generated-on-android-device-for-files-modified-only-on-a-desktop-pc/19060
|
||||
if build.IsAndroid {
|
||||
return time.Time{}
|
||||
}
|
||||
if sys, ok := fi.FileInfo.Sys().(*syscall.Stat_t); ok {
|
||||
return time.Unix(0, sys.Ctim.Nano())
|
||||
}
|
||||
return time.Time{}
|
||||
}
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var execExts map[string]bool
|
||||
@@ -58,10 +57,6 @@ func (e basicFileInfo) Group() int {
|
||||
return -1
|
||||
}
|
||||
|
||||
func (basicFileInfo) InodeChangeTime() time.Time {
|
||||
return time.Time{}
|
||||
}
|
||||
|
||||
// osFileInfo converts e to os.FileInfo that is suitable
|
||||
// to be passed to os.SameFile.
|
||||
func (e *basicFileInfo) osFileInfo() os.FileInfo {
|
||||
|
||||
@@ -1024,7 +1024,3 @@ func (f *fakeFileInfo) Group() int {
|
||||
func (*fakeFileInfo) Sys() interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (*fakeFileInfo) InodeChangeTime() time.Time {
|
||||
return time.Time{}
|
||||
}
|
||||
|
||||
@@ -101,7 +101,6 @@ type FileInfo interface {
|
||||
IsSymlink() bool
|
||||
Owner() int
|
||||
Group() int
|
||||
InodeChangeTime() time.Time // may be zero if not supported
|
||||
}
|
||||
|
||||
// FileMode is similar to os.FileMode
|
||||
|
||||
@@ -1789,19 +1789,6 @@ loop:
|
||||
lastFile = job.file
|
||||
}
|
||||
|
||||
if !job.file.IsDeleted() && !job.file.IsInvalid() {
|
||||
// Now that the file is finalized, grab possibly updated
|
||||
// inode change time from disk into the local FileInfo. We
|
||||
// use this change time to check for changes to xattrs etc
|
||||
// on next scan.
|
||||
if err := f.updateFileInfoChangeTime(&job.file); err != nil {
|
||||
// This means on next scan the likely incorrect change time
|
||||
// (resp. whatever caused the error) will cause this file to
|
||||
// change. Log at info level to leave a trace if a user
|
||||
// notices, but no need to warn
|
||||
f.sl.Warn("Failed to update metadata at database commit", slogutil.FilePath(job.file.Name), slogutil.Error(err))
|
||||
}
|
||||
}
|
||||
job.file.Sequence = 0
|
||||
|
||||
batch.Append(job.file)
|
||||
@@ -2187,22 +2174,6 @@ func (f *sendReceiveFolder) withLimiter(ctx context.Context, fn func() error) er
|
||||
return fn()
|
||||
}
|
||||
|
||||
// updateFileInfoChangeTime updates the inode change time in the FileInfo,
|
||||
// because that depends on the current, new, state of the file on disk.
|
||||
func (f *sendReceiveFolder) updateFileInfoChangeTime(file *protocol.FileInfo) error {
|
||||
info, err := f.mtimefs.Lstat(file.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if ct := info.InodeChangeTime(); !ct.IsZero() {
|
||||
file.InodeChangeNs = ct.UnixNano()
|
||||
} else {
|
||||
file.InodeChangeNs = 0
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// A []FileError is sent as part of an event and will be JSON serialized.
|
||||
type FileError struct {
|
||||
Path string `json:"path"`
|
||||
|
||||
@@ -647,9 +647,6 @@ func TestDeleteIgnorePerms(t *testing.T) {
|
||||
fi, err := scanner.CreateFileInfo(stat, name, ffs, false, false, config.XattrFilter{})
|
||||
must(t, err)
|
||||
ffs.Chmod(name, 0o600)
|
||||
if info, err := ffs.Stat(name); err == nil {
|
||||
fi.InodeChangeNs = info.InodeChangeTime().UnixNano()
|
||||
}
|
||||
scanChan := make(chan string, 1)
|
||||
err = f.checkToBeDeleted(fi, fi, true, scanChan)
|
||||
must(t, err)
|
||||
|
||||
@@ -139,10 +139,6 @@ type FileInfo struct {
|
||||
// the protocol.
|
||||
LocalFlags FlagLocal
|
||||
|
||||
// The time when the inode was last changed (i.e., permissions, xattrs
|
||||
// etc changed). This is host-local, not sent over the wire.
|
||||
InodeChangeNs int64
|
||||
|
||||
// The size of the data appended to the encrypted file on disk. This is
|
||||
// host-local, not sent over the wire.
|
||||
EncryptionTrailerSize int
|
||||
@@ -184,7 +180,6 @@ func (f *FileInfo) ToWire(withInternalFields bool) *bep.FileInfo {
|
||||
}
|
||||
if withInternalFields {
|
||||
w.LocalFlags = uint32(f.LocalFlags)
|
||||
w.InodeChangeNs = f.InodeChangeNs
|
||||
w.EncryptionTrailerSize = int32(f.EncryptionTrailerSize)
|
||||
}
|
||||
return w
|
||||
@@ -284,7 +279,6 @@ type FileInfoWithoutBlocks interface {
|
||||
GetBlockSize() int32
|
||||
GetPlatform() *bep.PlatformData
|
||||
GetLocalFlags() uint32
|
||||
GetInodeChangeNs() int64
|
||||
GetEncryptionTrailerSize() int32
|
||||
GetDeleted() bool
|
||||
GetInvalid() bool
|
||||
@@ -322,7 +316,6 @@ func fileInfoFromWireWithBlocks(w FileInfoWithoutBlocks, blocks []BlockInfo) Fil
|
||||
func FileInfoFromDB(w *bep.FileInfo) FileInfo {
|
||||
f := FileInfoFromWire(w)
|
||||
f.LocalFlags = FlagLocal(w.LocalFlags)
|
||||
f.InodeChangeNs = w.InodeChangeNs
|
||||
f.EncryptionTrailerSize = int(w.EncryptionTrailerSize)
|
||||
return f
|
||||
}
|
||||
@@ -330,7 +323,6 @@ func FileInfoFromDB(w *bep.FileInfo) FileInfo {
|
||||
func FileInfoFromDBTruncated(w FileInfoWithoutBlocks) FileInfo {
|
||||
f := fileInfoFromWireWithBlocks(w, nil)
|
||||
f.LocalFlags = FlagLocal(w.GetLocalFlags())
|
||||
f.InodeChangeNs = w.GetInodeChangeNs()
|
||||
f.EncryptionTrailerSize = int(w.GetEncryptionTrailerSize())
|
||||
f.truncated = true
|
||||
return f
|
||||
@@ -339,14 +331,14 @@ func FileInfoFromDBTruncated(w FileInfoWithoutBlocks) FileInfo {
|
||||
func (f FileInfo) String() string {
|
||||
switch f.Type {
|
||||
case FileInfoTypeDirectory:
|
||||
return fmt.Sprintf("Directory{Name:%q, Sequence:%d, Permissions:0%o, ModTime:%v, Version:%v, Deleted:%v, Invalid:%v, LocalFlags:0x%x, NoPermissions:%v, Platform:%v, InodeChangeTime:%v}",
|
||||
f.Name, f.Sequence, f.Permissions, f.ModTime(), f.Version, f.Deleted, f.IsInvalid(), f.LocalFlags, f.NoPermissions, f.Platform, f.InodeChangeTime())
|
||||
return fmt.Sprintf("Directory{Name:%q, Sequence:%d, Permissions:0%o, ModTime:%v, Version:%v, Deleted:%v, Invalid:%v, LocalFlags:0x%x, NoPermissions:%v, Platform:%v}",
|
||||
f.Name, f.Sequence, f.Permissions, f.ModTime(), f.Version, f.Deleted, f.IsInvalid(), f.LocalFlags, f.NoPermissions, f.Platform)
|
||||
case FileInfoTypeFile:
|
||||
return fmt.Sprintf("File{Name:%q, Sequence:%d, Permissions:0%o, ModTime:%v, Version:%v, Length:%d, Deleted:%v, Invalid:%v, LocalFlags:0x%x, NoPermissions:%v, BlockSize:%d, NumBlocks:%d, BlocksHash:%x, Platform:%v, InodeChangeTime:%v}",
|
||||
f.Name, f.Sequence, f.Permissions, f.ModTime(), f.Version, f.Size, f.Deleted, f.IsInvalid(), f.LocalFlags, f.NoPermissions, f.RawBlockSize, len(f.Blocks), f.BlocksHash, f.Platform, f.InodeChangeTime())
|
||||
return fmt.Sprintf("File{Name:%q, Sequence:%d, Permissions:0%o, ModTime:%v, Version:%v, Length:%d, Deleted:%v, Invalid:%v, LocalFlags:0x%x, NoPermissions:%v, BlockSize:%d, NumBlocks:%d, BlocksHash:%x, Platform:%v}",
|
||||
f.Name, f.Sequence, f.Permissions, f.ModTime(), f.Version, f.Size, f.Deleted, f.IsInvalid(), f.LocalFlags, f.NoPermissions, f.RawBlockSize, len(f.Blocks), f.BlocksHash, f.Platform)
|
||||
case FileInfoTypeSymlink, FileInfoTypeSymlinkDirectory, FileInfoTypeSymlinkFile:
|
||||
return fmt.Sprintf("Symlink{Name:%q, Type:%v, Sequence:%d, Version:%v, Deleted:%v, Invalid:%v, LocalFlags:0x%x, NoPermissions:%v, SymlinkTarget:%q, Platform:%v, InodeChangeTime:%v}",
|
||||
f.Name, f.Type, f.Sequence, f.Version, f.Deleted, f.IsInvalid(), f.LocalFlags, f.NoPermissions, f.SymlinkTarget, f.Platform, f.InodeChangeTime())
|
||||
return fmt.Sprintf("Symlink{Name:%q, Type:%v, Sequence:%d, Version:%v, Deleted:%v, Invalid:%v, LocalFlags:0x%x, NoPermissions:%v, SymlinkTarget:%q, Platform:%v}",
|
||||
f.Name, f.Type, f.Sequence, f.Version, f.Deleted, f.IsInvalid(), f.LocalFlags, f.NoPermissions, f.SymlinkTarget, f.Platform)
|
||||
default:
|
||||
panic("mystery file type detected")
|
||||
}
|
||||
@@ -462,10 +454,6 @@ func (f FileInfo) PlatformData() PlatformData {
|
||||
return f.Platform
|
||||
}
|
||||
|
||||
func (f FileInfo) InodeChangeTime() time.Time {
|
||||
return time.Unix(0, f.InodeChangeNs)
|
||||
}
|
||||
|
||||
func (f FileInfo) FileBlocksHash() []byte {
|
||||
return f.BlocksHash
|
||||
}
|
||||
@@ -514,12 +502,6 @@ func (f FileInfo) isEquivalent(other FileInfo, comp FileInfoComparison) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// If we care about either ownership or xattrs, are recording inode change
|
||||
// times and it changed, they are not equal.
|
||||
if !(comp.IgnoreOwnership && comp.IgnoreXattrs) && f.InodeChangeNs != 0 && other.InodeChangeNs != 0 && f.InodeChangeNs != other.InodeChangeNs {
|
||||
return false
|
||||
}
|
||||
|
||||
// Mask out the ignored local flags before checking IsInvalid() below
|
||||
f.LocalFlags &^= comp.IgnoreFlags
|
||||
other.LocalFlags &^= comp.IgnoreFlags
|
||||
|
||||
@@ -121,12 +121,11 @@ func (fakeInfo) ModTime() time.Time { return time.Unix(1234567890, 0) }
|
||||
func (f fakeInfo) IsDir() bool {
|
||||
return strings.Contains(filepath.Base(f.name), "dir") || f.name == "."
|
||||
}
|
||||
func (f fakeInfo) IsRegular() bool { return !f.IsDir() }
|
||||
func (fakeInfo) IsSymlink() bool { return false }
|
||||
func (fakeInfo) Owner() int { return 0 }
|
||||
func (fakeInfo) Group() int { return 0 }
|
||||
func (fakeInfo) Sys() interface{} { return nil }
|
||||
func (fakeInfo) InodeChangeTime() time.Time { return time.Time{} }
|
||||
func (f fakeInfo) IsRegular() bool { return !f.IsDir() }
|
||||
func (fakeInfo) IsSymlink() bool { return false }
|
||||
func (fakeInfo) Owner() int { return 0 }
|
||||
func (fakeInfo) Group() int { return 0 }
|
||||
func (fakeInfo) Sys() interface{} { return nil }
|
||||
|
||||
type fakeFile struct {
|
||||
name string
|
||||
|
||||
@@ -740,12 +740,6 @@ func CreateFileInfo(fi fs.FileInfo, name string, filesystem fs.Filesystem, scanO
|
||||
}
|
||||
}
|
||||
|
||||
if ct := fi.InodeChangeTime(); !ct.IsZero() {
|
||||
f.InodeChangeNs = ct.UnixNano()
|
||||
} else {
|
||||
f.InodeChangeNs = 0
|
||||
}
|
||||
|
||||
if fi.IsSymlink() {
|
||||
f.Type = protocol.FileInfoTypeSymlink
|
||||
target, err := filesystem.ReadSymlink(name)
|
||||
|
||||
Reference in New Issue
Block a user