]> arthur.barton.de Git - bup.git/blob - lib/bup/drecurse.py
Don't import * from helpers
[bup.git] / lib / bup / drecurse.py
1
2 import stat, os
3
4 from bup.helpers import should_rx_exclude_path, debug1
5 import bup.xstat as xstat
6
7
8 try:
9     O_LARGEFILE = os.O_LARGEFILE
10 except AttributeError:
11     O_LARGEFILE = 0
12 try:
13     O_NOFOLLOW = os.O_NOFOLLOW
14 except AttributeError:
15     O_NOFOLLOW = 0
16
17
18 # the use of fchdir() and lstat() is for two reasons:
19 #  - help out the kernel by not making it repeatedly look up the absolute path
20 #  - avoid race conditions caused by doing listdir() on a changing symlink
21 class OsFile:
22     def __init__(self, path):
23         self.fd = None
24         self.fd = os.open(path, os.O_RDONLY|O_LARGEFILE|O_NOFOLLOW|os.O_NDELAY)
25         
26     def __del__(self):
27         if self.fd:
28             fd = self.fd
29             self.fd = None
30             os.close(fd)
31
32     def fchdir(self):
33         os.fchdir(self.fd)
34
35     def stat(self):
36         return xstat.fstat(self.fd)
37
38
39 _IFMT = stat.S_IFMT(0xffffffff)  # avoid function call in inner loop
40 def _dirlist():
41     l = []
42     for n in os.listdir('.'):
43         try:
44             st = xstat.lstat(n)
45         except OSError as e:
46             add_error(Exception('%s: %s' % (resolve_parent(n), str(e))))
47             continue
48         if (st.st_mode & _IFMT) == stat.S_IFDIR:
49             n += '/'
50         l.append((n,st))
51     l.sort(reverse=True)
52     return l
53
54
55 def _recursive_dirlist(prepend, xdev, bup_dir=None,
56                        excluded_paths=None,
57                        exclude_rxs=None):
58     for (name,pst) in _dirlist():
59         path = prepend + name
60         if excluded_paths:
61             if os.path.normpath(path) in excluded_paths:
62                 debug1('Skipping %r: excluded.\n' % path)
63                 continue
64         if exclude_rxs and should_rx_exclude_path(path, exclude_rxs):
65             continue
66         if name.endswith('/'):
67             if bup_dir != None:
68                 if os.path.normpath(path) == bup_dir:
69                     debug1('Skipping BUP_DIR.\n')
70                     continue
71             if xdev != None and pst.st_dev != xdev:
72                 debug1('Skipping contents of %r: different filesystem.\n' % path)
73             else:
74                 try:
75                     OsFile(name).fchdir()
76                 except OSError as e:
77                     add_error('%s: %s' % (prepend, e))
78                 else:
79                     for i in _recursive_dirlist(prepend=prepend+name, xdev=xdev,
80                                                 bup_dir=bup_dir,
81                                                 excluded_paths=excluded_paths,
82                                                 exclude_rxs=exclude_rxs):
83                         yield i
84                     os.chdir('..')
85         yield (path, pst)
86
87
88 def recursive_dirlist(paths, xdev, bup_dir=None, excluded_paths=None,
89                       exclude_rxs=None):
90     startdir = OsFile('.')
91     try:
92         assert(type(paths) != type(''))
93         for path in paths:
94             try:
95                 pst = xstat.lstat(path)
96                 if stat.S_ISLNK(pst.st_mode):
97                     yield (path, pst)
98                     continue
99             except OSError as e:
100                 add_error('recursive_dirlist: %s' % e)
101                 continue
102             try:
103                 pfile = OsFile(path)
104             except OSError as e:
105                 add_error(e)
106                 continue
107             pst = pfile.stat()
108             if xdev:
109                 xdev = pst.st_dev
110             else:
111                 xdev = None
112             if stat.S_ISDIR(pst.st_mode):
113                 pfile.fchdir()
114                 prepend = os.path.join(path, '')
115                 for i in _recursive_dirlist(prepend=prepend, xdev=xdev,
116                                             bup_dir=bup_dir,
117                                             excluded_paths=excluded_paths,
118                                             exclude_rxs=exclude_rxs):
119                     yield i
120                 startdir.fchdir()
121             else:
122                 prepend = path
123             yield (prepend,pst)
124     except:
125         try:
126             startdir.fchdir()
127         except:
128             pass
129         raise