From ca343b73728d89f5edecc8a32bfdc7b097193019 Mon Sep 17 00:00:00 2001 From: Jakob Borg Date: Wed, 1 May 2024 08:54:24 +0200 Subject: [PATCH] lib/config: Add file inside folder marker directory --- lib/config/folderconfiguration.go | 46 ++++++++++++++++++++++++------- lib/model/model.go | 4 +-- 2 files changed, 38 insertions(+), 12 deletions(-) diff --git a/lib/config/folderconfiguration.go b/lib/config/folderconfiguration.go index 3079c0f4cf3..8765fc4e4e7 100644 --- a/lib/config/folderconfiguration.go +++ b/lib/config/folderconfiguration.go @@ -7,6 +7,8 @@ package config import ( + "bytes" + "crypto/sha256" "errors" "fmt" "path" @@ -90,27 +92,51 @@ func (f *FolderConfiguration) CreateMarker() error { return nil } - permBits := fs.FileMode(0o777) - if build.IsWindows { - // Windows has no umask so we must chose a safer set of bits to - // begin with. - permBits = 0o700 - } - fs := f.Filesystem(nil) - err := fs.Mkdir(DefaultMarkerName, permBits) + ffs := f.Filesystem(nil) + + // Create the marker as a directory + err := ffs.Mkdir(DefaultMarkerName, 0o755) if err != nil { return err } - if dir, err := fs.Open("."); err != nil { + + // Create a file inside it, reducing the risk of the marker directory + // being removed by automated cleanup tools. + markerFile := filepath.Join(DefaultMarkerName, f.markerFilename()) + if err := fs.WriteFile(ffs, markerFile, f.markerContents(), 0o644); err != nil { + return err + } + + // Sync & hide the containing directory + if dir, err := ffs.Open("."); err != nil { l.Debugln("folder marker: open . failed:", err) } else if err := dir.Sync(); err != nil { l.Debugln("folder marker: fsync . failed:", err) } - fs.Hide(DefaultMarkerName) + ffs.Hide(DefaultMarkerName) return nil } +func (f *FolderConfiguration) RemoveMarker() error { + ffs := f.Filesystem(nil) + _ = ffs.Remove(filepath.Join(DefaultMarkerName, f.markerFilename())) + return ffs.Remove(DefaultMarkerName) +} + +func (f *FolderConfiguration) markerFilename() string { + h := sha256.Sum256([]byte(f.ID)) + return fmt.Sprintf("syncthing-folder-%x.txt", h[:3]) +} + +func (f *FolderConfiguration) markerContents() []byte { + var buf bytes.Buffer + buf.WriteString("# This directory is a Syncthing folder marker.\n# Do not delete.\n\n") + fmt.Fprintf(&buf, "folderID: %s\n", f.ID) + fmt.Fprintf(&buf, "created: %s\n", time.Now().Format(time.RFC3339)) + return buf.Bytes() +} + // CheckPath returns nil if the folder root exists and contains the marker file func (f *FolderConfiguration) CheckPath() error { return f.checkFilesystemPath(f.Filesystem(nil), ".") diff --git a/lib/model/model.go b/lib/model/model.go index 487dff7dca3..f88118eb9c6 100644 --- a/lib/model/model.go +++ b/lib/model/model.go @@ -464,9 +464,9 @@ func (m *model) removeFolder(cfg config.FolderConfiguration) { if isPathUnique { // Remove (if empty and removable) or move away (if non-empty or // otherwise not removable) Syncthing-specific marker files. - fs := cfg.Filesystem(nil) - if err := fs.Remove(config.DefaultMarkerName); err != nil { + if err := cfg.RemoveMarker(); err != nil && !errors.Is(err, os.ErrNotExist) { moved := config.DefaultMarkerName + time.Now().Format(".removed-20060102-150405") + fs := cfg.Filesystem(nil) _ = fs.Rename(config.DefaultMarkerName, moved) } }