Merge pull request #2136 from calmh/noarchivedir

Clarify and correct handling of existing files/directories when pulling
This commit is contained in:
Audrius Butkevicius 2015-08-15 14:31:38 +01:00
commit 50a1858367

View File

@ -1260,34 +1260,48 @@ func (p *rwFolder) performFinish(state *sharedPullerState) error {
p.virtualMtimeRepo.UpdateMtime(state.file.Name, info.ModTime(), t) p.virtualMtimeRepo.UpdateMtime(state.file.Name, info.ModTime(), t)
} }
var err error if stat, err := osutil.Lstat(state.realName); err == nil {
if p.inConflict(state.version, state.file.Version) { // There is an old file or directory already in place. We need to
// The new file has been changed in conflict with the existing one. We // handle that.
// should file it away as a conflict instead of just removing or
// archiving. Also merge with the version vector we had, to indicate switch {
// we have resolved the conflict. case stat.IsDir() || stat.Mode()&os.ModeSymlink != 0:
state.file.Version = state.file.Version.Merge(state.version) // It's a directory or a symlink. These are not versioned or
err = osutil.InWritableDir(moveForConflict, state.realName) // archived for conflicts, only removed (which of course fails for
} else if p.versioner != nil { // non-empty directories).
// If we should use versioning, let the versioner archive the old
// file before we replace it. Archiving a non-existent file is not // TODO: This is the place where we want to remove temporary files
// an error. // and future hard ignores before attempting a directory delete.
err = p.versioner.Archive(state.realName) // Should share code with p.deletDir().
} else {
err = nil if err = osutil.InWritableDir(osutil.Remove, state.realName); err != nil {
} return err
if err != nil { }
return err
case p.inConflict(state.version, state.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.
state.file.Version = state.file.Version.Merge(state.version)
if err = osutil.InWritableDir(moveForConflict, state.realName); err != nil {
return err
}
case p.versioner != nil:
// If we should use versioning, let the versioner archive the old
// file before we replace it. Archiving a non-existent file is not
// an error.
if err = p.versioner.Archive(state.realName); err != nil {
return err
}
}
} }
// If the target path is a symlink or a directory, we cannot copy
// over it, hence remove it before proceeding.
stat, err := osutil.Lstat(state.realName)
if err == nil && (stat.IsDir() || stat.Mode()&os.ModeSymlink != 0) {
osutil.InWritableDir(osutil.Remove, state.realName)
}
// Replace the original content with the new one // Replace the original content with the new one
if err = osutil.Rename(state.tempName, state.realName); err != nil { if err := osutil.Rename(state.tempName, state.realName); err != nil {
return err return err
} }