diff --git a/lib/config/folderconfiguration.go b/lib/config/folderconfiguration.go index d8f8666c6..2f06b6951 100644 --- a/lib/config/folderconfiguration.go +++ b/lib/config/folderconfiguration.go @@ -282,8 +282,19 @@ func (l FolderDeviceConfigurationList) Len() int { return len(l) } -func (f *FolderConfiguration) CheckFreeSpace() error { - return checkFreeSpace(f.MinDiskFree, f.Filesystem()) +func (f *FolderConfiguration) CheckAvailableSpace(req int64) error { + fs := f.Filesystem() + usage, err := fs.Usage(".") + if err != nil { + return nil + } + usage.Free -= req + if usage.Free > 0 { + if err := checkFreeSpace(f.MinDiskFree, usage); err == nil { + return nil + } + } + return fmt.Errorf("insufficient space in %v %v", fs.Type(), fs.URI()) } type FolderConfigurationList []FolderConfiguration diff --git a/lib/config/size.go b/lib/config/size.go index 5c6fe5b7e..20c3f38d1 100644 --- a/lib/config/size.go +++ b/lib/config/size.go @@ -76,22 +76,19 @@ func (Size) ParseDefault(s string) (interface{}, error) { return ParseSize(s) } -func checkFreeSpace(req Size, fs fs.Filesystem) error { +func checkFreeSpace(req Size, usage fs.Usage) error { val := req.BaseValue() if val <= 0 { return nil } - usage, err := fs.Usage(".") if req.Percentage() { freePct := (float64(usage.Free) / float64(usage.Total)) * 100 - if err == nil && freePct < val { - return fmt.Errorf("insufficient space in %v %v: %f %% < %v", fs.Type(), fs.URI(), freePct, req) - } - } else { - if err == nil && float64(usage.Free) < val { - return fmt.Errorf("insufficient space in %v %v: %v < %v", fs.Type(), fs.URI(), usage.Free, req) + if freePct < val { + return fmt.Errorf("%f %% < %v", freePct, req) } + } else if float64(usage.Free) < val { + return fmt.Errorf("%v < %v", usage.Free, req) } return nil diff --git a/lib/config/wrapper.go b/lib/config/wrapper.go index 1cbd6beba..17c1f5fdf 100644 --- a/lib/config/wrapper.go +++ b/lib/config/wrapper.go @@ -445,5 +445,8 @@ func (w *Wrapper) MyName() string { // CheckHomeFreeSpace returns nil if the home disk has the required amount of // free space, or if home disk free space checking is disabled. func (w *Wrapper) CheckHomeFreeSpace() error { - return checkFreeSpace(w.Options().MinHomeDiskFree, fs.NewFilesystem(fs.FilesystemTypeBasic, filepath.Dir(w.ConfigPath()))) + if usage, err := fs.NewFilesystem(fs.FilesystemTypeBasic, filepath.Dir(w.ConfigPath())).Usage("."); err == nil { + return checkFreeSpace(w.Options().MinHomeDiskFree, usage) + } + return nil } diff --git a/lib/model/folder.go b/lib/model/folder.go index 9716e272e..add212e68 100644 --- a/lib/model/folder.go +++ b/lib/model/folder.go @@ -254,10 +254,6 @@ func (f *folder) getHealthError() error { return err } - if err := f.CheckFreeSpace(); err != nil { - return err - } - if err := f.model.cfg.CheckHomeFreeSpace(); err != nil { return err } diff --git a/lib/model/folder_sendrecv.go b/lib/model/folder_sendrecv.go index 9fd530f18..06029cdd7 100644 --- a/lib/model/folder_sendrecv.go +++ b/lib/model/folder_sendrecv.go @@ -839,9 +839,12 @@ func (f *sendReceiveFolder) renameFile(source, target protocol.FileInfo, dbUpdat l.Debugln(f, "taking rename shortcut", source.Name, "->", target.Name) if f.versioner != nil { - err = osutil.Copy(f.fs, source.Name, target.Name) + err = f.CheckAvailableSpace(source.Size) if err == nil { - err = osutil.InWritableDir(f.versioner.Archive, f.fs, source.Name) + err = osutil.Copy(f.fs, source.Name, target.Name) + if err == nil { + err = osutil.InWritableDir(f.versioner.Archive, f.fs, source.Name) + } } } else { err = osutil.TryRename(f.fs, source.Name, target.Name) @@ -1003,12 +1006,9 @@ func (f *sendReceiveFolder) handleFile(file protocol.FileInfo, copyChan chan<- c blocksSize = file.Size } - if f.MinDiskFree.BaseValue() > 0 { - if usage, err := f.fs.Usage("."); err == nil && usage.Free < blocksSize { - l.Warnf(`Folder "%s": insufficient disk space in %s for %s: have %.2f MiB, need %.2f MiB`, f.folderID, f.fs.URI(), file.Name, float64(usage.Free)/1024/1024, float64(blocksSize)/1024/1024) - f.newError("disk space", file.Name, errors.New("insufficient space")) - return - } + if err := f.CheckAvailableSpace(blocksSize); err != nil { + f.newError("pulling file", file.Name, err) + return } // Shuffle the blocks diff --git a/lib/model/folder_sendrecv_test.go b/lib/model/folder_sendrecv_test.go index b3b007836..d074d50dd 100644 --- a/lib/model/folder_sendrecv_test.go +++ b/lib/model/folder_sendrecv_test.go @@ -91,15 +91,17 @@ func setUpSendReceiveFolder(model *Model) *sendReceiveFolder { initialScanFinished: make(chan struct{}), ctx: context.TODO(), FolderConfiguration: config.FolderConfiguration{ + FilesystemType: fs.FilesystemTypeBasic, + Path: "testdata", PullerMaxPendingKiB: defaultPullerPendingKiB, }, }, - fs: fs.NewMtimeFS(fs.NewFilesystem(fs.FilesystemTypeBasic, "testdata"), db.NewNamespacedKV(model.db, "mtime")), queue: newJobQueue(), errors: make(map[string]string), errorsMut: sync.NewMutex(), } + f.fs = fs.NewMtimeFS(f.Filesystem(), db.NewNamespacedKV(model.db, "mtime")) // Folders are never actually started, so no initial scan will be done close(f.initialScanFinished)