diff --git a/model/blockqueue.go b/model/blockqueue.go index e88482385..ef14ab3c5 100644 --- a/model/blockqueue.go +++ b/model/blockqueue.go @@ -16,6 +16,7 @@ type bqBlock struct { file scanner.File block scanner.Block // get this block from the network copy []scanner.Block // copy these blocks from the old version of the file + first bool last bool } @@ -47,24 +48,30 @@ func (q *blockQueue) addBlock(a bqAdd) { return } } + + l := len(a.need) + if len(a.have) > 0 { // First queue a copy operation q.queued = append(q.queued, bqBlock{ - file: a.file, - copy: a.have, + file: a.file, + copy: a.have, + first: true, + last: l == 0, }) } + // Queue the needed blocks individually - l := len(a.need) for i, b := range a.need { q.queued = append(q.queued, bqBlock{ file: a.file, block: b, + first: len(a.have) == 0 && i == 0, last: i == l-1, }) } - if l == 0 { + if len(a.need)+len(a.have) == 0 { // If we didn't have anything to fetch, queue an empty block with the "last" flag set to close the file. q.queued = append(q.queued, bqBlock{ file: a.file, diff --git a/model/puller.go b/model/puller.go index 1ac29cb5c..d375cc601 100644 --- a/model/puller.go +++ b/model/puller.go @@ -373,6 +373,29 @@ func (p *puller) handleBlock(b bqBlock) bool { return true } + if len(b.copy) > 0 && len(b.copy) == len(b.file.Blocks) && b.last { + // We are supposed to copy the entire file, and then fetch nothing. + // We don't actually need to make the copy. + if debug { + l.Debugln("taking shortcut:", f) + } + fp := filepath.Join(p.repoCfg.Directory, f.Name) + t := time.Unix(f.Modified, 0) + err := os.Chtimes(fp, t, t) + if debug && err != nil { + l.Debugf("pull: error: %q / %q: %v", p.repoCfg.ID, f.Name, err) + } + if !p.repoCfg.IgnorePerms && protocol.HasPermissionBits(f.Flags) { + err = os.Chmod(fp, os.FileMode(f.Flags&0777)) + if debug && err != nil { + l.Debugf("pull: error: %q / %q: %v", p.repoCfg.ID, f.Name, err) + } + } + + p.model.updateLocal(p.repoCfg.ID, f) + return true + } + of, ok := p.openFiles[f.Name] of.done = b.last