926d3201bc72053ee3e9e64633adaefd5496d787
[platform/upstream/btrfs-progs.git] / bcp
1 #!/usr/bin/env python
2 # Copyright (C) 2007 Oracle.  All rights reserved.
3 #
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public
6 # License v2 as published by the Free Software Foundation.
7
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 # General Public License for more details.
12
13 # You should have received a copy of the GNU General Public
14 # License along with this program; if not, write to the
15 # Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16 # Boston, MA 021110-1307, USA.
17 #
18 import sys, os, stat, fcntl
19 from optparse import OptionParser
20
21 def copylink(srcname, dst, filename, statinfo):
22     dstname = os.path.join(dst, filename)
23     if not os.path.exists(dstname):
24         link_target = os.readlink(srcname)
25         os.symlink(link_target, dstname)
26
27 def copydev(srcname, dst, filename, statinfo):
28     devbits = statinfo.st_mode & (stat.S_IFBLK | stat.S_IFCHR)
29     mode = stat.S_IMODE(statinfo.st_mode) | devbits
30     dstname = os.path.join(dst, filename)
31     if not os.path.exists(dstname):
32         os.mknod(dstname, mode, statinfo.st_rdev)
33
34 def copyfile(srcname, dst, filename, statinfo):
35     written = 0
36     dstname = os.path.join(dst, filename)
37
38     try:
39         os.unlink(dstname)
40     except:
41         pass
42
43     if options.link:
44         os.link(srcname, dstname)
45         return
46
47     dstf = file(dstname, 'w')
48     srcf = file(srcname, 'r')
49
50     ret = 1
51
52     try:
53         if not options.copy:
54             ret = fcntl.ioctl(dstf.fileno(), 1074041865, srcf.fileno())
55     except:
56         pass
57
58     if ret != 0:
59         while True:
60             buf = srcf.read(256 * 1024)
61             if not buf:
62                 break
63             written += len(buf)
64             dstf.write(buf)
65
66     os.chmod(dstname, stat.S_IMODE(statinfo.st_mode))
67     os.chown(dstname, statinfo.st_uid, statinfo.st_gid)
68
69
70 usage = "usage: %prog [options]"
71 parser = OptionParser(usage=usage)
72 parser.add_option("-l", "--link", help="Create hard links", default=False,
73                   action="store_true")
74 parser.add_option("-c", "--copy", help="Copy file bytes (don't cow)",
75                   default=False, action="store_true")
76
77 (options,args) = parser.parse_args()
78
79 if len(args) < 2:
80     sys.stderr.write("source or destination not specified\n")
81     sys.exit(1)
82
83 if options.link and options.copy:
84     sys.stderr.write("Both -l and -c specified, using copy mode\n")
85     options.link = False
86
87
88 src = args[0]
89 dst = args[1]
90
91 if not os.path.exists(dst):
92     os.makedirs(dst)
93
94 iter = os.walk(src, topdown=True)
95
96 for (dirpath, dirnames, filenames) in iter:
97     for x in dirnames:
98         srcname = os.path.join(dirpath, x)
99         statinfo = os.lstat(srcname)
100
101         if srcname.startswith(src):
102             part = srcname[len(src) + 1:]
103
104         if stat.S_ISLNK(statinfo.st_mode):
105             copylink(srcname, dst, part, statinfo)
106             continue
107
108         dst_dir = os.path.join(dst, part)
109         if not os.path.exists(dst_dir):
110             os.makedirs(dst_dir)
111
112         os.chmod(dst_dir, stat.S_IMODE(statinfo.st_mode))
113         os.chown(dst_dir, statinfo.st_uid, statinfo.st_gid)
114
115     for f in filenames:
116         srcname = os.path.join(dirpath, f)
117         if srcname.startswith(src):
118             part = srcname[len(src) + 1:]
119
120         statinfo = os.lstat(srcname)
121         st_mode = statinfo.st_mode
122
123         if stat.S_ISLNK(st_mode):
124             copylink(srcname, dst, part, statinfo)
125
126         elif stat.S_ISBLK(st_mode) or stat.S_ISCHR(st_mode):
127             copydev(srcname, dst, part, statinfo)
128
129         elif stat.S_ISREG(st_mode):
130             copyfile(srcname, dst, part, statinfo)