-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Split directory recursion stuff from cmd-index.py into drecurse.py.
Also add a new command, 'bup drecurse', which just recurses through a directory tree and prints all the filenames. This is useful for timing performance vs. the native 'find' command. The result is a bit embarrassing; for my home directory of about 188000 files, drecurse is about 10x slower: $ time bup drecurse -q ~ real 0m2.935s user 0m2.312s sys 0m0.580s $ time find ~ -printf '' real 0m0.385s user 0m0.096s sys 0m0.284s time find ~ -printf '%s\n' >/dev/null real 0m0.662s user 0m0.208s sys 0m0.456s
- Loading branch information
Showing
6 changed files
with
138 additions
and
110 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
#!/usr/bin/env python | ||
import options, drecurse | ||
from helpers import * | ||
|
||
optspec = """ | ||
bup drecurse <path> | ||
-- | ||
x,xdev don't cross filesystem boundaries | ||
q,quiet don't actually print filenames | ||
""" | ||
o = options.Options('bup drecurse', optspec) | ||
(opt, flags, extra) = o.parse(sys.argv[1:]) | ||
|
||
if len(extra) != 1: | ||
log("drecurse: exactly one filename expected\n") | ||
o.usage() | ||
|
||
for (name,st) in drecurse.recursive_dirlist(extra, opt.xdev): | ||
if not opt.quiet: | ||
print name |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
import stat | ||
from helpers import * | ||
|
||
try: | ||
O_LARGEFILE = os.O_LARGEFILE | ||
except AttributeError: | ||
O_LARGEFILE = 0 | ||
|
||
|
||
class OsFile: | ||
def __init__(self, path): | ||
self.fd = None | ||
self.fd = os.open(path, os.O_RDONLY|O_LARGEFILE|os.O_NOFOLLOW) | ||
|
||
def __del__(self): | ||
if self.fd: | ||
fd = self.fd | ||
self.fd = None | ||
os.close(fd) | ||
|
||
def fchdir(self): | ||
os.fchdir(self.fd) | ||
|
||
|
||
# the use of fchdir() and lstat() are for two reasons: | ||
# - help out the kernel by not making it repeatedly look up the absolute path | ||
# - avoid race conditions caused by doing listdir() on a changing symlink | ||
def dirlist(path): | ||
l = [] | ||
try: | ||
OsFile(path).fchdir() | ||
except OSError, e: | ||
add_error(e) | ||
return l | ||
for n in os.listdir('.'): | ||
try: | ||
st = os.lstat(n) | ||
except OSError, e: | ||
add_error(Exception('in %s: %s' % (index.realpath(path), str(e)))) | ||
continue | ||
if stat.S_ISDIR(st.st_mode): | ||
n += '/' | ||
l.append((os.path.join(path, n), st)) | ||
l.sort(reverse=True) | ||
return l | ||
|
||
|
||
def _recursive_dirlist(path, xdev): | ||
olddir = OsFile('.') | ||
for (path,pst) in dirlist(path): | ||
if xdev != None and pst.st_dev != xdev: | ||
log('Skipping %r: different filesystem.\n' % path) | ||
continue | ||
if stat.S_ISDIR(pst.st_mode): | ||
for i in _recursive_dirlist(path, xdev=xdev): | ||
yield i | ||
yield (path,pst) | ||
olddir.fchdir() | ||
|
||
|
||
def _matchlen(a,b): | ||
bi = iter(b) | ||
count = 0 | ||
for ai in a: | ||
try: | ||
if bi.next() == ai: | ||
count += 1 | ||
except StopIteration: | ||
break | ||
return count | ||
|
||
|
||
def recursive_dirlist(paths, xdev): | ||
assert(type(paths) != type('')) | ||
last = () | ||
for path in paths: | ||
ps = pathsplit(path) | ||
while _matchlen(ps, last) < len(last): | ||
yield (''.join(last), None) | ||
last.pop() | ||
pst = os.lstat(path) | ||
if xdev: | ||
xdev = pst.st_dev | ||
else: | ||
xdev = None | ||
if stat.S_ISDIR(pst.st_mode): | ||
for i in _recursive_dirlist(path, xdev=xdev): | ||
yield i | ||
yield (path,pst) | ||
last = ps[:-1] | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters