2 * Copyright (c) 2005 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@backplane.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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
34 * $DragonFly: src/sbin/jscan/dump_mirror.c,v 1.8 2005/11/06 12:32:56 swildner Exp $
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,
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);
57 dump_mirror(struct jsession *ss, struct jdata *jd)
61 if ((js = jaddrecord(ss, jd)) != NULL) {
62 dump_mirror_stream(ss, js);
65 jsession_update_transid(ss, jd->jd_transid);
69 dump_mirror_stream(struct jsession *ss, struct jstream *js)
71 struct journal_rawrecbeg head;
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),
86 switch(head.streamid & JREC_STREAMID_MASK) {
87 case JREC_STREAMID_SYNCPT & JREC_STREAMID_MASK:
89 case JREC_STREAMID_PAD & JREC_STREAMID_MASK:
91 case JREC_STREAMID_DISCONT & JREC_STREAMID_MASK:
93 case JREC_STREAMID_ANNOTATE & JREC_STREAMID_MASK:
103 * Execute a meta-transaction, e.g. something like 'WRITE'. Meta-transactions
104 * are almost universally nested.
107 dump_mirror_toprecord(struct jsession *ss, struct jstream *js,
108 off_t *off, off_t recsize, int level)
110 struct journal_subrecord sub;
118 bzero(&jattr, sizeof(jattr));
121 while (recsize > 0) {
122 if ((error = jsread(js, base, &sub, sizeof(sub))) != 0)
124 if (sub.recsize == -1) {
125 if ((sub.rectype & JMASK_NESTED) == 0) {
126 printf("Record size of -1 only works for nested records\n");
130 payload = 0x7FFFFFFF;
131 subsize = 0x7FFFFFFF;
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) {
145 if (ss->ss_direction == JD_FORWARDS)
146 dump_mirror_rebuild_redo(sub.rectype, js, &jattr);
148 dump_mirror_rebuild_undo(sub.rectype, js, &jattr);
152 if (sub.recsize == -1) {
153 if ((sub.rectype & JMASK_NESTED) == 0) {
154 printf("Record size of -1 only works for nested records\n");
158 recsize -= ((*off + 7) & ~7) - base;
159 base = (*off + 7) & ~7;
162 subsize = sizeof(sub);
166 if (sub.rectype & JMASK_LAST)
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.
182 dump_mirror_subrecord(enum jdirection direction, struct jstream *js,
183 off_t *off, off_t recsize, int level,
186 struct journal_subrecord sub;
195 while (recsize > 0) {
196 if ((error = jsread(js, base, &sub, sizeof(sub))) != 0)
198 rectype = sub.rectype & JTYPE_MASK; /* includes the nested bit */
199 if (sub.recsize == -1) {
200 payload = 0x7FFFFFFF;
201 subsize = 0x7FFFFFFF;
203 payload = sub.recsize - sizeof(sub);
204 subsize = (sub.recsize + 7) & ~7;
208 *off = base + sizeof(sub);
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,
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,
231 case JTYPE_CRED: /* NESTED */
233 * Ignore audit information
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,
245 } else if (rectype & JMASK_SUBRECORD) {
246 error = dump_mirror_payload(sub.rectype, js, *off, payload,
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);
262 error = dump_mirror_subrecord(direction, js, off, payload,
265 recsize -= ((*off + 7) & ~7) - base;
266 base = (*off + 7) & ~7;
269 subsize = sizeof(sub);
275 if (sub.rectype & JMASK_LAST)
283 dump_mirror_payload(int16_t rectype, struct jstream *js, off_t off,
284 int recsize, int level __unused, struct jattr *jattr)
287 struct jattr_data *data;
293 if ((rectype & ~JMASK_LAST) != JLEAF_FILEDATA) {
294 error = jsreadp(js, off, (const void **)&buf, recsize);
302 switch(rectype & ~JMASK_LAST) {
306 case JLEAF_SYMLINKDATA:
307 jattr->symlinkdata = dupdatastr(buf, recsize);
308 jattr->symlinklen = recsize;
311 if ((data = jattr->last_data) == NULL) {
312 jattr->data.off = off;
313 jattr->data.bytes = recsize;
314 jattr->last_data = &jattr->data;
316 data->next = malloc(sizeof(jattr->data));
319 data->bytes = recsize;
321 jattr->last_data = data;
325 jattr->path1 = dupdatapath(buf, recsize);
328 jattr->path2 = dupdatapath(buf, recsize);
331 jattr->path3 = dupdatapath(buf, recsize);
334 jattr->path4 = dupdatapath(buf, recsize);
337 jattr->uid = buf_to_int64(buf, recsize);
340 jattr->gid = buf_to_int64(buf, recsize);
343 jattr->vtype = buf_to_int64(buf, recsize);
346 jattr->modes = buf_to_int64(buf, recsize);
349 jattr->fflags = buf_to_int64(buf, recsize);
352 jattr->pid = buf_to_int64(buf, recsize);
355 jattr->ppid = buf_to_int64(buf, recsize);
358 jattr->comm = dupdatastr(buf, recsize);
361 jattr->attrname = dupdatastr(buf, recsize);
364 jattr->pathref = dupdatapath(buf, recsize);
366 case JLEAF_RESERVED_0F:
369 jattr->seekpos = buf_to_int64(buf, recsize);
372 jattr->inum = buf_to_int64(buf, recsize);
375 jattr->nlink = buf_to_int64(buf, recsize);
378 jattr->fsid = buf_to_int64(buf, recsize);
381 jattr->size = buf_to_int64(buf, recsize);
384 jattr->atime = *(const struct timeval *)buf;
387 jattr->mtime = *(const struct timeval *)buf;
390 jattr->ctime = *(const struct timeval *)buf;
393 jattr->gen = buf_to_int64(buf, recsize);
396 jattr->flags = buf_to_int64(buf, recsize);
399 jattr->udev = buf_to_int64(buf, recsize);
402 jattr->filerev = buf_to_int64(buf, recsize);
411 dump_mirror_rebuild_redo(u_int16_t rectype, struct jstream *js,
414 struct jattr_data *data;
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);
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);
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) {
445 jsreadcallback(js, write, fd, data->off, data->bytes);
453 case JTYPE_SETEXTATTR:
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);
470 if (jattr->pathref && jattr->path1) {
471 link(jattr->pathref, jattr->path1);
475 if (jattr->symlinkdata && jattr->path1) {
476 symlink(jattr->symlinkdata, jattr->path1);
483 remove(jattr->path1);
487 if (jattr->path1 && jattr->modes != (mode_t)-1) {
488 mkdir(jattr->path1, jattr->modes);
497 if (jattr->path1 && jattr->path2) {
498 rename(jattr->path1, jattr->path2);
506 * UNDO function using parsed primary data and parsed UNDO data. This
510 dump_mirror_rebuild_undo(u_int16_t rectype, struct jstream *js,
513 struct jattr_data *data;
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);
525 dosetattr(jattr->pathref, -1, jattr);
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) {
534 jsreadcallback(js, write, fd, data->off, data->bytes);
539 if (jattr->size != -1)
540 truncate(jattr->pathref, jattr->size);
544 case JTYPE_SETEXTATTR:
548 * note: both path1 and pathref will exist.
551 remove(jattr->path1);
555 remove(jattr->path1);
559 undo_recreate(jattr->path1, js, jattr);
563 if (jattr->symlinkdata && jattr->path1) {
564 undo_recreate(jattr->path1, js, jattr);
572 undo_recreate(jattr->path1, js, jattr);
581 if (jattr->path1 && jattr->modes != (mode_t)-1) {
582 mkdir(jattr->path1, jattr->modes);
587 undo_recreate(jattr->path2, js, jattr);
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.
600 undo_recreate(const char *filename, struct jstream *js, struct jattr *jattr)
602 struct jattr_data *data;
606 fprintf(stderr, "RECREATE %s (type %d)\n", filename, jattr->vtype);
609 switch(jattr->vtype) {
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) {
617 jsreadcallback(js, write, fd, data->off, data->bytes);
620 dosetattr(filename, fd, jattr);
626 mkdir(filename, 0600);
627 dosetattr(filename, -1, jattr);
632 mknod(filename, S_IFBLK|0666, jattr->udev);
633 dosetattr(filename, -1, jattr);
637 if (jattr->symlinkdata) {
638 symlink(jattr->symlinkdata, filename);
639 dosetattr(filename, -1, jattr);
648 dosetattr(const char *filename, int fd, struct jattr *jattr)
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);
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);