1/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
3 *
4 *  Copyright (C) 2001 Cluster File Systems, Inc. <braam@clusterfs.com>
5 *
6 *   This file is part of InterMezzo, http://www.inter-mezzo.org.
7 *
8 *   InterMezzo is free software; you can redistribute it and/or
9 *   modify it under the terms of version 2 of the GNU General Public
10 *   License as published by the Free Software Foundation.
11 *
12 *   InterMezzo is distributed in the hope that it will be useful,
13 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 *   GNU General Public License for more details.
16 *
17 *   You should have received a copy of the GNU General Public License
18 *   along with InterMezzo; if not, write to the Free Software
19 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 *
21 * Unpacking of KML records
22 *
23 */
24
25#ifdef __KERNEL__
26#  include <linux/module.h>
27#  include <linux/errno.h>
28#  include <linux/kernel.h>
29#  include <linux/major.h>
30#  include <linux/sched.h>
31#  include <linux/lp.h>
32#  include <linux/slab.h>
33#  include <linux/ioport.h>
34#  include <linux/fcntl.h>
35#  include <linux/delay.h>
36#  include <linux/skbuff.h>
37#  include <linux/proc_fs.h>
38#  include <linux/vmalloc.h>
39#  include <linux/fs.h>
40#  include <linux/poll.h>
41#  include <linux/init.h>
42#  include <linux/list.h>
43#  include <linux/stat.h>
44#  include <asm/io.h>
45#  include <asm/segment.h>
46#  include <asm/system.h>
47#  include <asm/poll.h>
48#  include <asm/uaccess.h>
49#else
50#  include <time.h>
51#  include <stdio.h>
52#  include <string.h>
53#  include <stdlib.h>
54#  include <errno.h>
55#  include <sys/stat.h>
56#  include <glib.h>
57#endif
58
59#include <linux/intermezzo_lib.h>
60#include <linux/intermezzo_idl.h>
61#include <linux/intermezzo_fs.h>
62
63int kml_unpack_version(struct presto_version **ver, char **buf, char *end)
64{
65	char *ptr = *buf;
66        struct presto_version *pv;
67
68	UNLOGP(*ver, struct presto_version, ptr, end);
69        pv = *ver;
70        pv->pv_mtime   = NTOH__u64(pv->pv_mtime);
71        pv->pv_ctime   = NTOH__u64(pv->pv_ctime);
72        pv->pv_size    = NTOH__u64(pv->pv_size);
73
74	*buf = ptr;
75
76        return 0;
77}
78
79
80static int kml_unpack_noop(struct kml_rec *rec, char **buf, char *end)
81{
82	return 0;
83}
84
85
86static int kml_unpack_get_fileid(struct kml_rec *rec, char **buf, char *end)
87{
88	char *ptr = *buf;
89
90	LUNLOGV(rec->pathlen, __u32, ptr, end);
91	UNLOGL(rec->path, char, rec->pathlen, ptr, end);
92
93	*buf = ptr;
94	return 0;
95}
96
97static int kml_unpack_create(struct kml_rec *rec, char **buf, char *end)
98{
99	char *ptr = *buf;
100
101	kml_unpack_version(&rec->old_parentv, &ptr, end);
102	kml_unpack_version(&rec->new_parentv, &ptr, end);
103	kml_unpack_version(&rec->new_objectv, &ptr, end);
104	LUNLOGV(rec->mode, __u32, ptr, end);
105	LUNLOGV(rec->uid, __u32, ptr, end);
106	LUNLOGV(rec->gid, __u32, ptr, end);
107	LUNLOGV(rec->pathlen, __u32, ptr, end);
108	UNLOGL(rec->path, char, rec->pathlen, ptr, end);
109
110	*buf = ptr;
111
112	return 0;
113}
114
115
116static int kml_unpack_mkdir(struct kml_rec *rec, char **buf, char *end)
117{
118	char *ptr = *buf;
119
120	kml_unpack_version(&rec->old_parentv, &ptr, end);
121	kml_unpack_version(&rec->new_parentv, &ptr, end);
122	kml_unpack_version(&rec->new_objectv, &ptr, end);
123	LUNLOGV(rec->mode, __u32, ptr, end);
124	LUNLOGV(rec->uid, __u32, ptr, end);
125	LUNLOGV(rec->gid, __u32, ptr, end);
126	LUNLOGV(rec->pathlen, __u32, ptr, end);
127	UNLOGL(rec->path, char, rec->pathlen, ptr, end);
128
129	*buf = ptr;
130
131	return 0;
132}
133
134
135static int kml_unpack_unlink(struct kml_rec *rec, char **buf, char *end)
136{
137	char *ptr = *buf;
138
139	kml_unpack_version(&rec->old_parentv, &ptr, end);
140	kml_unpack_version(&rec->new_parentv, &ptr, end);
141	kml_unpack_version(&rec->old_objectv, &ptr, end);
142        LUNLOGV(rec->old_mode, __u32, ptr, end);
143        LUNLOGV(rec->old_rdev, __u32, ptr, end);
144        LUNLOGV(rec->old_uid, __u64, ptr, end);
145        LUNLOGV(rec->old_gid, __u64, ptr, end);
146	LUNLOGV(rec->pathlen, __u32, ptr, end);
147	LUNLOGV(rec->targetlen, __u32, ptr, end);
148        LUNLOGV(rec->old_targetlen, __u32, ptr, end);
149	UNLOGL(rec->path, char, rec->pathlen, ptr, end);
150	UNLOGL(rec->target, char, rec->targetlen, ptr, end);
151        UNLOGL(rec->old_target, char, rec->old_targetlen, ptr, end);
152
153	*buf = ptr;
154
155	return 0;
156}
157
158
159static int kml_unpack_rmdir(struct kml_rec *rec, char **buf, char *end)
160{
161	char *ptr = *buf;
162
163	kml_unpack_version(&rec->old_parentv, &ptr, end);
164	kml_unpack_version(&rec->new_parentv, &ptr, end);
165	kml_unpack_version(&rec->old_objectv, &ptr, end);
166        LUNLOGV(rec->old_mode, __u32, ptr, end);
167        LUNLOGV(rec->old_rdev, __u32, ptr, end);
168        LUNLOGV(rec->old_uid, __u64, ptr, end);
169        LUNLOGV(rec->old_gid, __u64, ptr, end);
170	LUNLOGV(rec->pathlen, __u32, ptr, end);
171	LUNLOGV(rec->targetlen, __u32, ptr, end);
172	UNLOGL(rec->path, char, rec->pathlen, ptr, end);
173	UNLOGL(rec->target, char, rec->targetlen, ptr, end);
174
175	*buf = ptr;
176
177	return 0;
178}
179
180
181static int kml_unpack_close(struct kml_rec *rec, char **buf, char *end)
182{
183	char *ptr = *buf;
184
185	LUNLOGV(rec->mode, __u32, ptr, end);  // used for open_mode
186	LUNLOGV(rec->uid, __u32, ptr, end);   // used for open_uid
187	LUNLOGV(rec->gid, __u32, ptr, end);   // used for open_gid
188	kml_unpack_version(&rec->old_objectv, &ptr, end);
189	kml_unpack_version(&rec->new_objectv, &ptr, end);
190	LUNLOGV(rec->ino, __u64, ptr, end);
191	LUNLOGV(rec->generation, __u32, ptr, end);
192	LUNLOGV(rec->pathlen, __u32, ptr, end);
193	UNLOGL(rec->path, char, rec->pathlen, ptr, end);
194
195	*buf = ptr;
196
197	return 0;
198}
199
200
201static int kml_unpack_symlink(struct kml_rec *rec, char **buf, char *end)
202{
203	char *ptr = *buf;
204
205	kml_unpack_version(&rec->old_parentv, &ptr, end);
206	kml_unpack_version(&rec->new_parentv, &ptr, end);
207	kml_unpack_version(&rec->new_objectv, &ptr, end);
208	LUNLOGV(rec->uid, __u32, ptr, end);
209	LUNLOGV(rec->gid, __u32, ptr, end);
210	LUNLOGV(rec->pathlen, __u32, ptr, end);
211	LUNLOGV(rec->targetlen, __u32, ptr, end);
212	UNLOGL(rec->path, char, rec->pathlen, ptr, end);
213	UNLOGL(rec->target, char, rec->targetlen, ptr, end);
214
215	*buf = ptr;
216
217	return 0;
218}
219
220
221static int kml_unpack_rename(struct kml_rec *rec, char **buf, char *end)
222{
223	char *ptr = *buf;
224
225	kml_unpack_version(&rec->old_objectv, &ptr, end);
226	kml_unpack_version(&rec->new_objectv, &ptr, end);
227	kml_unpack_version(&rec->old_parentv, &ptr, end);
228	kml_unpack_version(&rec->new_parentv, &ptr, end);
229	LUNLOGV(rec->pathlen, __u32, ptr, end);
230	LUNLOGV(rec->targetlen, __u32, ptr, end);
231	UNLOGL(rec->path, char, rec->pathlen, ptr, end);
232	UNLOGL(rec->target, char, rec->targetlen, ptr, end);
233
234	*buf = ptr;
235
236	return 0;
237}
238
239
240static int kml_unpack_setattr(struct kml_rec *rec, char **buf, char *end)
241{
242	char *ptr = *buf;
243
244	kml_unpack_version(&rec->old_objectv, &ptr, end);
245	LUNLOGV(rec->valid, __u32, ptr, end);
246	LUNLOGV(rec->mode, __u32, ptr, end);
247	LUNLOGV(rec->uid, __u32, ptr, end);
248	LUNLOGV(rec->gid, __u32, ptr, end);
249	LUNLOGV(rec->size, __u64, ptr, end);
250	LUNLOGV(rec->mtime, __u64, ptr, end);
251	LUNLOGV(rec->ctime, __u64, ptr, end);
252	LUNLOGV(rec->flags, __u32, ptr, end);
253        LUNLOGV(rec->old_mode, __u32, ptr, end);
254        LUNLOGV(rec->old_rdev, __u32, ptr, end);
255        LUNLOGV(rec->old_uid, __u64, ptr, end);
256        LUNLOGV(rec->old_gid, __u64, ptr, end);
257	LUNLOGV(rec->pathlen, __u32, ptr, end);
258	UNLOGL(rec->path, char, rec->pathlen, ptr, end);
259
260	*buf = ptr;
261
262	return 0;
263}
264
265
266static int kml_unpack_link(struct kml_rec *rec, char **buf, char *end)
267{
268	char *ptr = *buf;
269
270	kml_unpack_version(&rec->old_parentv, &ptr, end);
271	kml_unpack_version(&rec->new_parentv, &ptr, end);
272	kml_unpack_version(&rec->new_objectv, &ptr, end);
273	LUNLOGV(rec->pathlen, __u32, ptr, end);
274	LUNLOGV(rec->targetlen, __u32, ptr, end);
275	UNLOGL(rec->path, char, rec->pathlen, ptr, end);
276	UNLOGL(rec->target, char, rec->targetlen, ptr, end);
277
278	*buf = ptr;
279
280	return 0;
281}
282
283static int kml_unpack_mknod(struct kml_rec *rec, char **buf, char *end)
284{
285	char *ptr = *buf;
286
287	kml_unpack_version(&rec->old_parentv, &ptr, end);
288	kml_unpack_version(&rec->new_parentv, &ptr, end);
289	kml_unpack_version(&rec->new_objectv, &ptr, end);
290	LUNLOGV(rec->mode, __u32, ptr, end);
291	LUNLOGV(rec->uid, __u32, ptr, end);
292	LUNLOGV(rec->gid, __u32, ptr, end);
293	LUNLOGV(rec->major, __u32, ptr, end);
294	LUNLOGV(rec->minor, __u32, ptr, end);
295	LUNLOGV(rec->pathlen, __u32, ptr, end);
296	UNLOGL(rec->path, char, rec->pathlen, ptr, end);
297
298	*buf = ptr;
299
300	return 0;
301}
302
303
304static int kml_unpack_write(struct kml_rec *rec, char **buf, char *end)
305{
306	printf("NOT IMPLEMENTED");
307	return 0;
308}
309
310
311static int kml_unpack_release(struct kml_rec *rec, char **buf, char *end)
312{
313	printf("NOT IMPLEMENTED");
314	return 0;
315}
316
317
318static int kml_unpack_trunc(struct kml_rec *rec, char **buf, char *end)
319{
320	printf("NOT IMPLEMENTED");
321	return 0;
322}
323
324
325static int kml_unpack_setextattr(struct kml_rec *rec, char **buf, char *end)
326{
327	char *ptr = *buf;
328
329	kml_unpack_version(&rec->old_objectv, &ptr, end);
330	kml_unpack_version(&rec->new_objectv, &ptr, end);
331	LUNLOGV(rec->flags, __u32, ptr, end);
332	LUNLOGV(rec->mode, __u32, ptr, end);
333	LUNLOGV(rec->pathlen, __u32, ptr, end);
334	LUNLOGV(rec->namelen, __u32, ptr, end);
335	LUNLOGV(rec->targetlen, __u32, ptr, end);
336        UNLOGL(rec->path, char, rec->pathlen, ptr, end);
337	UNLOGL(rec->name, char, rec->namelen, ptr, end);
338	UNLOGL(rec->target, char, rec->targetlen, ptr, end);
339
340	*buf = ptr;
341
342	return 0;
343}
344
345
346static int kml_unpack_delextattr(struct kml_rec *rec, char **buf, char *end)
347{
348	char *ptr = *buf;
349
350	kml_unpack_version(&rec->old_objectv, &ptr, end);
351	kml_unpack_version(&rec->new_objectv, &ptr, end);
352	LUNLOGV(rec->flags, __u32, ptr, end);
353	LUNLOGV(rec->mode, __u32, ptr, end);
354	LUNLOGV(rec->pathlen, __u32, ptr, end);
355	LUNLOGV(rec->namelen, __u32, ptr, end);
356	LUNLOGV(rec->targetlen, __u32, ptr, end);
357	UNLOGL(rec->path, char, rec->pathlen, ptr, end);
358	UNLOGL(rec->name, char, rec->namelen, ptr, end);
359
360	*buf = ptr;
361
362	return 0;
363}
364
365static int kml_unpack_open(struct kml_rec *rec, char **buf, char *end)
366{
367	printf("NOT IMPLEMENTED");
368	return 0;
369}
370
371static int kml_unpack_kml_trunc(struct kml_rec *rec, char **buf, char *end)
372{
373
374	printf("NOT IMPLEMENTED");
375	return 0;
376}
377
378
379typedef int (*unpacker)(struct kml_rec *rec, char **buf, char *end);
380
381static unpacker unpackers[KML_OPCODE_NUM] =
382{
383	[KML_OPCODE_NOOP] = kml_unpack_noop,
384	[KML_OPCODE_CREATE] = kml_unpack_create,
385	[KML_OPCODE_MKDIR] = kml_unpack_mkdir,
386	[KML_OPCODE_UNLINK] = kml_unpack_unlink,
387	[KML_OPCODE_RMDIR] = kml_unpack_rmdir,
388	[KML_OPCODE_CLOSE] = kml_unpack_close,
389	[KML_OPCODE_SYMLINK] = kml_unpack_symlink,
390	[KML_OPCODE_RENAME] = kml_unpack_rename,
391	[KML_OPCODE_SETATTR] = kml_unpack_setattr,
392	[KML_OPCODE_LINK] = kml_unpack_link,
393	[KML_OPCODE_OPEN] = kml_unpack_open,
394	[KML_OPCODE_MKNOD] = kml_unpack_mknod,
395	[KML_OPCODE_WRITE] = kml_unpack_write,
396	[KML_OPCODE_RELEASE] = kml_unpack_release,
397	[KML_OPCODE_TRUNC] = kml_unpack_trunc,
398	[KML_OPCODE_SETEXTATTR] = kml_unpack_setextattr,
399	[KML_OPCODE_DELEXTATTR] = kml_unpack_delextattr,
400	[KML_OPCODE_KML_TRUNC] = kml_unpack_kml_trunc,
401	[KML_OPCODE_GET_FILEID] = kml_unpack_get_fileid
402};
403
404int kml_unpack_prefix(struct kml_rec *rec, char **buf, char *end)
405{
406	char *ptr = *buf;
407        int n;
408
409        UNLOGP(rec->prefix.hdr, struct kml_prefix_hdr, ptr, end);
410        rec->prefix.hdr->len     = NTOH__u32(rec->prefix.hdr->len);
411        rec->prefix.hdr->version = NTOH__u32(rec->prefix.hdr->version);
412        rec->prefix.hdr->pid     = NTOH__u32(rec->prefix.hdr->pid);
413        rec->prefix.hdr->auid    = NTOH__u32(rec->prefix.hdr->auid);
414        rec->prefix.hdr->fsuid   = NTOH__u32(rec->prefix.hdr->fsuid);
415        rec->prefix.hdr->fsgid   = NTOH__u32(rec->prefix.hdr->fsgid);
416        rec->prefix.hdr->opcode  = NTOH__u32(rec->prefix.hdr->opcode);
417        rec->prefix.hdr->ngroups = NTOH__u32(rec->prefix.hdr->ngroups);
418
419	UNLOGL(rec->prefix.groups, __u32, rec->prefix.hdr->ngroups, ptr, end);
420        for (n = 0; n < rec->prefix.hdr->ngroups; n++) {
421                rec->prefix.groups[n] = NTOH__u32(rec->prefix.groups[n]);
422        }
423
424	*buf = ptr;
425
426        return 0;
427}
428
429int kml_unpack_suffix(struct kml_rec *rec, char **buf, char *end)
430{
431	char *ptr = *buf;
432
433	UNLOGP(rec->suffix, struct kml_suffix, ptr, end);
434        rec->suffix->prevrec   = NTOH__u32(rec->suffix->prevrec);
435        rec->suffix->recno    = NTOH__u32(rec->suffix->recno);
436        rec->suffix->time     = NTOH__u32(rec->suffix->time);
437        rec->suffix->len      = NTOH__u32(rec->suffix->len);
438
439	*buf = ptr;
440
441        return 0;
442}
443
444int kml_unpack(struct kml_rec *rec, char **buf, char *end)
445{
446	char *ptr = *buf;
447	int err;
448
449        if (((unsigned long)ptr % 4) != 0) {
450                printf("InterMezzo: %s: record misaligned.\n", __FUNCTION__);
451                return -EINVAL;
452        }
453
454        while (ptr < end) {
455                __u32 *i = (__u32 *)ptr;
456                if (*i)
457                        break;
458                ptr += sizeof(*i);
459        }
460	*buf = ptr;
461
462	memset(rec, 0, sizeof(*rec));
463
464        err = kml_unpack_prefix(rec, &ptr, end);
465	if (err) {
466                printf("InterMezzo: %s: unpack_prefix failed: %d\n",
467                       __FUNCTION__, err);
468		return err;
469        }
470
471        if (rec->prefix.hdr->opcode < 0  ||
472            rec->prefix.hdr->opcode >= KML_OPCODE_NUM) {
473                printf("InterMezzo: %s: invalid opcode (%d)\n",
474                       __FUNCTION__, rec->prefix.hdr->opcode);
475		return -EINVAL;
476        }
477	err = unpackers[rec->prefix.hdr->opcode](rec, &ptr, end);
478	if (err) {
479                printf("InterMezzo: %s: unpacker failed: %d\n",
480                       __FUNCTION__, err);
481		return err;
482        }
483
484        err = kml_unpack_suffix(rec, &ptr, end);
485	if (err) {
486                printf("InterMezzo: %s: unpack_suffix failed: %d\n",
487                       __FUNCTION__, err);
488		return err;
489        }
490
491
492	if (rec->prefix.hdr->len != rec->suffix->len) {
493                printf("InterMezzo: %s: lengths don't match\n",
494                       __FUNCTION__);
495		return -EINVAL;
496        }
497        if ((rec->prefix.hdr->len % 4) != 0) {
498                printf("InterMezzo: %s: record length not a "
499                       "multiple of 4.\n", __FUNCTION__);
500                return -EINVAL;
501        }
502        if (ptr - *buf != rec->prefix.hdr->len) {
503                printf("InterMezzo: %s: unpacking error\n",
504                       __FUNCTION__);
505                return -EINVAL;
506        }
507        while (ptr < end) {
508                __u32 *i = (__u32 *)ptr;
509                if (*i)
510                        break;
511                ptr += sizeof(*i);
512        }
513	*buf = ptr;
514	return 0;
515}
516
517
518#ifndef __KERNEL__
519#define STR(ptr) ((ptr))? (ptr) : ""
520
521#define OPNAME(n) [KML_OPCODE_##n] = #n
522static char *opnames[KML_OPCODE_NUM] = {
523	OPNAME(NOOP),
524	OPNAME(CREATE),
525	OPNAME(MKDIR),
526	OPNAME(UNLINK),
527	OPNAME(RMDIR),
528	OPNAME(CLOSE),
529	OPNAME(SYMLINK),
530	OPNAME(RENAME),
531	OPNAME(SETATTR),
532	OPNAME(LINK),
533	OPNAME(OPEN),
534	OPNAME(MKNOD),
535	OPNAME(WRITE),
536	OPNAME(RELEASE),
537	OPNAME(TRUNC),
538	OPNAME(SETEXTATTR),
539	OPNAME(DELEXTATTR),
540	OPNAME(KML_TRUNC),
541	OPNAME(GET_FILEID)
542};
543#undef OPNAME
544
545static char *print_opname(int op)
546{
547	if (op < 0 || op >= sizeof (opnames) / sizeof (*opnames))
548		return NULL;
549	return opnames[op];
550}
551
552
553static char *print_time(__u64 i)
554{
555	char buf[128];
556
557	memset(buf, 0, 128);
558
559#ifndef __KERNEL__
560	strftime(buf, 128, "%Y/%m/%d %H:%M:%S", gmtime((time_t *)&i));
561#else
562	sprintf(buf, "%Ld\n", i);
563#endif
564
565	return strdup(buf);
566}
567
568static char *print_version(struct presto_version *ver)
569{
570	char ver_buf[128];
571	char *mtime;
572	char *ctime;
573
574	if (!ver || ver->pv_ctime == 0) {
575		return strdup("");
576	}
577	mtime = print_time(ver->pv_mtime);
578	ctime = print_time(ver->pv_ctime);
579	sprintf(ver_buf, "mtime %s, ctime %s, len %lld",
580		mtime, ctime, ver->pv_size);
581	free(mtime);
582	free(ctime);
583	return strdup(ver_buf);
584}
585
586
587char *kml_print_rec(struct kml_rec *rec, int brief)
588{
589	char *str;
590	char *nov, *oov, *ntv, *otv, *npv, *opv;
591	char *rectime, *mtime, *ctime;
592
593        if (brief) {
594		str = g_strdup_printf(" %08d %7s %*s %*s",
595                                      rec->suffix->recno,
596                                      print_opname (rec->prefix.hdr->opcode),
597                                      rec->pathlen, STR(rec->path),
598                                      rec->targetlen, STR(rec->target));
599
600		return str;
601	}
602
603	rectime = print_time(rec->suffix->time);
604	mtime = print_time(rec->mtime);
605	ctime = print_time(rec->ctime);
606
607	nov = print_version(rec->new_objectv);
608	oov = print_version(rec->old_objectv);
609	ntv = print_version(rec->new_targetv);
610	otv = print_version(rec->old_targetv);
611	npv = print_version(rec->new_parentv);
612	opv = print_version(rec->old_parentv);
613
614	str = g_strdup_printf("\n -- Record:\n"
615		"    Recno     %d\n"
616		"    KML off   %lld\n"
617		"    Version   %d\n"
618		"    Len       %d\n"
619		"    Suf len   %d\n"
620		"    Time      %s\n"
621		"    Opcode    %d\n"
622		"    Op        %s\n"
623		"    Pid       %d\n"
624		"    AUid      %d\n"
625		"    Fsuid     %d\n"
626		"    Fsgid     %d\n"
627		"    Prevrec   %d\n"
628		"    Ngroups   %d\n"
629		//"    Groups    @{$self->{groups}}\n"
630		" -- Path:\n"
631		"    Inode     %d\n"
632		"    Gen num   %u\n"
633                "    Old mode  %o\n"
634                "    Old rdev  %x\n"
635                "    Old uid   %llu\n"
636                "    Old gid   %llu\n"
637		"    Path      %*s\n"
638		//"    Open_mode %o\n",
639		"    Pathlen   %d\n"
640		"    Tgt       %*s\n"
641		"    Tgtlen    %d\n"
642		"    Old Tgt   %*s\n"
643		"    Old Tgtln %d\n"
644		" -- Attr:\n"
645		"    Valid     %x\n"
646		"    mode %o, uid %d, gid %d, size %lld, mtime %s, ctime %s rdev %x (%d:%d)\n"
647		" -- Versions:\n"
648		"    New object %s\n"
649		"    Old object %s\n"
650		"    New target %s\n"
651		"    Old target %s\n"
652		"    New parent %s\n"
653		"    Old parent %s\n",
654
655		rec->suffix->recno,
656		rec->offset,
657		rec->prefix.hdr->version,
658		rec->prefix.hdr->len,
659		rec->suffix->len,
660		rectime,
661		rec->prefix.hdr->opcode,
662		print_opname (rec->prefix.hdr->opcode),
663		rec->prefix.hdr->pid,
664		rec->prefix.hdr->auid,
665		rec->prefix.hdr->fsuid,
666		rec->prefix.hdr->fsgid,
667		rec->suffix->prevrec,
668		rec->prefix.hdr->ngroups,
669		rec->ino,
670		rec->generation,
671                rec->old_mode,
672                rec->old_rdev,
673                rec->old_uid,
674                rec->old_gid,
675		rec->pathlen,
676		STR(rec->path),
677		rec->pathlen,
678		rec->targetlen,
679		STR(rec->target),
680		rec->targetlen,
681		rec->old_targetlen,
682		STR(rec->old_target),
683		rec->old_targetlen,
684
685		rec->valid,
686		rec->mode,
687		rec->uid,
688		rec->gid,
689		rec->size,
690		mtime,
691		ctime,
692		rec->rdev, rec->major, rec->minor,
693		nov, oov, ntv, otv, npv, opv);
694
695	free(nov);
696	free(oov);
697	free(ntv);
698	free(otv);
699	free(npv);
700	free(opv);
701
702	free(rectime);
703	free(ctime);
704	free(mtime);
705
706	return str;
707}
708#endif
709