2 from __future__ import absolute_import
5 from bup.compat import str_type
11 should_rx_exclude_path)
12 from bup.io import path_msg
13 import bup.xstat as xstat
15 # the use of fchdir() and lstat() is for two reasons:
16 # - help out the kernel by not making it repeatedly look up the absolute path
17 # - avoid race conditions caused by doing listdir() on a changing symlink
20 O_LARGEFILE = os.O_LARGEFILE
21 except AttributeError:
24 O_NOFOLLOW = os.O_NOFOLLOW
25 except AttributeError:
29 def finalized_fd(path):
30 fd = os.open(path, os.O_RDONLY|O_LARGEFILE|O_NOFOLLOW|os.O_NDELAY)
31 return finalized(fd, lambda x: os.close(x))
36 for n in os.listdir(b'.'):
40 add_error(Exception('%s: %s' % (resolve_parent(n), str(e))))
42 if stat.S_ISDIR(st.st_mode):
48 def _recursive_dirlist(prepend, xdev, bup_dir=None,
51 xdev_exceptions=frozenset()):
52 for (name,pst) in _dirlist():
55 if os.path.normpath(path) in excluded_paths:
56 debug1('Skipping %r: excluded.\n' % path_msg(path))
58 if exclude_rxs and should_rx_exclude_path(path, exclude_rxs):
60 if name.endswith(b'/'):
62 if os.path.normpath(path) == bup_dir:
63 debug1('Skipping BUP_DIR.\n')
65 if xdev != None and pst.st_dev != xdev \
66 and path not in xdev_exceptions:
67 debug1('Skipping contents of %r: different filesystem.\n'
71 with finalized_fd(name) as fd:
74 add_error('%s: %s' % (prepend, e))
76 for i in _recursive_dirlist(prepend=prepend+name, xdev=xdev,
78 excluded_paths=excluded_paths,
79 exclude_rxs=exclude_rxs,
80 xdev_exceptions=xdev_exceptions):
86 def recursive_dirlist(paths, xdev, bup_dir=None,
89 xdev_exceptions=frozenset()):
90 with finalized_fd(b'.') as startdir:
92 assert not isinstance(paths, str_type)
95 pst = xstat.lstat(path)
96 if stat.S_ISLNK(pst.st_mode):
100 add_error('recursive_dirlist: %s' % e)
103 opened_pfile = finalized_fd(path)
107 with opened_pfile as pfile:
108 pst = xstat.fstat(pfile)
113 if stat.S_ISDIR(pst.st_mode):
115 prepend = os.path.join(path, b'')
116 for i in _recursive_dirlist(prepend=prepend, xdev=xdev,
118 excluded_paths=excluded_paths,
119 exclude_rxs=exclude_rxs,
120 xdev_exceptions=xdev_exceptions):