]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - mdrestore/xfs_mdrestore.c
xfs: create refcount update intent log items
[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_indices;
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_indices = (block_size - sizeof(xfs_metablock_t)) / sizeof(__be64);
84
85 metablock = (xfs_metablock_t *)calloc(max_indices + 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_indices)
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 /*
113 * Normally the upper bound would be simply XFS_MAX_SECTORSIZE
114 * but the metadump format has a maximum number of BBSIZE blocks
115 * it can store in a single metablock.
116 */
117 if (sb.sb_sectsize < XFS_MIN_SECTORSIZE ||
118 sb.sb_sectsize > XFS_MAX_SECTORSIZE ||
119 sb.sb_sectsize > max_indices * block_size)
120 fatal("bad sector size %u in metadump image\n", sb.sb_sectsize);
121
122 ((xfs_dsb_t*)block_buffer)->sb_inprogress = 1;
123
124 if (is_target_file) {
125 /* ensure regular files are correctly sized */
126
127 if (ftruncate64(dst_fd, sb.sb_dblocks * sb.sb_blocksize))
128 fatal("cannot set filesystem image size: %s\n",
129 strerror(errno));
130 } else {
131 /* ensure device is sufficiently large enough */
132
133 char *lb[XFS_MAX_SECTORSIZE] = { NULL };
134 off64_t off;
135
136 off = sb.sb_dblocks * sb.sb_blocksize - sizeof(lb);
137 if (pwrite64(dst_fd, lb, sizeof(lb), off) < 0)
138 fatal("failed to write last block, is target too "
139 "small? (error: %s)\n", strerror(errno));
140 }
141
142 bytes_read = 0;
143
144 for (;;) {
145 if (show_progress && (bytes_read & ((1 << 20) - 1)) == 0)
146 print_progress("%lld MB read", bytes_read >> 20);
147
148 for (cur_index = 0; cur_index < mb_count; cur_index++) {
149 if (pwrite64(dst_fd, &block_buffer[cur_index <<
150 tmb.mb_blocklog], block_size,
151 be64_to_cpu(block_index[cur_index]) <<
152 BBSHIFT) < 0)
153 fatal("error writing block %llu: %s\n",
154 be64_to_cpu(block_index[cur_index]) << BBSHIFT,
155 strerror(errno));
156 }
157 if (mb_count < max_indices)
158 break;
159
160 if (fread(metablock, block_size, 1, src_f) != 1)
161 fatal("error reading from file: %s\n", strerror(errno));
162
163 mb_count = be16_to_cpu(metablock->mb_count);
164 if (mb_count == 0)
165 break;
166 if (mb_count > max_indices)
167 fatal("bad block count: %u\n", mb_count);
168
169 if (fread(block_buffer, mb_count << tmb.mb_blocklog,
170 1, src_f) != 1)
171 fatal("error reading from file: %s\n", strerror(errno));
172
173 bytes_read += block_size + (mb_count << tmb.mb_blocklog);
174 }
175
176 if (progress_since_warning)
177 putchar('\n');
178
179 memset(block_buffer, 0, sb.sb_sectsize);
180 sb.sb_inprogress = 0;
181 libxfs_sb_to_disk((xfs_dsb_t *)block_buffer, &sb);
182 if (xfs_sb_version_hascrc(&sb)) {
183 xfs_update_cksum(block_buffer, sb.sb_sectsize,
184 offsetof(struct xfs_sb, sb_crc));
185 }
186
187 if (pwrite(dst_fd, block_buffer, sb.sb_sectsize, 0) < 0)
188 fatal("error writing primary superblock: %s\n", strerror(errno));
189
190 free(metablock);
191 }
192
193 static void
194 usage(void)
195 {
196 fprintf(stderr, "Usage: %s [-V] [-g] source target\n", progname);
197 exit(1);
198 }
199
200 extern int platform_check_ismounted(char *, char *, struct stat64 *, int);
201
202 int
203 main(
204 int argc,
205 char **argv)
206 {
207 FILE *src_f;
208 int dst_fd;
209 int c;
210 int open_flags;
211 struct stat64 statbuf;
212 int is_target_file;
213
214 progname = basename(argv[0]);
215
216 while ((c = getopt(argc, argv, "gV")) != EOF) {
217 switch (c) {
218 case 'g':
219 show_progress = 1;
220 break;
221 case 'V':
222 printf("%s version %s\n", progname, VERSION);
223 exit(0);
224 default:
225 usage();
226 }
227 }
228
229 if (argc - optind != 2)
230 usage();
231
232 /* open source */
233 if (strcmp(argv[optind], "-") == 0) {
234 src_f = stdin;
235 if (isatty(fileno(stdin)))
236 fatal("cannot read from a terminal\n");
237 } else {
238 src_f = fopen(argv[optind], "rb");
239 if (src_f == NULL)
240 fatal("cannot open source dump file\n");
241 }
242 optind++;
243
244 /* check and open target */
245 open_flags = O_RDWR;
246 is_target_file = 0;
247 if (stat64(argv[optind], &statbuf) < 0) {
248 /* ok, assume it's a file and create it */
249 open_flags |= O_CREAT;
250 is_target_file = 1;
251 } else if (S_ISREG(statbuf.st_mode)) {
252 open_flags |= O_TRUNC;
253 is_target_file = 1;
254 } else {
255 /*
256 * check to make sure a filesystem isn't mounted on the device
257 */
258 if (platform_check_ismounted(argv[optind], NULL, &statbuf, 0))
259 fatal("a filesystem is mounted on target device \"%s\","
260 " cannot restore to a mounted filesystem.\n",
261 argv[optind]);
262 }
263
264 dst_fd = open(argv[optind], open_flags, 0644);
265 if (dst_fd < 0)
266 fatal("couldn't open target \"%s\"\n", argv[optind]);
267
268 perform_restore(src_f, dst_fd, is_target_file);
269
270 close(dst_fd);
271 if (src_f != stdin)
272 fclose(src_f);
273
274 return 0;
275 }