btrfs-progs: Fix 'btrfs device stats --check' cli option
[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, force_name):
22     dstname = os.path.join(dst, force_name or 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, force_name):
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, force_name or filename)
31     if not os.path.exists(dstname):
32         os.mknod(dstname, mode, statinfo.st_rdev)
33
34 def copyfile(srcname, dst, filename, statinfo, force_name):
35     written = 0
36     dstname = os.path.join(dst, force_name or filename)
37
38     st_mode = statinfo.st_mode
39     if stat.S_ISLNK(st_mode):
40         copylink(srcname, dst, part, statinfo, None)
41         return
42     elif stat.S_ISBLK(st_mode) or stat.S_ISCHR(st_mode):
43         copydev(srcname, dst, part, statinfo, None)
44         return
45     elif not stat.S_ISREG(st_mode):
46         return
47
48     try:
49         os.unlink(dstname)
50     except:
51         pass
52
53     if options.link:
54         os.link(srcname, dstname)
55         return
56
57     dstf = file(dstname, 'w')
58     srcf = file(srcname, 'r')
59
60     ret = 1
61
62     try:
63         if not options.copy:
64             ret = fcntl.ioctl(dstf.fileno(), 1074041865, srcf.fileno())
65     except:
66         pass
67
68     if ret != 0:
69         while True:
70             buf = srcf.read(256 * 1024)
71             if not buf:
72                 break
73             written += len(buf)
74             dstf.write(buf)
75
76     os.chmod(dstname, stat.S_IMODE(statinfo.st_mode))
77     os.chown(dstname, statinfo.st_uid, statinfo.st_gid)
78
79
80 usage = "usage: %prog [options]"
81 parser = OptionParser(usage=usage)
82 parser.add_option("-l", "--link", help="Create hard links", default=False,
83                   action="store_true")
84 parser.add_option("-c", "--copy", help="Copy file bytes (don't cow)",
85                   default=False, action="store_true")
86
87 (options,args) = parser.parse_args()
88
89 if len(args) < 2:
90     sys.stderr.write("source or destination not specified\n")
91     sys.exit(1)
92
93 if options.link and options.copy:
94     sys.stderr.write("Both -l and -c specified, using copy mode\n")
95     options.link = False
96
97
98 total_args = len(args)
99 src_args = total_args - 1
100 orig_dst = args[-1]
101
102 if src_args > 1:
103     if not os.path.exists(orig_dst):
104         os.makedirs(orig_dst)
105     if not os.path.isdir(orig_dst):
106         sys.stderr.write("Destination %s is not a directory\n" % orig_dst)
107         exit(1)
108
109 for srci in xrange(0, src_args):
110     src = args[srci]
111     if os.path.isfile(src):
112         statinfo = os.lstat(src)
113         force_name = None
114         if src_args == 1:
115             if not os.path.isdir(orig_dst):
116                 force_name = os.path.basename(orig_dst)
117                 orig_dst = os.path.dirname(orig_dst) or '.'
118         copyfile(src, orig_dst, os.path.basename(src), statinfo, force_name)
119         continue
120
121     if src_args > 1 or os.path.exists(orig_dst):
122         dst = os.path.join(orig_dst, os.path.basename(src))
123     else:
124         dst = orig_dst
125
126     if not os.path.exists(dst):
127         os.makedirs(dst)
128         statinfo = os.stat(src)
129         os.chmod(dst, stat.S_IMODE(statinfo.st_mode))
130         os.chown(dst, statinfo.st_uid, statinfo.st_gid)
131         
132     iter = os.walk(src, topdown=True)
133
134     for (dirpath, dirnames, filenames) in iter:
135         for x in dirnames:
136             srcname = os.path.join(dirpath, x)
137             statinfo = os.lstat(srcname)
138
139             part = os.path.relpath(srcname, src)
140
141             if stat.S_ISLNK(statinfo.st_mode):
142                 copylink(srcname, dst, part, statinfo, None)
143                 continue
144
145             dst_dir = os.path.join(dst, part)
146             if not os.path.exists(dst_dir):
147                 os.makedirs(dst_dir)
148
149             os.chmod(dst_dir, stat.S_IMODE(statinfo.st_mode))
150             os.chown(dst_dir, statinfo.st_uid, statinfo.st_gid)
151
152         for f in filenames:
153             srcname = os.path.join(dirpath, f)
154             part = os.path.relpath(srcname, src)
155
156             statinfo = os.lstat(srcname)
157             copyfile(srcname, dst, part, statinfo, None)
158
159