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