]> arthur.barton.de Git - bup.git/blob - lib/bup/drecurse.py
Modify drecurse.py and index.py to use xstat functions.
[bup.git] / lib / bup / drecurse.py
1 import stat
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
10
11 # the use of fchdir() and lstat() is for two reasons:
12 #  - help out the kernel by not making it repeatedly look up the absolute path
13 #  - avoid race conditions caused by doing listdir() on a changing symlink
14 class OsFile:
15     def __init__(self, path):
16         self.fd = None
17         self.fd = os.open(path, 
18                           os.O_RDONLY|O_LARGEFILE|os.O_NOFOLLOW|os.O_NDELAY)
19         
20     def __del__(self):
21         if self.fd:
22             fd = self.fd
23             self.fd = None
24             os.close(fd)
25
26     def fchdir(self):
27         os.fchdir(self.fd)
28
29     def stat(self):
30         return xstat.fstat(self.fd)
31
32
33 _IFMT = stat.S_IFMT(0xffffffff)  # avoid function call in inner loop
34 def _dirlist():
35     l = []
36     for n in os.listdir('.'):
37         try:
38             st = xstat.lstat(n)
39         except OSError, e:
40             add_error(Exception('%s: %s' % (realpath(n), str(e))))
41             continue
42         if (st.st_mode & _IFMT) == stat.S_IFDIR:
43             n += '/'
44         l.append((n,st))
45     l.sort(reverse=True)
46     return l
47
48
49 def _recursive_dirlist(prepend, xdev):
50     for (name,pst) in _dirlist():
51         if name.endswith('/'):
52             if xdev != None and pst.st_dev != xdev:
53                 log('Skipping %r: different filesystem.\n' % (prepend+name))
54                 continue
55             try:
56                 OsFile(name).fchdir()
57             except OSError, e:
58                 add_error('%s: %s' % (prepend, e))
59             else:
60                 for i in _recursive_dirlist(prepend=prepend+name, xdev=xdev):
61                     yield i
62                 os.chdir('..')
63         yield (prepend + name, pst)
64
65
66 def recursive_dirlist(paths, xdev):
67     startdir = OsFile('.')
68     try:
69         assert(type(paths) != type(''))
70         for path in paths:
71             try:
72                 pst = xstat.lstat(path)
73                 if stat.S_ISLNK(pst.st_mode):
74                     yield (path, pst)
75                     continue
76             except OSError, e:
77                 add_error('recursive_dirlist: %s' % e)
78                 continue
79             try:
80                 pfile = OsFile(path)
81             except OSError, e:
82                 add_error(e)
83                 continue
84             pst = pfile.stat()
85             if xdev:
86                 xdev = pst.st_dev
87             else:
88                 xdev = None
89             if stat.S_ISDIR(pst.st_mode):
90                 pfile.fchdir()
91                 prepend = os.path.join(path, '')
92                 for i in _recursive_dirlist(prepend=prepend, xdev=xdev):
93                     yield i
94                 startdir.fchdir()
95             else:
96                 prepend = path
97             yield (prepend,pst)
98     except:
99         try:
100             startdir.fchdir()
101         except:
102             pass
103         raise