#!/usr/bin/env python # Copyright (C) 2007 Oracle. All rights reserved. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public # License v2 as published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public # License along with this program; if not, write to the # Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 021110-1307, USA. # import sys, os, stat, fcntl from optparse import OptionParser def copylink(srcname, dst, filename, statinfo, force_name): dstname = os.path.join(dst, force_name or filename) if not os.path.exists(dstname): link_target = os.readlink(srcname) os.symlink(link_target, dstname) def copydev(srcname, dst, filename, statinfo, force_name): devbits = statinfo.st_mode & (stat.S_IFBLK | stat.S_IFCHR) mode = stat.S_IMODE(statinfo.st_mode) | devbits dstname = os.path.join(dst, force_name or filename) if not os.path.exists(dstname): os.mknod(dstname, mode, statinfo.st_rdev) def copyfile(srcname, dst, filename, statinfo, force_name): written = 0 dstname = os.path.join(dst, force_name or filename) st_mode = statinfo.st_mode if stat.S_ISLNK(st_mode): copylink(srcname, dst, part, statinfo, None) return elif stat.S_ISBLK(st_mode) or stat.S_ISCHR(st_mode): copydev(srcname, dst, part, statinfo, None) return elif not stat.S_ISREG(st_mode): return try: os.unlink(dstname) except: pass if options.link: os.link(srcname, dstname) return dstf = file(dstname, 'w') srcf = file(srcname, 'r') ret = 1 try: if not options.copy: ret = fcntl.ioctl(dstf.fileno(), 1074041865, srcf.fileno()) except: pass if ret != 0: while True: buf = srcf.read(256 * 1024) if not buf: break written += len(buf) dstf.write(buf) os.chmod(dstname, stat.S_IMODE(statinfo.st_mode)) os.chown(dstname, statinfo.st_uid, statinfo.st_gid) usage = "usage: %prog [options]" parser = OptionParser(usage=usage) parser.add_option("-l", "--link", help="Create hard links", default=False, action="store_true") parser.add_option("-c", "--copy", help="Copy file bytes (don't cow)", default=False, action="store_true") (options,args) = parser.parse_args() if len(args) < 2: sys.stderr.write("source or destination not specified\n") sys.exit(1) if options.link and options.copy: sys.stderr.write("Both -l and -c specified, using copy mode\n") options.link = False total_args = len(args) src_args = total_args - 1 orig_dst = args[-1] if src_args > 1: if not os.path.exists(orig_dst): os.makedirs(orig_dst) if not os.path.isdir(orig_dst): sys.stderr.write("Destination %s is not a directory\n" % orig_dst) exit(1) for srci in xrange(0, src_args): src = args[srci] if os.path.isfile(src): statinfo = os.lstat(src) force_name = None if src_args == 1: if not os.path.isdir(orig_dst): force_name = os.path.basename(orig_dst) orig_dst = os.path.dirname(orig_dst) or '.' copyfile(src, orig_dst, os.path.basename(src), statinfo, force_name) continue if src_args > 1 or os.path.exists(orig_dst): dst = os.path.join(orig_dst, os.path.basename(src)) else: dst = orig_dst if not os.path.exists(dst): os.makedirs(dst) statinfo = os.stat(src) os.chmod(dst, stat.S_IMODE(statinfo.st_mode)) os.chown(dst, statinfo.st_uid, statinfo.st_gid) iter = os.walk(src, topdown=True) for (dirpath, dirnames, filenames) in iter: for x in dirnames: srcname = os.path.join(dirpath, x) statinfo = os.lstat(srcname) part = os.path.relpath(srcname, src) if stat.S_ISLNK(statinfo.st_mode): copylink(srcname, dst, part, statinfo, None) continue dst_dir = os.path.join(dst, part) if not os.path.exists(dst_dir): os.makedirs(dst_dir) os.chmod(dst_dir, stat.S_IMODE(statinfo.st_mode)) os.chown(dst_dir, statinfo.st_uid, statinfo.st_gid) for f in filenames: srcname = os.path.join(dirpath, f) part = os.path.relpath(srcname, src) statinfo = os.lstat(srcname) copyfile(srcname, dst, part, statinfo, None)