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