| #!/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) |
| |
| |