|
@@ -387,6 +387,10 @@ func (f *sendReceiveFolder) processNeeded(snap *db.Snapshot, dbUpdateChan chan<-
|
|
|
}
|
|
|
|
|
|
case runtime.GOOS == "windows" && file.IsSymlink():
|
|
|
+ if err := f.handleSymlinkCheckExisting(file, snap, scanChan); err != nil {
|
|
|
+ f.newPullError(file.Name, fmt.Errorf("handling unsupported symlink: %w", err))
|
|
|
+ break
|
|
|
+ }
|
|
|
file.SetUnsupported(f.shortID)
|
|
|
l.Debugln(f, "Invalidating symlink (unsupported)", file.Name)
|
|
|
dbUpdateChan <- dbUpdateJob{file, dbUpdateInvalidate}
|
|
@@ -728,39 +732,9 @@ func (f *sendReceiveFolder) handleSymlink(file protocol.FileInfo, snap *db.Snaps
|
|
|
return
|
|
|
}
|
|
|
|
|
|
- // There is already something under that name, we need to handle that.
|
|
|
- switch info, err := f.fs.Lstat(file.Name); {
|
|
|
- case err != nil && !fs.IsNotExist(err):
|
|
|
- f.newPullError(file.Name, errors.Wrap(err, "checking for existing symlink"))
|
|
|
+ if f.handleSymlinkCheckExisting(file, snap, scanChan); err != nil {
|
|
|
+ f.newPullError(file.Name, fmt.Errorf("handling symlink: %w", err))
|
|
|
return
|
|
|
- case err == nil:
|
|
|
- // Check that it is what we have in the database.
|
|
|
- curFile, hasCurFile := f.model.CurrentFolderFile(f.folderID, file.Name)
|
|
|
- if err := f.scanIfItemChanged(file.Name, info, curFile, hasCurFile, scanChan); err != nil {
|
|
|
- err = errors.Wrap(err, "handling symlink")
|
|
|
- f.newPullError(file.Name, err)
|
|
|
- return
|
|
|
- }
|
|
|
- // Remove it to replace with the symlink. This also handles the
|
|
|
- // "change symlink type" path.
|
|
|
- if !curFile.IsDirectory() && !curFile.IsSymlink() && f.inConflict(curFile.Version, file.Version) {
|
|
|
- // The new file has been changed in conflict with the existing one. We
|
|
|
- // should file it away as a conflict instead of just removing or
|
|
|
- // archiving. Also merge with the version vector we had, to indicate
|
|
|
- // we have resolved the conflict.
|
|
|
- // Directories and symlinks aren't checked for conflicts.
|
|
|
-
|
|
|
- file.Version = file.Version.Merge(curFile.Version)
|
|
|
- err = f.inWritableDir(func(name string) error {
|
|
|
- return f.moveForConflict(name, file.ModifiedBy.String(), scanChan)
|
|
|
- }, curFile.Name)
|
|
|
- } else {
|
|
|
- err = f.deleteItemOnDisk(curFile, snap, scanChan)
|
|
|
- }
|
|
|
- if err != nil {
|
|
|
- f.newPullError(file.Name, errors.Wrap(err, "symlink remove"))
|
|
|
- return
|
|
|
- }
|
|
|
}
|
|
|
|
|
|
// We declare a function that acts on only the path name, so
|
|
@@ -779,6 +753,38 @@ func (f *sendReceiveFolder) handleSymlink(file protocol.FileInfo, snap *db.Snaps
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+func (f *sendReceiveFolder) handleSymlinkCheckExisting(file protocol.FileInfo, snap *db.Snapshot, scanChan chan<- string) error {
|
|
|
+ // If there is already something under that name, we need to handle that.
|
|
|
+ info, err := f.fs.Lstat(file.Name)
|
|
|
+ if err != nil {
|
|
|
+ if fs.IsNotExist(err) {
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ // Check that it is what we have in the database.
|
|
|
+ curFile, hasCurFile := f.model.CurrentFolderFile(f.folderID, file.Name)
|
|
|
+ if err := f.scanIfItemChanged(file.Name, info, curFile, hasCurFile, scanChan); err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ // Remove it to replace with the symlink. This also handles the
|
|
|
+ // "change symlink type" path.
|
|
|
+ if !curFile.IsDirectory() && !curFile.IsSymlink() && f.inConflict(curFile.Version, file.Version) {
|
|
|
+ // The new file has been changed in conflict with the existing one. We
|
|
|
+ // should file it away as a conflict instead of just removing or
|
|
|
+ // archiving. Also merge with the version vector we had, to indicate
|
|
|
+ // we have resolved the conflict.
|
|
|
+ // Directories and symlinks aren't checked for conflicts.
|
|
|
+
|
|
|
+ file.Version = file.Version.Merge(curFile.Version)
|
|
|
+ return f.inWritableDir(func(name string) error {
|
|
|
+ return f.moveForConflict(name, file.ModifiedBy.String(), scanChan)
|
|
|
+ }, curFile.Name)
|
|
|
+ } else {
|
|
|
+ return f.deleteItemOnDisk(curFile, snap, scanChan)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
// deleteDir attempts to remove a directory that was deleted on a remote
|
|
|
func (f *sendReceiveFolder) deleteDir(file protocol.FileInfo, snap *db.Snapshot, dbUpdateChan chan<- dbUpdateJob, scanChan chan<- string) {
|
|
|
// Used in the defer closure below, updated by the function body. Take
|