def getattr(self, path): global opt if self.verbose > 0: log('--getattr(%r)\n' % path) res = vfs.lresolve(self.repo, path, want_meta=(not self.fake_metadata)) log('res: %r\n' % (res, )) name, item = res[-1] if not item: return -errno.ENOENT if self.fake_metadata: item = vfs.augment_item_meta(self.repo, item, include_size=True) else: item = vfs.ensure_item_has_metadata(self.repo, item, include_size=True) meta = item.meta # FIXME: do we want/need to do anything more with nlink? st = fuse.Stat(st_mode=meta.mode, st_nlink=1, st_size=meta.size) st.st_mode = meta.mode st.st_uid = meta.uid st.st_gid = meta.gid st.st_atime = max(0, xstat.fstime_floor_secs(meta.atime)) st.st_mtime = max(0, xstat.fstime_floor_secs(meta.mtime)) st.st_ctime = max(0, xstat.fstime_floor_secs(meta.ctime)) return st
def readlink(self, path): if self.verbose > 0: log('--readlink(%r)\n' % path) res = vfs.lresolve(self.repo, path) name, item = res[-1] if not item: return -errno.ENOENT return vfs.readlink(repo, item)
def read(self, path, size, offset): if self.verbose > 0: log('--read(%r)\n' % path) res = vfs.lresolve(self.repo, path) name, item = res[-1] if not item: return -errno.ENOENT with vfs.fopen(repo, item) as f: f.seek(offset) return f.read(size)
def open(self, path, flags): if self.verbose > 0: log('--open(%r)\n' % path) res = vfs.lresolve(self.repo, path) name, item = res[-1] if not item: return -errno.ENOENT accmode = os.O_RDONLY | os.O_WRONLY | os.O_RDWR if (flags & accmode) != os.O_RDONLY: return -errno.EACCES
def run_augment_item_meta_tests(repo, file_path, file_size, link_path, link_target): _, file_item = vfs.resolve(repo, file_path)[-1] _, link_item = vfs.lresolve(repo, link_path)[-1] wvpass(isinstance(file_item.meta, Metadata)) wvpass(isinstance(link_item.meta, Metadata)) # Note: normally, modifying item.meta values is forbidden file_item.meta.size = file_item.meta.size or vfs.item_size(repo, file_item) link_item.meta.size = link_item.meta.size or vfs.item_size(repo, link_item) ## Ensure a fully populated item is left alone augmented = vfs.augment_item_meta(repo, file_item) wvpass(augmented is file_item) wvpass(augmented.meta is file_item.meta) augmented = vfs.augment_item_meta(repo, file_item, include_size=True) wvpass(augmented is file_item) wvpass(augmented.meta is file_item.meta) ## Ensure a missing size is handled poperly file_item.meta.size = None augmented = vfs.augment_item_meta(repo, file_item) wvpass(augmented is file_item) wvpass(augmented.meta is file_item.meta) augmented = vfs.augment_item_meta(repo, file_item, include_size=True) wvpass(augmented is not file_item) wvpasseq(file_size, augmented.meta.size) ## Ensure a meta mode is handled properly mode_item = file_item._replace(meta=vfs.default_file_mode) augmented = vfs.augment_item_meta(repo, mode_item) augmented_w_size = vfs.augment_item_meta(repo, mode_item, include_size=True) for item in (augmented, augmented_w_size): meta = item.meta wvpass(item is not file_item) wvpass(isinstance(meta, Metadata)) wvpasseq(vfs.default_file_mode, meta.mode) wvpasseq((0, 0, 0, 0, 0), (meta.uid, meta.gid, meta.atime, meta.mtime, meta.ctime)) wvpass(augmented.meta.size is None) wvpasseq(file_size, augmented_w_size.meta.size) ## Ensure symlinks are handled properly mode_item = link_item._replace(meta=vfs.default_symlink_mode) augmented = vfs.augment_item_meta(repo, mode_item) wvpass(augmented is not mode_item) wvpass(isinstance(augmented.meta, Metadata)) wvpasseq(link_target, augmented.meta.symlink_target) wvpasseq(len(link_target), augmented.meta.size) augmented = vfs.augment_item_meta(repo, mode_item, include_size=True) wvpass(augmented is not mode_item) wvpass(isinstance(augmented.meta, Metadata)) wvpasseq(link_target, augmented.meta.symlink_target) wvpasseq(len(link_target), augmented.meta.size)
def readdir(self, path, offset): assert not offset # We don't return offsets, so offset should be unused res = vfs.lresolve(self.repo, path) dir_name, dir_item = res[-1] if not dir_item: yield -errno.ENOENT yield fuse.Direntry('..') # FIXME: make sure want_meta=False is being completely respected for ent_name, ent_item in vfs.contents(repo, dir_item, want_meta=False): yield fuse.Direntry(ent_name.replace('/', '-'))
def test_metadata_method(): with no_lingering_errors(): with test_tempdir('bup-tmetadata-') as tmpdir: bup_dir = tmpdir + '/bup' data_path = tmpdir + '/foo' os.mkdir(data_path) ex('touch', data_path + '/file') ex('ln', '-s', 'file', data_path + '/symlink') test_time1 = 13 * 1000000000 test_time2 = 42 * 1000000000 utime(data_path + '/file', (0, test_time1)) lutime(data_path + '/symlink', (0, 0)) utime(data_path, (0, test_time2)) ex(bup_path, '-d', bup_dir, 'init') ex(bup_path, '-d', bup_dir, 'index', '-v', data_path) ex(bup_path, '-d', bup_dir, 'save', '-tvvn', 'test', data_path) git.check_repo_or_die(bup_dir) repo = LocalRepo() resolved = vfs.lresolve(repo, '/test/latest' + resolve_parent(data_path)) leaf_name, leaf_item = resolved[-1] m = leaf_item.meta WVPASS(m.mtime == test_time2) WVPASS(leaf_name == 'foo') contents = tuple(vfs.contents(repo, leaf_item)) WVPASS(len(contents) == 3) WVPASSEQ(frozenset(name for name, item in contents), frozenset(('.', 'file', 'symlink'))) for name, item in contents: if name == 'file': m = item.meta WVPASS(m.mtime == test_time1) elif name == 'symlink': m = item.meta WVPASSEQ(m.symlink_target, 'file') WVPASSEQ(m.size, 4) WVPASSEQ(m.mtime, 0)
def dead_items(repo, paths): """Return an optimized set of removals, reporting errors via add_error, and if there are any errors, return None, None.""" dead_branches = {} dead_saves = {} # Scan for bad requests, and opportunities to optimize for path in paths: try: resolved = vfs.lresolve(repo, path) except vfs.IOError as e: add_error(e) continue else: leaf_name, leaf_item = resolved[-1] if not leaf_item: add_error('error: cannot access %r in %r' % ('/'.join(name for name, item in resolved), path)) continue if isinstance(leaf_item, vfs.RevList): # rm /foo branchname = leaf_name dead_branches[branchname] = leaf_item dead_saves.pop(branchname, None) # rm /foo obviates rm /foo/bar elif isinstance(leaf_item, vfs.Commit): # rm /foo/bar if leaf_name == 'latest': add_error("error: cannot delete 'latest' symlink") else: branchname, branchitem = resolved[-2] if branchname not in dead_branches: dead = leaf_item, branchitem dead_saves.setdefault(branchname, []).append(dead) else: add_error("don't know how to remove %r yet" % path) if saved_errors: return None, None return dead_branches, dead_saves
git.check_repo_or_die() if not extra: o.fatal('must specify a target') if len(extra) > 1: o.fatal('only one target file allowed') if opt.bupm and opt.meta: o.fatal('--meta and --bupm are incompatible') target = extra[0] if not re.match(r'/*[^/]+/[^/]+', target): o.fatal("path %r doesn't include a branch and revision" % target) repo = LocalRepo() resolved = vfs.lresolve(repo, target) leaf_name, leaf_item = resolved[-1] if not leaf_item: log('error: cannot access %r in %r\n' % ('/'.join(name for name, item in resolved), path)) sys.exit(1) mode = vfs.item_mode(leaf_item) if opt.bupm: if not stat.S_ISDIR(mode): o.fatal('%r is not a directory' % target) _, bupm_oid = vfs.tree_data_and_bupm(repo, leaf_item.oid) if bupm_oid: with vfs.tree_data_reader(repo, bupm_oid) as meta_stream: sys.stdout.write(meta_stream.read())
def main(): o = options.Options(optspec) opt, flags, extra = o.parse(sys.argv[1:]) verbosity = opt.verbose if not opt.quiet else -1 git.check_repo_or_die() if not extra: o.fatal('must specify at least one filename to restore') exclude_rxs = parse_rx_excludes(flags, o.fatal) owner_map = {} for map_type in ('user', 'group', 'uid', 'gid'): owner_map[map_type] = parse_owner_mappings(map_type, flags, o.fatal) if opt.outdir: mkdirp(opt.outdir) os.chdir(opt.outdir) repo = RemoteRepo(opt.remote) if opt.remote else LocalRepo() top = os.getcwd() hardlinks = {} for path in extra: if not valid_restore_path(path): add_error("path %r doesn't include a branch and revision" % path) continue try: resolved = vfs.lresolve(repo, path, want_meta=True) except vfs.IOError as e: add_error(e) continue path_parent, path_name = os.path.split(path) leaf_name, leaf_item = resolved[-1] if not leaf_item: add_error('error: cannot access %r in %r' % ('/'.join(name for name, item in resolved), path)) continue if not path_name or path_name == '.': # Source is /foo/what/ever/ or /foo/what/ever/. -- extract # what/ever/* to the current directory, and if name == '.' # (i.e. /foo/what/ever/.), then also restore what/ever's # metadata to the current directory. treeish = vfs.item_mode(leaf_item) if not treeish: add_error('%r cannot be restored as a directory' % path) else: items = vfs.contents(repo, leaf_item, want_meta=True) dot, leaf_item = next(items, None) assert (dot == '.') for sub_name, sub_item in items: restore(repo, '', sub_name, sub_item, top, opt.sparse, opt.numeric_ids, owner_map, exclude_rxs, verbosity, hardlinks) if path_name == '.': leaf_item = vfs.augment_item_meta(repo, leaf_item, include_size=True) apply_metadata(leaf_item.meta, '.', opt.numeric_ids, owner_map) else: restore(repo, '', leaf_name, leaf_item, top, opt.sparse, opt.numeric_ids, owner_map, exclude_rxs, verbosity, hardlinks) if verbosity >= 0: progress('Restoring: %d, done.\n' % total_restored) die_if_errors()
def within_repo(repo, opt): if opt.commit_hash: opt.hash = True def item_line(item, name): return item_info(item, name, show_hash=opt.hash, commit_hash=opt.commit_hash, long_fmt=opt.long_listing, classification=opt.classification, numeric_ids=opt.numeric_ids, human_readable=opt.human_readable) ret = 0 pending = [] for path in opt.paths: try: if opt.directory: resolved = vfs.lresolve(repo, path) else: resolved = vfs.try_resolve(repo, path) leaf_name, leaf_item = resolved[-1] if not leaf_item: log('error: cannot access %r in %r\n' % ('/'.join(name for name, item in resolved), path)) ret = 1 continue if not opt.directory and S_ISDIR(vfs.item_mode(leaf_item)): items = vfs.contents(repo, leaf_item) if opt.show_hidden == 'all': # Match non-bup "ls -a ... /". parent = resolved[-2] if len(resolved) > 1 else resolved[0] items = chain(items, (('..', parent[1]), )) for sub_name, sub_item in sorted(items, key=lambda x: x[0]): if opt.show_hidden != 'all' and sub_name == '.': continue if sub_name.startswith('.') and \ opt.show_hidden not in ('almost', 'all'): continue if opt.l: sub_item = vfs.ensure_item_has_metadata( repo, sub_item, include_size=True) else: sub_item = vfs.augment_item_meta(repo, sub_item, include_size=True) line = item_line(sub_item, sub_name) if not opt.long_listing and istty1: pending.append(line) else: print(line) else: leaf_item = vfs.augment_item_meta(repo, leaf_item, include_size=True) line = item_line(leaf_item, os.path.normpath(path)) if not opt.long_listing and istty1: pending.append(line) else: print(line) except vfs.IOError as ex: log('bup: %s\n' % ex) ret = 1 if pending: sys.stdout.write(columnate(pending, '')) return ret