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