xref: /illumos-gate/usr/src/cmd/fs.d/nfs/nfslog/fhtab.c (revision ddb365bfc9e868ad24ccdcb0dc91af18b10df082)
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 /*
28  * Code to maintain the runtime and on-disk filehandle mapping table for
29  * nfslog.
30  */
31 
32 #include <assert.h>
33 #include <errno.h>
34 #include <nfs/nfs.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <strings.h>
38 #include <syslog.h>
39 #include <libintl.h>
40 #include <unistd.h>
41 #include <nfs/nfs.h>
42 #include <nfs/nfs_log.h>
43 #include "fhtab.h"
44 #include "nfslogd.h"
45 
46 #define	ROUNDUP32(val)		(((val) + 3) & ~3)
47 
48 #define	IS_DOT_FILENAME(name)						\
49 	((strcmp(name, ".") == 0) || (strcmp(name, "..") == 0))
50 
51 #define	PRINT_LINK_DATA(fp, func, dfh, name, str)			\
52 	(void) fprintf(fp, "%s: name '%s', dfh ",			\
53 		func, (((name) != NULL) ? name : ""));			\
54 	debug_opaque_print(fp, dfh, sizeof (*(dfh)));			\
55 	(void) fprintf(fp, "%s\n", str);
56 
57 
58 #define	PRINT_FULL_DATA(fp, func, dfh, fh, name, str)			\
59 	(void) fprintf(fp, "%s: name '%s', dfh ",			\
60 		func, (((name) != NULL) ? name : ""));			\
61 	debug_opaque_print(fp, dfh, sizeof (*(dfh)));			\
62 	if ((fh) != NULL) {						\
63 		(void) fprintf(fp, ", fh ");				\
64 		debug_opaque_print(fp, fh, sizeof (*(fh)));		\
65 	}								\
66 	(void) fprintf(fp, "%s\n", str);
67 
68 /*
69  * export handle cache
70  */
71 struct export_handle_cache {
72 	fhandle_t			fh;
73 	char				*name;
74 	struct export_handle_cache	*next;
75 };
76 
77 static struct export_handle_cache	*exp_handle_cache = NULL;
78 
79 extern bool_t nfsl_prin_fh;
80 
81 static int	fh_add(char *, fhandle_t *, fhandle_t *, char *);
82 
83 static char *get_export_path(fhandle_t *, char *);
84 static void sprint_fid(char *, uint_t, const fhandle_t *);
85 static void fh_print_all_keys(char *fhpath, fhandle_t *fh);
86 static int fh_compare(fhandle_t *fh1, fhandle_t *fh2);
87 static fhlist_ent *fh_lookup(char *fhpath, fhandle_t *fh, fhlist_ent *fhrecp,
88 	int *errorp);
89 static int fh_remove_mc_link(char *fhpath, fhandle_t *dfh, char *name,
90 	char **pathp);
91 static int fh_remove(char *fhpath, fhandle_t *dfh, char *name, char **pathp);
92 static int fh_rename(char *fhpath, fhandle_t *from_dfh, char *from_name,
93 	char **from_pathp, fhandle_t *to_dfh, char *to_name);
94 
95 static fhlist_ent *fh_lookup_link(char *fhpath, fhandle_t *dfh, fhandle_t *fh,
96 	char *name, fhlist_ent *fhrecp, int *errorp);
97 static struct nfsl_fh_proc_disp *nfslog_find_fh_dispatch(
98 	nfslog_request_record *);
99 static struct export_handle_cache *find_fh_in_export_cache(fhandle_t *fh);
100 static void add_fh_to_export_cache(fhandle_t *fh, char *path);
101 static char *update_export_point(char *fhpath, fhandle_t *fh, char *path);
102 static char *fh_print_absolute(char *fhpath, fhandle_t *fh, char *name);
103 static void nfslog_null_fhargs(caddr_t *nfsl_args, caddr_t *nfsl_res,
104 	char *fhpath, char **pathp1, char **pathp2);
105 static void nfslog_LOOKUP_calc(fhandle_t *dfh, char *name, fhandle_t *fh,
106 	char *fhpath, char **pathp1, char **pathp2, char *str);
107 
108 /*
109  * NFS VERSION 2
110  */
111 
112 /*
113  * Functions for updating the fhtable for fhtoppath and for returning
114  * the absolute pathname
115  */
116 static void nfslog_GETATTR2_fhargs(fhandle_t *,
117 	nfsstat *, char *fhpath, char **, char **);
118 static void nfslog_SETATTR2_fhargs(nfslog_setattrargs *, nfsstat *,
119 	char *, char **, char **);
120 static void nfslog_LOOKUP2_fhargs(nfslog_diropargs *, nfslog_diropres *,
121 	char *, char **, char **);
122 static void nfslog_READLINK2_fhargs(fhandle_t *, nfslog_rdlnres *,
123 	char *, char **, char **);
124 static void nfslog_READ2_fhargs(nfslog_nfsreadargs *, nfslog_rdresult *,
125 	char *, char **, char **);
126 static void nfslog_WRITE2_fhargs(nfslog_writeargs *, nfslog_writeresult *,
127 	char *, char **, char **);
128 static void nfslog_CREATE2_fhargs(nfslog_createargs *, nfslog_diropres*,
129 	char *, char **, char **);
130 static void nfslog_REMOVE2_fhargs(nfslog_diropargs *, nfsstat *,
131 	char *, char **, char **);
132 static void nfslog_RENAME2_fhargs(nfslog_rnmargs *, nfsstat *,
133 	char *, char **, char **);
134 static void nfslog_LINK2_fhargs(nfslog_linkargs *, nfsstat *,
135 	char *, char **, char **);
136 static void nfslog_SYMLINK2_fhargs(nfslog_symlinkargs *, nfsstat *,
137 	char *, char **, char **);
138 static void nfslog_READDIR2_fhargs(nfslog_rddirargs *, nfslog_rddirres *,
139 	char *, char **, char **);
140 static void nfslog_STATFS2_fhargs(fhandle_t *, nfsstat *,
141 	char *, char **, char **);
142 
143 /*
144  * NFS VERSION 3
145  *
146  * Functions for updating the fhtable for fhtoppath
147  */
148 static void nfslog_GETATTR3_fhargs(nfs_fh3 *, nfsstat3 *,
149 	char *, char **, char **);
150 static void nfslog_SETATTR3_fhargs(nfslog_SETATTR3args *,	nfsstat3 *,
151 	char *, char **, char **);
152 static void nfslog_LOOKUP3_fhargs(nfslog_diropargs3 *, nfslog_LOOKUP3res *,
153 	char *, char **, char **);
154 static void nfslog_ACCESS3_fhargs(nfs_fh3 *, nfsstat3 *,
155 	char *, char **, char **);
156 static void nfslog_READLINK3_fhargs(nfs_fh3 *, nfslog_READLINK3res *,
157 	char *, char **, char **);
158 static void nfslog_READ3_fhargs(nfslog_READ3args *, nfslog_READ3res *,
159 	char *, char **, char **);
160 static void nfslog_WRITE3_fhargs(nfslog_WRITE3args *, nfslog_WRITE3res *,
161 	char *, char **, char **);
162 static void nfslog_CREATE3_fhargs(nfslog_CREATE3args *, nfslog_CREATE3res *,
163 	char *, char **, char **);
164 static void nfslog_MKDIR3_fhargs(nfslog_MKDIR3args *, nfslog_MKDIR3res *,
165 	char *, char **, char **);
166 static void nfslog_SYMLINK3_fhargs(nfslog_SYMLINK3args *, nfslog_SYMLINK3res *,
167 	char *, char **, char **);
168 static void nfslog_MKNOD3_fhargs(nfslog_MKNOD3args *, nfslog_MKNOD3res *,
169 	char *, char **, char **);
170 static void nfslog_REMOVE3_fhargs(nfslog_REMOVE3args *, nfsstat3 *,
171 	char *, char **, char **);
172 static void nfslog_RMDIR3_fhargs(nfslog_RMDIR3args *, nfsstat3 *,
173 	char *, char **, char **);
174 static void nfslog_RENAME3_fhargs(nfslog_RENAME3args *, nfsstat3 *,
175 	char *, char **, char **);
176 static void nfslog_LINK3_fhargs(nfslog_LINK3args *, nfsstat3 *,
177 	char *, char **, char **);
178 static void nfslog_READDIR3_fhargs(nfs_fh3 *, nfsstat3 *,
179 	char *, char **, char **);
180 static void nfslog_READDIRPLUS3_fhargs(nfslog_READDIRPLUS3args *,
181 	nfslog_READDIRPLUS3res *,
182 	char *, char **, char **);
183 static void nfslog_FSSTAT3_fhargs(nfs_fh3 *, nfsstat3 *,
184 	char *, char **, char **);
185 static void nfslog_FSINFO3_fhargs(nfs_fh3 *, nfsstat3 *,
186 	char *, char **, char **);
187 static void nfslog_PATHCONF3_fhargs(nfs_fh3 *, nfsstat3 *,
188 	char *, char **, char **);
189 static void nfslog_COMMIT3_fhargs(nfslog_COMMIT3args *, nfsstat3 *,
190 	char *, char **, char **);
191 
192 /*
193  * NFSLOG VERSION 1
194  *
195  * Functions for updating the fhtable for fhtoppath
196  */
197 static void nfslog_SHARE_fhargs(nfslog_sharefsargs *, nfslog_sharefsres *,
198 	char *, char **, char **);
199 static void nfslog_UNSHARE_fhargs(nfslog_sharefsargs *, nfslog_sharefsres *,
200 	char *, char **, char **);
201 static void nfslog_GETFH_fhargs(nfslog_getfhargs *, nfsstat *,
202 	char *, char **, char **);
203 
204 /*
205  * Define the actions taken per prog/vers/proc:
206  *
207  * In some cases, the nl types are the same as the nfs types and a simple
208  * bcopy should suffice. Rather that define tens of identical procedures,
209  * simply define these to bcopy. Similarly this takes care of different
210  * procs that use same parameter struct.
211  */
212 
213 static struct nfsl_fh_proc_disp nfsl_fh_proc_v2[] = {
214 	/*
215 	 * NFS VERSION 2
216 	 */
217 
218 	/* RFS_NULL = 0 */
219 	{nfslog_null_fhargs, xdr_void, xdr_void, 0, 0},
220 
221 	/* RFS_GETATTR = 1 */
222 	{nfslog_GETATTR2_fhargs, xdr_fhandle, xdr_nfsstat,
223 		sizeof (fhandle_t), sizeof (nfsstat)},
224 
225 	/* RFS_SETATTR = 2 */
226 	{nfslog_SETATTR2_fhargs, xdr_nfslog_setattrargs, xdr_nfsstat,
227 		sizeof (nfslog_setattrargs), sizeof (nfsstat)},
228 
229 	/* RFS_ROOT = 3 *** NO LONGER SUPPORTED *** */
230 	{nfslog_null_fhargs, xdr_void, xdr_void, 0, 0},
231 
232 	/* RFS_LOOKUP = 4 */
233 	{nfslog_LOOKUP2_fhargs, xdr_nfslog_diropargs, xdr_nfslog_diropres,
234 		sizeof (nfslog_diropargs), sizeof (nfslog_diropres)},
235 
236 	/* RFS_READLINK = 5 */
237 	{nfslog_READLINK2_fhargs, xdr_fhandle, xdr_nfslog_rdlnres,
238 		sizeof (fhandle_t), sizeof (nfslog_rdlnres)},
239 
240 	/* RFS_READ = 6 */
241 	{nfslog_READ2_fhargs, xdr_nfslog_nfsreadargs, xdr_nfslog_rdresult,
242 		sizeof (nfslog_nfsreadargs), sizeof (nfslog_rdresult)},
243 
244 	/* RFS_WRITECACHE = 7 *** NO LONGER SUPPORTED *** */
245 	{nfslog_null_fhargs, xdr_void, xdr_void, 0, 0},
246 
247 	/* RFS_WRITE = 8 */
248 	{nfslog_WRITE2_fhargs, xdr_nfslog_writeargs, xdr_nfslog_writeresult,
249 		sizeof (nfslog_writeargs), sizeof (nfslog_writeresult)},
250 
251 	/* RFS_CREATE = 9 */
252 	{nfslog_CREATE2_fhargs, xdr_nfslog_createargs, xdr_nfslog_diropres,
253 		sizeof (nfslog_createargs), sizeof (nfslog_diropres)},
254 
255 	/* RFS_REMOVE = 10 */
256 	{nfslog_REMOVE2_fhargs, xdr_nfslog_diropargs, xdr_nfsstat,
257 		sizeof (nfslog_diropargs), sizeof (nfsstat)},
258 
259 	/* RFS_RENAME = 11 */
260 	{nfslog_RENAME2_fhargs, xdr_nfslog_rnmargs, xdr_nfsstat,
261 		sizeof (nfslog_rnmargs), sizeof (nfsstat)},
262 
263 	/* RFS_LINK = 12 */
264 	{nfslog_LINK2_fhargs, xdr_nfslog_linkargs, xdr_nfsstat,
265 		sizeof (nfslog_linkargs), sizeof (nfsstat)},
266 
267 	/* RFS_SYMLINK = 13 */
268 	{nfslog_SYMLINK2_fhargs, xdr_nfslog_symlinkargs, xdr_nfsstat,
269 		sizeof (nfslog_symlinkargs), sizeof (nfsstat)},
270 
271 	/* RFS_MKDIR = 14 */
272 	{nfslog_CREATE2_fhargs, xdr_nfslog_createargs, xdr_nfslog_diropres,
273 		sizeof (nfslog_createargs), sizeof (nfslog_diropres)},
274 
275 	/* RFS_RMDIR = 15 */
276 	{nfslog_REMOVE2_fhargs, xdr_nfslog_diropargs, xdr_nfsstat,
277 		sizeof (nfslog_diropargs), sizeof (nfsstat)},
278 
279 	/* RFS_READDIR = 16 */
280 	{nfslog_READDIR2_fhargs, xdr_nfslog_rddirargs, xdr_nfslog_rddirres,
281 		sizeof (nfslog_rddirargs), sizeof (nfslog_rddirres)},
282 
283 	/* RFS_STATFS = 17 */
284 	{nfslog_STATFS2_fhargs, xdr_fhandle, xdr_nfsstat,
285 		sizeof (fhandle_t), sizeof (nfsstat)},
286 };
287 
288 
289 /*
290  * NFS VERSION 3
291  */
292 
293 static struct nfsl_fh_proc_disp nfsl_fh_proc_v3[] = {
294 
295 	/* RFS_NULL = 0 */
296 	{nfslog_null_fhargs, xdr_void, xdr_void, 0, 0},
297 
298 	/* RFS3_GETATTR = 1 */
299 	{nfslog_GETATTR3_fhargs, xdr_nfs_fh3, xdr_nfsstat3,
300 		sizeof (nfs_fh3), sizeof (nfsstat3)},
301 
302 	/* RFS3_SETATTR = 2 */
303 	{nfslog_SETATTR3_fhargs, xdr_nfslog_SETATTR3args, xdr_nfsstat3,
304 		sizeof (nfslog_SETATTR3args), sizeof (nfsstat3)},
305 
306 	/* RFS3_LOOKUP = 3 */
307 	{nfslog_LOOKUP3_fhargs, xdr_nfslog_diropargs3, xdr_nfslog_LOOKUP3res,
308 		sizeof (nfslog_diropargs3), sizeof (nfslog_LOOKUP3res)},
309 
310 	/* RFS3_ACCESS = 4 */
311 	{nfslog_ACCESS3_fhargs, xdr_nfs_fh3, xdr_nfsstat3,
312 		sizeof (nfs_fh3), sizeof (nfsstat3)},
313 
314 	/* RFS3_READLINK = 5 */
315 	{nfslog_READLINK3_fhargs, xdr_nfs_fh3, xdr_nfslog_READLINK3res,
316 		sizeof (nfs_fh3), sizeof (nfslog_READLINK3res)},
317 
318 	/* RFS3_READ = 6 */
319 	{nfslog_READ3_fhargs, xdr_nfslog_READ3args, xdr_nfslog_READ3res,
320 		sizeof (nfslog_READ3args), sizeof (nfslog_READ3res)},
321 
322 	/* RFS3_WRITE = 7 */
323 	{nfslog_WRITE3_fhargs, xdr_nfslog_WRITE3args, xdr_nfslog_WRITE3res,
324 		sizeof (nfslog_WRITE3args), sizeof (nfslog_WRITE3res)},
325 
326 	/* RFS3_CREATE = 8 */
327 	{nfslog_CREATE3_fhargs, xdr_nfslog_CREATE3args, xdr_nfslog_CREATE3res,
328 		sizeof (nfslog_CREATE3args), sizeof (nfslog_CREATE3res)},
329 
330 	/* RFS3_MKDIR = 9 */
331 	{nfslog_MKDIR3_fhargs, xdr_nfslog_MKDIR3args, xdr_nfslog_MKDIR3res,
332 		sizeof (nfslog_MKDIR3args), sizeof (nfslog_MKDIR3res)},
333 
334 	/* RFS3_SYMLINK = 10 */
335 	{nfslog_SYMLINK3_fhargs, xdr_nfslog_SYMLINK3args,
336 		xdr_nfslog_SYMLINK3res,
337 		sizeof (nfslog_SYMLINK3args), sizeof (nfslog_SYMLINK3res)},
338 
339 	/* RFS3_MKNOD = 11 */
340 	{nfslog_MKNOD3_fhargs, xdr_nfslog_MKNOD3args, xdr_nfslog_MKNOD3res,
341 		sizeof (nfslog_MKNOD3args), sizeof (nfslog_MKNOD3res)},
342 
343 	/* RFS3_REMOVE = 12 */
344 	{nfslog_REMOVE3_fhargs, xdr_nfslog_REMOVE3args, xdr_nfsstat3,
345 		sizeof (nfslog_REMOVE3args), sizeof (nfsstat3)},
346 
347 	/* RFS3_RMDIR = 13 */
348 	{nfslog_RMDIR3_fhargs, xdr_nfslog_RMDIR3args, xdr_nfsstat3,
349 		sizeof (nfslog_RMDIR3args), sizeof (nfsstat3)},
350 
351 	/* RFS3_RENAME = 14 */
352 	{nfslog_RENAME3_fhargs, xdr_nfslog_RENAME3args, xdr_nfsstat3,
353 		sizeof (nfslog_RENAME3args), sizeof (nfsstat3)},
354 
355 	/* RFS3_LINK = 15 */
356 	{nfslog_LINK3_fhargs, xdr_nfslog_LINK3args, xdr_nfsstat3,
357 		sizeof (nfslog_LINK3args), sizeof (nfsstat3)},
358 
359 	/* RFS3_READDIR = 16 */
360 	{nfslog_READDIR3_fhargs, xdr_nfs_fh3, xdr_nfsstat3,
361 		sizeof (nfs_fh3), sizeof (nfsstat3)},
362 
363 	/* RFS3_READDIRPLUS = 17 */
364 	{nfslog_READDIRPLUS3_fhargs,
365 		xdr_nfslog_READDIRPLUS3args, xdr_nfslog_READDIRPLUS3res,
366 		sizeof (nfslog_READDIRPLUS3args),
367 		sizeof (nfslog_READDIRPLUS3res)},
368 
369 	/* RFS3_FSSTAT = 18 */
370 	{nfslog_FSSTAT3_fhargs, xdr_nfs_fh3, xdr_nfsstat3,
371 		sizeof (nfs_fh3), sizeof (nfsstat3)},
372 
373 	/* RFS3_FSINFO = 19 */
374 	{nfslog_FSINFO3_fhargs, xdr_nfs_fh3, xdr_nfsstat3,
375 		sizeof (nfs_fh3), sizeof (nfsstat3)},
376 
377 	/* RFS3_PATHCONF = 20 */
378 	{nfslog_PATHCONF3_fhargs, xdr_nfs_fh3, xdr_nfsstat3,
379 		sizeof (nfs_fh3), sizeof (nfsstat3)},
380 
381 	/* RFS3_COMMIT = 21 */
382 	{nfslog_COMMIT3_fhargs, xdr_nfslog_COMMIT3args, xdr_nfsstat3,
383 		sizeof (nfslog_COMMIT3args), sizeof (nfsstat3)},
384 };
385 
386 /*
387  * NFSLOG VERSION 1
388  */
389 
390 static struct nfsl_fh_proc_disp nfsl_log_fh_proc_v1[] = {
391 
392 	/* NFSLOG_NULL = 0 */
393 	{nfslog_null_fhargs, xdr_void, xdr_void, 0, 0},
394 
395 	/* NFSLOG_SHARE = 1 */
396 	{nfslog_SHARE_fhargs, xdr_nfslog_sharefsargs, xdr_nfslog_sharefsres,
397 		sizeof (nfslog_sharefsargs), sizeof (nfslog_sharefsres)},
398 
399 	/* NFSLOG_UNSHARE = 2 */
400 	{nfslog_UNSHARE_fhargs, xdr_nfslog_sharefsargs, xdr_nfslog_sharefsres,
401 		sizeof (nfslog_sharefsargs), sizeof (nfslog_sharefsres)},
402 
403 	/* NFSLOG_LOOKUP3 = 3 */
404 	{nfslog_LOOKUP3_fhargs, xdr_nfslog_diropargs3, xdr_nfslog_LOOKUP3res,
405 		sizeof (nfslog_diropargs3), sizeof (nfslog_LOOKUP3res)},
406 
407 	/* NFSLOG_GETFH = 4 */
408 	{nfslog_GETFH_fhargs, xdr_nfslog_getfhargs, xdr_nfsstat,
409 		sizeof (nfslog_getfhargs), sizeof (nfsstat)},
410 };
411 
412 static struct nfsl_fh_vers_disp nfsl_fh_vers_disptable[] = {
413 	{sizeof (nfsl_fh_proc_v2) / sizeof (nfsl_fh_proc_v2[0]),
414 	    nfsl_fh_proc_v2},
415 	{sizeof (nfsl_fh_proc_v3) / sizeof (nfsl_fh_proc_v3[0]),
416 	    nfsl_fh_proc_v3},
417 };
418 
419 static struct nfsl_fh_vers_disp nfsl_log_fh_vers_disptable[] = {
420 	{sizeof (nfsl_log_fh_proc_v1) / sizeof (nfsl_log_fh_proc_v1[0]),
421 	    nfsl_log_fh_proc_v1},
422 };
423 
424 static struct nfsl_fh_prog_disp nfsl_fh_dispatch_table[] = {
425 	{NFS_PROGRAM,
426 	    NFS_VERSMIN,
427 	    sizeof (nfsl_fh_vers_disptable) /
428 		sizeof (nfsl_fh_vers_disptable[0]),
429 	    nfsl_fh_vers_disptable},
430 	{NFSLOG_PROGRAM,
431 	    NFSLOG_VERSMIN,
432 	    sizeof (nfsl_log_fh_vers_disptable) /
433 		sizeof (nfsl_log_fh_vers_disptable[0]),
434 	    nfsl_log_fh_vers_disptable},
435 };
436 
437 static int	nfsl_fh_dispatch_table_arglen =
438 			sizeof (nfsl_fh_dispatch_table) /
439 			sizeof (nfsl_fh_dispatch_table[0]);
440 
441 extern int debug;
442 
443 /*
444  * print the fid into the given string as a series of hex digits.
445  * XXX Ideally, we'd like to just convert the filehandle into an i-number,
446  * but the fid encoding is a little tricky (see nfs_fhtovp() and
447  * ufs_vget()) and may be private to UFS.
448  */
449 
450 static void
451 sprint_fid(char *buf, uint_t buflen, const fhandle_t *fh)
452 {
453 	int i;
454 	uchar_t byte;
455 	uint_t fhlen;
456 
457 	/*
458 	 * If the filehandle somehow got corrupted, only print the part
459 	 * that makes sense.
460 	 */
461 	if (fh->fh_len > NFS_FHMAXDATA)
462 		fhlen = NFS_FHMAXDATA;
463 	else
464 		fhlen = fh->fh_len;
465 	assert(2 * fhlen < buflen);
466 
467 	for (i = 0; i < fhlen; i++) {
468 		byte = fh->fh_data[i];
469 		(void) sprintf(buf + 2 * i, "%02x", byte);
470 	}
471 }
472 
473 static void
474 fh_print_all_keys(char *fhpath, fhandle_t *fh)
475 {
476 	if ((fhpath == NULL) || (fh == NULL) || (debug <= 1))
477 		return;
478 	(void) printf("\nBegin all database keys\n");
479 	db_print_all_keys(fhpath, &fh->fh_fsid, stdout);
480 	(void) printf("\nEnd   all database keys\n");
481 }
482 
483 #define	FH_ADD(path, dfh, fh, name) \
484 	fh_add(path, dfh, fh, name)
485 
486 /*
487  * Add the filehandle "fh", which has the name "name" and lives in
488  * directory "dfh", to the table "fhlist".  "fhlist" will be updated if the
489  * entry is added to the front of the list.
490  * Return 0 for success, error code otherwise.
491  */
492 static int
493 fh_add(char *fhpath, fhandle_t *dfh, fhandle_t *fh, char *name)
494 {
495 	uint_t	flags = 0;
496 	int	error;
497 
498 	if (IS_DOT_FILENAME(name)) {
499 		/* we don't insert these to the database but not an error */
500 		if (debug > 3) {
501 			PRINT_FULL_DATA(stdout, "fh_add", dfh, fh, name,
502 				" - no dot files")
503 		}
504 		return (0);
505 	}
506 	if (dfh && (memcmp(fh, dfh, NFS_FHSIZE) == 0)) {
507 		flags |= EXPORT_POINT;
508 	}
509 
510 	/* Add to database */
511 	error = db_add(fhpath, dfh, name, fh, flags);
512 	if (debug > 1) {
513 		if (error != 0) {
514 			(void) printf("db_add error %s:\n",
515 				((error >= 0) ? strerror(error) : "Unknown"));
516 			PRINT_FULL_DATA(stdout, "fh_add", dfh, fh, name, "")
517 		} else if (debug > 2) {
518 			PRINT_FULL_DATA(stdout, "fh_add", dfh, fh, name, "")
519 		}
520 	}
521 	return (error);
522 }
523 
524 /*
525  * fh_compare returns 0 if the file handles match, error code otherwise
526  */
527 static int
528 fh_compare(fhandle_t *fh1, fhandle_t *fh2)
529 {
530 	if (memcmp(fh1, fh2, NFS_FHSIZE))
531 		return (errno);
532 	else
533 		return (0);
534 }
535 
536 /*
537  * Try to find the filehandle "fh" in the table.  Returns 0 and the
538  * corresponding table entry if found, error otherwise.
539  * If successfull and fhrecpp is non-null then *fhrecpp points to the
540  * returned record. If *fhrecpp was initially null, that record had
541  * been malloc'd and must be freed by caller.
542  */
543 
544 static fhlist_ent *
545 fh_lookup(char *fhpath, fhandle_t *fh, fhlist_ent *fhrecp, int *errorp)
546 {
547 	if (debug > 3) {
548 		(void) printf("fh_lookup: fh ");
549 		debug_opaque_print(stdout, fh, sizeof (*fh));
550 		(void) printf("\n");
551 	}
552 	return (db_lookup(fhpath, fh, fhrecp, errorp));
553 }
554 
555 /*
556  * Remove the mc link if exists when removing a regular link.
557  * Return 0 for success, error code otherwise.
558  */
559 static int
560 fh_remove_mc_link(char *fhpath, fhandle_t *dfh, char *name, char **pathp)
561 {
562 	int	error;
563 	char	*str, *str1;
564 
565 	/* Delete the multi-component path if exists */
566 	if ((pathp == NULL) || (*pathp == NULL)) {
567 		str = nfslog_get_path(dfh, name, fhpath, "remove_mc_link");
568 		str1 = str;
569 	} else {
570 		str = *pathp;
571 		str1 = NULL;
572 	}
573 	error = db_delete_link(fhpath, &public_fh, str);
574 	if (str1 != NULL)
575 		free(str1);
576 	return (error);
577 }
578 
579 /*
580  * Remove the link entry from the fh table.
581  * Return 0 for success, error code otherwise.
582  */
583 static int
584 fh_remove(char *fhpath, fhandle_t *dfh, char *name, char **pathp)
585 {
586 	/*
587 	 * disconnect element from list
588 	 *
589 	 * Remove the link entry for the file. Remove fh entry if last link.
590 	 */
591 	if (IS_DOT_FILENAME(name)) {
592 		/* we don't insert these to the database but not an error */
593 		if (debug > 2) {
594 			PRINT_LINK_DATA(stdout, "fh_remove", dfh, name,
595 				" - no dot files")
596 		}
597 		return (0);
598 	}
599 	if (debug > 2) {
600 		PRINT_LINK_DATA(stdout, "fh_remove", dfh, name, "")
601 	}
602 	/* Delete the multi-component path if exists */
603 	(void) fh_remove_mc_link(fhpath, dfh, name, pathp);
604 	return (db_delete_link(fhpath, dfh, name));
605 }
606 
607 /*
608  * fh_rename - renames a link in the database (adds the new one if from link
609  * did not exist).
610  * Return 0 for success, error code otherwise.
611  */
612 static int
613 fh_rename(char *fhpath, fhandle_t *from_dfh, char *from_name, char **from_pathp,
614 	fhandle_t *to_dfh, char *to_name)
615 {
616 	if (debug > 2) {
617 		PRINT_LINK_DATA(stdout, "fh_rename: from:", from_dfh,
618 		    from_name, "")
619 		PRINT_LINK_DATA(stdout, "fh_rename: to  :", to_dfh,
620 		    to_name, "")
621 	}
622 	/*
623 	 * if any of these are dot files (should not happen), the rename
624 	 * becomes a "delete" or "add" operation because the dot files
625 	 * don't get in the database
626 	 */
627 	if (IS_DOT_FILENAME(to_name)) {
628 		/* it is just a delete op */
629 		if (debug > 2) {
630 			(void) printf("to: no dot files\nDelete from: '%s'\n",
631 				from_name);
632 		}
633 		return (fh_remove(fhpath, from_dfh, from_name, from_pathp));
634 	} else if (IS_DOT_FILENAME(from_name)) {
635 		/* we don't insert these to the database */
636 		if (debug > 2) {
637 			(void) printf("rename - from: no dot files\n");
638 		}
639 		/* can't insert the target, because don't have a handle */
640 		return (EINVAL);
641 	}
642 	/* Delete the multi-component path if exists */
643 	(void) fh_remove_mc_link(fhpath, from_dfh, from_name, from_pathp);
644 	return (db_rename_link(fhpath, from_dfh, from_name, to_dfh, to_name));
645 }
646 
647 /*
648  * fh_lookup_link - search the fhtable for the link defined by (dfh,name,fh).
649  * Return 0 and set *fhrecpp to the fhlist item corresponding to it if found,
650  * or error if not found.
651  * Possible configurations:
652  * 1. dfh, fh, name are all non-null: Only exact match accepted.
653  * 2. dfh,name non-null, fh null: return first match found.
654  * 3. fh,name non-null, dfh null: return first match found.
655  * 3. fh non-null, dfh, name null: return first match found.
656  * If successfull and fhrecpp is non-null then *fhrecpp points to the
657  * returned record. If *fhrecpp was initially null, that record had
658  * been malloc'd and must be freed by caller.
659  */
660 static fhlist_ent *
661 fh_lookup_link(char *fhpath, fhandle_t *dfh, fhandle_t *fh, char *name,
662 	fhlist_ent *fhrecp, int *errorp)
663 {
664 	fhlist_ent	*in_fhrecp = fhrecp;
665 
666 	if ((name != NULL) && IS_DOT_FILENAME(name)) {
667 		/* we don't insert these to the database but not an error */
668 		if (debug > 2) {
669 			PRINT_FULL_DATA(stdout, "fh_lookup_link", dfh, fh, name,
670 				" - no dot files\n")
671 		}
672 		*errorp = 0;
673 		return (NULL);
674 	}
675 	if (debug > 3) {
676 		PRINT_FULL_DATA(stdout, "fh_lookup_link", dfh, fh, name, "")
677 	}
678 	/* Add to database */
679 	if (fh != NULL) {
680 		fhrecp = db_lookup(fhpath, fh, fhrecp, errorp);
681 		if (fhrecp == NULL) {
682 			if (debug > 3)
683 				(void) printf("fh_lookup_link: fh not found\n");
684 			return (NULL);
685 		}
686 		/* Check if name and dfh match, if not search link */
687 		if (((dfh == NULL) || !fh_compare(dfh, &fhrecp->dfh)) &&
688 		    ((name == NULL) || (strcmp(name, fhrecp->name) == 0))) {
689 			/* found it */
690 			goto exit;
691 		}
692 		/* Found the primary record, but it's a different link */
693 		if (debug == 3) {	/* Only log if >2 but already printed */
694 			PRINT_FULL_DATA(stdout, "fh_lookup_link", dfh, fh,
695 				name, "")
696 		}
697 		if (debug > 2) {
698 			PRINT_LINK_DATA(stdout, "Different primary link",
699 				&fhrecp->dfh, fhrecp->name, "")
700 		}
701 		/* can now free the record unless it was supplied by caller */
702 		if (fhrecp != in_fhrecp) {
703 			free(fhrecp);
704 			fhrecp = NULL;
705 		}
706 	}
707 	/* If here, we must search by link */
708 	if ((dfh == NULL) || (name == NULL)) {
709 		if (debug > 2)
710 			(void) printf("fh_lookup_link: invalid params\n");
711 		*errorp = EINVAL;
712 		return (NULL);
713 	}
714 	fhrecp = db_lookup_link(fhpath, dfh, name, fhrecp, errorp);
715 	if (fhrecp == NULL) {
716 		if (debug > 3)
717 			(void) printf("fh_lookup_link: link not found: %s\n",
718 			    ((*errorp >= 0) ? strerror(*errorp) : "Unknown"));
719 		return (NULL);
720 	}
721 	/* If all args supplied, check if an exact match */
722 	if ((fh != NULL) && fh_compare(fh, &fhrecp->fh)) {
723 		if (debug > 2) {
724 			PRINT_FULL_DATA(stderr, "fh_lookup_link", dfh, fh,
725 				name, "")
726 			PRINT_LINK_DATA(stderr, "Different primary link",
727 			    &fhrecp->dfh, fhrecp->name, "")
728 		}
729 		if (fhrecp != in_fhrecp)
730 			free(fhrecp);
731 		*errorp = EINVAL;
732 		return (NULL);
733 	}
734 exit:
735 	if (debug > 3)
736 		(void) printf("lookup: found '%s' in fhtable\n", name);
737 	*errorp = 0;
738 	return (fhrecp);
739 }
740 
741 /*
742  * Export handle cache is maintained if we see an export handle that either
743  * cannot have the path for it determined, or we failed store it.
744  * Usually the path of an export handle can be identified in the NFSLOGTAB
745  * and since every path for that filesystem will be affected, it's worth
746  * caching the ones we had problem identifying.
747  */
748 
749 /*
750  * find_fh_in_export_cache - given an export fh, find it in the cache and
751  * return the handle
752  */
753 static struct export_handle_cache *
754 find_fh_in_export_cache(fhandle_t *fh)
755 {
756 	struct export_handle_cache	*p;
757 
758 	for (p = exp_handle_cache; p != NULL; p = p->next) {
759 		if (memcmp(fh, &p->fh, sizeof (*fh)) == 0)
760 			break;
761 	}
762 	return (p);
763 }
764 
765 static void
766 add_fh_to_export_cache(fhandle_t *fh, char *path)
767 {
768 	struct export_handle_cache	*new;
769 
770 	if ((new = malloc(sizeof (*new))) == NULL) {
771 		syslog(LOG_ERR, gettext(
772 		"add_fh_to_export_cache: alloc new for '%s' Error %s\n"),
773 			((path != NULL) ? path : ""), strerror(errno));
774 		return;
775 	}
776 	if (path != NULL) {
777 		if ((new->name = malloc(strlen(path) + 1)) == NULL) {
778 			syslog(LOG_ERR, gettext(
779 				"add_fh_to_export_cache: alloc '%s'"
780 				    " Error %s\n"), path, strerror(errno));
781 			free(new);
782 			return;
783 		}
784 		(void) strcpy(new->name, path);
785 	} else {
786 		new->name = NULL;
787 	}
788 	(void) memcpy(&new->fh, fh, sizeof (*fh));
789 	new->next = exp_handle_cache;
790 	exp_handle_cache = new;
791 }
792 
793 /*
794  * update_export_point - called when the path for fh cannot be determined.
795  * In the past it called get_export_path() to get the name of the
796  * export point given a filehandle. This was a hack, since there's no
797  * reason why the filehandle should be lost.
798  *
799  * If a match is found, insert the path to the database.
800  * Return the inserted fhrecp is found,
801  * and NULL if not. If it is an exported fs but not in the list, log a
802  * error.
803  * If input fhrecp is non-null, it is a valid address for result,
804  * otherwise malloc it.
805  */
806 static char *
807 update_export_point(char *fhpath, fhandle_t *fh, char *path)
808 {
809 	struct export_handle_cache	*p;
810 
811 	if ((fh == NULL) || memcmp(&fh->fh_data, &fh->fh_xdata, fh->fh_len)) {
812 		/* either null fh or not the root of a shared directory */
813 		return (NULL);
814 	}
815 	/* Did we already see (and fail) this one? */
816 	if ((p = find_fh_in_export_cache(fh)) != NULL) {
817 		/* Found it! */
818 		if (debug > 2) {
819 			PRINT_LINK_DATA(stdout, "update_export_point",
820 				fh, ((p->name != NULL) ? p->name : ""), "");
821 		}
822 		if (p->name == NULL)
823 			return (NULL);
824 		/*
825 		 * We should not normally be here - only add to cache if
826 		 * fh_add failed.
827 		 */
828 		if ((path == NULL) &&
829 		    ((path = malloc(strlen(p->name) + 1)) == NULL)) {
830 			syslog(LOG_ERR, gettext(
831 				"update_export_point: malloc '%s' Error %s"),
832 				    p->name, strerror(errno));
833 			return (NULL);
834 		}
835 		(void) strcpy(path, p->name);
836 		return (path);
837 	}
838 	if ((path = get_export_path(fh, path)) == NULL) {
839 		add_fh_to_export_cache(fh, NULL);
840 		return (NULL);
841 	}
842 	/* Found it! */
843 	if (debug > 2) {
844 		PRINT_LINK_DATA(stdout, "update_export_point", fh, path, "")
845 	}
846 	if (FH_ADD(fhpath, fh, fh, path)) {
847 		/* cache this handle so we don't repeat the search */
848 		add_fh_to_export_cache(fh, path);
849 	}
850 	return (path);
851 }
852 
853 /*
854  * HACK!!! To get rid of get_export_path() use
855  */
856 /* ARGSUSED */
857 static char *
858 get_export_path(fhandle_t *fh, char *path)
859 {
860 	return (NULL);
861 }
862 
863 /*
864  * Return the absolute pathname for the filehandle "fh", using the mapping
865  * table "fhlist".  The caller must free the return string.
866  * name is an optional dir component name, to be appended at the end
867  * (if name is non-null, the function assumes the fh is the parent directory)
868  *
869  * Note: The original code was recursive, which was much more elegant but
870  * ran out of stack...
871  */
872 
873 static char *
874 fh_print_absolute(char *fhpath, fhandle_t *fh, char *name)
875 {
876 	char		*str, *rootname, parent[MAXPATHLEN];
877 	int		i, j, k, len, error;
878 	fhlist_ent	fhrec, *fhrecp;
879 	fhandle_t	prevfh;
880 	int		namelen;
881 
882 	if (debug > 3)
883 		(void) printf("fh_print_absolute: input name '%s'\n",
884 			((name != NULL) ? name : ""));
885 	/* If name starts with '/' we are done */
886 	if ((name != NULL) && (name[0] == '/')) {
887 		if ((str = strdup(name)) == NULL) {
888 			syslog(LOG_ERR, gettext(
889 				"fh_print_absolute: strdup '%s' error %s\n"),
890 				name, strerror(errno));
891 		}
892 		return (str);
893 	}
894 	namelen = ((name != NULL) ? strlen(name) + 2 : 0);
895 	parent[0] = '\0';
896 
897 	/* remember the last filehandle we've seen */
898 	(void) memcpy((void *) &prevfh, (void *) fh, sizeof (*fh));
899 	fh = &prevfh;
900 
901 	/* dump all names in reverse order */
902 	while ((fhrecp = fh_lookup(fhpath, fh, &fhrec, &error)) != NULL &&
903 		!(fhrecp->flags & (EXPORT_POINT | PUBLIC_PATH))) {
904 
905 		if (debug > 3) {
906 			(void) printf("fh_print_absolute: name '%s'%s\n",
907 				fhrecp->name,
908 				((fhrecp->flags & EXPORT_POINT) ? "root" : ""));
909 		}
910 		if (memcmp(&prevfh, &fhrecp->dfh, sizeof (*fh)) == 0) {
911 			/* dfh == prevfh but not an export point */
912 			if (debug > 1) {
913 				(void) printf(
914 					"fh_print_absolute: fhrec loop:\n");
915 					debug_opaque_print(stdout, fhrecp,
916 					fhrecp->reclen);
917 			}
918 			break;
919 		}
920 		(void) strcat(parent, "/");
921 		(void) strcat(parent, fhrecp->name);
922 
923 		/* remember the last filehandle we've seen */
924 		(void) memcpy(&prevfh, &fhrecp->dfh, sizeof (fhrecp->dfh));
925 	}
926 	assert(fh == &prevfh);
927 
928 	if (fhrecp != NULL) {
929 		rootname = fhrecp->name;
930 	} else {
931 		/* Check if export point, just in case... */
932 		/* There should be enough room in parent, leave the '\0' */
933 		rootname = update_export_point(
934 				fhpath, fh, &parent[strlen(parent) + 1]);
935 	}
936 	/* Now need to reverse the order */
937 	if (rootname != NULL) {	/* *fhrecp is the export point */
938 		len = strlen(rootname) + 2;
939 	} else {
940 		len = 2 * (NFS_FHMAXDATA + fh->fh_len);	/* fid instead */
941 	}
942 	len = ROUNDUP32(len + namelen + strlen(parent));
943 	if ((str = malloc(len)) == NULL) {
944 		syslog(LOG_ERR, gettext(
945 			"fh_print_absolute: malloc %d error %s\n"),
946 			    len, strerror(errno));
947 		return (NULL);
948 	}
949 	/* first put the export point path in */
950 	if (rootname != NULL) {	/* *fhrecp is the export point */
951 		(void) strcpy(str, rootname);
952 	} else {
953 		sprint_fid(str, len, fh);
954 	}
955 	for (k = strlen(str), i = strlen(parent); (k < len) && (i >= 0); i--) {
956 		for (j = i; (j >= 0) && (parent[j] != '/'); j--);
957 		if (j < 0)
958 			break;
959 		(void) strcpy(&str[k], &parent[j]);
960 		k += strlen(&str[k]);
961 		parent[j] = '\0';
962 	}
963 	if ((name != NULL) && ((k + namelen) <= len)) {
964 		str[k] = '/';
965 		(void) strcpy(&str[k + 1], name);
966 	}
967 	if (debug > 3)
968 		(void) printf("fh_print_absolute: path '%s'\n", str);
969 	return (str);
970 }
971 
972 /*
973  * nfslog_find_fh_dispatch - get the dispatch struct for this request
974  */
975 static struct nfsl_fh_proc_disp *
976 nfslog_find_fh_dispatch(nfslog_request_record *logrec)
977 {
978 	nfslog_record_header		*logrechdr = &logrec->re_header;
979 	struct nfsl_fh_prog_disp	*progtable;	/* prog struct */
980 	struct nfsl_fh_vers_disp	*verstable;	/* version struct */
981 	int				i, vers;
982 
983 	/* Find prog element - search because can't use prog as array index */
984 	for (i = 0; (i < nfsl_fh_dispatch_table_arglen) &&
985 	    (logrechdr->rh_prognum != nfsl_fh_dispatch_table[i].nfsl_dis_prog);
986 		i++);
987 	if (i >= nfsl_fh_dispatch_table_arglen) {	/* program not logged */
988 		/* not an error */
989 		return (NULL);
990 	}
991 	progtable = &nfsl_fh_dispatch_table[i];
992 	/* Find vers element - no validity check - if here it's valid vers */
993 	vers = logrechdr->rh_version - progtable->nfsl_dis_versmin;
994 	verstable = &progtable->nfsl_dis_vers_table[vers];
995 	/* Find proc element - no validity check - if here it's valid proc */
996 	return (&verstable->nfsl_dis_proc_table[logrechdr->rh_procnum]);
997 }
998 
999 /* ARGSUSED */
1000 static void
1001 nfslog_null_fhargs(caddr_t *nfsl_args, caddr_t *nfsl_res,
1002 	char *fhpath, char **pathp1, char **pathp2)
1003 {
1004 	*pathp1 = NULL;
1005 	*pathp2 = NULL;
1006 }
1007 
1008 /*
1009  * nfslog_LOOKUP_calc - called by both lookup3 and lookup2. Handles the
1010  * mclookup as well as normal lookups.
1011  */
1012 /* ARGSUSED */
1013 static void
1014 nfslog_LOOKUP_calc(fhandle_t *dfh, char *name, fhandle_t *fh,
1015 	char *fhpath, char **pathp1, char **pathp2, char *str)
1016 {
1017 	int		error;
1018 	fhlist_ent	fhrec;
1019 	char		*name1 = NULL;
1020 
1021 	if (fh == &public_fh) {
1022 		/* a fake lookup to inform us of the public fs path */
1023 		if (error = FH_ADD(fhpath, fh, fh, name)) {
1024 			syslog(LOG_ERR, gettext(
1025 				"%s: Add Public fs '%s' failed: %s\n"),
1026 				str, name,
1027 				((error >= 0) ? strerror(error) : "Unknown"));
1028 		}
1029 		if (pathp1 != NULL) {
1030 			*pathp1 = nfslog_get_path(dfh, NULL, fhpath, str);
1031 			*pathp2 = NULL;
1032 		}
1033 		return;
1034 	}
1035 	if (pathp1 != NULL) {
1036 		*pathp1 = nfslog_get_path(dfh, name, fhpath, str);
1037 		*pathp2 = NULL;
1038 	}
1039 
1040 	/* If public fh mclookup, then insert complete path */
1041 	if (dfh == &public_fh) {
1042 		if (pathp1 != NULL) {
1043 			name = *pathp1;
1044 		} else {
1045 			name = nfslog_get_path(dfh, name, fhpath, str);
1046 			name1 = name;
1047 		}
1048 	}
1049 	if (fh_lookup_link(fhpath, dfh, fh, name, &fhrec, &error) != NULL) {
1050 		/* link already in table */
1051 		if (name1 != NULL)
1052 			free(name1);
1053 		return;
1054 	}
1055 	/* A new link so add it */
1056 	if (error = FH_ADD(fhpath, dfh, fh, name)) {
1057 		syslog(LOG_ERR, gettext(
1058 			"%s: Add fh for '%s' failed: %s\n"), str,
1059 			    name, ((error >= 0) ? strerror(error) : "Unknown"));
1060 	}
1061 	if (name1 != NULL)
1062 		free(name1);
1063 }
1064 
1065 /*
1066  * NFS VERSION 2
1067  */
1068 
1069 /* Functions for updating the fhtable for fhtoppath */
1070 
1071 /*
1072  * nfslog_GETATTR2_fhargs - updates path1 but no fhtable changes
1073  */
1074 /* ARGSUSED */
1075 static void
1076 nfslog_GETATTR2_fhargs(fhandle_t *args, nfsstat *res,
1077 	char *fhpath, char **pathp1, char **pathp2)
1078 {
1079 	if (debug > 2) {
1080 		(void) printf("=============\nGETATTR2: fh ");
1081 		debug_opaque_print(stdout, args, sizeof (*args));
1082 		(void) printf("\n");
1083 	}
1084 	if (pathp1 != NULL) {
1085 		*pathp1 = nfslog_get_path(NFSLOG_GET_FHANDLE2(args),
1086 				NULL, fhpath, "getattr2");
1087 		*pathp2 = NULL;
1088 	}
1089 }
1090 
1091 /*
1092  * nfslog_SETATTR2_fhargs - updates path1 but no fhtable changes
1093  */
1094 /* ARGSUSED */
1095 static void
1096 nfslog_SETATTR2_fhargs(nfslog_setattrargs *args, nfsstat *res,
1097 	char *fhpath, char **pathp1, char **pathp2)
1098 {
1099 	if (debug > 2) {
1100 		(void) printf("=============\nSETATTR2: fh ");
1101 		debug_opaque_print(stdout, &args->saa_fh,
1102 			sizeof (args->saa_fh));
1103 		(void) printf("\n");
1104 	}
1105 	if (pathp1 != NULL) {
1106 		*pathp1 = nfslog_get_path(NFSLOG_GET_FHANDLE2(&args->saa_fh),
1107 				NULL, fhpath, "setattr2");
1108 		*pathp2 = NULL;
1109 	}
1110 }
1111 
1112 /*
1113  * nfslog_LOOKUP2_fhargs - search the table to ensure we have not added this
1114  * one already. Note that if the response status was anything but okay,
1115  * there is no fh to check...
1116  */
1117 /* ARGSUSED */
1118 static void
1119 nfslog_LOOKUP2_fhargs(nfslog_diropargs *args, nfslog_diropres *res,
1120 	char *fhpath, char **pathp1, char **pathp2)
1121 {
1122 	char		*name;
1123 	fhandle_t	*dfh, *fh;
1124 
1125 	dfh = &args->da_fhandle;
1126 	name = args->da_name;
1127 	if (debug > 2) {
1128 		if (res->dr_status == NFS_OK)
1129 			fh = &res->nfslog_diropres_u.dr_ok.drok_fhandle;
1130 		else
1131 			fh = NULL;
1132 		PRINT_FULL_DATA(stdout, "=============\nLOOKUP2",
1133 			dfh, fh, name, "")
1134 		if (res->dr_status !=  NFS_OK)
1135 			(void) printf("status %d\n", res->dr_status);
1136 	}
1137 	dfh = NFSLOG_GET_FHANDLE2(dfh);
1138 	if ((dfh == &public_fh) && (name[0] == '\x80')) {
1139 		/* special mclookup */
1140 		name = &name[1];
1141 	}
1142 	if (res->dr_status != NFS_OK) {
1143 		if (pathp1 != NULL) {
1144 			*pathp1 = nfslog_get_path(dfh, name, fhpath, "lookup2");
1145 			*pathp2 = NULL;
1146 		}
1147 		return;
1148 	}
1149 	fh = NFSLOG_GET_FHANDLE2(&res->nfslog_diropres_u.dr_ok.drok_fhandle);
1150 	nfslog_LOOKUP_calc(dfh, name, fh, fhpath, pathp1, pathp2, "Lookup2");
1151 }
1152 
1153 /*
1154  * nfslog_READLINK2_fhargs - updates path1 but no fhtable changes
1155  */
1156 /* ARGSUSED */
1157 static void
1158 nfslog_READLINK2_fhargs(fhandle_t *args, nfslog_rdlnres *res,
1159 	char *fhpath, char **pathp1, char **pathp2)
1160 {
1161 	if (debug > 2) {
1162 		(void) printf("=============\nREADLINK2: fh ");
1163 		debug_opaque_print(stdout, args, sizeof (*args));
1164 		(void) printf("\n");
1165 	}
1166 	if (pathp1 != NULL) {
1167 		*pathp1 = nfslog_get_path(NFSLOG_GET_FHANDLE2(args),
1168 				NULL, fhpath, "readlink2");
1169 		*pathp2 = NULL;
1170 	}
1171 }
1172 
1173 /*
1174  * nfslog_READ2_fhargs - updates path1 but no fhtable changes
1175  */
1176 /* ARGSUSED */
1177 static void
1178 nfslog_READ2_fhargs(nfslog_nfsreadargs *args, nfslog_rdresult *res,
1179 	char *fhpath, char **pathp1, char **pathp2)
1180 {
1181 	if (debug > 2) {
1182 		(void) printf("=============\nREAD2: fh ");
1183 		debug_opaque_print(stdout, &args->ra_fhandle,
1184 			sizeof (args->ra_fhandle));
1185 		(void) printf("\n");
1186 	}
1187 	if (pathp1 != NULL) {
1188 		*pathp1 = nfslog_get_path(
1189 				NFSLOG_GET_FHANDLE2(&args->ra_fhandle),
1190 				NULL, fhpath, "read2");
1191 		*pathp2 = NULL;
1192 	}
1193 }
1194 
1195 /*
1196  * nfslog_WRITE2_fhargs - updates path1 but no fhtable changes
1197  */
1198 /* ARGSUSED */
1199 static void
1200 nfslog_WRITE2_fhargs(nfslog_writeargs *args, nfslog_writeresult *res,
1201 	char *fhpath, char **pathp1, char **pathp2)
1202 {
1203 	if (debug > 2) {
1204 		(void) printf("=============\nWRITE2: fh ");
1205 		debug_opaque_print(stdout, &args->waargs_fhandle,
1206 			sizeof (args->waargs_fhandle));
1207 		(void) printf("\n");
1208 	}
1209 	if (pathp1 != NULL) {
1210 		*pathp1 = nfslog_get_path(
1211 			NFSLOG_GET_FHANDLE2(&args->waargs_fhandle),
1212 			NULL, fhpath, "write2");
1213 		*pathp2 = NULL;
1214 	}
1215 }
1216 
1217 /*
1218  * nfslog_CREATE2_fhargs - if the operation succeeded, we are sure there can
1219  * be no such link in the fhtable, so just add it.
1220  */
1221 /* ARGSUSED */
1222 static void
1223 nfslog_CREATE2_fhargs(nfslog_createargs *args, nfslog_diropres *res,
1224 	char *fhpath, char **pathp1, char **pathp2)
1225 {
1226 	char		*name;
1227 	fhandle_t	*dfh, *fh;
1228 	int		error;
1229 
1230 	name = args->ca_da.da_name;
1231 	dfh = &args->ca_da.da_fhandle;
1232 	if (debug > 2) {
1233 		if (res->dr_status == NFS_OK)
1234 			fh = &res->nfslog_diropres_u.dr_ok.drok_fhandle;
1235 		else
1236 			fh = NULL;
1237 		PRINT_FULL_DATA(stdout, "=============\nCREATE2",
1238 			dfh, fh, name, "")
1239 		if (res->dr_status != NFS_OK)
1240 			(void) printf("status %d\n", res->dr_status);
1241 	}
1242 	dfh = NFSLOG_GET_FHANDLE2(dfh);
1243 	if (pathp1 != NULL) {
1244 		*pathp1 = nfslog_get_path(dfh, name, fhpath, "create2");
1245 		*pathp2 = NULL;
1246 	}
1247 
1248 	if (res->dr_status != NFS_OK)
1249 		/* no returned fh so nothing to add */
1250 		return;
1251 
1252 	/* A new file handle so add it */
1253 	fh = NFSLOG_GET_FHANDLE2(&res->nfslog_diropres_u.dr_ok.drok_fhandle);
1254 	if (error = FH_ADD(fhpath, dfh, fh, name)) {
1255 		syslog(LOG_ERR, gettext(
1256 			"Create2: Add fh for '%s' failed: %s\n"),
1257 			    name, ((error >= 0) ? strerror(error) : "Unknown"));
1258 	}
1259 }
1260 
1261 /*
1262  * nfslog_REMOVE2_fhargs - if the operation succeeded, remove the link from
1263  * the fhtable.
1264  */
1265 /* ARGSUSED */
1266 static void
1267 nfslog_REMOVE2_fhargs(nfslog_diropargs *args, nfsstat *res,
1268 	char *fhpath, char **pathp1, char **pathp2)
1269 {
1270 	char		*name;
1271 	fhandle_t	*dfh;
1272 	int		error;
1273 
1274 	name = args->da_name;
1275 	dfh = &args->da_fhandle;
1276 	if (debug > 2) {
1277 		PRINT_LINK_DATA(stdout, "=============\nREMOVE2", dfh, name, "")
1278 		if (*res != NFS_OK)
1279 			(void) printf("status %d\n", *res);
1280 	}
1281 	dfh = NFSLOG_GET_FHANDLE2(dfh);
1282 	if (pathp1 != NULL) {
1283 		*pathp1 = nfslog_get_path(dfh, name, fhpath, "remove2");
1284 		*pathp2 = NULL;
1285 	}
1286 
1287 	if (*res != NFS_OK)
1288 		/* remove failed so nothing to update */
1289 		return;
1290 
1291 	if (error = fh_remove(fhpath, dfh, name, pathp1)) {
1292 		syslog(LOG_ERR, gettext("Remove2: '%s' failed: %s\n"),
1293 			name, ((error >= 0) ? strerror(error) : "Unknown"));
1294 	}
1295 }
1296 
1297 /*
1298  * nfsl_RENAME2_fhargs - updates the dfh and name fields for the given fh
1299  *	to change them to the new name.
1300  */
1301 /* ARGSUSED */
1302 static void
1303 nfslog_RENAME2_fhargs(nfslog_rnmargs *args, nfsstat *res,
1304 	char *fhpath, char **pathp1, char **pathp2)
1305 {
1306 	char			*from_name, *to_name;
1307 	fhandle_t		*from_dfh, *to_dfh;
1308 	int			error;
1309 
1310 	from_name = args->rna_from.da_name;
1311 	from_dfh = &args->rna_from.da_fhandle;
1312 	to_name = args->rna_to.da_name;
1313 	to_dfh = &args->rna_to.da_fhandle;
1314 	if (debug > 2) {
1315 		PRINT_LINK_DATA(stdout, "=============\nRENAME2: from",
1316 			from_dfh, from_name, "")
1317 		PRINT_LINK_DATA(stdout, "RENAME2: to  ", to_dfh,
1318 			to_name, "")
1319 		if (*res != NFS_OK)
1320 			(void) printf("status %d\n", *res);
1321 	}
1322 	from_dfh = NFSLOG_GET_FHANDLE2(from_dfh);
1323 	to_dfh = NFSLOG_GET_FHANDLE2(to_dfh);
1324 	if (pathp1 != NULL) {
1325 		*pathp1 = nfslog_get_path(from_dfh, from_name, fhpath,
1326 			"rename2 from");
1327 		*pathp2 = nfslog_get_path(to_dfh, to_name, fhpath,
1328 			"rename2 to");
1329 	}
1330 
1331 	if (*res != NFS_OK)
1332 		/* rename failed so nothing to update */
1333 		return;
1334 
1335 	/* Rename the link in the database */
1336 	if (error = fh_rename(fhpath, from_dfh, from_name, pathp1,
1337 			to_dfh, to_name)) {
1338 		syslog(LOG_ERR, gettext(
1339 			"Rename2: Update from '%s' to '%s' failed: %s\n"),
1340 				from_name, to_name,
1341 				((error >= 0) ? strerror(error) : "Unknown"));
1342 	}
1343 }
1344 
1345 /*
1346  * nfslog_LINK2_fhargs - adds link name and fh to fhlist. Note that as a
1347  *	result we may have more than one name for an fh.
1348  */
1349 /* ARGSUSED */
1350 static void
1351 nfslog_LINK2_fhargs(nfslog_linkargs *args, nfsstat *res,
1352 	char *fhpath, char **pathp1, char **pathp2)
1353 {
1354 	char		*name;
1355 	fhandle_t	*dfh, *fh;
1356 	int		error;
1357 
1358 	fh = &args->la_from;
1359 	name = args->la_to.da_name;
1360 	dfh = &args->la_to.da_fhandle;
1361 	if (debug > 2) {
1362 		PRINT_FULL_DATA(stdout, "=============\nLINK2",
1363 			dfh, fh, name, "")
1364 		if (*res != NFS_OK)
1365 			(void) printf("status %d\n", *res);
1366 	}
1367 	dfh = NFSLOG_GET_FHANDLE2(dfh);
1368 	fh = NFSLOG_GET_FHANDLE2(fh);
1369 	if (pathp1 != NULL) {
1370 		*pathp1 = nfslog_get_path(fh, NULL, fhpath, "link2 from");
1371 		*pathp2 = nfslog_get_path(dfh, name, fhpath, "link2 to");
1372 	}
1373 
1374 	if (*res != NFS_OK)
1375 		/* no returned fh so nothing to add */
1376 		return;
1377 
1378 	/* A new link so add it, have fh_add find the link count */
1379 	if (error = FH_ADD(fhpath, dfh, fh, name)) {
1380 		syslog(LOG_ERR, gettext(
1381 			"Link2: Add fh for '%s' failed: %s\n"),
1382 			    name, ((error >= 0) ? strerror(error) : "Unknown"));
1383 	}
1384 }
1385 
1386 /*
1387  * nfslog_SYMLINK2_fhargs - adds symlink name and fh to fhlist if fh returned.
1388  */
1389 /* ARGSUSED */
1390 static void
1391 nfslog_SYMLINK2_fhargs(nfslog_symlinkargs *args, nfsstat *res,
1392 	char *fhpath, char **pathp1, char **pathp2)
1393 {
1394 	char		*name;
1395 	fhandle_t	*dfh;
1396 
1397 	name = args->sla_from.da_name;
1398 	dfh = &args->sla_from.da_fhandle;
1399 	if (debug > 2) {
1400 		PRINT_LINK_DATA(stdout, "=============\nSYMLINK2",
1401 			dfh, name, "")
1402 	}
1403 	dfh = NFSLOG_GET_FHANDLE2(dfh);
1404 	if (pathp1 != NULL) {
1405 		*pathp1 = nfslog_get_path(dfh, name, fhpath, "symlink2");
1406 		*pathp2 = NULL;
1407 	}
1408 }
1409 
1410 /*
1411  * nfslog_READDIR2_fhargs - updates path1 but no fhtable changes
1412  */
1413 /* ARGSUSED */
1414 static void
1415 nfslog_READDIR2_fhargs(nfslog_rddirargs *args, nfslog_rddirres *res,
1416 	char *fhpath, char **pathp1, char **pathp2)
1417 {
1418 	if (debug > 2) {
1419 		(void) printf("=============\nREADDIR2: fh ");
1420 		debug_opaque_print(stdout, &args->rda_fh,
1421 			sizeof (args->rda_fh));
1422 		(void) printf("\n");
1423 	}
1424 	if (pathp1 != NULL) {
1425 		*pathp1 = nfslog_get_path(NFSLOG_GET_FHANDLE2(&args->rda_fh),
1426 				NULL, fhpath, "readdir2");
1427 		*pathp2 = NULL;
1428 	}
1429 }
1430 
1431 /*
1432  * nfslog_STATFS2_fhargs - updates path1 but no fhtable changes
1433  */
1434 /* ARGSUSED */
1435 static void
1436 nfslog_STATFS2_fhargs(fhandle_t *args, nfsstat *res,
1437 	char *fhpath, char **pathp1, char **pathp2)
1438 {
1439 	if (debug > 2) {
1440 		(void) printf("=============\nSTATFS2: fh ");
1441 		debug_opaque_print(stdout, args, sizeof (*args));
1442 		(void) printf("\n");
1443 	}
1444 	if (pathp1 != NULL) {
1445 		*pathp1 = nfslog_get_path(NFSLOG_GET_FHANDLE2(args),
1446 				NULL, fhpath, "statfs2");
1447 		*pathp2 = NULL;
1448 	}
1449 }
1450 
1451 /*
1452  * NFS VERSION 3
1453  */
1454 
1455 /* Functions for updating the fhtable for fhtoppath */
1456 
1457 /*
1458  * nfslog_GETATTR3_fhargs - updates path1 but no fhtable changes
1459  */
1460 /* ARGSUSED */
1461 static void
1462 nfslog_GETATTR3_fhargs(nfs_fh3 *args, nfsstat3 *res,
1463 	char *fhpath, char **pathp1, char **pathp2)
1464 {
1465 	if (debug > 2) {
1466 		(void) printf("=============\nGETATTR3: fh ");
1467 		debug_opaque_print(stdout, args, sizeof (*args));
1468 		(void) printf("\n");
1469 	}
1470 	if (pathp1 != NULL) {
1471 		*pathp1 = nfslog_get_path(NFSLOG_GET_FHANDLE3(args), NULL,
1472 			fhpath, "getattr3");
1473 		*pathp2 = NULL;
1474 	}
1475 }
1476 
1477 /*
1478  * nfslog_SETATTR3_fhargs - updates path1 but no fhtable changes
1479  */
1480 /* ARGSUSED */
1481 static void
1482 nfslog_SETATTR3_fhargs(nfslog_SETATTR3args *args,	nfsstat3 *res,
1483 	char *fhpath, char **pathp1, char **pathp2)
1484 {
1485 	if (debug > 2) {
1486 		(void) printf("=============\nSETATTR3: fh ");
1487 		debug_opaque_print(stdout, &args->object,
1488 			sizeof (args->object));
1489 		(void) printf("\n");
1490 	}
1491 	if (pathp1 != NULL) {
1492 		*pathp1 = nfslog_get_path(NFSLOG_GET_FHANDLE3(&args->object),
1493 			NULL, fhpath, "setattr3");
1494 		*pathp2 = NULL;
1495 	}
1496 }
1497 
1498 /*
1499  * nfslog_LOOKUP3_fhargs - search the table to ensure we have not added this
1500  * one already. Note that if the response status was anything but okay,
1501  * there is no fh to check...
1502  */
1503 /* ARGSUSED */
1504 static void
1505 nfslog_LOOKUP3_fhargs(nfslog_diropargs3 *args, nfslog_LOOKUP3res *res,
1506 	char *fhpath, char **pathp1, char **pathp2)
1507 {
1508 	char		*name;
1509 	fhandle_t	*dfh, *fh;
1510 
1511 	name = args->name;
1512 	dfh = NFSLOG_GET_FHANDLE3(&args->dir);
1513 
1514 	if (debug > 2) {
1515 		if (res->status == NFS3_OK)
1516 			fh = NFSLOG_GET_FHANDLE3(
1517 				&res->nfslog_LOOKUP3res_u.object);
1518 		else
1519 			fh = NULL;
1520 		PRINT_FULL_DATA(stdout, "=============\nLOOKUP3",
1521 			dfh, fh, name, "")
1522 		if (res->status != NFS3_OK)
1523 			(void) printf("status %d\n", res->status);
1524 	}
1525 	if ((dfh == &public_fh) && (name[0] == '\x80')) {
1526 		/* special mclookup */
1527 		name = &name[1];
1528 	}
1529 	if (res->status != NFS3_OK) {
1530 		if (pathp1 != NULL) {
1531 			*pathp1 = nfslog_get_path(dfh, name, fhpath, "lookup3");
1532 			*pathp2 = NULL;
1533 		}
1534 		return;
1535 	}
1536 	fh = NFSLOG_GET_FHANDLE3(&res->nfslog_LOOKUP3res_u.object);
1537 	nfslog_LOOKUP_calc(dfh, name, fh, fhpath, pathp1, pathp2, "Lookup3");
1538 }
1539 
1540 /*
1541  * nfslog_ACCESS3_fhargs - updates path1 but no fhtable changes
1542  */
1543 /* ARGSUSED */
1544 static void
1545 nfslog_ACCESS3_fhargs(nfs_fh3 *args, nfsstat3 *res,
1546 	char *fhpath, char **pathp1, char **pathp2)
1547 {
1548 	if (debug > 2) {
1549 		(void) printf("=============\nACCESS3: fh ");
1550 		debug_opaque_print(stdout, args,
1551 			sizeof (*args));
1552 		(void) printf("\n");
1553 	}
1554 	if (pathp1 != NULL) {
1555 		*pathp1 = nfslog_get_path(NFSLOG_GET_FHANDLE3(args),
1556 			NULL, fhpath, "access3");
1557 		*pathp2 = NULL;
1558 	}
1559 }
1560 
1561 /*
1562  * nfslog_READLINK3_fhargs - updates path1 but no fhtable changes
1563  */
1564 /* ARGSUSED */
1565 static void
1566 nfslog_READLINK3_fhargs(nfs_fh3 *args, nfslog_READLINK3res *res,
1567 	char *fhpath, char **pathp1, char **pathp2)
1568 {
1569 	if (debug > 2) {
1570 		(void) printf("=============\nREADLINK3: fh ");
1571 		debug_opaque_print(stdout, args, sizeof (*args));
1572 		(void) printf("\n");
1573 	}
1574 	if (pathp1 != NULL) {
1575 		*pathp1 = nfslog_get_path(NFSLOG_GET_FHANDLE3(args), NULL,
1576 			fhpath, "readlink3");
1577 		*pathp2 = NULL;
1578 	}
1579 }
1580 
1581 /*
1582  * nfslog_READ3_fhargs - updates path1 but no fhtable changes
1583  */
1584 /* ARGSUSED */
1585 static void
1586 nfslog_READ3_fhargs(nfslog_READ3args *args, nfslog_READ3res *res,
1587 	char *fhpath, char **pathp1, char **pathp2)
1588 {
1589 	if (debug > 2) {
1590 		(void) printf("=============\nREAD3: fh ");
1591 		debug_opaque_print(stdout, &args->file,
1592 			sizeof (args->file));
1593 		(void) printf("\n");
1594 	}
1595 	if (pathp1 != NULL) {
1596 		*pathp1 = nfslog_get_path(NFSLOG_GET_FHANDLE3(&args->file),
1597 			NULL, fhpath, "read3");
1598 		*pathp2 = NULL;
1599 	}
1600 }
1601 
1602 /*
1603  * nfslog_WRITE3_fhargs - updates path1 but no fhtable changes
1604  */
1605 /* ARGSUSED */
1606 static void
1607 nfslog_WRITE3_fhargs(nfslog_WRITE3args *args, nfslog_WRITE3res *res,
1608 	char *fhpath, char **pathp1, char **pathp2)
1609 {
1610 	if (debug > 2) {
1611 		(void) printf("=============\nWRITE3: fh ");
1612 		debug_opaque_print(stdout, &args->file,
1613 			sizeof (args->file));
1614 		(void) printf("\n");
1615 	}
1616 	if (pathp1 != NULL) {
1617 		*pathp1 = nfslog_get_path(NFSLOG_GET_FHANDLE3(&args->file),
1618 			NULL, fhpath, "write3");
1619 		*pathp2 = NULL;
1620 	}
1621 }
1622 
1623 /*
1624  * nfslog_CREATE3_fhargs - if the operation succeeded, we are sure there can
1625  * be no such link in the fhtable, so just add it.
1626  */
1627 /* ARGSUSED */
1628 static void
1629 nfslog_CREATE3_fhargs(nfslog_CREATE3args *args, nfslog_CREATE3res *res,
1630 	char *fhpath, char **pathp1, char **pathp2)
1631 {
1632 	char		*name;
1633 	fhandle_t	*dfh, *fh;
1634 	int		error;
1635 
1636 	name = args->where.name;
1637 	dfh = NFSLOG_GET_FHANDLE3(&args->where.dir);
1638 
1639 	if (debug > 2) {
1640 		if (res->status == NFS3_OK)
1641 			fh = NFSLOG_GET_FHANDLE3(
1642 				&res->nfslog_CREATE3res_u.ok.obj.handle);
1643 		else
1644 			fh = NULL;
1645 		PRINT_FULL_DATA(stdout, "=============\nCREATE3",
1646 			dfh, fh, name, "")
1647 		if (res->status != NFS3_OK)
1648 			(void) printf("status %d\n", res->status);
1649 	}
1650 	if (pathp1 != NULL) {
1651 		*pathp1 = nfslog_get_path(dfh, name, fhpath, "create3");
1652 		*pathp2 = NULL;
1653 	}
1654 
1655 	if ((res->status != NFS3_OK) ||
1656 		!res->nfslog_CREATE3res_u.ok.obj.handle_follows)
1657 		/* no returned fh so nothing to add */
1658 		return;
1659 
1660 	/* A new file handle so add it */
1661 	fh = NFSLOG_GET_FHANDLE3(&res->nfslog_CREATE3res_u.ok.obj.handle);
1662 	if (error = FH_ADD(fhpath, dfh, fh, name)) {
1663 		syslog(LOG_ERR, gettext(
1664 			"Create3: Add fh for '%s' failed: %s\n"),
1665 			    name, ((error >= 0) ? strerror(error) : "Unknown"));
1666 	}
1667 }
1668 
1669 /*
1670  * nfslog_MKDIR3_fhargs - if the operation succeeded, we are sure there can
1671  * be no such link in the fhtable, so just add it.
1672  */
1673 /* ARGSUSED */
1674 static void
1675 nfslog_MKDIR3_fhargs(nfslog_MKDIR3args *args, nfslog_MKDIR3res *res,
1676 	char *fhpath, char **pathp1, char **pathp2)
1677 {
1678 	char		*name;
1679 	fhandle_t	*dfh, *fh;
1680 	int		error;
1681 
1682 	name = args->where.name;
1683 	dfh = NFSLOG_GET_FHANDLE3(&args->where.dir);
1684 
1685 	if (debug > 2) {
1686 		if (res->status == NFS3_OK)
1687 			fh = NFSLOG_GET_FHANDLE3(
1688 				&res->nfslog_MKDIR3res_u.obj.handle);
1689 		else
1690 			fh = NULL;
1691 		PRINT_FULL_DATA(stdout, "=============\nMKDIR3",
1692 			dfh, fh, name, "")
1693 		if (res->status != NFS3_OK)
1694 			(void) printf("status %d\n", res->status);
1695 	}
1696 	if (pathp1 != NULL) {
1697 		*pathp1 = nfslog_get_path(dfh, name, fhpath, "mkdir3");
1698 		*pathp2 = NULL;
1699 	}
1700 
1701 	if ((res->status != NFS3_OK) ||
1702 		!res->nfslog_MKDIR3res_u.obj.handle_follows)
1703 		/* no returned fh so nothing to add */
1704 		return;
1705 
1706 	/* A new file handle so add it */
1707 	fh = NFSLOG_GET_FHANDLE3(&res->nfslog_MKDIR3res_u.obj.handle);
1708 	if (error = FH_ADD(fhpath, dfh, fh, name)) {
1709 		syslog(LOG_ERR, gettext(
1710 			"Mkdir3: Add fh for '%s' failed: %s\n"),
1711 			    name, ((error >= 0) ? strerror(error) : "Unknown"));
1712 	}
1713 }
1714 
1715 /*
1716  * nfslog_REMOVE3_fhargs - if the operation succeeded, remove the link from
1717  * the fhtable.
1718  */
1719 /* ARGSUSED */
1720 static void
1721 nfslog_REMOVE3_fhargs(nfslog_REMOVE3args *args, nfsstat3 *res,
1722 	char *fhpath, char **pathp1, char **pathp2)
1723 {
1724 	char		*name;
1725 	fhandle_t	*dfh;
1726 	int		error;
1727 
1728 	name = args->object.name;
1729 	dfh = NFSLOG_GET_FHANDLE3(&args->object.dir);
1730 
1731 	if (debug > 2) {
1732 		PRINT_LINK_DATA(stdout, "=============\nREMOVE3", dfh, name, "")
1733 		if (*res != NFS3_OK)
1734 			(void) printf("status %d\n", *res);
1735 	}
1736 	if (pathp1 != NULL) {
1737 		*pathp1 = nfslog_get_path(dfh, name, fhpath, "remove3");
1738 		*pathp2 = NULL;
1739 	}
1740 
1741 	if (*res != NFS3_OK)
1742 		/* remove failed so nothing to update */
1743 		return;
1744 
1745 	if (error = fh_remove(fhpath, dfh, name, pathp1)) {
1746 		syslog(LOG_ERR, gettext("Remove3: '%s' failed: %s\n"),
1747 			name, ((error >= 0) ? strerror(error) : "Unknown"));
1748 	}
1749 }
1750 
1751 /*
1752  * nfslog_RMDIR3_fhargs - if the operation succeeded, remove the link from
1753  * the fhtable.
1754  */
1755 /* ARGSUSED */
1756 static void
1757 nfslog_RMDIR3_fhargs(nfslog_RMDIR3args *args, nfsstat3 *res,
1758 	char *fhpath, char **pathp1, char **pathp2)
1759 {
1760 	char		*name;
1761 	fhandle_t	*dfh;
1762 	int		error;
1763 
1764 	name = args->object.name;
1765 	dfh = NFSLOG_GET_FHANDLE3(&args->object.dir);
1766 
1767 	if (debug > 2) {
1768 		PRINT_LINK_DATA(stdout, "=============\nRMDIR3", dfh, name, "")
1769 		if (*res != NFS3_OK)
1770 			(void) printf("status %d\n", *res);
1771 	}
1772 	if (pathp1 != NULL) {
1773 		*pathp1 = nfslog_get_path(dfh, name, fhpath, "rmdir3");
1774 		*pathp2 = NULL;
1775 	}
1776 
1777 	if (*res != NFS3_OK)
1778 		/* rmdir failed so nothing to update */
1779 		return;
1780 
1781 	if (error = fh_remove(fhpath, dfh, name, pathp1)) {
1782 		syslog(LOG_ERR, gettext("Rmdir3: '%s' failed: %s\n"),
1783 			name, ((error >= 0) ? strerror(error) : "Unknown"));
1784 	}
1785 }
1786 
1787 /*
1788  * nfslog_RENAME3_fhargs - if the operation succeeded, update the existing
1789  * fhtable entry to point to new dir and name.
1790  */
1791 /* ARGSUSED */
1792 static void
1793 nfslog_RENAME3_fhargs(nfslog_RENAME3args *args, nfsstat3 *res,
1794 	char *fhpath, char **pathp1, char **pathp2)
1795 {
1796 	char			*from_name, *to_name;
1797 	fhandle_t		*from_dfh, *to_dfh;
1798 	int			error;
1799 
1800 	from_name = args->from.name;
1801 	from_dfh = NFSLOG_GET_FHANDLE3(&args->from.dir);
1802 	to_name = args->to.name;
1803 	to_dfh = NFSLOG_GET_FHANDLE3(&args->to.dir);
1804 
1805 	if (debug > 2) {
1806 		PRINT_LINK_DATA(stdout, "=============\nRENAME3: from",
1807 			from_dfh, from_name, "")
1808 		PRINT_LINK_DATA(stdout, "=============\nRENAME3: to  ",
1809 			to_dfh, to_name, "")
1810 		if (*res != NFS3_OK)
1811 			(void) printf("status %d\n", *res);
1812 	}
1813 	if (pathp1 != NULL) {
1814 		*pathp1 = nfslog_get_path(from_dfh, from_name, fhpath,
1815 			"rename3 from");
1816 		*pathp2 = nfslog_get_path(to_dfh, to_name, fhpath,
1817 			"rename3 to");
1818 	}
1819 	if (*res != NFS3_OK)
1820 		/* rename failed so nothing to update */
1821 		return;
1822 
1823 	if (error = fh_rename(fhpath, from_dfh, from_name, pathp1,
1824 			to_dfh, to_name)) {
1825 		syslog(LOG_ERR, gettext(
1826 			"Rename3: Update from '%s' to '%s' failed: %s\n"),
1827 				from_name, to_name,
1828 				((error >= 0) ? strerror(error) : "Unknown"));
1829 	}
1830 }
1831 
1832 /*
1833  * nfslog_LINK3_fhargs - if the operation succeeded, we are sure there can
1834  * be no such link in the fhtable, so just add it.
1835  */
1836 /* ARGSUSED */
1837 static void
1838 nfslog_LINK3_fhargs(nfslog_LINK3args *args, nfsstat3 *res,
1839 	char *fhpath, char **pathp1, char **pathp2)
1840 {
1841 	char			*name;
1842 	fhandle_t		*dfh, *fh;
1843 	int			error;
1844 
1845 	fh = NFSLOG_GET_FHANDLE3(&args->file);
1846 	name = args->link.name;
1847 	dfh = NFSLOG_GET_FHANDLE3(&args->link.dir);
1848 
1849 	if (debug > 2) {
1850 		PRINT_FULL_DATA(stdout, "=============\nLINK3",
1851 			dfh, fh, name, "")
1852 		if (*res != NFS3_OK)
1853 			(void) printf("status %d\n", *res);
1854 	}
1855 	if (pathp1 != NULL) {
1856 		*pathp1 = nfslog_get_path(fh, NULL, fhpath, "link3 from");
1857 		*pathp2 = nfslog_get_path(dfh, name, fhpath, "link3 to");
1858 	}
1859 
1860 	if (*res != NFS3_OK)
1861 		/* link failed so nothing to add */
1862 		return;
1863 
1864 	/* A new link so add it, have fh_add find link count */
1865 	if (error = FH_ADD(fhpath, dfh, fh, name)) {
1866 		syslog(LOG_ERR, gettext(
1867 			"Link3: Add fh for '%s' failed: %s\n"),
1868 			    name, ((error >= 0) ? strerror(error) : "Unknown"));
1869 	}
1870 }
1871 
1872 /*
1873  * nfslog_MKNOD3_fhargs - if the operation succeeded, we are sure there can
1874  * be no such link in the fhtable, so just add it.
1875  */
1876 /* ARGSUSED */
1877 static void
1878 nfslog_MKNOD3_fhargs(nfslog_MKNOD3args *args, nfslog_MKNOD3res *res,
1879 	char *fhpath, char **pathp1, char **pathp2)
1880 {
1881 	char		*name;
1882 	fhandle_t	*dfh, *fh;
1883 	int		error;
1884 
1885 	name = args->where.name;
1886 	dfh = NFSLOG_GET_FHANDLE3(&args->where.dir);
1887 
1888 	if (debug > 2) {
1889 		if (res->status == NFS3_OK)
1890 			fh = NFSLOG_GET_FHANDLE3(
1891 				&res->nfslog_MKNOD3res_u.obj.handle);
1892 		else
1893 			fh = NULL;
1894 		PRINT_FULL_DATA(stdout, "=============\nMKNOD3",
1895 			dfh, fh, name, "")
1896 		if (res->status != NFS3_OK)
1897 			(void) printf("status %d\n", res->status);
1898 	}
1899 	if (pathp1 != NULL) {
1900 		*pathp1 = nfslog_get_path(dfh, name, fhpath, "mknod3");
1901 		*pathp2 = NULL;
1902 	}
1903 	if ((res->status != NFS3_OK) ||
1904 		!res->nfslog_MKNOD3res_u.obj.handle_follows)
1905 		/* no returned fh so nothing to add */
1906 		return;
1907 
1908 	/* A new file handle so add it */
1909 	fh = NFSLOG_GET_FHANDLE3(&res->nfslog_MKNOD3res_u.obj.handle);
1910 	if (error = FH_ADD(fhpath, dfh, fh, name)) {
1911 		syslog(LOG_ERR, gettext("Mknod3: Add fh for '%s' failed: %s\n"),
1912 			name, ((error >= 0) ? strerror(error) : "Unknown"));
1913 	}
1914 }
1915 
1916 /*
1917  * nfslog_SYMLINK3_fhargs - if the operation succeeded, we are sure there can
1918  * be no such link in the fhtable, so just add it.
1919  */
1920 /* ARGSUSED */
1921 static void
1922 nfslog_SYMLINK3_fhargs(nfslog_SYMLINK3args *args, nfslog_SYMLINK3res *res,
1923 	char *fhpath, char **pathp1, char **pathp2)
1924 {
1925 	char		*name;
1926 	fhandle_t	*dfh, *fh;
1927 	int		error;
1928 
1929 	name = args->where.name;
1930 	dfh = NFSLOG_GET_FHANDLE3(&args->where.dir);
1931 
1932 	if (debug > 2) {
1933 		if (res->status == NFS3_OK)
1934 			fh = NFSLOG_GET_FHANDLE3(
1935 				&res->nfslog_SYMLINK3res_u.obj.handle);
1936 		else
1937 			fh = NULL;
1938 		PRINT_FULL_DATA(stdout, "=============\nSYMLINK3",
1939 			dfh, fh, name, "")
1940 		if (res->status != NFS3_OK)
1941 			(void) printf("status %d\n", res->status);
1942 	}
1943 	if (pathp1 != NULL) {
1944 		*pathp1 = nfslog_get_path(dfh, name, fhpath, "symlink3");
1945 		*pathp2 = NULL;
1946 	}
1947 
1948 	if ((res->status != NFS3_OK) ||
1949 		!res->nfslog_SYMLINK3res_u.obj.handle_follows)
1950 		/* no returned fh so nothing to add */
1951 		return;
1952 
1953 	/* A new file handle so add it */
1954 	fh = NFSLOG_GET_FHANDLE3(&res->nfslog_SYMLINK3res_u.obj.handle);
1955 	if (error = FH_ADD(fhpath, dfh, fh, name)) {
1956 		syslog(LOG_ERR, gettext(
1957 			"Symlink3: Add fh for '%s' failed: %s\n"),
1958 			    name, ((error >= 0) ? strerror(error) : "Unknown"));
1959 	}
1960 }
1961 
1962 /*
1963  * nfslog_READDIR3_fhargs - updates path1 but no fhtable changes
1964  */
1965 /* ARGSUSED */
1966 static void
1967 nfslog_READDIR3_fhargs(nfs_fh3 *args, nfsstat3 *res,
1968 	char *fhpath, char **pathp1, char **pathp2)
1969 {
1970 	if (debug > 2) {
1971 		(void) printf("=============\nREADDIR3: fh ");
1972 		debug_opaque_print(stdout, args,
1973 			sizeof (*args));
1974 		(void) printf("\n");
1975 	}
1976 	if (pathp1 != NULL) {
1977 		*pathp1 = nfslog_get_path(NFSLOG_GET_FHANDLE3(args),
1978 			NULL, fhpath, "readdir3");
1979 		*pathp2 = NULL;
1980 	}
1981 }
1982 
1983 /*
1984  * nfslog_READDIRPLUS3_fhargs - updates path1 but no fhtable changes
1985  */
1986 /* ARGSUSED */
1987 static void
1988 nfslog_READDIRPLUS3_fhargs(nfslog_READDIRPLUS3args *args,
1989 	nfslog_READDIRPLUS3res *res,
1990 	char *fhpath, char **pathp1, char **pathp2)
1991 {
1992 	char		*name;
1993 	fhandle_t	*dfh, *fh;
1994 	nfslog_entryplus3 *ep;
1995 
1996 	if (debug > 2) {
1997 		(void) printf("=============\nREADDIRPLUS3: fh ");
1998 		debug_opaque_print(stdout, &args->dir,
1999 			sizeof (args->dir));
2000 		(void) printf("\n");
2001 	}
2002 	if (pathp1 != NULL) {
2003 		*pathp1 = nfslog_get_path(NFSLOG_GET_FHANDLE3(&args->dir),
2004 			NULL, fhpath, "readdirplus3");
2005 		*pathp2 = NULL;
2006 	}
2007 
2008 	if (res->status == NFS3_OK) {
2009 
2010 		dfh = NFSLOG_GET_FHANDLE3(&args->dir);
2011 
2012 		/*
2013 		 * Loop through the fh/name pair and add them
2014 		 * to the mappings.
2015 		 */
2016 		for (ep = res->nfslog_READDIRPLUS3res_u.ok.reply.entries;
2017 			ep != NULL;
2018 			ep = ep->nextentry) {
2019 
2020 			name = ep->name;
2021 
2022 			fh = NFSLOG_GET_FHANDLE3(&ep->name_handle.handle);
2023 
2024 			nfslog_LOOKUP_calc(dfh, name, fh,
2025 				fhpath, NULL, NULL,
2026 				"ReaddirPlus3");
2027 		}
2028 	}
2029 }
2030 
2031 /*
2032  * nfslog_FSSTAT3_fhargs - updates path1 but no fhtable changes
2033  */
2034 /* ARGSUSED */
2035 static void
2036 nfslog_FSSTAT3_fhargs(nfs_fh3 *args, nfsstat3 *res,
2037 	char *fhpath, char **pathp1, char **pathp2)
2038 {
2039 	if (debug > 2) {
2040 		(void) printf("=============\nFSSTAT3: fh ");
2041 		debug_opaque_print(stdout, args,
2042 			sizeof (*args));
2043 		(void) printf("\n");
2044 	}
2045 	if (pathp1 != NULL) {
2046 		*pathp1 = nfslog_get_path(NFSLOG_GET_FHANDLE3(args), NULL,
2047 			fhpath, "fsstat3");
2048 		*pathp2 = NULL;
2049 	}
2050 }
2051 
2052 /*
2053  * nfslog_FSINFO3_fhargs - updates path1 but no fhtable changes
2054  */
2055 /* ARGSUSED */
2056 static void
2057 nfslog_FSINFO3_fhargs(nfs_fh3 *args, nfsstat3 *res,
2058 	char *fhpath, char **pathp1, char **pathp2)
2059 {
2060 	if (debug > 2) {
2061 		(void) printf("=============\nFSINFO3: fh ");
2062 		debug_opaque_print(stdout, args,
2063 			sizeof (*args));
2064 		(void) printf("\n");
2065 	}
2066 	if (pathp1 != NULL) {
2067 		*pathp1 = nfslog_get_path(NFSLOG_GET_FHANDLE3(args), NULL,
2068 			fhpath, "fsinfo3");
2069 		*pathp2 = NULL;
2070 	}
2071 }
2072 
2073 /*
2074  * nfslog_PATHCONF3_fhargs - updates path1 but no fhtable changes
2075  */
2076 /* ARGSUSED */
2077 static void
2078 nfslog_PATHCONF3_fhargs(nfs_fh3 *args, nfsstat3 *res,
2079 	char *fhpath, char **pathp1, char **pathp2)
2080 {
2081 	if (debug > 2) {
2082 		(void) printf("=============\nPATHCONF3: fh ");
2083 		debug_opaque_print(stdout, args,
2084 			sizeof (*args));
2085 		(void) printf("\n");
2086 	}
2087 	if (pathp1 != NULL) {
2088 		*pathp1 = nfslog_get_path(NFSLOG_GET_FHANDLE3(args), NULL,
2089 			fhpath, "pathconf3");
2090 		*pathp2 = NULL;
2091 	}
2092 }
2093 
2094 /*
2095  * nfslog_COMMIT3_fhargs - updates path1 but no fhtable changes
2096  */
2097 /* ARGSUSED */
2098 static void
2099 nfslog_COMMIT3_fhargs(nfslog_COMMIT3args *args, nfsstat3 *res,
2100 	char *fhpath, char **pathp1, char **pathp2)
2101 {
2102 	if (debug > 2) {
2103 		(void) printf("=============\nCOMMIT3: fh ");
2104 		debug_opaque_print(stdout, &args->file,
2105 			sizeof (args->file));
2106 		(void) printf("\n");
2107 	}
2108 	if (pathp1 != NULL) {
2109 		*pathp1 = nfslog_get_path(NFSLOG_GET_FHANDLE3(&args->file),
2110 			NULL, fhpath, "commit3");
2111 		*pathp2 = NULL;
2112 	}
2113 }
2114 
2115 /*
2116  * NFSLOG VERSION 1
2117  */
2118 
2119 /*
2120  * nfslog_SHARE_fhargs - adds export path and handle to fhlist
2121  */
2122 /* ARGSUSED */
2123 static void
2124 nfslog_SHARE_fhargs(nfslog_sharefsargs *args, nfslog_sharefsres *res,
2125 	char *fhpath, char **pathp1, char **pathp2)
2126 {
2127 	fhlist_ent	fhrec;
2128 	fhandle_t	*fh;
2129 	int		error;
2130 
2131 	if (debug > 2) {
2132 		(void) printf(
2133 			"=============\nSHARE: name '%s', fh ", args->sh_path);
2134 		debug_opaque_print(stdout, &args->sh_fh_buf,
2135 			sizeof (fhandle_t));
2136 		(void) printf("\n");
2137 	}
2138 
2139 	fh = &args->sh_fh_buf;
2140 
2141 	/*
2142 	 * This bcopy is done because the fh_data for the export/share directory
2143 	 * is not meaningful with respect to the database keys.  Therefore, we
2144 	 * copy the export or fh_xdata fid to the fh_data so that a reasonable
2145 	 * entry will be added in the data base.
2146 	 */
2147 	bcopy(fh->fh_xdata, fh->fh_data, fh->fh_xlen);
2148 
2149 	/* If debug print the database */
2150 	if (debug > 10) {
2151 		fh_print_all_keys(fhpath, fh);
2152 	}
2153 	if (fh_lookup_link(fhpath, fh, fh,
2154 		args->sh_path, &fhrec, &error) == NULL) {
2155 		if (error = FH_ADD(fhpath, fh, fh, args->sh_path)) {
2156 			syslog(LOG_ERR, gettext(
2157 				"Share: Add fh for '%s' failed: %s\n"),
2158 				    args->sh_path, ((error >= 0) ?
2159 				    strerror(error) : "Unknown"));
2160 		}
2161 	}
2162 	if (pathp1 != NULL) {
2163 		*pathp1 = nfslog_get_path(fh, NULL, fhpath, "share");
2164 		*pathp2 = NULL;
2165 	}
2166 }
2167 
2168 /*
2169  * nfslog_UNSHARE_fhargs - remove export path and handle from fhlist
2170  */
2171 /* ARGSUSED */
2172 static void
2173 nfslog_UNSHARE_fhargs(nfslog_sharefsargs *args, nfslog_sharefsres *res,
2174 	char *fhpath, char **pathp1, char **pathp2)
2175 {
2176 	fhandle_t	*fh;
2177 	int		error;
2178 
2179 	if (debug > 2) {
2180 		(void) printf("=============\nUNSHARE: name '%s', fh ",
2181 			args->sh_path);
2182 		debug_opaque_print(stdout, &args->sh_fh_buf,
2183 			sizeof (fhandle_t));
2184 		(void) printf("\n");
2185 	}
2186 
2187 	fh = &args->sh_fh_buf;
2188 
2189 	/*
2190 	 * This bcopy is done because the fh_data for the export/share directory
2191 	 * is not meaningful with respect to the database keys.  Therefore, we
2192 	 * copy the export or fh_xdata fid to the fh_data so that a reasonable
2193 	 * entry will be added in the data base.
2194 	 */
2195 	bcopy(fh->fh_xdata, fh->fh_data, fh->fh_xlen);
2196 
2197 	/* If debug print the database */
2198 	if (debug > 10) {
2199 		fh_print_all_keys(fhpath, fh);
2200 	}
2201 	if (pathp1 != NULL) {
2202 		*pathp1 = nfslog_get_path(fh, NULL, fhpath, "share");
2203 		*pathp2 = NULL;
2204 	}
2205 	if (error = fh_remove(fhpath, fh, args->sh_path, pathp1)) {
2206 		syslog(LOG_ERR, gettext("Unshare: '%s' failed: %s\n"),
2207 			args->sh_path, ((error >= 0) ? strerror(error) :
2208 			"Unknown"));
2209 	}
2210 }
2211 
2212 /* ARGSUSED */
2213 static void
2214 nfslog_GETFH_fhargs(nfslog_getfhargs *args, nfsstat *res,
2215 	char *fhpath, char **pathp1, char **pathp2)
2216 {
2217 	fhlist_ent	fhrec;
2218 	fhandle_t	*fh;
2219 	int		error;
2220 
2221 	if (debug > 2) {
2222 		(void) printf("=============\nGETFH3: name '%s', fh ",
2223 			args->gfh_path);
2224 		debug_opaque_print(stdout, &args->gfh_fh_buf,
2225 			sizeof (fhandle_t));
2226 		(void) printf("\n");
2227 	}
2228 
2229 	fh = &args->gfh_fh_buf;
2230 
2231 	/* If debug print the database */
2232 	if (debug > 10) {
2233 		fh_print_all_keys(fhpath, fh);
2234 	}
2235 	if (fh_lookup_link(fhpath, fh, fh,
2236 		args->gfh_path, &fhrec, &error) == NULL) {
2237 		if (error = FH_ADD(fhpath, fh, fh, args->gfh_path)) {
2238 			syslog(LOG_ERR, gettext(
2239 				"Getfh: Add fh for '%s' failed: %s\n"),
2240 				    args->gfh_path, ((error >= 0) ?
2241 				    strerror(error) : "Unknown"));
2242 		}
2243 	}
2244 	if (pathp1 != NULL) {
2245 		*pathp1 = nfslog_get_path(fh, NULL, fhpath, "getfh");
2246 		*pathp2 = NULL;
2247 	}
2248 }
2249 
2250 /*
2251  * Exported function
2252  */
2253 
2254 /*
2255  * nfslog_get_path - gets the path for this file. fh must be supplied,
2256  * name may be null. If name is supplied, fh is assumed to be a directory
2257  * filehandle, with name as its component. fhpath is the generic path for the
2258  * fhtopath table and prtstr is the name of the caller (for debug purposes).
2259  * Returns the malloc'd path. The caller must free it later.
2260  */
2261 char *
2262 nfslog_get_path(fhandle_t *fh, char *name, char *fhpath, char *prtstr)
2263 {
2264 	char	*pathp = fh_print_absolute(fhpath, fh, name);
2265 
2266 	if (debug > 3) {
2267 		(void) printf("   %s: path '%s', fh ", prtstr, pathp);
2268 		debug_opaque_print(stdout, fh, sizeof (*fh));
2269 		(void) printf("\n");
2270 	}
2271 	return (pathp);
2272 }
2273 
2274 /*
2275  * nfslog_process_fh_rec - updates the fh table based on the rpc req
2276  * Return 0 for success, error otherwise. If success return the path
2277  * for the input file handle(s) if so indicated.
2278  */
2279 int
2280 nfslog_process_fh_rec(struct nfslog_lr *lrp, char *fhpath, char **pathp1,
2281 	char **pathp2, bool_t return_path)
2282 {
2283 	struct nfsl_fh_proc_disp	*disp;
2284 	nfslog_request_record 		*logrec = &lrp->log_record;
2285 	nfslog_record_header		*logrechdr = &logrec->re_header;
2286 
2287 	if ((disp = nfslog_find_fh_dispatch(logrec)) != NULL) {
2288 		/*
2289 		 * Allocate space for the args and results and decode
2290 		 */
2291 		logrec->re_rpc_arg = calloc(1, disp->args_size);
2292 
2293 		if (!(*disp->xdr_args)(&lrp->xdrs, logrec->re_rpc_arg)) {
2294 			free(logrec->re_rpc_arg);
2295 			logrec->re_rpc_arg = NULL;
2296 			syslog(LOG_ERR, gettext("argument decode failed"));
2297 			return (FALSE);
2298 		}
2299 		/* used later for free of data structures */
2300 		lrp->xdrargs = disp->xdr_args;
2301 
2302 		logrec->re_rpc_res = calloc(1, disp->res_size);
2303 		if (!(*disp->xdr_res)(&lrp->xdrs, logrec->re_rpc_res)) {
2304 			free(logrec->re_rpc_res);
2305 			logrec->re_rpc_res = NULL;
2306 			syslog(LOG_ERR, gettext("results decode failed"));
2307 			return (FALSE);
2308 		}
2309 		/* used later for free of data structures */
2310 		lrp->xdrres = disp->xdr_res;
2311 
2312 		/*
2313 		 * Process the operation within the context of the file handle
2314 		 * mapping process
2315 		 */
2316 		if (return_path) {
2317 			(*disp->nfsl_dis_args)(logrec->re_rpc_arg,
2318 				logrec->re_rpc_res, fhpath, pathp1, pathp2);
2319 		} else {
2320 			if ((logrechdr->rh_version == NFS_VERSION &&
2321 				logrechdr->rh_procnum == RFS_LINK) ||
2322 				(logrechdr->rh_version == NFS_V3 &&
2323 				logrechdr->rh_procnum == NFSPROC3_LINK)) {
2324 
2325 				(*disp->nfsl_dis_args)(logrec->re_rpc_arg,
2326 					logrec->re_rpc_res,
2327 					fhpath,	pathp1, pathp2);
2328 			} else {
2329 				(*disp->nfsl_dis_args)(logrec->re_rpc_arg,
2330 					logrec->re_rpc_res,
2331 					fhpath, NULL, NULL);
2332 			}
2333 		}
2334 		return (TRUE);
2335 	} else {
2336 		syslog(LOG_ERR, gettext("procedure unknown"));
2337 		return (FALSE);
2338 	}
2339 }
2340