Add bcp to test the clone file ioctl
authorChris Mason <chris.mason@oracle.com>
Fri, 2 May 2008 19:08:08 +0000 (15:08 -0400)
committerDavid Woodhouse <dwmw2@hera.kernel.org>
Fri, 2 May 2008 19:08:08 +0000 (15:08 -0400)
bcp [new file with mode: 0755]

diff --git a/bcp b/bcp
new file mode 100755 (executable)
index 0000000..926d320
--- /dev/null
+++ b/bcp
@@ -0,0 +1,130 @@
+#!/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):
+    dstname = os.path.join(dst, filename)
+    if not os.path.exists(dstname):
+        link_target = os.readlink(srcname)
+        os.symlink(link_target, dstname)
+
+def copydev(srcname, dst, filename, statinfo):
+    devbits = statinfo.st_mode & (stat.S_IFBLK | stat.S_IFCHR)
+    mode = stat.S_IMODE(statinfo.st_mode) | devbits
+    dstname = os.path.join(dst, filename)
+    if not os.path.exists(dstname):
+        os.mknod(dstname, mode, statinfo.st_rdev)
+
+def copyfile(srcname, dst, filename, statinfo):
+    written = 0
+    dstname = os.path.join(dst, filename)
+
+    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
+
+
+src = args[0]
+dst = args[1]
+
+if not os.path.exists(dst):
+    os.makedirs(dst)
+
+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)
+
+        if srcname.startswith(src):
+            part = srcname[len(src) + 1:]
+
+        if stat.S_ISLNK(statinfo.st_mode):
+            copylink(srcname, dst, part, statinfo)
+            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)
+        if srcname.startswith(src):
+            part = srcname[len(src) + 1:]
+
+        statinfo = os.lstat(srcname)
+        st_mode = statinfo.st_mode
+
+        if stat.S_ISLNK(st_mode):
+            copylink(srcname, dst, part, statinfo)
+
+        elif stat.S_ISBLK(st_mode) or stat.S_ISCHR(st_mode):
+            copydev(srcname, dst, part, statinfo)
+
+        elif stat.S_ISREG(st_mode):
+            copyfile(srcname, dst, part, statinfo)