lib/fs: Properly handle case insensitive systems (fixes #1787, fixes #2739, fixes #5708)

With this change we emulate a case sensitive filesystem on top of
insensitive filesystems. This means we correctly pick up case-only renames
and throw a case conflict error when there would be multiple files differing
only in case.

This safety check has a small performance hit (about 20% more filesystem
operations when scanning for changes). The new advanced folder option
`caseSensitiveFS` can be used to disable the safety checks, retaining the
previous behavior on systems known to be fully case sensitive.

Co-authored-by: Jakob Borg <jakob@kastelo.net>
This commit is contained in:
Simon Frei
2020-07-28 11:15:11 +02:00
committed by Jakob Borg
co-authored by Jakob Borg
parent 21dd9d6b43
commit 932d8c69de
27 changed files with 1241 additions and 187 deletions
+7 -3
View File
@@ -41,6 +41,10 @@ const (
)
func generateFiles(dir string, files, maxexp int, srcname string) error {
return generateFilesWithTime(dir, files, maxexp, srcname, time.Now())
}
func generateFilesWithTime(dir string, files, maxexp int, srcname string, t0 time.Time) error {
fd, err := os.Open(srcname)
if err != nil {
return err
@@ -69,7 +73,7 @@ func generateFiles(dir string, files, maxexp int, srcname string) error {
}
s += rand.Int63n(a)
if err := generateOneFile(fd, p1, s); err != nil {
if err := generateOneFile(fd, p1, s, t0); err != nil {
return err
}
}
@@ -77,7 +81,7 @@ func generateFiles(dir string, files, maxexp int, srcname string) error {
return nil
}
func generateOneFile(fd io.ReadSeeker, p1 string, s int64) error {
func generateOneFile(fd io.ReadSeeker, p1 string, s int64, t0 time.Time) error {
src := io.LimitReader(&inifiteReader{fd}, int64(s))
dst, err := os.Create(p1)
if err != nil {
@@ -96,7 +100,7 @@ func generateOneFile(fd io.ReadSeeker, p1 string, s int64) error {
os.Chmod(p1, os.FileMode(rand.Intn(0777)|0400))
t := time.Now().Add(-time.Duration(rand.Intn(30*86400)) * time.Second)
t := t0.Add(-time.Duration(rand.Intn(30*86400)) * time.Second)
err = os.Chtimes(p1, t, t)
if err != nil {
return err