Add bcp to test the clone file ioctl

This commit is contained in:
Chris Mason 2008-05-02 15:08:08 -04:00 committed by David Woodhouse
parent 9a73efb7d1
commit a94b1455aa

130
bcp Executable file
View File

@ -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)