]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - mdrestore/xfs_mdrestore.c
xfs_metadump: requires some object CRC recalculation
[thirdparty/xfsprogs-dev.git] / mdrestore / xfs_mdrestore.c
1 /*
2 * Copyright (c) 2007 Silicon Graphics, Inc.
3 * All Rights Reserved.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it would be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19 #include <libxfs.h>
20 #include "xfs_metadump.h"
21
22 char *progname;
23 int show_progress = 0;
24 int progress_since_warning = 0;
25
26 static void
27 fatal(const char *msg, ...)
28 {
29 va_list args;
30
31 va_start(args, msg);
32 fprintf(stderr, "%s: ", progname);
33 vfprintf(stderr, msg, args);
34 exit(1);
35 }
36
37 static void
38 print_progress(const char *fmt, ...)
39 {
40 char buf[60];
41 va_list ap;
42
43 va_start(ap, fmt);
44 vsnprintf(buf, sizeof(buf), fmt, ap);
45 va_end(ap);
46 buf[sizeof(buf)-1] = '\0';
47
48 printf("\r%-59s", buf);
49 fflush(stdout);
50 progress_since_warning = 1;
51 }
52
53 static void
54 perform_restore(
55 FILE *src_f,
56 int dst_fd,
57 int is_target_file)
58 {
59 xfs_metablock_t *metablock; /* header + index + blocks */
60 __be64 *block_index;
61 char *block_buffer;
62 int block_size;
63 int max_indicies;
64 int cur_index;
65 int mb_count;
66 xfs_metablock_t tmb;
67 xfs_sb_t sb;
68 __int64_t bytes_read;
69
70 /*
71 * read in first blocks (superblock 0), set "inprogress" flag for it,
72 * read in the rest of the file, and if complete, clear SB 0's
73 * "inprogress flag"
74 */
75
76 if (fread(&tmb, sizeof(tmb), 1, src_f) != 1)
77 fatal("error reading from file: %s\n", strerror(errno));
78
79 if (be32_to_cpu(tmb.mb_magic) != XFS_MD_MAGIC)
80 fatal("specified file is not a metadata dump\n");
81
82 block_size = 1 << tmb.mb_blocklog;
83 max_indicies = (block_size - sizeof(xfs_metablock_t)) / sizeof(__be64);
84
85 metablock = (xfs_metablock_t *)calloc(max_indicies + 1, block_size);
86 if (metablock == NULL)
87 fatal("memory allocation failure\n");
88
89 mb_count = be16_to_cpu(tmb.mb_count);
90 if (mb_count == 0 || mb_count > max_indicies)
91 fatal("bad block count: %u\n", mb_count);
92
93 block_index = (__be64 *)((char *)metablock + sizeof(xfs_metablock_t));
94 block_buffer = (char *)metablock + block_size;
95
96 if (fread(block_index, block_size - sizeof(tmb), 1, src_f) != 1)
97 fatal("error reading from file: %s\n", strerror(errno));
98
99 if (block_index[0] != 0)
100 fatal("first block is not the primary superblock\n");
101
102
103 if (fread(block_buffer, mb_count << tmb.mb_blocklog,
104 1, src_f) != 1)
105 fatal("error reading from file: %s\n", strerror(errno));
106
107 libxfs_sb_from_disk(&sb, (xfs_dsb_t *)block_buffer);
108
109 if (sb.sb_magicnum != XFS_SB_MAGIC)
110 fatal("bad magic number for primary superblock\n");
111
112 if (xfs_sb_version_hascrc(&sb))
113 fatal("Can't restore CRC enabled filesystems yet.\n");
114
115 ((xfs_dsb_t*)block_buffer)->sb_inprogress = 1;
116
117 if (is_target_file) {
118 /* ensure regular files are correctly sized */
119
120 if (ftruncate64(dst_fd, sb.sb_dblocks * sb.sb_blocksize))
121 fatal("cannot set filesystem image size: %s\n",
122 strerror(errno));
123 } else {
124 /* ensure device is sufficiently large enough */
125
126 char *lb[XFS_MAX_SECTORSIZE] = { NULL };
127 off64_t off;
128
129 off = sb.sb_dblocks * sb.sb_blocksize - sizeof(lb);
130 if (pwrite64(dst_fd, lb, sizeof(lb), off) < 0)
131 fatal("failed to write last block, is target too "
132 "small? (error: %s)\n", strerror(errno));
133 }
134
135 bytes_read = 0;
136
137 for (;;) {
138 if (show_progress && (bytes_read & ((1 << 20) - 1)) == 0)
139 print_progress("%lld MB read\n", bytes_read >> 20);
140
141 for (cur_index = 0; cur_index < mb_count; cur_index++) {
142 if (pwrite64(dst_fd, &block_buffer[cur_index <<
143 tmb.mb_blocklog], block_size,
144 be64_to_cpu(block_index[cur_index]) <<
145 BBSHIFT) < 0)
146 fatal("error writing block %llu: %s\n",
147 be64_to_cpu(block_index[cur_index]) << BBSHIFT,
148 strerror(errno));
149 }
150 if (mb_count < max_indicies)
151 break;
152
153 if (fread(metablock, block_size, 1, src_f) != 1)
154 fatal("error reading from file: %s\n", strerror(errno));
155
156 mb_count = be16_to_cpu(metablock->mb_count);
157 if (mb_count == 0)
158 break;
159 if (mb_count > max_indicies)
160 fatal("bad block count: %u\n", mb_count);
161
162 if (fread(block_buffer, mb_count << tmb.mb_blocklog,
163 1, src_f) != 1)
164 fatal("error reading from file: %s\n", strerror(errno));
165
166 bytes_read += block_size;
167 }
168
169 if (progress_since_warning)
170 putchar('\n');
171
172 memset(block_buffer, 0, sb.sb_sectsize);
173 sb.sb_inprogress = 0;
174 libxfs_sb_to_disk((xfs_dsb_t *)block_buffer, &sb, XFS_SB_ALL_BITS);
175 if (xfs_sb_version_hascrc(&sb)) {
176 xfs_update_cksum(block_buffer, sb.sb_sectsize,
177 offsetof(struct xfs_sb, sb_crc));
178 }
179
180 if (pwrite(dst_fd, block_buffer, sb.sb_sectsize, 0) < 0)
181 fatal("error writing primary superblock: %s\n", strerror(errno));
182
183 free(metablock);
184 }
185
186 static void
187 usage(void)
188 {
189 fprintf(stderr, "Usage: %s [-V] [-g] source target\n", progname);
190 exit(1);
191 }
192
193 extern int platform_check_ismounted(char *, char *, struct stat64 *, int);
194
195 int
196 main(
197 int argc,
198 char **argv)
199 {
200 FILE *src_f;
201 int dst_fd;
202 int c;
203 int open_flags;
204 struct stat64 statbuf;
205 int is_target_file;
206
207 progname = basename(argv[0]);
208
209 while ((c = getopt(argc, argv, "gV")) != EOF) {
210 switch (c) {
211 case 'g':
212 show_progress = 1;
213 break;
214 case 'V':
215 printf("%s version %s\n", progname, VERSION);
216 exit(0);
217 default:
218 usage();
219 }
220 }
221
222 if (argc - optind != 2)
223 usage();
224
225 /* open source */
226 if (strcmp(argv[optind], "-") == 0) {
227 src_f = stdin;
228 if (isatty(fileno(stdin)))
229 fatal("cannot read from a terminal\n");
230 } else {
231 src_f = fopen(argv[optind], "rb");
232 if (src_f == NULL)
233 fatal("cannot open source dump file\n");
234 }
235 optind++;
236
237 /* check and open target */
238 open_flags = O_RDWR;
239 is_target_file = 0;
240 if (stat64(argv[optind], &statbuf) < 0) {
241 /* ok, assume it's a file and create it */
242 open_flags |= O_CREAT;
243 is_target_file = 1;
244 } else if (S_ISREG(statbuf.st_mode)) {
245 open_flags |= O_TRUNC;
246 is_target_file = 1;
247 } else {
248 /*
249 * check to make sure a filesystem isn't mounted on the device
250 */
251 if (platform_check_ismounted(argv[optind], NULL, &statbuf, 0))
252 fatal("a filesystem is mounted on target device \"%s\","
253 " cannot restore to a mounted filesystem.\n",
254 argv[optind]);
255 }
256
257 dst_fd = open(argv[optind], open_flags, 0644);
258 if (dst_fd < 0)
259 fatal("couldn't open target \"%s\"\n", argv[optind]);
260
261 perform_restore(src_f, dst_fd, is_target_file);
262
263 close(dst_fd);
264 if (src_f != stdin)
265 fclose(src_f);
266
267 return 0;
268 }