xref: /illumos-gate/usr/src/cmd/fs.d/nfs/nfslog/nfslog_trans.c (revision 89b2a9fbeabf42fa54594df0e5927bcc50a07cc9)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright (c) 1999 by Sun Microsystems, Inc.
24  * All rights reserved.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <stdio.h>
30 #include <errno.h>
31 #include <malloc.h>
32 #include <strings.h>
33 #include <stddef.h>
34 #include <search.h>
35 #include <syslog.h>
36 #include <libintl.h>
37 #include <unistd.h>
38 #include <rpc/rpc.h>
39 #include <netconfig.h>
40 #include <netdir.h>
41 #include <nfs/nfs_sec.h>
42 #include <nfs/export.h>
43 #include <rpc/auth.h>
44 #include <rpc/svc.h>
45 #include <rpc/xdr.h>
46 #include <rpc/clnt.h>
47 #include <nfs/nfs.h>
48 #include <nfs/nfs_log.h>
49 #include <assert.h>
50 #include "fhtab.h"
51 #include "nfslogd.h"
52 
53 /*
54  * How long should an entry stay in the list before being forced
55  * out and a trans log entry printed
56  */
57 #define	TRANS_ENTRY_TIMEOUT	60
58 
59 extern char *addrtoname(void *);
60 
61 struct transentry {
62 	struct transentry *next;
63 	struct transentry *prev;
64 	timestruc32_t	starttime;	/* when did transaction start? */
65 	timestruc32_t	lastupdate;	/* last operation for this entry */
66 #define	TRANS_OPER_READ		1
67 #define	TRANS_OPER_WRITE	2
68 #define	TRANS_OPER_SETATTR	3
69 #define	TRANS_OPER_REMOVE	4
70 #define	TRANS_OPER_MKDIR	5
71 #define	TRANS_OPER_CREATE	6
72 #define	TRANS_OPER_RMDIR	7
73 #define	TRANS_OPER_RENAME	8
74 #define	TRANS_OPER_MKNOD	9
75 #define	TRANS_OPER_LINK		10
76 #define	TRANS_OPER_SYMLINK	11
77 	uchar_t		optype;		/* read, write, ...? */
78 #define	TRANS_DATATYPE_NA		/* not applicable data type */
79 #define	TRANS_DATATYPE_ASCII	0	/* transfer done as ascii */
80 #define	TRANS_DATATYPE_BINARY	1	/* transfer done as binary */
81 	uchar_t		datatype;
82 /*
83  * Action taken by server before transfer was made -- noaction,
84  * compressed, tar or uncompressed.
85  */
86 #define	TRANS_OPTION_NOACTION	0
87 	uchar_t		transoption;
88 	char		*pathname;
89 	struct netbuf	*pnb;
90 	uid_t		uid;
91 	int		nfsvers;
92 	char		*netid;
93 	char		*principal_name;
94 	uint64_t	totalbytes;	/* total operated upon in history */
95 	union {
96 		fhandle_t fh;
97 		nfs_fh3 fh3;
98 	} fh_u;
99 };
100 
101 struct nfslog_trans_file {
102 	struct nfslog_trans_file	*next;	/* next file in list */
103 	struct nfslog_trans_file	*prev;	/* next file in list */
104 	int	refcnt;		/* number of references to this struct */
105 	char	*path;		/* pathname of file */
106 	FILE	*fp;		/* file pointer */
107 	/* timestamp of the last transaction processed for this file */
108 	timestruc32_t	lasttrans_timestamp;
109 	/* 'current' time that last trans was processed */
110 	time_t		last_trans_read;
111 	uint32_t trans_to_log;	/* transactions that are to be logged */
112 	uint32_t trans_output_type;
113 	struct transentry *te_list_v3_read;
114 	struct transentry *te_list_v3_write;
115 	struct transentry *te_list_v2_read;
116 	struct transentry *te_list_v2_write;
117 };
118 
119 static struct nfslog_trans_file *trans_file_head = NULL;
120 
121 static void nfslog_print_trans_logentry(struct transentry *,
122 	struct nfslog_trans_file *);
123 
124 
125 static struct netbuf *
126 netbufdup(struct netbuf *pnb)
127 {
128 	struct netbuf *pnewnb;
129 	uint32_t	size;
130 
131 	size = offsetof(struct netbuf, buf);
132 	size += pnb->len;
133 
134 	if ((pnewnb = (struct netbuf *)malloc(sizeof (*pnewnb))) == NULL)
135 		return (NULL);
136 	if ((pnewnb->buf = malloc(pnb->len)) == NULL) {
137 		free(pnewnb);
138 		return (NULL);
139 	}
140 
141 	pnewnb->maxlen = pnb->maxlen;
142 	pnewnb->len = pnb->len;
143 	bcopy(pnb->buf, pnewnb->buf, pnb->len);
144 	return (pnewnb);
145 }
146 
147 static void
148 freenetbuf(struct netbuf *pnb)
149 {
150 	free(pnb->buf);
151 	free(pnb);
152 }
153 
154 static struct transentry *
155 create_te()
156 {
157 	struct transentry *pte;
158 
159 	if ((pte = (struct transentry *)calloc(1, sizeof (*pte))) == NULL) {
160 		/* failure message or action */
161 		return (NULL);
162 	}
163 
164 	pte->next = pte->prev = NULL;
165 
166 	return (pte);
167 }
168 
169 static struct transentry *
170 insert_te(
171 	struct transentry *te_list,
172 	struct transentry *entry)
173 {
174 	struct transentry *pte;
175 
176 	/*
177 	 * First check for any non-filehandle comparisons that may be needed.
178 	 */
179 	switch (entry->optype) {
180 	case TRANS_OPER_REMOVE:
181 	case TRANS_OPER_RENAME:
182 		for (pte = te_list->next; pte != te_list; pte = pte->next) {
183 			/* if path names match, then return */
184 			if (strcmp(pte->pathname, entry->pathname) == 0) {
185 				return (pte);
186 			}
187 		}
188 		return (NULL);
189 	default:
190 		break;
191 	}
192 
193 	for (pte = te_list->next; pte != te_list; pte = pte->next) {
194 		/* If the file handles match, then we have a hit */
195 		if (entry->nfsvers == NFS_VERSION) {
196 			if (bcmp(&(pte->fh_u.fh), &(entry->fh_u.fh),
197 				sizeof (fhandle_t)) == 0) {
198 				switch (entry->optype) {
199 				case TRANS_OPER_READ:
200 				case TRANS_OPER_WRITE:
201 					if (pte->uid ==	entry->uid) {
202 						return (pte);
203 					}
204 					break;
205 				default:
206 					return (pte);
207 				}
208 			}
209 		} else {
210 			if (pte->fh_u.fh3.fh3_length ==
211 				entry->fh_u.fh3.fh3_length &&
212 				bcmp(pte->fh_u.fh3.fh3_u.data,
213 					entry->fh_u.fh3.fh3_u.data,
214 					pte->fh_u.fh3.fh3_length) == 0)
215 				switch (entry->optype) {
216 				case TRANS_OPER_READ:
217 				case TRANS_OPER_WRITE:
218 					if (pte->uid ==	entry->uid) {
219 						return (pte);
220 					}
221 					break;
222 				default:
223 					return (pte);
224 				}
225 		}
226 	}
227 	/*
228 	 * XXX - should compare more of the information to make sure
229 	 * it is a match.
230 	 */
231 
232 	/*
233 	 * other operation types do not generate an entry for
234 	 * further analysis
235 	 */
236 	switch (entry->optype) {
237 	case TRANS_OPER_READ:
238 	case TRANS_OPER_WRITE:
239 		break;
240 	default:
241 		return (NULL);
242 	}
243 
244 	insque(entry, te_list);
245 
246 	return (NULL); /* NULL signifies insertion and no record found */
247 }
248 
249 static void
250 remove_te(struct transentry *pte)
251 {
252 	if (pte->next)
253 		remque(pte);
254 
255 	if (pte->principal_name) free(pte->principal_name);
256 	if (pte->pathname) free(pte->pathname);
257 	if (pte->pnb) freenetbuf(pte->pnb);
258 	if (pte->netid) free(pte->netid);
259 
260 	free(pte);
261 }
262 
263 /*
264  * nfslog_trans_file_free - frees a record
265  */
266 static void
267 nfslog_trans_file_free(struct nfslog_trans_file *transrec)
268 {
269 	if (transrec == NULL)
270 		return;
271 	if (transrec->path != NULL) {
272 		if (debug)
273 			(void) printf("freeing transpath '%s'\n",
274 				transrec->path);
275 		free(transrec->path);
276 	}
277 	free(transrec);
278 }
279 
280 /*
281  * On success returns a pointer to the trans_file that matches
282  * 'path', 'output_type' and 'transtolog'.  The reference count for this
283  * object is incremented as well.
284  * Returns NULL if it is not in the list.
285  */
286 static struct nfslog_trans_file *
287 nfslog_trans_file_find(
288 	char *path,
289 	uint32_t output_type,
290 	uint32_t transtolog)
291 {
292 	struct nfslog_trans_file *tfp;
293 
294 	for (tfp = trans_file_head; tfp != NULL; tfp = tfp->next) {
295 		if ((strcmp(path, tfp->path) == 0) &&
296 		    (output_type == tfp->trans_output_type) &&
297 		    (transtolog == tfp->trans_to_log)) {
298 			if (debug)
299 				(void) printf("Found transfile '%s'\n", path);
300 			(tfp->refcnt)++;
301 			return (tfp);
302 		}
303 	}
304 	return (NULL);
305 }
306 
307 
308 /*
309  * nfslog_close_trans_file - decrements the reference count on
310  * this object. On last reference it closes transfile and
311  * frees resources
312  */
313 static void
314 nfslog_close_trans_file(struct nfslog_trans_file *tf)
315 {
316 	assert(tf != NULL);
317 	assert(tf->refcnt > 0);
318 	if (tf->refcnt > 1) {
319 		(tf->refcnt)--;
320 		return;
321 	}
322 
323 	if (tf->fp != NULL) {
324 		(void) fsync(fileno(tf->fp));
325 		(void) fclose(tf->fp);
326 	}
327 
328 	/*
329 	 * Disconnect from list
330 	 */
331 	tf->prev->next = tf->next;
332 	if (tf->next != NULL)
333 		tf->next->prev = tf->prev;
334 
335 	/*
336 	 * Adjust the head of the list if appropriate
337 	 */
338 	if (tf == trans_file_head)
339 		trans_file_head = tf->next;
340 
341 	nfslog_trans_file_free(tf);
342 }
343 
344 /*
345  * nfslog_open_trans_file - open the output trans file and mallocs.
346  * The object is then inserted at the beginning of the global
347  * transfile list.
348  *	Returns 0 for success, error else.
349  *
350  * *error contains the last error encountered on this object. It can
351  * be used to avoid reporting the same error endlessly, by comparing
352  * the current error to the last error. It is reset to the current error
353  * code on return.
354  */
355 void *
356 nfslog_open_trans_file(
357 	char *transpath,
358 	uint32_t output_type,
359 	uint32_t transtolog,
360 	int *error)
361 {
362 	int			preverror = *error;
363 	struct nfslog_trans_file	*transrec;
364 
365 	transrec = nfslog_trans_file_find(transpath, output_type, transtolog);
366 	if (transrec != NULL)
367 		return (transrec);
368 
369 	if ((transrec = malloc(sizeof (*transrec))) == NULL) {
370 		*error = errno;
371 		if (*error != preverror) {
372 			syslog(LOG_ERR, gettext("nfslog_open_trans_file: %s"),
373 				strerror(*error));
374 		}
375 		return (NULL);
376 	}
377 	bzero(transrec, sizeof (*transrec));
378 
379 	if ((transrec->path = strdup(transpath)) == NULL) {
380 		*error = errno;
381 		if (*error != preverror) {
382 			syslog(LOG_ERR, gettext("nfslog_open_trans_file: %s"),
383 				strerror(*error));
384 		}
385 		nfslog_trans_file_free(transrec);
386 		return (NULL);
387 	}
388 
389 	if ((transrec->fp = fopen(transpath, "a")) == NULL) {
390 		*error = errno;
391 		if (*error != preverror) {
392 			syslog(LOG_ERR, gettext("Cannot open '%s': %s"),
393 				transpath, strerror(*error));
394 		}
395 		nfslog_trans_file_free(transrec);
396 		return (NULL);
397 	}
398 
399 	transrec->te_list_v3_read =
400 		(struct transentry *)malloc(sizeof (struct transentry));
401 	transrec->te_list_v3_write =
402 		(struct transentry *)malloc(sizeof (struct transentry));
403 	transrec->te_list_v2_read =
404 		(struct transentry *)malloc(sizeof (struct transentry));
405 	transrec->te_list_v2_write =
406 		(struct transentry *)malloc(sizeof (struct transentry));
407 
408 	if (transrec->te_list_v3_read == NULL ||
409 		transrec->te_list_v3_write == NULL ||
410 		transrec->te_list_v2_read == NULL ||
411 		transrec->te_list_v2_write == NULL) {
412 		if (transrec->te_list_v3_read)
413 			free(transrec->te_list_v3_read);
414 		if (transrec->te_list_v3_write)
415 			free(transrec->te_list_v3_write);
416 		if (transrec->te_list_v2_read)
417 			free(transrec->te_list_v2_read);
418 		if (transrec->te_list_v2_write)
419 			free(transrec->te_list_v2_write);
420 		nfslog_close_trans_file(transrec);
421 		return (NULL);
422 	}
423 
424 	transrec->te_list_v3_read->next =
425 		transrec->te_list_v3_read->prev = transrec->te_list_v3_read;
426 	transrec->te_list_v3_write->next =
427 		transrec->te_list_v3_write->prev = transrec->te_list_v3_write;
428 	transrec->te_list_v2_read->next =
429 		transrec->te_list_v2_read->prev = transrec->te_list_v2_read;
430 	transrec->te_list_v2_write->next =
431 		transrec->te_list_v2_write->prev = transrec->te_list_v2_write;
432 
433 	/*
434 	 * Indicate what transaction types to log
435 	 */
436 	transrec->trans_to_log = transtolog;
437 
438 	/*
439 	 * Indicate whether to print 'full' or 'basic' version
440 	 * of the transactions
441 	 */
442 	transrec->trans_output_type = output_type;
443 
444 	/*
445 	 * Insert at the beginning of the list.
446 	 */
447 	transrec->next = trans_file_head;
448 	if (trans_file_head != NULL)
449 		trans_file_head->prev = transrec;
450 	trans_file_head = transrec->prev = transrec;
451 
452 	transrec->refcnt = 1;
453 
454 	transrec->lasttrans_timestamp.tv_sec = 0;
455 	transrec->lasttrans_timestamp.tv_nsec = 0;
456 	transrec->last_trans_read = time(0);
457 
458 	if (debug)
459 		(void) printf("New transfile '%s'\n", transrec->path);
460 
461 	return (transrec);
462 }
463 
464 void
465 nfslog_process_trans_timeout(
466 	struct nfslog_trans_file *tf,
467 	uint32_t force_flush)
468 {
469 	struct transentry *pte;
470 	time_t cur_time = time(0);
471 
472 	/*
473 	 * If we have not seen a transaction on this file for
474 	 * a long time, then we need to flush everything out since
475 	 * we may not be getting anything else in for awhile.
476 	 */
477 	if (difftime(cur_time, tf->last_trans_read) >
478 		(2 * MAX(TRANS_ENTRY_TIMEOUT, idle_time)))
479 		force_flush = TRUE;
480 
481 restart1:
482 	for (pte = tf->te_list_v3_read->next;
483 		pte != tf->te_list_v3_read;
484 		pte = pte->next) {
485 		if (force_flush == TRUE ||
486 			(difftime(tf->lasttrans_timestamp.tv_sec,
487 				pte->lastupdate.tv_sec) >
488 			MAX(TRANS_ENTRY_TIMEOUT, idle_time))) {
489 			nfslog_print_trans_logentry(pte, tf);
490 			remove_te(pte);
491 			goto restart1;
492 		}
493 	}
494 restart2:
495 	for (pte = tf->te_list_v3_write->next;
496 		pte != tf->te_list_v3_write;
497 		pte = pte->next) {
498 		if (force_flush == TRUE ||
499 			(difftime(tf->lasttrans_timestamp.tv_sec,
500 				pte->lastupdate.tv_sec) >
501 			MAX(TRANS_ENTRY_TIMEOUT, idle_time))) {
502 			nfslog_print_trans_logentry(pte, tf);
503 			remove_te(pte);
504 			goto restart2;
505 		}
506 	}
507 restart3:
508 	for (pte = tf->te_list_v2_read->next;
509 		pte != tf->te_list_v2_read;
510 		pte = pte->next) {
511 		if (force_flush == TRUE ||
512 			(difftime(tf->lasttrans_timestamp.tv_sec,
513 				pte->lastupdate.tv_sec) >
514 			MAX(TRANS_ENTRY_TIMEOUT, idle_time))) {
515 			nfslog_print_trans_logentry(pte, tf);
516 			remove_te(pte);
517 			goto restart3;
518 		}
519 	}
520 restart4:
521 	for (pte = tf->te_list_v2_write->next;
522 		pte != tf->te_list_v2_write;
523 		pte = pte->next) {
524 		if (force_flush == TRUE ||
525 			(difftime(tf->lasttrans_timestamp.tv_sec,
526 				pte->lastupdate.tv_sec) >
527 			MAX(TRANS_ENTRY_TIMEOUT, idle_time))) {
528 			nfslog_print_trans_logentry(pte, tf);
529 			remove_te(pte);
530 			goto restart4;
531 		}
532 	}
533 
534 	(void) fflush(tf->fp);
535 }
536 
537 /*
538  * Flushes outstanding transactions to disk, and closes
539  * the transaction log.
540  */
541 void
542 nfslog_close_transactions(void **transcookie)
543 {
544 	assert(*transcookie != NULL);
545 	nfslog_process_trans_timeout(
546 		(struct nfslog_trans_file *)(*transcookie), TRUE);
547 	nfslog_close_trans_file((struct nfslog_trans_file *)(*transcookie));
548 	*transcookie = NULL;
549 }
550 
551 static struct transentry *
552 trans_read(
553 	nfslog_request_record *logrec,
554 	struct nfslog_trans_file *tf,
555 	char *fhpath,
556 	char *path1)
557 {
558 	struct transentry *newte;
559 	struct transentry *pte = NULL;
560 	/* LINTED */
561 	nfslog_nfsreadargs *args = (nfslog_nfsreadargs *)logrec->re_rpc_arg;
562 	/* LINTED */
563 	nfslog_rdresult *res = (nfslog_rdresult *)logrec->re_rpc_res;
564 
565 	if (res->r_status != NFS_OK)
566 		return (NULL);
567 
568 	if ((newte = create_te()) == NULL)
569 		return (NULL);
570 
571 	if (!path1) {
572 		newte->pathname = nfslog_get_path(&args->ra_fhandle,
573 			NULL, fhpath, "trans_read");
574 	} else {
575 		newte->pathname = strdup(path1);
576 	}
577 
578 	/* prep the struct for insertion */
579 	newte->starttime = logrec->re_header.rh_timestamp;
580 	newte->lastupdate = logrec->re_header.rh_timestamp;
581 	newte->optype = TRANS_OPER_READ;
582 	newte->datatype = TRANS_DATATYPE_BINARY;
583 	newte->transoption = TRANS_OPTION_NOACTION;
584 	newte->pnb = netbufdup(&(logrec->re_ipaddr));
585 	newte->uid = logrec->re_header.rh_uid;
586 	newte->nfsvers = NFS_VERSION;
587 	newte->netid = strdup(logrec->re_netid);
588 	if (logrec->re_principal_name)
589 		newte->principal_name = strdup(logrec->re_principal_name);
590 	else
591 		newte->principal_name = NULL;
592 	newte->totalbytes = res->nfslog_rdresult_u.r_ok.rrok_count;
593 	newte->fh_u.fh = *(NFSLOG_GET_FHANDLE2(&args->ra_fhandle));
594 
595 	if (res->nfslog_rdresult_u.r_ok.rrok_count <
596 		res->nfslog_rdresult_u.r_ok.filesize) {
597 		if (pte = insert_te(tf->te_list_v2_read, newte)) {
598 			/* free this since entry was found (not inserted) */
599 			remove_te(newte);
600 
601 			pte->totalbytes +=
602 				res->nfslog_rdresult_u.r_ok.rrok_count;
603 
604 			if (pte->lastupdate.tv_sec <=
605 				logrec->re_header.rh_timestamp.tv_sec)
606 				pte->lastupdate =
607 					logrec->re_header.rh_timestamp;
608 
609 			if (pte->totalbytes <
610 				res->nfslog_rdresult_u.r_ok.filesize) {
611 				pte = NULL; /* prevent printing of log entry */
612 			}
613 		}
614 	} else {
615 		pte = newte; /* print a log record - complete file read */
616 	}
617 
618 	return (pte);
619 }
620 
621 static struct transentry *
622 trans_write(
623 	nfslog_request_record *logrec,
624 	struct nfslog_trans_file *tf,
625 	char *fhpath,
626 	char *path1)
627 {
628 	struct transentry *newte;
629 	struct transentry *pte = NULL;
630 	/* LINTED */
631 	nfslog_writeargs *args = (nfslog_writeargs *)logrec->re_rpc_arg;
632 	/* LINTED */
633 	nfslog_writeresult *res = (nfslog_writeresult *)logrec->re_rpc_res;
634 
635 	if (res->wr_status != NFS_OK)
636 		return (NULL);
637 
638 	if ((newte = create_te()) == NULL)
639 		return (NULL);
640 
641 	if (!path1) {
642 		newte->pathname = nfslog_get_path(&args->waargs_fhandle,
643 			NULL, fhpath, "trans_write");
644 	} else {
645 		newte->pathname = strdup(path1);
646 	}
647 
648 	newte->starttime = logrec->re_header.rh_timestamp;
649 	newte->lastupdate = logrec->re_header.rh_timestamp;
650 	newte->optype = TRANS_OPER_WRITE;
651 	newte->datatype = TRANS_DATATYPE_BINARY;
652 	newte->transoption = TRANS_OPTION_NOACTION;
653 	newte->pnb = netbufdup(&(logrec->re_ipaddr));
654 	newte->uid = logrec->re_header.rh_uid;
655 	newte->nfsvers = NFS_VERSION;
656 	newte->netid = strdup(logrec->re_netid);
657 	if (logrec->re_principal_name)
658 		newte->principal_name = strdup(logrec->re_principal_name);
659 	else
660 		newte->principal_name = NULL;
661 	newte->totalbytes = args->waargs_totcount;
662 	newte->fh_u.fh = *(NFSLOG_GET_FHANDLE2(&args->waargs_fhandle));
663 
664 	if (pte = insert_te(tf->te_list_v2_write, newte)) {
665 		/*
666 		 * if the write would have increased the total byte count
667 		 * over the filesize, then generate a log entry and remove
668 		 * the write record and insert the new one.
669 		 */
670 		if (pte->totalbytes + args->waargs_totcount >
671 			res->nfslog_writeresult_u.wr_size) {
672 			nfslog_print_trans_logentry(pte, tf);
673 			remove_te(pte);
674 			(void) insert_te(tf->te_list_v2_write, newte);
675 			pte = NULL;
676 		} else {
677 			/* free this since entry was found (not inserted) */
678 			remove_te(newte);
679 
680 			pte->totalbytes += args->waargs_totcount;
681 
682 			if (pte->lastupdate.tv_sec <=
683 				logrec->re_header.rh_timestamp.tv_sec) {
684 				pte->lastupdate =
685 					logrec->re_header.rh_timestamp;
686 			}
687 			pte = NULL; /* prevent printing of log entry */
688 		}
689 	}
690 	return (pte);
691 }
692 
693 static struct transentry *
694 trans_setattr(
695 	nfslog_request_record *logrec,
696 	struct nfslog_trans_file *tf,
697 	char *fhpath,
698 	char *path1)
699 {
700 	struct transentry *newte;
701 	struct transentry *pte = NULL;
702 	/* LINTED */
703 	nfslog_setattrargs *args = (nfslog_setattrargs *)logrec->re_rpc_arg;
704 	/* LINTED */
705 	nfsstat *res = (nfsstat *)logrec->re_rpc_res;
706 
707 	if (*res != NFS_OK)
708 		return (NULL);
709 
710 	if (args->saa_sa.sa_size == (uint32_t)-1)
711 		return (NULL);
712 	/*
713 	 * should check the size of the file to see if it
714 	 * is being truncated below current eof.  if so
715 	 * a record should be generated.... XXX
716 	 */
717 	if (args->saa_sa.sa_size != 0)
718 		return (NULL);
719 
720 	if ((newte = create_te()) == NULL)
721 		return (NULL);
722 
723 	if (!path1) {
724 		newte->pathname  = nfslog_get_path(&args->saa_fh, NULL,
725 			fhpath,	"trans_setattr2");
726 	} else {
727 		newte->pathname = strdup(path1);
728 	}
729 
730 	newte->starttime = logrec->re_header.rh_timestamp;
731 	newte->lastupdate = logrec->re_header.rh_timestamp;
732 	newte->optype = TRANS_OPER_SETATTR;
733 	newte->datatype = TRANS_DATATYPE_BINARY;
734 	newte->transoption = TRANS_OPTION_NOACTION;
735 	newte->pnb = netbufdup(&(logrec->re_ipaddr));
736 	newte->uid = logrec->re_header.rh_uid;
737 	newte->nfsvers = NFS_VERSION;
738 	newte->netid = strdup(logrec->re_netid);
739 	if (logrec->re_principal_name)
740 		newte->principal_name = strdup(logrec->re_principal_name);
741 	else
742 		newte->principal_name = NULL;
743 	newte->totalbytes = 0;
744 	newte->fh_u.fh = *(NFSLOG_GET_FHANDLE2(&args->saa_fh));
745 
746 	if (pte = insert_te(tf->te_list_v2_write, newte)) {
747 		nfslog_print_trans_logentry(pte, tf);
748 		remove_te(pte);
749 	}
750 	if (pte = insert_te(tf->te_list_v2_read, newte)) {
751 		nfslog_print_trans_logentry(pte, tf);
752 		remove_te(pte);
753 	}
754 
755 	return (newte);
756 }
757 
758 static struct transentry *
759 trans_create(
760 	nfslog_request_record *logrec,
761 	struct nfslog_trans_file *tf,
762 	char *fhpath,
763 	char *path1)
764 {
765 	struct transentry *newte;
766 	struct transentry *pte = NULL;
767 	/* LINTED */
768 	nfslog_createargs *args = (nfslog_createargs *)logrec->re_rpc_arg;
769 	/* LINTED */
770 	nfslog_diropres *res = (nfslog_diropres *)logrec->re_rpc_res;
771 
772 	if (res->dr_status != NFS_OK)
773 		return (NULL);
774 
775 	if ((newte = create_te()) == NULL)
776 		return (NULL);
777 
778 	if (!path1) {
779 		newte->pathname =
780 			nfslog_get_path(&args->ca_da.da_fhandle,
781 				args->ca_da.da_name,
782 				fhpath, "trans_create2");
783 	} else {
784 		newte->pathname = strdup(path1);
785 	}
786 
787 	newte->starttime = logrec->re_header.rh_timestamp;
788 	newte->lastupdate = logrec->re_header.rh_timestamp;
789 	newte->optype = TRANS_OPER_CREATE;
790 	newte->datatype = TRANS_DATATYPE_BINARY;
791 	newte->transoption = TRANS_OPTION_NOACTION;
792 	newte->pnb = netbufdup(&(logrec->re_ipaddr));
793 	newte->uid = logrec->re_header.rh_uid;
794 	newte->nfsvers = NFS_VERSION;
795 	newte->netid = strdup(logrec->re_netid);
796 	if (logrec->re_principal_name)
797 		newte->principal_name = strdup(logrec->re_principal_name);
798 	else
799 		newte->principal_name = NULL;
800 
801 	if (args->ca_sa.sa_size == (uint32_t)-1)
802 		newte->totalbytes = 0;
803 	else
804 		newte->totalbytes = args->ca_sa.sa_size;
805 
806 	newte->fh_u.fh = *(NFSLOG_GET_FHANDLE2(
807 		&res->nfslog_diropres_u.dr_ok.drok_fhandle));
808 
809 	/*
810 	 * if the file is being truncated on create, we need to flush
811 	 * any outstanding read/write transactions
812 	 */
813 	if (args->ca_sa.sa_size != (uint32_t)-1) {
814 		if (pte = insert_te(tf->te_list_v2_write, newte)) {
815 			nfslog_print_trans_logentry(pte, tf);
816 			remove_te(pte);
817 		}
818 		if (pte = insert_te(tf->te_list_v2_read, newte)) {
819 			nfslog_print_trans_logentry(pte, tf);
820 			remove_te(pte);
821 		}
822 	}
823 
824 	return (newte);
825 }
826 
827 static struct transentry *
828 trans_remove(
829 	nfslog_request_record *logrec,
830 	struct nfslog_trans_file *tf,
831 	char *fhpath,
832 	char *path1)
833 {
834 	struct transentry *newte;
835 	struct transentry *pte = NULL;
836 	/* LINTED */
837 	nfslog_diropargs *args = (nfslog_diropargs *)logrec->re_rpc_arg;
838 	/* LINTED */
839 	nfsstat *res = (nfsstat *)logrec->re_rpc_res;
840 
841 	if (*res != NFS_OK)
842 		return (NULL);
843 
844 	if ((newte = create_te()) == NULL)
845 		return (NULL);
846 
847 	if (!path1) {
848 		char *name = args->da_name;
849 		fhandle_t *dfh = &args->da_fhandle;
850 		newte->pathname = nfslog_get_path(dfh, name,
851 			fhpath, "trans_remove2");
852 	} else {
853 		newte->pathname = strdup(path1);
854 	}
855 
856 	newte->starttime = logrec->re_header.rh_timestamp;
857 	newte->lastupdate = logrec->re_header.rh_timestamp;
858 	newte->optype = TRANS_OPER_REMOVE;
859 	newte->datatype = TRANS_DATATYPE_BINARY;
860 	newte->transoption = TRANS_OPTION_NOACTION;
861 	newte->pnb = netbufdup(&(logrec->re_ipaddr));
862 	newte->uid = logrec->re_header.rh_uid;
863 	newte->nfsvers = NFS_VERSION;
864 	newte->netid = strdup(logrec->re_netid);
865 	if (logrec->re_principal_name)
866 		newte->principal_name = strdup(logrec->re_principal_name);
867 	else
868 		newte->principal_name = NULL;
869 	newte->totalbytes = 0;
870 	newte->fh_u.fh = *(NFSLOG_GET_FHANDLE2(&args->da_fhandle));
871 
872 	if (pte = insert_te(tf->te_list_v2_write, newte)) {
873 		nfslog_print_trans_logentry(pte, tf);
874 		remove_te(pte);
875 	}
876 	if (pte = insert_te(tf->te_list_v2_read, newte)) {
877 		nfslog_print_trans_logentry(pte, tf);
878 		remove_te(pte);
879 	}
880 	if (pte = insert_te(tf->te_list_v3_write, newte)) {
881 		nfslog_print_trans_logentry(pte, tf);
882 		remove_te(pte);
883 	}
884 	if (pte = insert_te(tf->te_list_v3_read, newte)) {
885 		nfslog_print_trans_logentry(pte, tf);
886 		remove_te(pte);
887 	}
888 
889 	return (newte);
890 }
891 
892 static struct transentry *
893 trans_mkdir(
894 	nfslog_request_record *logrec,
895 	char *fhpath,
896 	char *path1)
897 {
898 	struct transentry *newte;
899 	/* LINTED */
900 	nfslog_createargs *args = (nfslog_createargs *)logrec->re_rpc_arg;
901 	/* LINTED */
902 	nfslog_diropres *res = (nfslog_diropres *)logrec->re_rpc_res;
903 
904 	if (res->dr_status != NFS_OK)
905 		return (NULL);
906 
907 	if ((newte = create_te()) == NULL)
908 		return (NULL);
909 
910 	if (!path1) {
911 		nfslog_diropargs *dargs = &args->ca_da;
912 		char *name = dargs->da_name;
913 		fhandle_t *dfh = &dargs->da_fhandle;
914 		newte->pathname = nfslog_get_path(dfh, name,
915 			fhpath, "trans_mkdir2");
916 	} else {
917 		newte->pathname = strdup(path1);
918 	}
919 
920 	newte->starttime = logrec->re_header.rh_timestamp;
921 	newte->lastupdate = logrec->re_header.rh_timestamp;
922 	newte->optype = TRANS_OPER_MKDIR;
923 	newte->datatype = TRANS_DATATYPE_BINARY;
924 	newte->transoption = TRANS_OPTION_NOACTION;
925 	newte->pnb = netbufdup(&(logrec->re_ipaddr));
926 	newte->uid = logrec->re_header.rh_uid;
927 	newte->nfsvers = NFS_VERSION;
928 	newte->netid = strdup(logrec->re_netid);
929 	if (logrec->re_principal_name)
930 		newte->principal_name = strdup(logrec->re_principal_name);
931 	else
932 		newte->principal_name = NULL;
933 	newte->totalbytes = 0;
934 	newte->fh_u.fh = *(NFSLOG_GET_FHANDLE2(&args->ca_da.da_fhandle));
935 
936 	return (newte);
937 }
938 
939 static struct transentry *
940 trans_rmdir(
941 	nfslog_request_record *logrec,
942 	char *fhpath,
943 	char *path1)
944 {
945 	struct transentry *newte;
946 	/* LINTED */
947 	nfslog_diropargs *args = (nfslog_diropargs *)logrec->re_rpc_arg;
948 	/* LINTED */
949 	nfsstat *res = (nfsstat *)logrec->re_rpc_res;
950 
951 	if (*res != NFS_OK)
952 		return (NULL);
953 
954 	if ((newte = create_te()) == NULL)
955 		return (NULL);
956 
957 	if (!path1) {
958 		char *name = args->da_name;
959 		fhandle_t *dfh = &args->da_fhandle;
960 		newte->pathname = nfslog_get_path(dfh, name,
961 			fhpath, "trans_rmdir2");
962 	} else {
963 		newte->pathname = strdup(path1);
964 	}
965 
966 	newte->starttime = logrec->re_header.rh_timestamp;
967 	newte->lastupdate = logrec->re_header.rh_timestamp;
968 	newte->optype = TRANS_OPER_RMDIR;
969 	newte->datatype = TRANS_DATATYPE_BINARY;
970 	newte->transoption = TRANS_OPTION_NOACTION;
971 	newte->pnb = netbufdup(&(logrec->re_ipaddr));
972 	newte->uid = logrec->re_header.rh_uid;
973 	newte->nfsvers = NFS_VERSION;
974 	newte->netid = strdup(logrec->re_netid);
975 	if (logrec->re_principal_name)
976 		newte->principal_name = strdup(logrec->re_principal_name);
977 	else
978 		newte->principal_name = NULL;
979 	newte->totalbytes = 0;
980 	newte->fh_u.fh = *(NFSLOG_GET_FHANDLE2(&args->da_fhandle));
981 
982 	return (newte);
983 }
984 
985 static struct transentry *
986 trans_rename(
987 	nfslog_request_record *logrec,
988 	struct nfslog_trans_file *tf,
989 	char *fhpath,
990 	char *path1,
991 	char *path2)
992 {
993 	struct transentry *newte;
994 	struct transentry *pte = NULL;
995 	/* LINTED */
996 	nfslog_rnmargs *args = (nfslog_rnmargs *)logrec->re_rpc_arg;
997 	/* LINTED */
998 	nfsstat *res = (nfsstat *)logrec->re_rpc_res;
999 	char *tpath1 = NULL;
1000 	char *tpath2 = NULL;
1001 
1002 	if (*res != NFS_OK)
1003 		return (NULL);
1004 
1005 	if ((newte = create_te()) == NULL)
1006 		return (NULL);
1007 
1008 	if (!path1) {
1009 		char *from_name, *to_name;
1010 		fhandle_t *from_dfh, *to_dfh;
1011 
1012 		from_name = args->rna_from.da_name;
1013 		from_dfh = &args->rna_from.da_fhandle;
1014 		to_name = args->rna_to.da_name;
1015 		to_dfh = &args->rna_to.da_fhandle;
1016 
1017 		path1 = tpath1 = nfslog_get_path(from_dfh, from_name,
1018 			fhpath,	"trans_rename from");
1019 		path2 = tpath2 = nfslog_get_path(to_dfh, to_name,
1020 			fhpath, "trans_rename to");
1021 	}
1022 
1023 	newte->pathname = path1; /* no need to strdup here */
1024 	newte->starttime = logrec->re_header.rh_timestamp;
1025 	newte->lastupdate = logrec->re_header.rh_timestamp;
1026 	newte->optype = TRANS_OPER_RENAME;
1027 	newte->datatype = TRANS_DATATYPE_BINARY;
1028 	newte->transoption = TRANS_OPTION_NOACTION;
1029 	newte->pnb = netbufdup(&(logrec->re_ipaddr));
1030 	newte->uid = logrec->re_header.rh_uid;
1031 	newte->nfsvers = NFS_VERSION;
1032 	newte->netid = strdup(logrec->re_netid);
1033 	if (logrec->re_principal_name)
1034 		newte->principal_name = strdup(logrec->re_principal_name);
1035 	else
1036 		newte->principal_name = NULL;
1037 	newte->totalbytes = 0;
1038 	newte->fh_u.fh = *(NFSLOG_GET_FHANDLE2(&args->rna_from.da_fhandle));
1039 
1040 	/* switch path names for the file for renames */
1041 	if (pte = insert_te(tf->te_list_v2_write, newte)) {
1042 		free(pte->pathname);
1043 		pte->pathname = strdup(path2);
1044 	}
1045 	if (pte = insert_te(tf->te_list_v2_read, newte)) {
1046 		free(pte->pathname);
1047 		pte->pathname = strdup(path2);
1048 	}
1049 	if (pte = insert_te(tf->te_list_v3_write, newte)) {
1050 		free(pte->pathname);
1051 		pte->pathname = strdup(path2);
1052 	}
1053 	if (pte = insert_te(tf->te_list_v3_read, newte)) {
1054 		free(pte->pathname);
1055 		pte->pathname = strdup(path2);
1056 	}
1057 
1058 	newte->pathname = (char *)malloc(strlen(path1) + strlen(path2) + 3);
1059 	/* check for NULL malloc */
1060 	(void) sprintf(newte->pathname, "%s->%s", path1, path2);
1061 
1062 	if (tpath1) {
1063 		free(tpath1);
1064 		free(tpath2);
1065 	}
1066 
1067 	return (newte);
1068 }
1069 
1070 static struct transentry *
1071 trans_link(
1072 	nfslog_request_record *logrec,
1073 	char *fhpath,
1074 	char *path1,
1075 	char *path2)
1076 {
1077 	struct transentry *newte;
1078 	/* LINTED */
1079 	nfslog_linkargs *args = (nfslog_linkargs *)logrec->re_rpc_arg;
1080 	/* LINTED */
1081 	nfsstat *res = (nfsstat *)logrec->re_rpc_res;
1082 	char *tpath1 = NULL;
1083 	char *tpath2 = NULL;
1084 
1085 	if (*res != NFS_OK)
1086 		return (NULL);
1087 
1088 	if ((newte = create_te()) == NULL)
1089 		return (NULL);
1090 
1091 	if (!path1) {
1092 		fhandle_t *fh = &args->la_from;
1093 		char *name = args->la_to.da_name;
1094 		fhandle_t *dfh = &args->la_to.da_fhandle;
1095 
1096 		path1 = tpath1 = nfslog_get_path(fh, NULL,
1097 			fhpath, "trans_link from");
1098 		path2 = tpath2 = nfslog_get_path(dfh, name,
1099 			fhpath, "trans_link to");
1100 	}
1101 
1102 	newte->starttime = logrec->re_header.rh_timestamp;
1103 	newte->lastupdate = logrec->re_header.rh_timestamp;
1104 	newte->optype = TRANS_OPER_LINK;
1105 	newte->datatype = TRANS_DATATYPE_BINARY;
1106 	newte->transoption = TRANS_OPTION_NOACTION;
1107 	newte->pnb = netbufdup(&(logrec->re_ipaddr));
1108 	newte->uid = logrec->re_header.rh_uid;
1109 	newte->nfsvers = NFS_VERSION;
1110 	newte->netid = strdup(logrec->re_netid);
1111 	if (logrec->re_principal_name)
1112 		newte->principal_name = strdup(logrec->re_principal_name);
1113 	else
1114 		newte->principal_name = NULL;
1115 	newte->totalbytes = 0;
1116 	newte->fh_u.fh = *(NFSLOG_GET_FHANDLE2(&args->la_from));
1117 
1118 	newte->pathname = (char *)malloc(strlen(path1) + strlen(path2) + 3);
1119 	/* check for NULL malloc */
1120 	(void) sprintf(newte->pathname, "%s->%s", path1, path2);
1121 
1122 	if (tpath1) {
1123 		free(tpath1);
1124 		free(tpath2);
1125 	}
1126 
1127 	return (newte);
1128 }
1129 
1130 static struct transentry *
1131 trans_symlink(
1132 	nfslog_request_record *logrec,
1133 	char *fhpath,
1134 	char *path1)
1135 {
1136 	struct transentry *newte;
1137 	/* LINTED */
1138 	nfslog_symlinkargs *args = (nfslog_symlinkargs *)logrec->re_rpc_arg;
1139 	/* LINTED */
1140 	nfsstat *res = (nfsstat *)logrec->re_rpc_res;
1141 	char *tpath1 = NULL;
1142 
1143 	if (*res != NFS_OK)
1144 		return (NULL);
1145 
1146 	if ((newte = create_te()) == NULL)
1147 		return (NULL);
1148 
1149 	if (!path1) {
1150 		char *name = args->sla_from.da_name;
1151 		fhandle_t *dfh = &args->sla_from.da_fhandle;
1152 
1153 		path1 = tpath1 = nfslog_get_path(dfh, name,
1154 			fhpath, "trans_symlink");
1155 	}
1156 
1157 	newte->starttime = logrec->re_header.rh_timestamp;
1158 	newte->lastupdate = logrec->re_header.rh_timestamp;
1159 	newte->optype = TRANS_OPER_SYMLINK;
1160 	newte->datatype = TRANS_DATATYPE_BINARY;
1161 	newte->transoption = TRANS_OPTION_NOACTION;
1162 	newte->pnb = netbufdup(&(logrec->re_ipaddr));
1163 	newte->uid = logrec->re_header.rh_uid;
1164 	newte->nfsvers = NFS_VERSION;
1165 	newte->netid = strdup(logrec->re_netid);
1166 	if (logrec->re_principal_name)
1167 		newte->principal_name = strdup(logrec->re_principal_name);
1168 	else
1169 		newte->principal_name = NULL;
1170 	newte->totalbytes = 0;
1171 	newte->fh_u.fh = *(NFSLOG_GET_FHANDLE2(&args->sla_from.da_fhandle));
1172 
1173 	newte->pathname = (char *)malloc(strlen(path1) +
1174 		strlen(args->sla_tnm) + 3);
1175 	(void) sprintf(newte->pathname, "%s->%s", path1, args->sla_tnm);
1176 
1177 	if (tpath1)
1178 		free(tpath1);
1179 
1180 	return (newte);
1181 }
1182 
1183 static struct transentry *
1184 trans_read3(
1185 	nfslog_request_record *logrec,
1186 	struct nfslog_trans_file *tf,
1187 	char *fhpath,
1188 	char *path1)
1189 {
1190 	struct transentry *newte;
1191 	struct transentry *pte = NULL;
1192 	/* LINTED */
1193 	nfslog_READ3args *args = (nfslog_READ3args *)logrec->re_rpc_arg;
1194 	/* LINTED */
1195 	nfslog_READ3res *res = (nfslog_READ3res *)logrec->re_rpc_res;
1196 
1197 	if (res->status != NFS3_OK)
1198 		return (NULL);
1199 
1200 	if ((newte = create_te()) == NULL)
1201 		return (NULL);
1202 
1203 	if (!path1) {
1204 		fhandle_t *fh = NFSLOG_GET_FHANDLE3(&args->file);
1205 		newte->pathname = nfslog_get_path(fh, NULL,
1206 			fhpath, "trans_read3");
1207 	} else {
1208 		newte->pathname = strdup(path1);
1209 	}
1210 
1211 	/* prep the struct for insertion */
1212 	newte->starttime = logrec->re_header.rh_timestamp;
1213 	newte->lastupdate = logrec->re_header.rh_timestamp;
1214 	newte->optype = TRANS_OPER_READ;
1215 	newte->datatype = TRANS_DATATYPE_BINARY;
1216 	newte->transoption = TRANS_OPTION_NOACTION;
1217 	newte->pnb = netbufdup(&(logrec->re_ipaddr));
1218 	newte->uid = logrec->re_header.rh_uid;
1219 	newte->nfsvers = NFS_V3;
1220 	newte->netid = strdup(logrec->re_netid);
1221 	if (logrec->re_principal_name)
1222 		newte->principal_name = strdup(logrec->re_principal_name);
1223 	else
1224 		newte->principal_name = NULL;
1225 	newte->totalbytes = res->nfslog_READ3res_u.ok.count;
1226 	newte->fh_u.fh3 = args->file;
1227 
1228 	if (res->nfslog_READ3res_u.ok.count <
1229 		res->nfslog_READ3res_u.ok.filesize) {
1230 		if (pte = insert_te(tf->te_list_v3_read, newte)) {
1231 			/* free this since entry was found (not inserted) */
1232 			remove_te(newte);
1233 
1234 			pte->totalbytes += res->nfslog_READ3res_u.ok.count;
1235 
1236 			if (pte->lastupdate.tv_sec <=
1237 				logrec->re_header.rh_timestamp.tv_sec)
1238 				pte->lastupdate =
1239 					logrec->re_header.rh_timestamp;
1240 
1241 			if (pte->totalbytes <
1242 				res->nfslog_READ3res_u.ok.filesize) {
1243 				pte = NULL; /* prevent printing of log entry */
1244 			}
1245 		}
1246 	} else {
1247 		pte = newte; /* print a log record - complete file read */
1248 	}
1249 
1250 	return (pte);
1251 }
1252 
1253 static struct transentry *
1254 trans_write3(
1255 	nfslog_request_record *logrec,
1256 	struct nfslog_trans_file *tf,
1257 	char *fhpath,
1258 	char *path1)
1259 {
1260 	struct transentry *newte;
1261 	struct transentry *pte = NULL;
1262 	/* LINTED */
1263 	nfslog_WRITE3args *args = (nfslog_WRITE3args *)logrec->re_rpc_arg;
1264 	/* LINTED */
1265 	nfslog_WRITE3res *res = (nfslog_WRITE3res *)logrec->re_rpc_res;
1266 
1267 	if (res->status != NFS3_OK)
1268 		return (NULL);
1269 
1270 	if ((newte = create_te()) == NULL)
1271 		return (NULL);
1272 
1273 	if (!path1) {
1274 		fhandle_t *fh = NFSLOG_GET_FHANDLE3(&args->file);
1275 		newte->pathname = nfslog_get_path(fh, NULL,
1276 			fhpath, "trans_write3");
1277 	} else {
1278 		newte->pathname = strdup(path1);
1279 	}
1280 
1281 	newte->starttime = logrec->re_header.rh_timestamp;
1282 	newte->lastupdate = logrec->re_header.rh_timestamp;
1283 	newte->optype = TRANS_OPER_WRITE;
1284 	newte->datatype = TRANS_DATATYPE_BINARY;
1285 	newte->transoption = TRANS_OPTION_NOACTION;
1286 	newte->pnb = netbufdup(&(logrec->re_ipaddr));
1287 	newte->uid = logrec->re_header.rh_uid;
1288 	newte->nfsvers = NFS_V3;
1289 	newte->netid = strdup(logrec->re_netid);
1290 	if (logrec->re_principal_name)
1291 		newte->principal_name = strdup(logrec->re_principal_name);
1292 	else
1293 		newte->principal_name = NULL;
1294 	newte->totalbytes = res->nfslog_WRITE3res_u.ok.count;
1295 	newte->fh_u.fh3 = args->file;
1296 
1297 	if (pte = insert_te(tf->te_list_v3_write, newte)) {
1298 		/*
1299 		 * if the write would have increased the total byte count
1300 		 * over the filesize, then generate a log entry and remove
1301 		 * the write record and insert the new one.
1302 		 */
1303 		if (pte->totalbytes + res->nfslog_WRITE3res_u.ok.count >
1304 			res->nfslog_WRITE3res_u.ok.filesize) {
1305 			nfslog_print_trans_logentry(pte, tf);
1306 			remove_te(pte);
1307 			(void) insert_te(tf->te_list_v3_write, newte);
1308 			pte = NULL;
1309 		} else {
1310 			/* free this since entry was found (not inserted) */
1311 			remove_te(newte);
1312 
1313 			pte->totalbytes += res->nfslog_WRITE3res_u.ok.count;
1314 
1315 			if (pte->lastupdate.tv_sec <=
1316 				logrec->re_header.rh_timestamp.tv_sec) {
1317 				pte->lastupdate =
1318 					logrec->re_header.rh_timestamp;
1319 			}
1320 			pte = NULL; /* prevent printing of log entry */
1321 		}
1322 	}
1323 	return (pte);
1324 }
1325 
1326 static struct transentry *
1327 trans_setattr3(
1328 	nfslog_request_record *logrec,
1329 	struct nfslog_trans_file *tf,
1330 	char *fhpath,
1331 	char *path1)
1332 {
1333 	struct transentry *newte;
1334 	struct transentry *pte = NULL;
1335 	/* LINTED */
1336 	nfslog_SETATTR3args *args = (nfslog_SETATTR3args *)logrec->re_rpc_arg;
1337 	/* LINTED */
1338 	nfsstat3 *res = (nfsstat3 *)logrec->re_rpc_res;
1339 
1340 	if (*res != NFS3_OK)
1341 		return (NULL);
1342 
1343 	if (!args->size.set_it)
1344 		return (NULL);
1345 	/*
1346 	 * should check the size of the file to see if it
1347 	 * is being truncated below current eof.  if so
1348 	 * a record should be generated.... XXX
1349 	 */
1350 	if (args->size.size != 0)
1351 		return (NULL);
1352 
1353 	if ((newte = create_te()) == NULL)
1354 		return (NULL);
1355 
1356 	if (!path1) {
1357 		fhandle_t *fh = NFSLOG_GET_FHANDLE3(&args->object);
1358 		newte->pathname = nfslog_get_path(fh, NULL,
1359 			fhpath, "trans_setattr3");
1360 	} else {
1361 		newte->pathname = strdup(path1);
1362 	}
1363 
1364 	newte->starttime = logrec->re_header.rh_timestamp;
1365 	newte->lastupdate = logrec->re_header.rh_timestamp;
1366 	newte->optype = TRANS_OPER_SETATTR;
1367 	newte->datatype = TRANS_DATATYPE_BINARY;
1368 	newte->transoption = TRANS_OPTION_NOACTION;
1369 	newte->pnb = netbufdup(&(logrec->re_ipaddr));
1370 	newte->uid = logrec->re_header.rh_uid;
1371 	newte->nfsvers = NFS_V3;
1372 	newte->netid = strdup(logrec->re_netid);
1373 	if (logrec->re_principal_name)
1374 		newte->principal_name = strdup(logrec->re_principal_name);
1375 	else
1376 		newte->principal_name = NULL;
1377 	newte->totalbytes = 0;
1378 	newte->fh_u.fh3 = args->object;
1379 
1380 	if (pte = insert_te(tf->te_list_v3_write, newte)) {
1381 		nfslog_print_trans_logentry(pte, tf);
1382 		remove_te(pte);
1383 	}
1384 	if (pte = insert_te(tf->te_list_v3_read, newte)) {
1385 		nfslog_print_trans_logentry(pte, tf);
1386 		remove_te(pte);
1387 	}
1388 
1389 	return (newte);
1390 }
1391 
1392 static struct transentry *
1393 trans_create3(
1394 	nfslog_request_record *logrec,
1395 	struct nfslog_trans_file *tf,
1396 	char *fhpath,
1397 	char *path1)
1398 {
1399 	struct transentry *newte;
1400 	struct transentry *pte = NULL;
1401 	/* LINTED */
1402 	nfslog_CREATE3args *args = (nfslog_CREATE3args *)logrec->re_rpc_arg;
1403 	/* LINTED */
1404 	nfslog_CREATE3res *res = (nfslog_CREATE3res *)logrec->re_rpc_res;
1405 
1406 	if (res->status != NFS3_OK)
1407 		return (NULL);
1408 
1409 	if ((newte = create_te()) == NULL)
1410 		return (NULL);
1411 
1412 	if (!path1) {
1413 		newte->pathname =
1414 			nfslog_get_path(NFSLOG_GET_FHANDLE3(&args->where.dir),
1415 				args->where.name,
1416 				fhpath, "trans_create3");
1417 	} else {
1418 		newte->pathname = strdup(path1);
1419 	}
1420 
1421 	newte->starttime = logrec->re_header.rh_timestamp;
1422 	newte->lastupdate = logrec->re_header.rh_timestamp;
1423 	newte->optype = TRANS_OPER_CREATE;
1424 	newte->datatype = TRANS_DATATYPE_BINARY;
1425 	newte->transoption = TRANS_OPTION_NOACTION;
1426 	newte->pnb = netbufdup(&(logrec->re_ipaddr));
1427 	newte->uid = logrec->re_header.rh_uid;
1428 	newte->nfsvers = NFS_V3;
1429 	newte->netid = strdup(logrec->re_netid);
1430 	if (logrec->re_principal_name)
1431 		newte->principal_name = strdup(logrec->re_principal_name);
1432 	else
1433 		newte->principal_name = NULL;
1434 
1435 	if (!args->how.nfslog_createhow3_u.size.set_it)
1436 		newte->totalbytes = 0;
1437 	else
1438 		newte->totalbytes =
1439 			args->how.nfslog_createhow3_u.size.size;
1440 
1441 	newte->fh_u.fh3 = args->where.dir;
1442 
1443 	if (args->how.nfslog_createhow3_u.size.set_it) {
1444 		if (pte = insert_te(tf->te_list_v3_write, newte)) {
1445 			nfslog_print_trans_logentry(pte, tf);
1446 			remove_te(pte);
1447 		}
1448 		if (pte = insert_te(tf->te_list_v3_read, newte)) {
1449 			nfslog_print_trans_logentry(pte, tf);
1450 			remove_te(pte);
1451 		}
1452 	}
1453 
1454 	return (newte);
1455 }
1456 
1457 static struct transentry *
1458 trans_remove3(
1459 	nfslog_request_record *logrec,
1460 	struct nfslog_trans_file *tf,
1461 	char *fhpath,
1462 	char *path1)
1463 {
1464 	struct transentry *newte;
1465 	struct transentry *pte = NULL;
1466 	/* LINTED */
1467 	nfslog_REMOVE3args *args = (nfslog_REMOVE3args *)logrec->re_rpc_arg;
1468 	/* LINTED */
1469 	nfsstat3 *res = (nfsstat3 *)logrec->re_rpc_res;
1470 
1471 	if (*res != NFS3_OK)
1472 		return (NULL);
1473 
1474 	if ((newte = create_te()) == NULL)
1475 		return (NULL);
1476 
1477 	if (!path1) {
1478 		newte->pathname =
1479 			nfslog_get_path(NFSLOG_GET_FHANDLE3(&args->object.dir),
1480 				args->object.name,
1481 				fhpath, "trans_remove3");
1482 	} else {
1483 		newte->pathname = strdup(path1);
1484 	}
1485 
1486 	newte->starttime = logrec->re_header.rh_timestamp;
1487 	newte->lastupdate = logrec->re_header.rh_timestamp;
1488 	newte->optype = TRANS_OPER_REMOVE;
1489 	newte->datatype = TRANS_DATATYPE_BINARY;
1490 	newte->transoption = TRANS_OPTION_NOACTION;
1491 	newte->pnb = netbufdup(&(logrec->re_ipaddr));
1492 	newte->uid = logrec->re_header.rh_uid;
1493 	newte->nfsvers = NFS_V3;
1494 	newte->netid = strdup(logrec->re_netid);
1495 	if (logrec->re_principal_name)
1496 		newte->principal_name = strdup(logrec->re_principal_name);
1497 	else
1498 		newte->principal_name = NULL;
1499 	newte->totalbytes = 0;
1500 	newte->fh_u.fh3 = args->object.dir;
1501 
1502 	if (pte = insert_te(tf->te_list_v3_write, newte)) {
1503 		nfslog_print_trans_logentry(pte, tf);
1504 		remove_te(pte);
1505 	}
1506 	if (pte = insert_te(tf->te_list_v3_read, newte)) {
1507 		nfslog_print_trans_logentry(pte, tf);
1508 		remove_te(pte);
1509 	}
1510 	if (pte = insert_te(tf->te_list_v2_write, newte)) {
1511 		nfslog_print_trans_logentry(pte, tf);
1512 		remove_te(pte);
1513 	}
1514 	if (pte = insert_te(tf->te_list_v2_read, newte)) {
1515 		nfslog_print_trans_logentry(pte, tf);
1516 		remove_te(pte);
1517 	}
1518 
1519 	return (newte);
1520 }
1521 
1522 static struct transentry *
1523 trans_mkdir3(
1524 	nfslog_request_record *logrec,
1525 	char *fhpath,
1526 	char *path1)
1527 {
1528 	struct transentry *newte;
1529 	/* LINTED */
1530 	nfslog_MKDIR3args *args = (nfslog_MKDIR3args *)logrec->re_rpc_arg;
1531 	/* LINTED */
1532 	nfslog_MKDIR3res *res = (nfslog_MKDIR3res *)logrec->re_rpc_res;
1533 
1534 	if (res->status != NFS3_OK)
1535 		return (NULL);
1536 
1537 	if ((newte = create_te()) == NULL)
1538 		return (NULL);
1539 
1540 	if (!path1) {
1541 		newte->pathname =
1542 			nfslog_get_path(NFSLOG_GET_FHANDLE3(&args->where.dir),
1543 				args->where.name,
1544 				fhpath, "trans_mkdir3");
1545 	} else {
1546 		newte->pathname = strdup(path1);
1547 	}
1548 
1549 	newte->starttime = logrec->re_header.rh_timestamp;
1550 	newte->lastupdate = logrec->re_header.rh_timestamp;
1551 	newte->optype = TRANS_OPER_MKDIR;
1552 	newte->datatype = TRANS_DATATYPE_BINARY;
1553 	newte->transoption = TRANS_OPTION_NOACTION;
1554 	newte->pnb = netbufdup(&(logrec->re_ipaddr));
1555 	newte->uid = logrec->re_header.rh_uid;
1556 	newte->nfsvers = NFS_V3;
1557 	newte->netid = strdup(logrec->re_netid);
1558 	if (logrec->re_principal_name)
1559 		newte->principal_name = strdup(logrec->re_principal_name);
1560 	else
1561 		newte->principal_name = NULL;
1562 	newte->totalbytes = 0;
1563 	newte->fh_u.fh3 = args->where.dir;
1564 
1565 	return (newte);
1566 }
1567 
1568 static struct transentry *
1569 trans_rmdir3(
1570 	nfslog_request_record *logrec,
1571 	char *fhpath,
1572 	char *path1)
1573 {
1574 	struct transentry *newte;
1575 	/* LINTED */
1576 	nfslog_RMDIR3args *args = (nfslog_RMDIR3args *)logrec->re_rpc_arg;
1577 	/* LINTED */
1578 	nfsstat3 *res = (nfsstat3 *)logrec->re_rpc_res;
1579 
1580 	if (*res != NFS3_OK)
1581 		return (NULL);
1582 
1583 	if ((newte = create_te()) == NULL)
1584 		return (NULL);
1585 
1586 	if (!path1) {
1587 		newte->pathname =
1588 			nfslog_get_path(NFSLOG_GET_FHANDLE3(&args->object.dir),
1589 				args->object.name,
1590 				fhpath, "trans_rmdir3");
1591 	} else {
1592 		newte->pathname = strdup(path1);
1593 	}
1594 
1595 	newte->starttime = logrec->re_header.rh_timestamp;
1596 	newte->lastupdate = logrec->re_header.rh_timestamp;
1597 	newte->optype = TRANS_OPER_RMDIR;
1598 	newte->datatype = TRANS_DATATYPE_BINARY;
1599 	newte->transoption = TRANS_OPTION_NOACTION;
1600 	newte->pnb = netbufdup(&(logrec->re_ipaddr));
1601 	newte->uid = logrec->re_header.rh_uid;
1602 	newte->nfsvers = NFS_V3;
1603 	newte->netid = strdup(logrec->re_netid);
1604 	if (logrec->re_principal_name)
1605 		newte->principal_name = strdup(logrec->re_principal_name);
1606 	else
1607 		newte->principal_name = NULL;
1608 	newte->totalbytes = 0;
1609 	newte->fh_u.fh3 = args->object.dir;
1610 
1611 	return (newte);
1612 }
1613 
1614 static struct transentry *
1615 trans_rename3(
1616 	nfslog_request_record *logrec,
1617 	struct nfslog_trans_file *tf,
1618 	char *fhpath,
1619 	char *path1,
1620 	char *path2)
1621 {
1622 	struct transentry *newte;
1623 	struct transentry *pte = NULL;
1624 	/* LINTED */
1625 	nfslog_RENAME3args *args = (nfslog_RENAME3args *)logrec->re_rpc_arg;
1626 	/* LINTED */
1627 	nfsstat3 *res = (nfsstat3 *)logrec->re_rpc_res;
1628 	char *tpath1 = NULL;
1629 	char *tpath2 = NULL;
1630 
1631 	if (*res != NFS3_OK)
1632 		return (NULL);
1633 
1634 	if ((newte = create_te()) == NULL)
1635 		return (NULL);
1636 
1637 	if (!path1) {
1638 		path1 = tpath1 =
1639 			nfslog_get_path(NFSLOG_GET_FHANDLE3(&args->from.dir),
1640 				args->from.name, fhpath, "trans_rename3 from");
1641 		path2 = tpath2 =
1642 			nfslog_get_path(NFSLOG_GET_FHANDLE3(&args->to.dir),
1643 				args->to.name, fhpath, "trans_rename3 to");
1644 	}
1645 
1646 	newte->pathname = path1; /* no need to strdup here */
1647 	newte->starttime = logrec->re_header.rh_timestamp;
1648 	newte->lastupdate = logrec->re_header.rh_timestamp;
1649 	newte->optype = TRANS_OPER_RENAME;
1650 	newte->datatype = TRANS_DATATYPE_BINARY;
1651 	newte->transoption = TRANS_OPTION_NOACTION;
1652 	newte->pnb = netbufdup(&(logrec->re_ipaddr));
1653 	newte->uid = logrec->re_header.rh_uid;
1654 	newte->nfsvers = NFS_V3;
1655 	newte->netid = strdup(logrec->re_netid);
1656 	if (logrec->re_principal_name)
1657 		newte->principal_name = strdup(logrec->re_principal_name);
1658 	else
1659 		newte->principal_name = NULL;
1660 	newte->totalbytes = 0;
1661 	newte->fh_u.fh3 = args->from.dir;
1662 
1663 	/* switch path names for the file for renames */
1664 	if (pte = insert_te(tf->te_list_v3_write, newte)) {
1665 		free(pte->pathname);
1666 		pte->pathname = strdup(path2);
1667 	}
1668 	if (pte = insert_te(tf->te_list_v3_read, newte)) {
1669 		free(pte->pathname);
1670 		pte->pathname = strdup(path2);
1671 	}
1672 	if (pte = insert_te(tf->te_list_v2_write, newte)) {
1673 		free(pte->pathname);
1674 		pte->pathname = strdup(path2);
1675 	}
1676 	if (pte = insert_te(tf->te_list_v2_read, newte)) {
1677 		free(pte->pathname);
1678 		pte->pathname = strdup(path2);
1679 	}
1680 
1681 	newte->pathname = (char *)malloc(strlen(path1) + strlen(path2) + 3);
1682 	/* check for NULL malloc */
1683 	(void) sprintf(newte->pathname, "%s->%s", path1, path2);
1684 
1685 	if (tpath1) {
1686 		free(tpath1);
1687 		free(tpath2);
1688 	}
1689 
1690 	return (newte);
1691 }
1692 
1693 static struct transentry *
1694 trans_mknod3(
1695 	nfslog_request_record *logrec,
1696 	char *fhpath,
1697 	char *path1)
1698 {
1699 	struct transentry *newte;
1700 	/* LINTED */
1701 	nfslog_MKNOD3args *args = (nfslog_MKNOD3args *)logrec->re_rpc_arg;
1702 	/* LINTED */
1703 	nfslog_MKNOD3res *res = (nfslog_MKNOD3res *)logrec->re_rpc_res;
1704 
1705 	if (res->status != NFS3_OK)
1706 		return (NULL);
1707 
1708 	if ((newte = create_te()) == NULL)
1709 		return (NULL);
1710 
1711 	if (!path1) {
1712 		newte->pathname =
1713 			nfslog_get_path(NFSLOG_GET_FHANDLE3(&args->where.dir),
1714 				args->where.name,
1715 				fhpath, "trans_mknod3");
1716 	} else {
1717 		newte->pathname = strdup(path1);
1718 	}
1719 
1720 	newte->starttime = logrec->re_header.rh_timestamp;
1721 	newte->lastupdate = logrec->re_header.rh_timestamp;
1722 	newte->optype = TRANS_OPER_MKNOD;
1723 	newte->datatype = TRANS_DATATYPE_BINARY;
1724 	newte->transoption = TRANS_OPTION_NOACTION;
1725 	newte->pnb = netbufdup(&(logrec->re_ipaddr));
1726 	newte->uid = logrec->re_header.rh_uid;
1727 	newte->nfsvers = NFS_V3;
1728 	newte->netid = strdup(logrec->re_netid);
1729 	if (logrec->re_principal_name)
1730 		newte->principal_name = strdup(logrec->re_principal_name);
1731 	else
1732 		newte->principal_name = NULL;
1733 
1734 	newte->totalbytes = 0;
1735 	newte->fh_u.fh3 = args->where.dir;
1736 
1737 	return (newte);
1738 }
1739 
1740 static struct transentry *
1741 trans_link3(
1742 	nfslog_request_record *logrec,
1743 	char *fhpath,
1744 	char *path1,
1745 	char *path2)
1746 {
1747 	struct transentry *newte;
1748 	/* LINTED */
1749 	nfslog_LINK3args *args = (nfslog_LINK3args *)logrec->re_rpc_arg;
1750 	/* LINTED */
1751 	nfsstat3 *res = (nfsstat3 *)logrec->re_rpc_res;
1752 
1753 	char *tpath1 = NULL;
1754 	char *tpath2 = NULL;
1755 
1756 	if (*res != NFS3_OK)
1757 		return (NULL);
1758 
1759 	if ((newte = create_te()) == NULL)
1760 		return (NULL);
1761 
1762 	if (!path1) {
1763 		tpath1 = nfslog_get_path(NFSLOG_GET_FHANDLE3(&args->file),
1764 			NULL, fhpath, "trans_link3 from");
1765 		tpath2 = nfslog_get_path(NFSLOG_GET_FHANDLE3(&args->link.dir),
1766 			args->link.name, fhpath, "trans_link3 to");
1767 		path1 = tpath1;
1768 		path2 = tpath2;
1769 	}
1770 
1771 	newte->starttime = logrec->re_header.rh_timestamp;
1772 	newte->lastupdate = logrec->re_header.rh_timestamp;
1773 	newte->optype = TRANS_OPER_LINK;
1774 	newte->datatype = TRANS_DATATYPE_BINARY;
1775 	newte->transoption = TRANS_OPTION_NOACTION;
1776 	newte->pnb = netbufdup(&(logrec->re_ipaddr));
1777 	newte->uid = logrec->re_header.rh_uid;
1778 	newte->nfsvers = NFS_V3;
1779 	newte->netid = strdup(logrec->re_netid);
1780 	if (logrec->re_principal_name)
1781 		newte->principal_name = strdup(logrec->re_principal_name);
1782 	else
1783 		newte->principal_name = NULL;
1784 	newte->totalbytes = 0;
1785 	newte->fh_u.fh3 = args->file;
1786 
1787 	newte->pathname = (char *)malloc(strlen(path1) + strlen(path2) + 3);
1788 	/* check for NULL malloc */
1789 	(void) sprintf(newte->pathname, "%s->%s", path1, path2);
1790 
1791 	if (tpath1) {
1792 		free(tpath1);
1793 		free(tpath2);
1794 	}
1795 
1796 	return (newte);
1797 }
1798 
1799 static struct transentry *
1800 trans_symlink3(
1801 	nfslog_request_record *logrec,
1802 	char *fhpath,
1803 	char *path1)
1804 {
1805 	struct transentry *newte;
1806 	/* LINTED */
1807 	nfslog_SYMLINK3args *args = (nfslog_SYMLINK3args *)logrec->re_rpc_arg;
1808 	/* LINTED */
1809 	nfslog_SYMLINK3res *res = (nfslog_SYMLINK3res *)logrec->re_rpc_res;
1810 	char *name;
1811 
1812 	if (res->status != NFS3_OK)
1813 		return (NULL);
1814 
1815 	if ((newte = create_te()) == NULL)
1816 		return (NULL);
1817 
1818 	if (path1) {
1819 		name = strdup(path1);
1820 	} else {
1821 		name = nfslog_get_path(NFSLOG_GET_FHANDLE3(&args->where.dir),
1822 			args->where.name, fhpath, "trans_symlink3");
1823 	}
1824 
1825 	newte->starttime = logrec->re_header.rh_timestamp;
1826 	newte->lastupdate = logrec->re_header.rh_timestamp;
1827 	newte->optype = TRANS_OPER_SYMLINK;
1828 	newte->datatype = TRANS_DATATYPE_BINARY;
1829 	newte->transoption = TRANS_OPTION_NOACTION;
1830 	newte->pnb = netbufdup(&(logrec->re_ipaddr));
1831 	newte->uid = logrec->re_header.rh_uid;
1832 	newte->nfsvers = NFS_V3;
1833 	newte->netid = strdup(logrec->re_netid);
1834 	if (logrec->re_principal_name)
1835 		newte->principal_name = strdup(logrec->re_principal_name);
1836 	else
1837 		newte->principal_name = NULL;
1838 	newte->totalbytes = 0;
1839 	newte->fh_u.fh3 = args->where.dir;
1840 
1841 	newte->pathname = (char *)malloc(strlen(name) +
1842 		strlen(args->symlink_data) + 3);
1843 	/* check for NULL malloc */
1844 	(void) sprintf(newte->pathname, "%s->%s", name, args->symlink_data);
1845 
1846 	free(name);
1847 
1848 	return (newte);
1849 }
1850 
1851 /*
1852  * nfslog_process_trans_rec - processes the record in the buffer and outputs
1853  *	to the trans log.
1854  * Return 0 for success, errno else.
1855  */
1856 int
1857 nfslog_process_trans_rec(void *transcookie, nfslog_request_record *logrec,
1858 	char *fhpath, char *path1, char *path2)
1859 {
1860 	struct transentry	*pte = NULL;
1861 	struct nfslog_trans_file *tf = (struct nfslog_trans_file *)transcookie;
1862 
1863 	/* ignore programs other than nfs */
1864 	if (logrec->re_header.rh_prognum != NFS_PROGRAM)
1865 		return (0);
1866 
1867 	/* update the timestamp for use later in the timeout sequences */
1868 	if (tf->lasttrans_timestamp.tv_sec <
1869 		logrec->re_header.rh_timestamp.tv_sec)
1870 		tf->lasttrans_timestamp =
1871 			logrec->re_header.rh_timestamp;
1872 
1873 	/* current time of this processing */
1874 	tf->last_trans_read = time(0);
1875 
1876 	/* ignore anything that is not a read or write */
1877 	switch (logrec->re_header.rh_version) {
1878 	case NFS_VERSION:
1879 		switch (logrec->re_header.rh_procnum) {
1880 		case RFS_READ:
1881 			if (tf->trans_to_log & TRANSTOLOG_OPER_READ)
1882 				pte = trans_read(logrec, tf, fhpath, path1);
1883 			break;
1884 		case RFS_WRITE:
1885 			if (tf->trans_to_log & TRANSTOLOG_OPER_WRITE)
1886 				pte = trans_write(logrec, tf, fhpath, path1);
1887 			break;
1888 		case RFS_SETATTR:
1889 			if (tf->trans_to_log & TRANSTOLOG_OPER_SETATTR)
1890 				pte = trans_setattr(logrec, tf,
1891 					fhpath, path1);
1892 			break;
1893 		case RFS_REMOVE:
1894 			if (tf->trans_to_log & TRANSTOLOG_OPER_REMOVE)
1895 				pte = trans_remove(logrec, tf,	fhpath, path1);
1896 			break;
1897 		case RFS_MKDIR:
1898 			if (tf->trans_to_log & TRANSTOLOG_OPER_MKDIR)
1899 				pte = trans_mkdir(logrec, fhpath, path1);
1900 			break;
1901 		case RFS_RMDIR:
1902 			if (tf->trans_to_log & TRANSTOLOG_OPER_RMDIR)
1903 				pte = trans_rmdir(logrec, fhpath, path1);
1904 			break;
1905 		case RFS_CREATE:
1906 			if (tf->trans_to_log & TRANSTOLOG_OPER_CREATE)
1907 				pte = trans_create(logrec, tf, fhpath, path1);
1908 			break;
1909 		case RFS_RENAME:
1910 			if (tf->trans_to_log & TRANSTOLOG_OPER_RENAME)
1911 				pte = trans_rename(logrec, tf,
1912 					fhpath, path1, path2);
1913 			break;
1914 		case RFS_LINK:
1915 			if (tf->trans_to_log & TRANSTOLOG_OPER_LINK)
1916 				pte = trans_link(logrec, fhpath, path1, path2);
1917 			break;
1918 		case RFS_SYMLINK:
1919 			if (tf->trans_to_log & TRANSTOLOG_OPER_SYMLINK)
1920 				pte = trans_symlink(logrec, fhpath, path1);
1921 			break;
1922 		default:
1923 			break;
1924 		}
1925 		break;
1926 	case NFS_V3:
1927 		switch (logrec->re_header.rh_procnum) {
1928 		case NFSPROC3_READ:
1929 			if (tf->trans_to_log & TRANSTOLOG_OPER_READ)
1930 				pte = trans_read3(logrec, tf, fhpath, path1);
1931 			break;
1932 		case NFSPROC3_WRITE:
1933 			if (tf->trans_to_log & TRANSTOLOG_OPER_WRITE)
1934 				pte = trans_write3(logrec, tf, fhpath, path1);
1935 			break;
1936 		case NFSPROC3_SETATTR:
1937 			if (tf->trans_to_log & TRANSTOLOG_OPER_SETATTR)
1938 				pte = trans_setattr3(logrec, tf,
1939 					fhpath, path1);
1940 			break;
1941 		case NFSPROC3_REMOVE:
1942 			if (tf->trans_to_log & TRANSTOLOG_OPER_REMOVE)
1943 				pte = trans_remove3(logrec, tf,
1944 					fhpath, path1);
1945 			break;
1946 		case NFSPROC3_MKDIR:
1947 			if (tf->trans_to_log & TRANSTOLOG_OPER_MKDIR)
1948 				pte = trans_mkdir3(logrec, fhpath, path1);
1949 			break;
1950 		case NFSPROC3_RMDIR:
1951 			if (tf->trans_to_log & TRANSTOLOG_OPER_RMDIR)
1952 				pte = trans_rmdir3(logrec, fhpath, path1);
1953 			break;
1954 		case NFSPROC3_CREATE:
1955 			if (tf->trans_to_log & TRANSTOLOG_OPER_CREATE)
1956 				pte = trans_create3(logrec, tf,
1957 					fhpath, path1);
1958 			break;
1959 		case NFSPROC3_RENAME:
1960 			if (tf->trans_to_log & TRANSTOLOG_OPER_RENAME)
1961 				pte = trans_rename3(logrec, tf,
1962 					fhpath, path1, path2);
1963 			break;
1964 		case NFSPROC3_MKNOD:
1965 			if (tf->trans_to_log & TRANSTOLOG_OPER_MKNOD)
1966 				pte = trans_mknod3(logrec, fhpath, path1);
1967 			break;
1968 		case NFSPROC3_LINK:
1969 			if (tf->trans_to_log & TRANSTOLOG_OPER_LINK)
1970 				pte = trans_link3(logrec,
1971 					fhpath, path1, path2);
1972 			break;
1973 		case NFSPROC3_SYMLINK:
1974 			if (tf->trans_to_log & TRANSTOLOG_OPER_SYMLINK)
1975 				pte = trans_symlink3(logrec, fhpath, path1);
1976 			break;
1977 		default:
1978 			break;
1979 		}
1980 		break;
1981 	default:
1982 		break;
1983 	}
1984 
1985 	if (pte != NULL) {
1986 		nfslog_print_trans_logentry(pte, tf);
1987 		remove_te(pte);
1988 	}
1989 
1990 	return (0);
1991 }
1992 
1993 static void
1994 nfslog_print_trans_logentry(struct transentry *pte,
1995 	struct nfslog_trans_file *tf)
1996 {
1997 	char *remotehost;
1998 	char datatype;
1999 	char transoption;
2000 	char *optype;
2001 	char *prin;
2002 	int prinid;
2003 	char nfs_ident[32];
2004 
2005 	remotehost = addrtoname(pte->pnb->buf);
2006 
2007 	datatype = (pte->datatype == TRANS_DATATYPE_BINARY ? 'b' : 'a');
2008 	transoption = (pte->transoption == TRANS_OPTION_NOACTION ? '_' : '?');
2009 
2010 	if (tf->trans_output_type == TRANSLOG_BASIC) {
2011 		(void) strcpy(nfs_ident, "nfs");
2012 	} else {
2013 		(void) strcpy(nfs_ident,
2014 			(pte->nfsvers == NFS_V3 ? "nfs3-" : "nfs-"));
2015 		(void) strcat(nfs_ident, pte->netid);
2016 	}
2017 
2018 	switch (pte->optype) {
2019 	case TRANS_OPER_READ:
2020 		optype = (tf->trans_output_type == TRANSLOG_EXTENDED ?
2021 			"read" : "o");
2022 		break;
2023 	case TRANS_OPER_WRITE:
2024 		optype = (tf->trans_output_type == TRANSLOG_EXTENDED ?
2025 			"write" : "i");
2026 		break;
2027 	case TRANS_OPER_REMOVE:
2028 		optype = (tf->trans_output_type == TRANSLOG_EXTENDED ?
2029 			"remove" : "?");
2030 		break;
2031 	case TRANS_OPER_MKDIR:
2032 		optype = (tf->trans_output_type == TRANSLOG_EXTENDED ?
2033 			"mkdir" : "?");
2034 		break;
2035 	case TRANS_OPER_CREATE:
2036 		optype = (tf->trans_output_type == TRANSLOG_EXTENDED ?
2037 			"create" : "?");
2038 		break;
2039 	case TRANS_OPER_RMDIR:
2040 		optype = (tf->trans_output_type == TRANSLOG_EXTENDED ?
2041 			"rmdir" : "?");
2042 		break;
2043 	case TRANS_OPER_SETATTR:
2044 		optype = (tf->trans_output_type == TRANSLOG_EXTENDED ?
2045 			"setattr" : "?");
2046 		break;
2047 	case TRANS_OPER_RENAME:
2048 		optype = (tf->trans_output_type == TRANSLOG_EXTENDED ?
2049 			"rename" : "?");
2050 		break;
2051 	case TRANS_OPER_MKNOD:
2052 		optype = (tf->trans_output_type == TRANSLOG_EXTENDED ?
2053 			"mknod" : "?");
2054 		break;
2055 	case TRANS_OPER_LINK:
2056 		optype = (tf->trans_output_type == TRANSLOG_EXTENDED ?
2057 			"link" : "?");
2058 		break;
2059 	case TRANS_OPER_SYMLINK:
2060 		optype = (tf->trans_output_type == TRANSLOG_EXTENDED ?
2061 			"symlink" : "?");
2062 		break;
2063 	default:
2064 		optype = "?";
2065 		break;
2066 	}
2067 	if (strcmp(pte->principal_name, "") == 0) {
2068 		prinid = 0;
2069 		prin = "*";
2070 	} else {
2071 		prinid = 1;
2072 		prin = pte->principal_name;
2073 	}
2074 	(void) fprintf(tf->fp,
2075 		"%.24s %d %s %d %s %c %c %s %c %ld %s %d %s\n",
2076 		ctime((time_t *)&pte->starttime.tv_sec),
2077 		pte->lastupdate.tv_sec - pte->starttime.tv_sec,
2078 		remotehost,
2079 		(uint32_t)pte->totalbytes,
2080 		pte->pathname,
2081 		datatype,
2082 		transoption,
2083 		optype,
2084 		'r', /* anonymous == 'a', guest == 'g', real == 'r'), */
2085 		pte->uid,
2086 		nfs_ident,
2087 		/* authenticated - fill in kerb/security? */
2088 		prinid,
2089 		/* authenticated ? authuser : "*" */
2090 		prin);
2091 }
2092