68
68
# OR with 0 on those platforms
69
69
O_BINARY = getattr(os, 'O_BINARY', 0)
71
# On posix, use lstat instead of stat so that we can
72
# operate on broken symlinks. On Windows revert to stat.
73
lstat = getattr(os, 'lstat', os.stat)
75
72
def make_readonly(filename):
76
73
"""Make a filename read-only."""
77
mod = lstat(filename).st_mode
74
mod = os.lstat(filename).st_mode
78
75
if not stat.S_ISLNK(mod):
79
76
mod = mod & 0777555
80
77
os.chmod(filename, mod)
83
80
def make_writable(filename):
84
mod = lstat(filename).st_mode
81
mod = os.lstat(filename).st_mode
85
82
if not stat.S_ISLNK(mod):
87
84
os.chmod(filename, mod)
87
def minimum_path_selection(paths):
88
"""Return the smallset subset of paths which are outside paths.
90
:param paths: A container (and hence not None) of paths.
91
:return: A set of paths sufficient to include everything in paths via
92
is_inside_any, drawn from the paths parameter.
97
other_paths = paths.difference([path])
98
if not is_inside_any(other_paths, path):
99
# this is a top level path, we must check it.
100
search_paths.add(path)
539
553
def pumpfile(fromfile, tofile):
540
"""Copy contents of one file to another."""
554
"""Copy contents of one file to another.
556
:return: The number of bytes copied.
543
561
b = fromfile.read(BUFSIZE)
549
569
def file_iterator(input_file, readsize=32768):
567
587
return s.hexdigest()
571
def sha_strings(strings):
590
def sha_file_by_name(fname):
591
"""Calculate the SHA1 of a file by reading the full text"""
593
f = os.open(fname, os.O_RDONLY | O_BINARY)
596
b = os.read(f, 1<<16)
604
def sha_strings(strings, _factory=sha.new):
572
605
"""Return the sha-1 of concatenation of strings"""
574
607
map(s.update, strings)
575
608
return s.hexdigest()
611
def sha_string(f, _factory=sha.new):
612
return _factory(f).hexdigest()
584
615
def fingerprint_file(f):
589
return {'size': size,
590
'sha1': s.hexdigest()}
617
return {'size': len(b),
618
'sha1': sha.new(b).hexdigest()}
593
621
def compare_files(a, b):
793
821
shutil.copyfile(src, dest)
795
def delete_any(full_path):
824
# Look Before You Leap (LBYL) is appropriate here instead of Easier to Ask for
825
# Forgiveness than Permission (EAFP) because:
826
# - root can damage a solaris file system by using unlink,
827
# - unlink raises different exceptions on different OSes (linux: EISDIR, win32:
828
# EACCES, OSX: EPERM) when invoked on a directory.
829
def delete_any(path):
796
830
"""Delete a file or directory."""
800
# We may be renaming a dangling inventory id
801
if e.errno not in (errno.EISDIR, errno.EACCES, errno.EPERM):
831
if isdir(path): # Takes care of symlinks
806
837
def has_symlinks():