Major continuing work on jscan, the userland backend for the journaling
[dragonfly.git] / sbin / jscan / dump_mirror.c
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  * 
34  * $DragonFly: src/sbin/jscan/dump_mirror.c,v 1.1 2005/07/05 00:26:03 dillon Exp $
35  */
36
37 #include "jscan.h"
38
39 static void dump_mirror_stream(struct jstream *js);
40 static int dump_mirror_toprecord(struct jstream *js, off_t *off, 
41                                  off_t recsize, int level);
42 static int dump_mirror_subrecord(struct jstream *js, off_t *off, 
43                                  off_t recsize, int level, struct jattr *jattr);
44 static int dump_mirror_payload(int16_t rectype, struct jstream *js, off_t off,
45                                  int recsize, int level, struct jattr *jattr);
46 static int dump_mirror_rebuild(u_int16_t rectype, struct jattr *jattr);
47
48 void
49 dump_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
59 static void
60 dump_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;
70         if (debug_opt)
71             printf("STREAM %04x {\n", (int)(u_int16_t)head.streamid);
72         if (sid >= JREC_STREAMID_JMIN && sid < JREC_STREAMID_JMAX) {
73             off_t off = sizeof(head);
74             dump_mirror_toprecord(js, &off, js->js_normalized_total -
75                                   sizeof(struct journal_rawrecbeg), 
76                                   1);
77         } else {
78             switch(head.streamid & JREC_STREAMID_MASK) {
79             case JREC_STREAMID_SYNCPT & JREC_STREAMID_MASK:
80                 if (debug_opt)
81                     printf("    SYNCPT\n");
82                 break;
83             case JREC_STREAMID_PAD & JREC_STREAMID_MASK:
84                 if (debug_opt)
85                     printf("    PAD\n");
86                 break;
87             case JREC_STREAMID_DISCONT & JREC_STREAMID_MASK:
88                 if (debug_opt)
89                     printf("    DISCONT\n");
90                 break;
91             case JREC_STREAMID_ANNOTATE & JREC_STREAMID_MASK:
92                 if (debug_opt)
93                     printf("    ANNOTATION\n");
94                 break;
95             default:
96                 if (debug_opt)
97                     printf("    UNKNOWN\n");
98                 break;
99             }
100         }
101         umask(save_umask);
102         if (debug_opt)
103             printf("}\n");
104 }
105
106 static int
107 dump_mirror_toprecord(struct jstream *js, off_t *off, off_t recsize, int level)
108 {
109     struct journal_subrecord sub;
110     struct jattr jattr;
111     int payload;
112     int subsize;
113     int error;
114     off_t base = *off;
115
116     error = 0;
117     bzero(&jattr, sizeof(jattr));
118     jattr_reset(&jattr);
119
120     while (recsize > 0) {
121         if ((error = jsread(js, base, &sub, sizeof(sub))) != 0)
122             break;
123         if (debug_opt) {
124             printf("%*.*s", level * 4, level * 4, "");
125             printf("@%lld ", base);
126             printf("RECORD %s [%04x/%d]", type_to_name(sub.rectype), 
127                    (int)(u_int16_t)sub.rectype, sub.recsize);
128         }
129         if (sub.recsize == -1) {
130             if ((sub.rectype & JMASK_NESTED) == 0) {
131                 printf("Record size of -1 only works for nested records\n");
132                 error = -1;
133                 break;
134             }
135             payload = 0x7FFFFFFF;
136             subsize = 0x7FFFFFFF;
137         } else {
138             payload = sub.recsize - sizeof(sub);
139             subsize = (sub.recsize + 7) & ~7;
140         }
141         if (sub.rectype & JMASK_NESTED) {
142             if (debug_opt)
143                 printf(" {\n");
144             *off = base + sizeof(sub);
145             error = dump_mirror_subrecord(js, off,
146                                           payload, level + 1, &jattr);
147             if (debug_opt)
148                 printf("%*.*s}\n", level * 4, level * 4, "");
149         } else if (sub.rectype & JMASK_SUBRECORD) {
150             if (debug_opt) {
151                 printf(" DATA (%d)", payload);
152                 error = dump_debug_payload(sub.rectype, js, base + sizeof(sub), payload, level);
153             }
154             *off = base + sizeof(sub) + payload;
155             if (debug_opt)
156                 printf("\n");
157         } else {
158             if (debug_opt)
159                 printf("[%d bytes of unknown content]\n", sub.recsize);
160         }
161         dump_mirror_rebuild(sub.rectype, &jattr);
162         jattr_reset(&jattr);
163         if (error)
164             break;
165         if (sub.recsize == -1) {
166             if ((sub.rectype & JMASK_NESTED) == 0) {
167                 printf("Record size of -1 only works for nested records\n");
168                 error = -1;
169                 break;
170             }
171             recsize -= ((*off + 7) & ~7) - base;
172             base = (*off + 7) & ~7;
173         } else {
174             if (subsize == 0)
175                 subsize = sizeof(sub);
176             recsize -= subsize;
177             base += subsize;
178         }
179         if (sub.rectype & JMASK_LAST)
180             break;
181     }
182     *off = base;
183     return(error);
184 }
185
186 static int
187 dump_mirror_subrecord(struct jstream *js, off_t *off, off_t recsize, int level,
188                       struct jattr *jattr)
189 {
190     struct journal_subrecord sub;
191     int payload;
192     int subsize;
193     int error;
194     u_int16_t rectype;
195     off_t base = *off;
196
197     error = 0;
198     while (recsize > 0) {
199         if ((error = jsread(js, base, &sub, sizeof(sub))) != 0)
200             break;
201         rectype = sub.rectype & JTYPE_MASK;
202         if (debug_opt) {
203             printf("%*.*s", level * 4, level * 4, "");
204             printf("@%lld ", base);
205             printf("RECORD %s [%04x/%d]", type_to_name(sub.rectype), 
206                    (int)(u_int16_t)sub.rectype, sub.recsize);
207         }
208         if (sub.recsize == -1) {
209             payload = 0x7FFFFFFF;
210             subsize = 0x7FFFFFFF;
211         } else {
212             payload = sub.recsize - sizeof(sub);
213             subsize = (sub.recsize + 7) & ~7;
214         }
215         if (sub.rectype & JMASK_NESTED) {
216             if (debug_opt)
217                 printf(" {\n");
218
219             /*
220              * Only recurse through vattr records.  XXX currently assuming
221              * only on VATTR subrecord.
222              */
223             *off = base + sizeof(sub);
224             if (payload && rectype == JTYPE_VATTR) {
225                 error = dump_mirror_subrecord(js, off, 
226                                               payload, level + 1, jattr);
227             } else {
228                 error = dump_mirror_subrecord(js, off, 
229                                               payload, level + 1, NULL);
230             }
231             if (debug_opt)
232                 printf("%*.*s}\n", level * 4, level * 4, "");
233         } else if (sub.rectype & JMASK_SUBRECORD) {
234             if (debug_opt) {
235                 printf(" DATA (%d)", payload);
236                 dump_debug_payload(sub.rectype, js, base + sizeof(sub), 
237                                    payload, level);
238             }
239             error = dump_mirror_payload(sub.rectype, js, base + sizeof(sub),
240                                        payload, level, jattr);
241             *off = base + sizeof(sub) + payload;
242             if (debug_opt)
243                 printf("\n");
244         } else {
245             if (debug_opt)
246                 printf("[%d bytes of unknown content]\n", sub.recsize);
247         }
248         if (error)
249             break;
250         if (sub.recsize == -1) {
251             recsize -= ((*off + 7) & ~7) - base;
252             base = (*off + 7) & ~7;
253         } else {
254             if (subsize == 0)
255                 subsize = sizeof(sub);
256             recsize -= subsize;
257             base += subsize;
258         }
259         if (sub.rectype & JMASK_LAST)
260             break;
261     }
262     *off = base;
263     return(error);
264 }
265
266 static int
267 dump_mirror_payload(int16_t rectype, struct jstream *js, off_t off, 
268              int recsize, int level __unused, struct jattr *jattr)
269 {
270     const char *buf;
271     int error;
272
273     if (jattr == NULL)
274         return (0);
275
276     error = jsreadp(js, off, (const void **)&buf, recsize);
277     if (error)
278         return (error);
279
280     switch(rectype & ~JMASK_LAST) {
281     case JLEAF_PAD:
282     case JLEAF_ABORT:
283         break;
284     case JLEAF_FILEDATA:
285         jattr->data = dupdata(buf, recsize);
286         jattr->datalen = recsize;
287         break;
288     case JLEAF_PATH1:
289         jattr->path1 = dupdatapath(buf, recsize);
290         break;
291     case JLEAF_PATH2:
292         jattr->path2 = dupdatapath(buf, recsize);
293         break;
294     case JLEAF_PATH3:
295         jattr->path3 = dupdatapath(buf, recsize);
296         break;
297     case JLEAF_PATH4:
298         jattr->path4 = dupdatapath(buf, recsize);
299         break;
300     case JLEAF_UID:
301         jattr->uid = buf_to_int64(buf, recsize);
302         break;
303     case JLEAF_GID:
304         jattr->gid = buf_to_int64(buf, recsize);
305         break;
306     case JLEAF_VTYPE:
307         jattr->vtype = buf_to_int64(buf, recsize);
308         break;
309     case JLEAF_MODES:
310         jattr->modes = buf_to_int64(buf, recsize);
311         break;
312     case JLEAF_FFLAGS:
313         jattr->fflags = buf_to_int64(buf, recsize);
314         break;
315     case JLEAF_PID:
316         jattr->pid = buf_to_int64(buf, recsize);
317         break;
318     case JLEAF_PPID:
319         jattr->ppid = buf_to_int64(buf, recsize);
320         break;
321     case JLEAF_COMM:
322         jattr->comm = dupdatastr(buf, recsize);
323         break;
324     case JLEAF_ATTRNAME:
325         jattr->attrname = dupdatastr(buf, recsize);
326         break;
327     case JLEAF_PATH_REF:
328         jattr->pathref = dupdatapath(buf, recsize);
329         break;
330     case JLEAF_RESERVED_0F:
331         break;
332     case JLEAF_SYMLINKDATA:
333         jattr->data = dupdata(buf, recsize);
334         jattr->datalen = recsize;
335         break;
336     case JLEAF_SEEKPOS:
337         jattr->seekpos = buf_to_int64(buf, recsize);
338         break;
339     case JLEAF_INUM:
340         jattr->inum = buf_to_int64(buf, recsize);
341         break;
342     case JLEAF_NLINK:
343         jattr->nlink = buf_to_int64(buf, recsize);
344         break;
345     case JLEAF_FSID:
346         jattr->fsid = buf_to_int64(buf, recsize);
347         break;
348     case JLEAF_SIZE:
349         jattr->size = buf_to_int64(buf, recsize);
350         break;
351     case JLEAF_ATIME:
352         jattr->atime = *(const struct timeval *)buf;
353         break;
354     case JLEAF_MTIME:
355         jattr->mtime = *(const struct timeval *)buf;
356         break;
357     case JLEAF_CTIME:
358         jattr->ctime = *(const struct timeval *)buf;
359         break;
360     case JLEAF_GEN:
361         jattr->gen = buf_to_int64(buf, recsize);
362         break;
363     case JLEAF_FLAGS:
364         jattr->flags = buf_to_int64(buf, recsize);
365         break;
366     case JLEAF_UDEV:
367         jattr->udev = buf_to_int64(buf, recsize);
368         break;
369     case JLEAF_FILEREV:
370         jattr->filerev = buf_to_int64(buf, recsize);
371         break;
372     default:
373         break;
374     }
375     return (0);
376 }
377
378 static int
379 dump_mirror_rebuild(u_int16_t rectype, struct jattr *jattr)
380 {
381     int error = 0;
382     int fd;
383
384 again:
385     switch(rectype) {
386     case JTYPE_SETATTR:
387         if (jattr->pathref) {
388             if (jattr->uid != (uid_t)-1)
389                 chown(jattr->pathref, jattr->uid, -1);
390             if (jattr->gid != (gid_t)-1)
391                 chown(jattr->pathref, -1, jattr->gid);
392             if (jattr->modes != (mode_t)-1)
393                 chmod(jattr->pathref, jattr->modes);
394             if (jattr->fflags != -1)
395                 chflags(jattr->pathref, jattr->fflags);
396             if (jattr->size != -1)
397                 truncate(jattr->pathref, jattr->size);
398         }
399         break;
400     case JTYPE_WRITE:
401     case JTYPE_PUTPAGES:
402         if (jattr->pathref && jattr->seekpos != -1 && jattr->data) {
403             if ((fd = open(jattr->pathref, O_RDWR)) >= 0) {
404                 lseek(fd, jattr->seekpos, 0);
405                 write(fd, jattr->data, jattr->datalen);
406                 close(fd);
407             }
408         }
409         break;
410     case JTYPE_SETACL:
411         break;
412     case JTYPE_SETEXTATTR:
413         break;
414     case JTYPE_CREATE:
415         /*
416          * note: both path1 and pathref will exist.
417          */
418         if (jattr->path1 && jattr->modes != (mode_t)-1) {
419             if ((fd = open(jattr->path1, O_CREAT, jattr->modes)) >= 0) {
420                 close(fd);
421                 rectype = JTYPE_SETATTR;
422                 goto again;
423             }
424         }
425         break;
426     case JTYPE_MKNOD:
427         break;
428     case JTYPE_LINK:
429         break;
430     case JTYPE_SYMLINK:
431         break;
432     case JTYPE_WHITEOUT:
433         break;
434     case JTYPE_REMOVE:
435         if (jattr->path1) {
436             remove(jattr->path1);
437         }
438         break;
439     case JTYPE_MKDIR:
440         if (jattr->path1 && jattr->modes != (mode_t)-1) {
441             mkdir(jattr->path1, jattr->modes);
442         }
443         break;
444     case JTYPE_RMDIR:
445         if (jattr->path1) {
446             rmdir(jattr->path1);
447         }
448         break;
449     case JTYPE_RENAME:
450         if (jattr->path1 && jattr->path2) {
451             rename(jattr->path1, jattr->path2);
452         }
453         break;
454     }
455     return(error);
456 }
457