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