Add support for mirroring symlinks and hardlinks.
[dragonfly.git] / sbin / jscan / dump_mirror.c
CommitLineData
712e03b0
MD
1/*
2 * Copyright (c) 2005 The DragonFly Project. All rights reserved.
3 *
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@backplane.com>
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
fa8f36eb 34 * $DragonFly: src/sbin/jscan/dump_mirror.c,v 1.4 2005/07/05 06:20:07 dillon Exp $
712e03b0
MD
35 */
36
37#include "jscan.h"
38
39static void dump_mirror_stream(struct jstream *js);
40static int dump_mirror_toprecord(struct jstream *js, off_t *off,
41 off_t recsize, int level);
42static int dump_mirror_subrecord(struct jstream *js, off_t *off,
43 off_t recsize, int level, struct jattr *jattr);
44static int dump_mirror_payload(int16_t rectype, struct jstream *js, off_t off,
45 int recsize, int level, struct jattr *jattr);
36d6bdee 46static int dump_mirror_rebuild(u_int16_t rectype, struct jstream *js, struct jattr *jattr);
712e03b0
MD
47
48void
49dump_mirror(struct jfile *jf)
50{
51 struct jstream *js;
52
53 while ((js = jscan_stream(jf)) != NULL) {
54 dump_mirror_stream(js);
55 jscan_dispose(js);
56 }
57}
58
59static void
60dump_mirror_stream(struct jstream *js)
61{
62 struct journal_rawrecbeg head;
63 int16_t sid;
64 mode_t save_umask;
65
66 save_umask = umask(0);
67 jsread(js, 0, &head, sizeof(head));
68
69 sid = head.streamid & JREC_STREAMID_MASK;
36d6bdee
MD
70 if (debug_opt) {
71 printf("STREAM %04x DATA (%lld) {\n",
72 (int)(u_int16_t)head.streamid, js->js_normalized_total);
73 }
712e03b0
MD
74 if (sid >= JREC_STREAMID_JMIN && sid < JREC_STREAMID_JMAX) {
75 off_t off = sizeof(head);
76 dump_mirror_toprecord(js, &off, js->js_normalized_total -
77 sizeof(struct journal_rawrecbeg),
78 1);
79 } else {
80 switch(head.streamid & JREC_STREAMID_MASK) {
81 case JREC_STREAMID_SYNCPT & JREC_STREAMID_MASK:
82 if (debug_opt)
83 printf(" SYNCPT\n");
84 break;
85 case JREC_STREAMID_PAD & JREC_STREAMID_MASK:
86 if (debug_opt)
87 printf(" PAD\n");
88 break;
89 case JREC_STREAMID_DISCONT & JREC_STREAMID_MASK:
90 if (debug_opt)
91 printf(" DISCONT\n");
92 break;
93 case JREC_STREAMID_ANNOTATE & JREC_STREAMID_MASK:
94 if (debug_opt)
95 printf(" ANNOTATION\n");
96 break;
97 default:
98 if (debug_opt)
99 printf(" UNKNOWN\n");
100 break;
101 }
102 }
103 umask(save_umask);
36d6bdee 104 if (debug_opt) {
712e03b0 105 printf("}\n");
36d6bdee
MD
106 fflush(stdout);
107 }
712e03b0
MD
108}
109
110static int
111dump_mirror_toprecord(struct jstream *js, off_t *off, off_t recsize, int level)
112{
113 struct journal_subrecord sub;
114 struct jattr jattr;
115 int payload;
116 int subsize;
117 int error;
118 off_t base = *off;
119
120 error = 0;
121 bzero(&jattr, sizeof(jattr));
122 jattr_reset(&jattr);
123
124 while (recsize > 0) {
125 if ((error = jsread(js, base, &sub, sizeof(sub))) != 0)
126 break;
127 if (debug_opt) {
128 printf("%*.*s", level * 4, level * 4, "");
129 printf("@%lld ", base);
130 printf("RECORD %s [%04x/%d]", type_to_name(sub.rectype),
131 (int)(u_int16_t)sub.rectype, sub.recsize);
132 }
133 if (sub.recsize == -1) {
134 if ((sub.rectype & JMASK_NESTED) == 0) {
135 printf("Record size of -1 only works for nested records\n");
136 error = -1;
137 break;
138 }
139 payload = 0x7FFFFFFF;
140 subsize = 0x7FFFFFFF;
141 } else {
142 payload = sub.recsize - sizeof(sub);
143 subsize = (sub.recsize + 7) & ~7;
144 }
145 if (sub.rectype & JMASK_NESTED) {
146 if (debug_opt)
147 printf(" {\n");
148 *off = base + sizeof(sub);
149 error = dump_mirror_subrecord(js, off,
150 payload, level + 1, &jattr);
151 if (debug_opt)
152 printf("%*.*s}\n", level * 4, level * 4, "");
153 } else if (sub.rectype & JMASK_SUBRECORD) {
154 if (debug_opt) {
155 printf(" DATA (%d)", payload);
156 error = dump_debug_payload(sub.rectype, js, base + sizeof(sub), payload, level);
157 }
158 *off = base + sizeof(sub) + payload;
159 if (debug_opt)
160 printf("\n");
36d6bdee
MD
161 } else if ((sub.rectype & JTYPE_MASK) == JLEAF_PAD) {
162 if (debug_opt) {
163 if (payload)
164 printf(" DATA (%d)", payload);
165 printf("\n");
166 }
712e03b0
MD
167 } else {
168 if (debug_opt)
36d6bdee 169 printf("[%d bytes of unknown content]\n", payload);
712e03b0 170 }
36d6bdee 171 dump_mirror_rebuild(sub.rectype, js, &jattr);
712e03b0
MD
172 jattr_reset(&jattr);
173 if (error)
174 break;
175 if (sub.recsize == -1) {
176 if ((sub.rectype & JMASK_NESTED) == 0) {
177 printf("Record size of -1 only works for nested records\n");
178 error = -1;
179 break;
180 }
181 recsize -= ((*off + 7) & ~7) - base;
182 base = (*off + 7) & ~7;
183 } else {
184 if (subsize == 0)
185 subsize = sizeof(sub);
186 recsize -= subsize;
187 base += subsize;
188 }
189 if (sub.rectype & JMASK_LAST)
190 break;
191 }
192 *off = base;
193 return(error);
194}
195
196static int
197dump_mirror_subrecord(struct jstream *js, off_t *off, off_t recsize, int level,
198 struct jattr *jattr)
199{
200 struct journal_subrecord sub;
201 int payload;
202 int subsize;
203 int error;
204 u_int16_t rectype;
205 off_t base = *off;
206
207 error = 0;
208 while (recsize > 0) {
209 if ((error = jsread(js, base, &sub, sizeof(sub))) != 0)
210 break;
211 rectype = sub.rectype & JTYPE_MASK;
212 if (debug_opt) {
213 printf("%*.*s", level * 4, level * 4, "");
214 printf("@%lld ", base);
36d6bdee 215 printf("SRECORD %s [%04x/%d]", type_to_name(sub.rectype),
712e03b0
MD
216 (int)(u_int16_t)sub.rectype, sub.recsize);
217 }
218 if (sub.recsize == -1) {
219 payload = 0x7FFFFFFF;
220 subsize = 0x7FFFFFFF;
221 } else {
222 payload = sub.recsize - sizeof(sub);
223 subsize = (sub.recsize + 7) & ~7;
224 }
225 if (sub.rectype & JMASK_NESTED) {
226 if (debug_opt)
227 printf(" {\n");
228
229 /*
230 * Only recurse through vattr records. XXX currently assuming
231 * only on VATTR subrecord.
232 */
233 *off = base + sizeof(sub);
234 if (payload && rectype == JTYPE_VATTR) {
235 error = dump_mirror_subrecord(js, off,
236 payload, level + 1, jattr);
237 } else {
238 error = dump_mirror_subrecord(js, off,
239 payload, level + 1, NULL);
240 }
241 if (debug_opt)
242 printf("%*.*s}\n", level * 4, level * 4, "");
243 } else if (sub.rectype & JMASK_SUBRECORD) {
244 if (debug_opt) {
245 printf(" DATA (%d)", payload);
246 dump_debug_payload(sub.rectype, js, base + sizeof(sub),
247 payload, level);
248 }
249 error = dump_mirror_payload(sub.rectype, js, base + sizeof(sub),
250 payload, level, jattr);
251 *off = base + sizeof(sub) + payload;
252 if (debug_opt)
253 printf("\n");
36d6bdee
MD
254 } else if ((sub.rectype & JTYPE_MASK) == JLEAF_PAD) {
255 if (debug_opt) {
256 if (payload)
257 printf(" DATA (%d)", payload);
258 printf("\n");
259 }
712e03b0
MD
260 } else {
261 if (debug_opt)
262 printf("[%d bytes of unknown content]\n", sub.recsize);
263 }
264 if (error)
265 break;
266 if (sub.recsize == -1) {
267 recsize -= ((*off + 7) & ~7) - base;
268 base = (*off + 7) & ~7;
269 } else {
270 if (subsize == 0)
271 subsize = sizeof(sub);
272 recsize -= subsize;
273 base += subsize;
274 }
275 if (sub.rectype & JMASK_LAST)
276 break;
277 }
278 *off = base;
279 return(error);
280}
281
282static int
283dump_mirror_payload(int16_t rectype, struct jstream *js, off_t off,
284 int recsize, int level __unused, struct jattr *jattr)
285{
286 const char *buf;
36d6bdee 287 struct jattr_data *data;
712e03b0
MD
288 int error;
289
290 if (jattr == NULL)
291 return (0);
292
36d6bdee
MD
293 if ((rectype & ~JMASK_LAST) != JLEAF_FILEDATA) {
294 error = jsreadp(js, off, (const void **)&buf, recsize);
295 if (error)
296 return (error);
297 } else {
298 buf = NULL;
299 error = 0;
300 }
712e03b0
MD
301
302 switch(rectype & ~JMASK_LAST) {
303 case JLEAF_PAD:
304 case JLEAF_ABORT:
305 break;
36d6bdee 306 case JLEAF_SYMLINKDATA:
fa8f36eb
MD
307 jattr->symlinkdata = dupdatastr(buf, recsize);
308 jattr->symlinklen = recsize;
309 break;
712e03b0 310 case JLEAF_FILEDATA:
36d6bdee
MD
311 if ((data = jattr->last_data) == NULL) {
312 jattr->data.off = off;
313 jattr->data.bytes = recsize;
314 jattr->last_data = &jattr->data;
315 } else {
316 data->next = malloc(sizeof(jattr->data));
317 data = data->next;
318 data->off = off;
319 data->bytes = recsize;
320 data->next = NULL;
321 jattr->last_data = data;
322 }
712e03b0
MD
323 break;
324 case JLEAF_PATH1:
325 jattr->path1 = dupdatapath(buf, recsize);
326 break;
327 case JLEAF_PATH2:
328 jattr->path2 = dupdatapath(buf, recsize);
329 break;
330 case JLEAF_PATH3:
331 jattr->path3 = dupdatapath(buf, recsize);
332 break;
333 case JLEAF_PATH4:
334 jattr->path4 = dupdatapath(buf, recsize);
335 break;
336 case JLEAF_UID:
337 jattr->uid = buf_to_int64(buf, recsize);
338 break;
339 case JLEAF_GID:
340 jattr->gid = buf_to_int64(buf, recsize);
341 break;
342 case JLEAF_VTYPE:
343 jattr->vtype = buf_to_int64(buf, recsize);
344 break;
345 case JLEAF_MODES:
346 jattr->modes = buf_to_int64(buf, recsize);
347 break;
348 case JLEAF_FFLAGS:
349 jattr->fflags = buf_to_int64(buf, recsize);
350 break;
351 case JLEAF_PID:
352 jattr->pid = buf_to_int64(buf, recsize);
353 break;
354 case JLEAF_PPID:
355 jattr->ppid = buf_to_int64(buf, recsize);
356 break;
357 case JLEAF_COMM:
358 jattr->comm = dupdatastr(buf, recsize);
359 break;
360 case JLEAF_ATTRNAME:
361 jattr->attrname = dupdatastr(buf, recsize);
362 break;
363 case JLEAF_PATH_REF:
364 jattr->pathref = dupdatapath(buf, recsize);
365 break;
366 case JLEAF_RESERVED_0F:
367 break;
712e03b0
MD
368 case JLEAF_SEEKPOS:
369 jattr->seekpos = buf_to_int64(buf, recsize);
370 break;
371 case JLEAF_INUM:
372 jattr->inum = buf_to_int64(buf, recsize);
373 break;
374 case JLEAF_NLINK:
375 jattr->nlink = buf_to_int64(buf, recsize);
376 break;
377 case JLEAF_FSID:
378 jattr->fsid = buf_to_int64(buf, recsize);
379 break;
380 case JLEAF_SIZE:
381 jattr->size = buf_to_int64(buf, recsize);
382 break;
383 case JLEAF_ATIME:
384 jattr->atime = *(const struct timeval *)buf;
385 break;
386 case JLEAF_MTIME:
387 jattr->mtime = *(const struct timeval *)buf;
388 break;
389 case JLEAF_CTIME:
390 jattr->ctime = *(const struct timeval *)buf;
391 break;
392 case JLEAF_GEN:
393 jattr->gen = buf_to_int64(buf, recsize);
394 break;
395 case JLEAF_FLAGS:
396 jattr->flags = buf_to_int64(buf, recsize);
397 break;
398 case JLEAF_UDEV:
399 jattr->udev = buf_to_int64(buf, recsize);
400 break;
401 case JLEAF_FILEREV:
402 jattr->filerev = buf_to_int64(buf, recsize);
403 break;
404 default:
405 break;
406 }
407 return (0);
408}
409
410static int
36d6bdee 411dump_mirror_rebuild(u_int16_t rectype, struct jstream *js, struct jattr *jattr)
712e03b0 412{
36d6bdee 413 struct jattr_data *data;
712e03b0
MD
414 int error = 0;
415 int fd;
416
417again:
418 switch(rectype) {
419 case JTYPE_SETATTR:
420 if (jattr->pathref) {
421 if (jattr->uid != (uid_t)-1)
422 chown(jattr->pathref, jattr->uid, -1);
423 if (jattr->gid != (gid_t)-1)
424 chown(jattr->pathref, -1, jattr->gid);
425 if (jattr->modes != (mode_t)-1)
426 chmod(jattr->pathref, jattr->modes);
427 if (jattr->fflags != -1)
428 chflags(jattr->pathref, jattr->fflags);
429 if (jattr->size != -1)
430 truncate(jattr->pathref, jattr->size);
431 }
432 break;
433 case JTYPE_WRITE:
434 case JTYPE_PUTPAGES:
36d6bdee 435 if (jattr->pathref && jattr->seekpos != -1) {
712e03b0
MD
436 if ((fd = open(jattr->pathref, O_RDWR)) >= 0) {
437 lseek(fd, jattr->seekpos, 0);
36d6bdee 438 for (data = &jattr->data; data; data = data->next) {
36d6bdee
MD
439 if (data->bytes)
440 jsreadcallback(js, write, fd, data->off, data->bytes);
441 }
712e03b0
MD
442 close(fd);
443 }
444 }
445 break;
446 case JTYPE_SETACL:
447 break;
448 case JTYPE_SETEXTATTR:
449 break;
450 case JTYPE_CREATE:
451 /*
452 * note: both path1 and pathref will exist.
453 */
454 if (jattr->path1 && jattr->modes != (mode_t)-1) {
455 if ((fd = open(jattr->path1, O_CREAT, jattr->modes)) >= 0) {
456 close(fd);
457 rectype = JTYPE_SETATTR;
458 goto again;
459 }
460 }
461 break;
462 case JTYPE_MKNOD:
463 break;
464 case JTYPE_LINK:
fa8f36eb
MD
465 if (jattr->pathref && jattr->path1) {
466 link(jattr->pathref, jattr->path1);
467 }
712e03b0
MD
468 break;
469 case JTYPE_SYMLINK:
fa8f36eb
MD
470 if (jattr->symlinkdata && jattr->path1) {
471 symlink(jattr->symlinkdata, jattr->path1);
472 }
712e03b0
MD
473 break;
474 case JTYPE_WHITEOUT:
475 break;
476 case JTYPE_REMOVE:
477 if (jattr->path1) {
478 remove(jattr->path1);
479 }
480 break;
481 case JTYPE_MKDIR:
482 if (jattr->path1 && jattr->modes != (mode_t)-1) {
483 mkdir(jattr->path1, jattr->modes);
484 }
485 break;
486 case JTYPE_RMDIR:
487 if (jattr->path1) {
488 rmdir(jattr->path1);
489 }
490 break;
491 case JTYPE_RENAME:
492 if (jattr->path1 && jattr->path2) {
493 rename(jattr->path1, jattr->path2);
494 }
495 break;
496 }
497 return(error);
498}
499