Although there's the NOFOLLOW precedent, this is really just to narrow
the API before we add it as a repo method, i.e. so we only have to
handle one function instead of two.
Signed-off-by: Rob Browning <rlb@defaultvalue.org>
Tested-by: Rob Browning <rlb@defaultvalue.org>
o.fatal("path %r doesn't include a branch and revision" % target)
repo = LocalRepo()
o.fatal("path %r doesn't include a branch and revision" % target)
repo = LocalRepo()
-resolved = vfs.lresolve(repo, target)
+resolved = vfs.resolve(repo, target, follow=False)
leaf_name, leaf_item = resolved[-1]
if not leaf_item:
log('error: cannot access %r in %r\n'
leaf_name, leaf_item = resolved[-1]
if not leaf_item:
log('error: cannot access %r in %r\n'
global opt
if self.verbose > 0:
log('--getattr(%r)\n' % path)
global opt
if self.verbose > 0:
log('--getattr(%r)\n' % path)
- res = vfs.lresolve(self.repo, path, want_meta=(not self.fake_metadata))
+ res = vfs.resolve(self.repo, path, want_meta=(not self.fake_metadata),
+ follow=False)
name, item = res[-1]
if not item:
return -errno.ENOENT
name, item = res[-1]
if not item:
return -errno.ENOENT
def readdir(self, path, offset):
assert not offset # We don't return offsets, so offset should be unused
def readdir(self, path, offset):
assert not offset # We don't return offsets, so offset should be unused
- res = vfs.lresolve(self.repo, path)
+ res = vfs.resolve(self.repo, path, follow=False)
dir_name, dir_item = res[-1]
if not dir_item:
yield -errno.ENOENT
dir_name, dir_item = res[-1]
if not dir_item:
yield -errno.ENOENT
def readlink(self, path):
if self.verbose > 0:
log('--readlink(%r)\n' % path)
def readlink(self, path):
if self.verbose > 0:
log('--readlink(%r)\n' % path)
- res = vfs.lresolve(self.repo, path)
+ res = vfs.resolve(self.repo, path, follow=False)
name, item = res[-1]
if not item:
return -errno.ENOENT
name, item = res[-1]
if not item:
return -errno.ENOENT
def open(self, path, flags):
if self.verbose > 0:
log('--open(%r)\n' % path)
def open(self, path, flags):
if self.verbose > 0:
log('--open(%r)\n' % path)
- res = vfs.lresolve(self.repo, path)
+ res = vfs.resolve(self.repo, path, follow=False)
name, item = res[-1]
if not item:
return -errno.ENOENT
name, item = res[-1]
if not item:
return -errno.ENOENT
def read(self, path, size, offset):
if self.verbose > 0:
log('--read(%r)\n' % path)
def read(self, path, size, offset):
if self.verbose > 0:
log('--read(%r)\n' % path)
- res = vfs.lresolve(self.repo, path)
+ res = vfs.resolve(self.repo, path, follow=False)
name, item = res[-1]
if not item:
return -errno.ENOENT
name, item = res[-1]
if not item:
return -errno.ENOENT
add_error("path %r doesn't include a branch and revision" % path)
continue
try:
add_error("path %r doesn't include a branch and revision" % path)
continue
try:
- resolved = vfs.lresolve(repo, path, want_meta=True)
+ resolved = vfs.resolve(repo, path, want_meta=True, follow=False)
except vfs.IOError as e:
add_error(e)
continue
except vfs.IOError as e:
add_error(e)
continue
for path in opt.paths:
try:
if opt.directory:
for path in opt.paths:
try:
if opt.directory:
- resolved = vfs.lresolve(repo, path)
+ resolved = vfs.resolve(repo, path, follow=False)
else:
resolved = vfs.try_resolve(repo, path)
else:
resolved = vfs.try_resolve(repo, path)
# Scan for bad requests, and opportunities to optimize
for path in paths:
try:
# Scan for bad requests, and opportunities to optimize
for path in paths:
try:
- resolved = vfs.lresolve(repo, path)
+ resolved = vfs.resolve(repo, path, follow=False)
except vfs.IOError as e:
add_error(e)
continue
except vfs.IOError as e:
add_error(e)
continue
ex(bup_path, '-d', bup_dir, 'save', '-tvvn', 'test', data_path)
git.check_repo_or_die(bup_dir)
repo = LocalRepo()
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))
+ resolved = vfs.resolve(repo,
+ '/test/latest' + resolve_parent(data_path),
+ follow=False)
leaf_name, leaf_item = resolved[-1]
m = leaf_item.meta
WVPASS(m.mtime == test_time2)
leaf_name, leaf_item = resolved[-1]
m = leaf_item.meta
WVPASS(m.mtime == test_time2)
file_path, file_size,
link_path, link_target):
_, file_item = vfs.resolve(repo, file_path)[-1]
file_path, file_size,
link_path, link_target):
_, file_item = vfs.resolve(repo, file_path)[-1]
- _, link_item = vfs.lresolve(repo, link_path)[-1]
+ _, link_item = vfs.resolve(repo, link_path, follow=False)[-1]
wvpass(isinstance(file_item.meta, Metadata))
wvpass(isinstance(link_item.meta, Metadata))
# Note: normally, modifying item.meta values is forbidden
wvpass(isinstance(file_item.meta, Metadata))
wvpass(isinstance(link_item.meta, Metadata))
# Note: normally, modifying item.meta values is forbidden
with no_lingering_errors():
with test_tempdir('bup-tvfs-') as tmpdir:
resolve = vfs.resolve
with no_lingering_errors():
with test_tempdir('bup-tvfs-') as tmpdir:
resolve = vfs.resolve
- lresolve = vfs.lresolve
bup_dir = tmpdir + '/bup'
environ['GIT_DIR'] = bup_dir
environ['BUP_DIR'] = bup_dir
bup_dir = tmpdir + '/bup'
environ['GIT_DIR'] = bup_dir
environ['BUP_DIR'] = bup_dir
('not-there', None))
wvpasseq(expected, res)
('not-there', None))
wvpasseq(expected, res)
- wvstart('lresolve: /test/latest/bad-symlink')
+ wvstart('resolve nofollow: /test/latest/bad-symlink')
- res = lresolve(repo, '/test/latest/bad-symlink')
+ res = resolve(repo, '/test/latest/bad-symlink', follow=False)
wvpasseq(4, len(res))
bad_symlink_value = tip_tree['bad-symlink']
expected_bad_symlink_item_w_meta = vfs.Item(meta=bad_symlink_value.meta,
wvpasseq(4, len(res))
bad_symlink_value = tip_tree['bad-symlink']
expected_bad_symlink_item_w_meta = vfs.Item(meta=bad_symlink_value.meta,
('file', expected_file_item_w_meta))
wvpasseq(expected, res)
('file', expected_file_item_w_meta))
wvpasseq(expected, res)
- wvstart('lresolve: /test/latest/file-symlink')
+ wvstart('resolve nofollow: /test/latest/file-symlink')
- res = lresolve(repo, '/test/latest/file-symlink')
+ res = resolve(repo, '/test/latest/file-symlink', follow=False)
wvpasseq(4, len(res))
file_symlink_value = tip_tree['file-symlink']
expected_file_symlink_item_w_meta = vfs.Item(meta=file_symlink_value.meta,
wvpasseq(4, len(res))
file_symlink_value = tip_tree['file-symlink']
expected_file_symlink_item_w_meta = vfs.Item(meta=file_symlink_value.meta,
'/test/latest/file-symlink/../',
'/test/latest/file-symlink/../.',
'/test/latest/file-symlink/../..'):
'/test/latest/file-symlink/../',
'/test/latest/file-symlink/../.',
'/test/latest/file-symlink/../..'):
- wvstart('lresolve: ' + path)
+ wvstart('resolve nofollow: ' + path)
+ resolve(repo, path, follow=False)
except vfs.IOError as res_ex:
wvpasseq(ENOTDIR, res_ex.errno)
wvpasseq(['', 'test', save_time_str, 'file'],
except vfs.IOError as res_ex:
wvpasseq(ENOTDIR, res_ex.errno)
wvpasseq(['', 'test', save_time_str, 'file'],
wvpasseq(ENOTDIR, res_ex.errno)
wvpasseq(None, res_ex.terminus)
wvpasseq(ENOTDIR, res_ex.errno)
wvpasseq(None, res_ex.terminus)
- wvstart('lresolve: /test/latest/dir-symlink')
+ wvstart('resolve nofollow: /test/latest/dir-symlink')
- res = lresolve(repo, '/test/latest/dir-symlink')
+ res = resolve(repo, '/test/latest/dir-symlink', follow=False)
wvpasseq(4, len(res))
dir_symlink_value = tip_tree['dir-symlink']
expected_dir_symlink_item_w_meta = vfs.Item(meta=dir_symlink_value.meta,
wvpasseq(4, len(res))
dir_symlink_value = tip_tree['dir-symlink']
expected_dir_symlink_item_w_meta = vfs.Item(meta=dir_symlink_value.meta,
('test', test_revlist_w_meta),
(save_time_str, expected_latest_item_w_meta),
('dir', expected_dir_item))
('test', test_revlist_w_meta),
(save_time_str, expected_latest_item_w_meta),
('dir', expected_dir_item))
+ def lresolve(*args, **keys):
+ return resolve(*args, **dict(keys, follow=False))
for resname, resolver in (('resolve', resolve),
for resname, resolver in (('resolve', resolve),
- ('lresolve', lresolve)):
+ ('resolve nofollow', lresolve)):
for path in ('/test/latest/dir-symlink/',
'/test/latest/dir-symlink/.'):
wvstart(resname + ': ' + path)
for path in ('/test/latest/dir-symlink/',
'/test/latest/dir-symlink/.'):
wvstart(resname + ': ' + path)
with no_lingering_errors():
with test_tempdir('bup-tvfs-resloop-') as tmpdir:
resolve = vfs.resolve
with no_lingering_errors():
with test_tempdir('bup-tvfs-resloop-') as tmpdir:
resolve = vfs.resolve
- lresolve = vfs.lresolve
bup_dir = tmpdir + '/bup'
environ['GIT_DIR'] = bup_dir
environ['BUP_DIR'] = bup_dir
bup_dir = tmpdir + '/bup'
environ['GIT_DIR'] = bup_dir
environ['BUP_DIR'] = bup_dir
from bup.git import BUP_CHUNKED, cp, get_commit_items, parse_commit, tree_decode
from bup.helpers import debug2, last
from bup.metadata import Metadata
from bup.git import BUP_CHUNKED, cp, get_commit_items, parse_commit, tree_decode
from bup.helpers import debug2, last
from bup.metadata import Metadata
-from bup.repo import LocalRepo, RemoteRepo
class IOError(exceptions.IOError):
class IOError(exceptions.IOError):
for x in item_gen:
yield x
for x in item_gen:
yield x
-def _resolve_path(repo, path, parent=None, want_meta=True, deref=False):
+def _resolve_path(repo, path, parent=None, want_meta=True, follow=True):
cache_key = b'res:%d%d%d:%s\0%s' \
cache_key = b'res:%d%d%d:%s\0%s' \
- % (bool(want_meta), bool(deref), repo.id(),
+ % (bool(want_meta), bool(follow), repo.id(),
('/'.join(x[0] for x in parent) if parent else ''),
'/'.join(path))
resolution = cache_get(cache_key)
('/'.join(x[0] for x in parent) if parent else ''),
'/'.join(path))
resolution = cache_get(cache_key)
% (parent,))
is_absolute, must_be_dir, future = _decompose_path(path)
if must_be_dir:
% (parent,))
is_absolute, must_be_dir, future = _decompose_path(path)
if must_be_dir:
if not future: # path was effectively '.' or '/'
if is_absolute:
return notice_resolution((('', _root),))
if not future: # path was effectively '.' or '/'
if is_absolute:
return notice_resolution((('', _root),))
item = item._replace(meta=dir_meta)
past.append((segment, item))
else: # symlink
item = item._replace(meta=dir_meta)
past.append((segment, item))
else: # symlink
- if not future and not deref:
+ if not future and not follow:
past.append((segment, item),)
continue
if hops > 100:
past.append((segment, item),)
continue
if hops > 100:
future.extend(target_future)
hops += 1
future.extend(target_future)
hops += 1
-def lresolve(repo, path, parent=None, want_meta=True):
- """Perform exactly the same function as resolve(), except if the final
- path element is a symbolic link, don't follow it, just return it
- in the result.
-
- """
- return _resolve_path(repo, path, parent=parent, want_meta=want_meta,
- deref=False)
-
-def resolve(repo, path, parent=None, want_meta=True):
+def resolve(repo, path, parent=None, want_meta=True, follow=True):
"""Follow the path in the virtual filesystem and return a tuple
representing the location, if any, denoted by the path. Each
element in the result tuple will be (name, info), where info will
be a VFS item that can be passed to functions like item_mode().
"""Follow the path in the virtual filesystem and return a tuple
representing the location, if any, denoted by the path. Each
element in the result tuple will be (name, info), where info will
be a VFS item that can be passed to functions like item_mode().
+ If follow is false, and if the final path element is a symbolic
+ link, don't follow it, just return it in the result.
+
If a path segment that does not exist is encountered during
resolution, the result will represent the location of the missing
item, and that item in the result will be None.
If a path segment that does not exist is encountered during
resolution, the result will represent the location of the missing
item, and that item in the result will be None.
"""
result = _resolve_path(repo, path, parent=parent, want_meta=want_meta,
"""
result = _resolve_path(repo, path, parent=parent, want_meta=want_meta,
_, leaf_item = result[-1]
_, leaf_item = result[-1]
+ if leaf_item and follow:
assert not S_ISLNK(item_mode(leaf_item))
return result
def try_resolve(repo, path, parent=None, want_meta=True):
"""If path does not refer to a symlink, does not exist, or refers to a
assert not S_ISLNK(item_mode(leaf_item))
return result
def try_resolve(repo, path, parent=None, want_meta=True):
"""If path does not refer to a symlink, does not exist, or refers to a
- valid symlink, behave exactly like resolve(). If path refers to
- an invalid symlink, behave like lresolve.
+ valid symlink, behave exactly like resolve(..., follow=True). If
+ path refers to an invalid symlink, behave like resolve(...,
+ follow=False).
- res = lresolve(repo, path, parent=parent, want_meta=want_meta)
+ res = resolve(repo, path, parent=parent, want_meta=want_meta, follow=False)
leaf_name, leaf_item = res[-1]
if not leaf_item:
return res
if not S_ISLNK(item_mode(leaf_item)):
return res
leaf_name, leaf_item = res[-1]
if not leaf_item:
return res
if not S_ISLNK(item_mode(leaf_item)):
return res
- deref = resolve(repo, leaf_name, parent=res[:-1], want_meta=want_meta)
- deref_name, deref_item = deref[-1]
- if deref_item:
- return deref
+ follow = resolve(repo, leaf_name, parent=res[:-1], want_meta=want_meta)
+ follow_name, follow_item = follow[-1]
+ if follow_item:
+ return follow
return res
def augment_item_meta(repo, item, include_size=False):
return res
def augment_item_meta(repo, item, include_size=False):