]> arthur.barton.de Git - bup.git/blob - lib/bup/drecurse.py
Improve formatting of error and warning messages.
[bup.git] / lib / bup / drecurse.py
1 import stat, os
2 from bup.helpers import *
3 import bup.xstat as xstat
4
5 try:
6     O_LARGEFILE = os.O_LARGEFILE
7 except AttributeError:
8     O_LARGEFILE = 0
9 try:
10     O_NOFOLLOW = os.O_NOFOLLOW
11 except AttributeError:
12     O_NOFOLLOW = 0
13
14
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
18 class OsFile:
19     def __init__(self, path):
20         self.fd = None
21         self.fd = os.open(path, os.O_RDONLY|O_LARGEFILE|O_NOFOLLOW|os.O_NDELAY)
22         
23     def __del__(self):
24         if self.fd:
25             fd = self.fd
26             self.fd = None
27             os.close(fd)
28
29     def fchdir(self):
30         os.fchdir(self.fd)
31
32     def stat(self):
33         return xstat.fstat(self.fd)
34
35
36 _IFMT = stat.S_IFMT(0xffffffff)  # avoid function call in inner loop
37 def _dirlist():
38     l = []
39     for n in os.listdir('.'):
40         try:
41             st = xstat.lstat(n)
42         except OSError, e:
43             add_error(Exception('%s: %s' % (realpath(n), str(e))))
44             continue
45         if (st.st_mode & _IFMT) == stat.S_IFDIR:
46             n += '/'
47         l.append((n,st))
48     l.sort(reverse=True)
49     return l
50
51
52 def _recursive_dirlist(prepend, xdev, bup_dir=None, excluded_paths=None):
53     for (name,pst) in _dirlist():
54         if name.endswith('/'):
55             if xdev != None and pst.st_dev != xdev:
56                 debug1('Skipping %r: different filesystem.\n' % (prepend+name))
57                 continue
58             if bup_dir != None:
59                 if os.path.normpath(prepend+name) == bup_dir:
60                     debug1('Skipping BUP_DIR.\n')
61                     continue
62             if excluded_paths:
63                 if os.path.normpath(prepend+name) in excluded_paths:
64                     debug1('Skipping %r: excluded.\n' % (prepend+name))
65                     continue
66             try:
67                 OsFile(name).fchdir()
68             except OSError, e:
69                 add_error('%s: %s' % (prepend, e))
70             else:
71                 for i in _recursive_dirlist(prepend=prepend+name, xdev=xdev,
72                                             bup_dir=bup_dir,
73                                             excluded_paths=excluded_paths):
74                     yield i
75                 os.chdir('..')
76         yield (prepend + name, pst)
77
78
79 def recursive_dirlist(paths, xdev, bup_dir=None, excluded_paths=None):
80     startdir = OsFile('.')
81     try:
82         assert(type(paths) != type(''))
83         for path in paths:
84             try:
85                 pst = xstat.lstat(path)
86                 if stat.S_ISLNK(pst.st_mode):
87                     yield (path, pst)
88                     continue
89             except OSError, e:
90                 add_error('recursive_dirlist: %s' % e)
91                 continue
92             try:
93                 pfile = OsFile(path)
94             except OSError, e:
95                 add_error(e)
96                 continue
97             pst = pfile.stat()
98             if xdev:
99                 xdev = pst.st_dev
100             else:
101                 xdev = None
102             if stat.S_ISDIR(pst.st_mode):
103                 pfile.fchdir()
104                 prepend = os.path.join(path, '')
105                 for i in _recursive_dirlist(prepend=prepend, xdev=xdev,
106                                             bup_dir=bup_dir,
107                                             excluded_paths=excluded_paths):
108                     yield i
109                 startdir.fchdir()
110             else:
111                 prepend = path
112             yield (prepend,pst)
113     except:
114         try:
115             startdir.fchdir()
116         except:
117             pass
118         raise
119
120 def parse_excludes(flags):
121     excluded_paths = []
122
123     for flag in flags:
124         (option, parameter) = flag
125         if option == '--exclude':
126             excluded_paths.append(realpath(parameter))
127
128         if option == '--exclude-from':
129             try:
130                 try:
131                     f = open(realpath(parameter))
132                     for exclude_path in f.readlines():
133                         excluded_paths.append(realpath(exclude_path.strip()))
134                 except Error, e:
135                     log("warning: couldn't read %s\n" % parameter)
136             finally:
137                 f.close()
138
139     return excluded_paths
140