diff options
Diffstat (limited to 'bcp')
-rwxr-xr-x | bcp | 159 |
1 files changed, 159 insertions, 0 deletions
@@ -0,0 +1,159 @@ +#!/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) + + |