* Silence -Wold-style-definition (i.e., ansify).
[dragonfly.git] / sbin / jscan / dump_mirror.c
blob32cce39bc20d1d67f5c7da31242adc9815287cff
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:
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.
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.
34 * $DragonFly: src/sbin/jscan/dump_mirror.c,v 1.8 2005/11/06 12:32:56 swildner Exp $
37 #include "jscan.h"
38 #include <sys/vfscache.h>
40 static void dump_mirror_stream(struct jsession *ss, struct jstream *js);
41 static int dump_mirror_toprecord(struct jsession *ss, struct jstream *js,
42 off_t *off, off_t recsize, int level);
43 static int dump_mirror_subrecord(enum jdirection direction, struct jstream *js,
44 off_t *off, off_t recsize, int level,
45 struct jattr *jattr);
46 static int dump_mirror_payload(int16_t rectype, struct jstream *js, off_t off,
47 int recsize, int level, struct jattr *jattr);
48 static int dump_mirror_rebuild_redo(u_int16_t rectype,
49 struct jstream *js, struct jattr *jattr);
50 static int dump_mirror_rebuild_undo(u_int16_t rectype,
51 struct jstream *js, struct jattr *jattr);
52 static void undo_recreate(const char *filename,
53 struct jstream *js, struct jattr *jattr);
54 static void dosetattr(const char *filename, int fd, struct jattr *jattr);
56 void
57 dump_mirror(struct jsession *ss, struct jdata *jd)
59 struct jstream *js;
61 if ((js = jaddrecord(ss, jd)) != NULL) {
62 dump_mirror_stream(ss, js);
63 jscan_dispose(js);
65 jsession_update_transid(ss, jd->jd_transid);
68 static void
69 dump_mirror_stream(struct jsession *ss, struct jstream *js)
71 struct journal_rawrecbeg head;
72 int16_t sid;
73 mode_t save_umask;
75 save_umask = umask(0);
76 jsread(js, 0, &head, sizeof(head));
78 sid = head.streamid & JREC_STREAMID_MASK;
79 if (sid >= JREC_STREAMID_JMIN && sid < JREC_STREAMID_JMAX) {
80 off_t off = sizeof(head);
81 dump_mirror_toprecord(ss, js, &off,
82 js->js_normalized_total -
83 sizeof(struct journal_rawrecbeg),
84 1);
85 } else {
86 switch(head.streamid & JREC_STREAMID_MASK) {
87 case JREC_STREAMID_SYNCPT & JREC_STREAMID_MASK:
88 break;
89 case JREC_STREAMID_PAD & JREC_STREAMID_MASK:
90 break;
91 case JREC_STREAMID_DISCONT & JREC_STREAMID_MASK:
92 break;
93 case JREC_STREAMID_ANNOTATE & JREC_STREAMID_MASK:
94 break;
95 default:
96 break;
99 umask(save_umask);
103 * Execute a meta-transaction, e.g. something like 'WRITE'. Meta-transactions
104 * are almost universally nested.
106 static int
107 dump_mirror_toprecord(struct jsession *ss, struct jstream *js,
108 off_t *off, off_t recsize, int level)
110 struct journal_subrecord sub;
111 struct jattr jattr;
112 int payload;
113 int subsize;
114 int error;
115 off_t base = *off;
117 error = 0;
118 bzero(&jattr, sizeof(jattr));
119 jattr_reset(&jattr);
121 while (recsize > 0) {
122 if ((error = jsread(js, base, &sub, sizeof(sub))) != 0)
123 break;
124 if (sub.recsize == -1) {
125 if ((sub.rectype & JMASK_NESTED) == 0) {
126 printf("Record size of -1 only works for nested records\n");
127 error = -1;
128 break;
130 payload = 0x7FFFFFFF;
131 subsize = 0x7FFFFFFF;
132 } else {
133 payload = sub.recsize - sizeof(sub);
134 subsize = (sub.recsize + 7) & ~7;
136 if (sub.rectype & JMASK_NESTED) {
137 *off = base + sizeof(sub);
138 error = dump_mirror_subrecord(ss->ss_direction, js, off,
139 payload, level + 1, &jattr);
140 } else if (sub.rectype & JMASK_SUBRECORD) {
141 *off = base + sizeof(sub) + payload;
142 } else if ((sub.rectype & JTYPE_MASK) == JLEAF_PAD) {
143 } else {
145 if (ss->ss_direction == JD_FORWARDS)
146 dump_mirror_rebuild_redo(sub.rectype, js, &jattr);
147 else
148 dump_mirror_rebuild_undo(sub.rectype, js, &jattr);
149 jattr_reset(&jattr);
150 if (error)
151 break;
152 if (sub.recsize == -1) {
153 if ((sub.rectype & JMASK_NESTED) == 0) {
154 printf("Record size of -1 only works for nested records\n");
155 error = -1;
156 break;
158 recsize -= ((*off + 7) & ~7) - base;
159 base = (*off + 7) & ~7;
160 } else {
161 if (subsize == 0)
162 subsize = sizeof(sub);
163 recsize -= subsize;
164 base += subsize;
166 if (sub.rectype & JMASK_LAST)
167 break;
169 *off = base;
170 return(error);
174 * Parse a meta-transaction's nested records. The highest subrecord layer
175 * starts at layer = 2 (the top layer specifying the command is layer = 1).
177 * The nested subrecord contains informational records containing primarily
178 * namespace data, and further subrecords containing nested
179 * audit, undo, and redo data.
181 static int
182 dump_mirror_subrecord(enum jdirection direction, struct jstream *js,
183 off_t *off, off_t recsize, int level,
184 struct jattr *jattr)
186 struct journal_subrecord sub;
187 int payload;
188 int subsize;
189 int error;
190 int skip;
191 u_int16_t rectype;
192 off_t base = *off;
194 error = 0;
195 while (recsize > 0) {
196 if ((error = jsread(js, base, &sub, sizeof(sub))) != 0)
197 break;
198 rectype = sub.rectype & JTYPE_MASK; /* includes the nested bit */
199 if (sub.recsize == -1) {
200 payload = 0x7FFFFFFF;
201 subsize = 0x7FFFFFFF;
202 } else {
203 payload = sub.recsize - sizeof(sub);
204 subsize = (sub.recsize + 7) & ~7;
207 skip = 1;
208 *off = base + sizeof(sub);
210 switch(rectype) {
211 case JTYPE_REDO: /* NESTED */
213 * Process redo information when scanning forwards.
215 if (direction == JD_FORWARDS) {
216 error = dump_mirror_subrecord(direction, js, off, payload,
217 level + 1, jattr);
218 skip = 0;
220 break;
221 case JTYPE_UNDO: /* NESTED */
223 * Process undo information when scanning backwards.
225 if (direction == JD_BACKWARDS) {
226 error = dump_mirror_subrecord(direction, js, off, payload,
227 level + 1, jattr);
228 skip = 0;
230 break;
231 case JTYPE_CRED: /* NESTED */
233 * Ignore audit information
235 break;
236 default: /* NESTED or non-NESTED */
238 * Execute these. Nested records might contain attribute
239 * information under an UNDO or REDO parent, for example.
241 if (rectype & JMASK_NESTED) {
242 error = dump_mirror_subrecord(direction, js, off, payload,
243 level + 1, jattr);
244 skip = 0;
245 } else if (rectype & JMASK_SUBRECORD) {
246 error = dump_mirror_payload(sub.rectype, js, *off, payload,
247 level, jattr);
249 break;
251 if (error)
252 break;
255 * skip only applies to nested subrecords. If the record size
256 * is unknown the record MUST be a nested record, and if we have
257 * not processed it we must recurse to figure out the actual size.
259 if (sub.recsize == -1) {
260 assert(sub.rectype & JMASK_NESTED);
261 if (skip) {
262 error = dump_mirror_subrecord(direction, js, off, payload,
263 level + 1, NULL);
265 recsize -= ((*off + 7) & ~7) - base;
266 base = (*off + 7) & ~7;
267 } else {
268 if (subsize == 0)
269 subsize = sizeof(sub);
270 recsize -= subsize;
271 base += subsize;
273 if (error)
274 break;
275 if (sub.rectype & JMASK_LAST)
276 break;
278 *off = base;
279 return(error);
282 static int
283 dump_mirror_payload(int16_t rectype, struct jstream *js, off_t off,
284 int recsize, int level __unused, struct jattr *jattr)
286 const char *buf;
287 struct jattr_data *data;
288 int error;
290 if (jattr == NULL)
291 return (0);
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;
302 switch(rectype & ~JMASK_LAST) {
303 case JLEAF_PAD:
304 case JLEAF_ABORT:
305 break;
306 case JLEAF_SYMLINKDATA:
307 jattr->symlinkdata = dupdatastr(buf, recsize);
308 jattr->symlinklen = recsize;
309 break;
310 case JLEAF_FILEDATA:
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;
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;
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;
407 return (0);
410 static int
411 dump_mirror_rebuild_redo(u_int16_t rectype, struct jstream *js,
412 struct jattr *jattr)
414 struct jattr_data *data;
415 int error = 0;
416 int fd;
418 if (verbose_opt > 2) {
419 fprintf(stderr, "REDO %04x %s %s\n",
420 js->js_head->streamid, type_to_name(rectype),
421 jattr->pathref ? jattr->pathref : jattr->path1);
423 switch(rectype) {
424 case JTYPE_SETATTR:
425 if (jattr->pathref) {
426 if (jattr->uid != (uid_t)-1)
427 chown(jattr->pathref, jattr->uid, -1);
428 if (jattr->gid != (gid_t)-1)
429 chown(jattr->pathref, -1, jattr->gid);
430 if (jattr->modes != (mode_t)-1)
431 chmod(jattr->pathref, jattr->modes);
432 if (jattr->fflags != -1)
433 chflags(jattr->pathref, jattr->fflags);
434 if (jattr->size != -1)
435 truncate(jattr->pathref, jattr->size);
437 break;
438 case JTYPE_WRITE:
439 case JTYPE_PUTPAGES:
440 if (jattr->pathref && jattr->seekpos != -1) {
441 if ((fd = open(jattr->pathref, O_RDWR)) >= 0) {
442 lseek(fd, jattr->seekpos, 0);
443 for (data = &jattr->data; data; data = data->next) {
444 if (data->bytes)
445 jsreadcallback(js, write, fd, data->off, data->bytes);
447 close(fd);
450 break;
451 case JTYPE_SETACL:
452 break;
453 case JTYPE_SETEXTATTR:
454 break;
455 case JTYPE_CREATE:
457 * note: both path1 and pathref will exist.
459 if (jattr->path1 && jattr->modes != (mode_t)-1) {
460 if ((fd = open(jattr->path1, O_CREAT, jattr->modes)) >= 0) {
461 dosetattr(jattr->path1, fd, jattr);
462 close(fd);
465 break;
466 case JTYPE_MKNOD:
467 /* XXX */
468 break;
469 case JTYPE_LINK:
470 if (jattr->pathref && jattr->path1) {
471 link(jattr->pathref, jattr->path1);
473 break;
474 case JTYPE_SYMLINK:
475 if (jattr->symlinkdata && jattr->path1) {
476 symlink(jattr->symlinkdata, jattr->path1);
478 break;
479 case JTYPE_WHITEOUT:
480 break;
481 case JTYPE_REMOVE:
482 if (jattr->path1) {
483 remove(jattr->path1);
485 break;
486 case JTYPE_MKDIR:
487 if (jattr->path1 && jattr->modes != (mode_t)-1) {
488 mkdir(jattr->path1, jattr->modes);
490 break;
491 case JTYPE_RMDIR:
492 if (jattr->path1) {
493 rmdir(jattr->path1);
495 break;
496 case JTYPE_RENAME:
497 if (jattr->path1 && jattr->path2) {
498 rename(jattr->path1, jattr->path2);
500 break;
502 return(error);
506 * UNDO function using parsed primary data and parsed UNDO data. This
507 * must typically
509 static int
510 dump_mirror_rebuild_undo(u_int16_t rectype, struct jstream *js,
511 struct jattr *jattr)
513 struct jattr_data *data;
514 int error = 0;
515 int fd;
517 if (verbose_opt > 2) {
518 fprintf(stderr, "UNDO %04x %s %s\n",
519 js->js_head->streamid, type_to_name(rectype),
520 jattr->pathref ? jattr->pathref : jattr->path1);
522 switch(rectype) {
523 case JTYPE_SETATTR:
524 if (jattr->pathref)
525 dosetattr(jattr->pathref, -1, jattr);
526 break;
527 case JTYPE_WRITE:
528 case JTYPE_PUTPAGES:
529 if (jattr->pathref && jattr->seekpos != -1) {
530 if ((fd = open(jattr->pathref, O_RDWR)) >= 0) {
531 lseek(fd, jattr->seekpos, 0);
532 for (data = &jattr->data; data; data = data->next) {
533 if (data->bytes)
534 jsreadcallback(js, write, fd, data->off, data->bytes);
536 close(fd);
539 if (jattr->size != -1)
540 truncate(jattr->pathref, jattr->size);
541 break;
542 case JTYPE_SETACL:
543 break;
544 case JTYPE_SETEXTATTR:
545 break;
546 case JTYPE_CREATE:
548 * note: both path1 and pathref will exist.
550 if (jattr->path1)
551 remove(jattr->path1);
552 break;
553 case JTYPE_MKNOD:
554 if (jattr->path1)
555 remove(jattr->path1);
556 break;
557 case JTYPE_LINK:
558 if (jattr->path1) {
559 undo_recreate(jattr->path1, js, jattr);
561 break;
562 case JTYPE_SYMLINK:
563 if (jattr->symlinkdata && jattr->path1) {
564 undo_recreate(jattr->path1, js, jattr);
566 break;
567 case JTYPE_WHITEOUT:
568 /* XXX */
569 break;
570 case JTYPE_REMOVE:
571 if (jattr->path1) {
572 undo_recreate(jattr->path1, js, jattr);
574 break;
575 case JTYPE_MKDIR:
576 if (jattr->path1) {
577 rmdir(jattr->path1);
579 break;
580 case JTYPE_RMDIR:
581 if (jattr->path1 && jattr->modes != (mode_t)-1) {
582 mkdir(jattr->path1, jattr->modes);
584 break;
585 case JTYPE_RENAME:
586 if (jattr->path2) {
587 undo_recreate(jattr->path2, js, jattr);
589 break;
591 return(error);
595 * This is a helper function for undoing operations which completely destroy
596 * the file that had existed previously. The caller will clean up the
597 * attributes (including file truncations/extensions) after the fact.
599 static void
600 undo_recreate(const char *filename, struct jstream *js, struct jattr *jattr)
602 struct jattr_data *data;
603 int fd;
605 if (verbose_opt > 2)
606 fprintf(stderr, "RECREATE %s (type %d)\n", filename, jattr->vtype);
608 remove(filename);
609 switch(jattr->vtype) {
610 case VREG:
611 if (jattr->size != -1) {
612 if ((fd = open(filename, O_RDWR|O_CREAT|O_TRUNC, 0600)) >= 0) {
613 if (jattr->seekpos != -1) {
614 lseek(fd, jattr->seekpos, 0);
615 for (data = &jattr->data; data; data = data->next) {
616 if (data->bytes)
617 jsreadcallback(js, write, fd, data->off, data->bytes);
620 dosetattr(filename, fd, jattr);
621 close(fd);
624 break;
625 case VDIR:
626 mkdir(filename, 0600);
627 dosetattr(filename, -1, jattr);
628 break;
629 case VBLK:
630 case VCHR:
631 if (jattr->udev) {
632 mknod(filename, S_IFBLK|0666, jattr->udev);
633 dosetattr(filename, -1, jattr);
635 break;
636 case VLNK:
637 if (jattr->symlinkdata) {
638 symlink(jattr->symlinkdata, filename);
639 dosetattr(filename, -1, jattr);
641 break;
642 default:
643 break;
647 static void
648 dosetattr(const char *filename, int fd, struct jattr *jattr)
650 if (fd >= 0) {
651 if (jattr->uid != (uid_t)-1 && jattr->gid != (gid_t)-1)
652 fchown(fd, jattr->uid, jattr->gid);
653 else if (jattr->uid != (uid_t)-1)
654 fchown(fd, jattr->uid, -1);
655 else if (jattr->gid != (gid_t)-1)
656 fchown(fd, -1, jattr->gid);
658 if (jattr->modes != (mode_t)-1)
659 fchmod(fd, jattr->modes);
660 if (jattr->fflags != -1)
661 fchflags(fd, jattr->fflags);
662 if (jattr->size != -1)
663 ftruncate(fd, jattr->size);
664 } else {
665 if (jattr->uid != (uid_t)-1 && jattr->gid != (gid_t)-1)
666 lchown(filename, jattr->uid, jattr->gid);
667 else if (jattr->uid != (uid_t)-1)
668 lchown(filename, jattr->uid, -1);
669 else if (jattr->gid != (gid_t)-1)
670 lchown(filename, -1, jattr->gid);
672 if (jattr->modes != (mode_t)-1)
673 lchmod(filename, jattr->modes);
674 if (jattr->fflags != -1)
675 chflags(filename, jattr->fflags);
676 if (jattr->size != -1)
677 truncate(filename, jattr->size);