func (p *memp) CopyTo(dst w.Path, opt w.CopyOptions) (bool, error) { p.fs.m.Lock() defer p.fs.m.Unlock() dstp, ok := dst.(*memp) if !ok { return false, w.ErrorBadHost } if p.path == dstp.path { return false, w.ErrorSameFile } srcf, err := p.internalLookup() if err != nil { return false, w.ErrorNotFound } // Can only move complete directory trees. if srcf.IsDirectory() && opt.Move && opt.Depth >= 0 { return false, w.ErrorIsDir } if _, err := dstp.parent().internalLookup(); err != nil { return false, w.ErrorMissingParent } newf := true _, err = dstp.internalLookup() if err == nil { if opt.Overwrite { newf = false p.removeSubtree(dstp.path) } else { return false, w.ErrorDestExists } } for orig, v := range p.fs.files { nn, ok := wp.Included(orig, p.path, opt.Depth) if !ok { continue } nn = path.Join(dstp.path, nn) if opt.Move { log.Printf("MOVE %s -> %s", orig, nn) // Note: As we adjust path here, it is important that // this move operation does not depend on anything // file-related. v.path = nn p.fs.files[nn] = v delete(p.fs.files, orig) } else { log.Printf("COPY %s -> %s", orig, nn) nv := v.clone(nn) p.fs.files[nn] = nv } } return newf, nil }
func (lm *lockmaster) refreshLock(tok string, path Path, duration time.Duration) (*lock, error) { lm.m.Lock() defer lm.m.Unlock() p := path.String() // We enforce all locks to be a minimum of ten seconds. if duration < minLockDuration { duration = minLockDuration } if duration > maxLockDuration { duration = maxLockDuration } l, ok := lm.locks[tok] if !ok { return nil, fmt.Errorf("unknown lock: %s", tok) } if l.expired() { delete(lm.locks, l.token) return nil, errors.New("expired lock") } if _, ok := wp.Included(p, l.path, l.depth); !ok { return nil, errors.New("path not within lock") } l.duration = duration l.touch() return l, nil }
func (lm *lockmaster) createLock(owner string, path Path, depth int, duration time.Duration) (*lock, error) { lm.m.Lock() defer lm.m.Unlock() p := path.String() // We enforce all locks to be a minimum of ten seconds. if duration < minLockDuration { duration = minLockDuration } if duration > maxLockDuration { duration = maxLockDuration } for _, l := range lm.locks { if l.expired() { delete(lm.locks, l.token) continue } // Check if the lock covers this path already. if _, ok := wp.Included(p, l.path, l.depth); ok { return nil, ErrorLocked } // Check if this crosses another lock. if _, ok := wp.Included(l.path, p, depth); ok { return nil, ErrorLocked } } l := &lock{ token: lm.generateToken(), depth: depth, owner: owner, duration: duration, modified: time.Now(), path: p, } lm.locks[l.token] = l return l, nil }
func (lm *lockmaster) isLocked(p, t string) bool { lm.m.Lock() defer lm.m.Unlock() l := lm.locks[t] if l == nil || l.expired() { delete(lm.locks, t) return false } _, ok := wp.Included(p, l.path, l.depth) return ok }
func (lm *lockmaster) getLockForPath(p string) *lock { lm.m.Lock() defer lm.m.Unlock() for _, l := range lm.locks { if l.expired() { delete(lm.locks, l.token) continue } if _, ok := wp.Included(p, l.path, l.depth); !ok { continue } return l } return nil }
func (p *memp) LookupSubtree(depth int) ([]w.File, error) { _, err := p.Lookup() if err != nil { return nil, err } p.fs.m.Lock() defer p.fs.m.Unlock() var files []w.File for fn, f := range p.fs.files { if _, ok := wp.Included(fn, p.path, depth); ok { files = append(files, f) } } return files, nil }