]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/nfsserver/nfs_srvsubs.c
This commit was generated by cvs2svn to compensate for changes in r84491,
[FreeBSD/FreeBSD.git] / sys / nfsserver / nfs_srvsubs.c
1 /*
2  * Copyright (c) 1989, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Rick Macklem at The University of Guelph.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *      This product includes software developed by the University of
19  *      California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  *
36  *      @(#)nfs_subs.c  8.8 (Berkeley) 5/22/95
37  * $FreeBSD$
38  */
39
40 #include <sys/cdefs.h>
41 __FBSDID("$FreeBSD$");
42
43 /*
44  * These functions support the macros and help fiddle mbuf chains for
45  * the nfs op functions. They do things like create the rpc header and
46  * copy data between mbuf chains and uio lists.
47  */
48
49 #include <sys/param.h>
50 #include <sys/systm.h>
51 #include <sys/kernel.h>
52 #include <sys/bio.h>
53 #include <sys/buf.h>
54 #include <sys/proc.h>
55 #include <sys/mount.h>
56 #include <sys/vnode.h>
57 #include <sys/namei.h>
58 #include <sys/mbuf.h>
59 #include <sys/socket.h>
60 #include <sys/stat.h>
61 #include <sys/malloc.h>
62 #include <sys/module.h>
63 #include <sys/sysent.h>
64 #include <sys/syscall.h>
65 #include <sys/sysproto.h>
66
67 #include <vm/vm.h>
68 #include <vm/vm_object.h>
69 #include <vm/vm_extern.h>
70 #include <vm/vm_zone.h>
71
72 #include <nfs/rpcv2.h>
73 #include <nfs/nfsproto.h>
74 #include <nfsserver/nfs.h>
75 #include <nfs/xdr_subs.h>
76 #include <nfsserver/nfsm_subs.h>
77
78 #include <netinet/in.h>
79
80 /*
81  * Data items converted to xdr at startup, since they are constant
82  * This is kinda hokey, but may save a little time doing byte swaps
83  */
84 u_int32_t nfs_xdrneg1;
85 u_int32_t rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr,
86         rpc_mismatch, rpc_auth_unix, rpc_msgaccepted;
87 u_int32_t nfs_prog, nfs_true, nfs_false;
88
89 /* And other global data */
90 static nfstype nfsv2_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK,
91                                  NFNON, NFCHR, NFNON };
92 #define vtonfsv2_type(a)        txdr_unsigned(nfsv2_type[((int32_t)(a))])
93 #define vtonfsv3_mode(m)        txdr_unsigned((m) & ALLPERMS)
94
95 int nfs_ticks;
96
97 struct nfssvc_sockhead nfssvc_sockhead;
98 int nfssvc_sockhead_flag;
99 struct nfsd_head nfsd_head;
100 int nfsd_head_flag;
101
102 static int nfs_prev_nfssvc_sy_narg;
103 static sy_call_t *nfs_prev_nfssvc_sy_call;
104
105 /*
106  * Mapping of old NFS Version 2 RPC numbers to generic numbers.
107  */
108 int nfsv3_procid[NFS_NPROCS] = {
109         NFSPROC_NULL,
110         NFSPROC_GETATTR,
111         NFSPROC_SETATTR,
112         NFSPROC_NOOP,
113         NFSPROC_LOOKUP,
114         NFSPROC_READLINK,
115         NFSPROC_READ,
116         NFSPROC_NOOP,
117         NFSPROC_WRITE,
118         NFSPROC_CREATE,
119         NFSPROC_REMOVE,
120         NFSPROC_RENAME,
121         NFSPROC_LINK,
122         NFSPROC_SYMLINK,
123         NFSPROC_MKDIR,
124         NFSPROC_RMDIR,
125         NFSPROC_READDIR,
126         NFSPROC_FSSTAT,
127         NFSPROC_NOOP,
128         NFSPROC_NOOP,
129         NFSPROC_NOOP,
130         NFSPROC_NOOP,
131         NFSPROC_NOOP,
132 };
133
134 /*
135  * and the reverse mapping from generic to Version 2 procedure numbers
136  */
137 int nfsrvv2_procid[NFS_NPROCS] = {
138         NFSV2PROC_NULL,
139         NFSV2PROC_GETATTR,
140         NFSV2PROC_SETATTR,
141         NFSV2PROC_LOOKUP,
142         NFSV2PROC_NOOP,
143         NFSV2PROC_READLINK,
144         NFSV2PROC_READ,
145         NFSV2PROC_WRITE,
146         NFSV2PROC_CREATE,
147         NFSV2PROC_MKDIR,
148         NFSV2PROC_SYMLINK,
149         NFSV2PROC_CREATE,
150         NFSV2PROC_REMOVE,
151         NFSV2PROC_RMDIR,
152         NFSV2PROC_RENAME,
153         NFSV2PROC_LINK,
154         NFSV2PROC_READDIR,
155         NFSV2PROC_NOOP,
156         NFSV2PROC_STATFS,
157         NFSV2PROC_NOOP,
158         NFSV2PROC_NOOP,
159         NFSV2PROC_NOOP,
160         NFSV2PROC_NOOP,
161 };
162
163 /*
164  * Maps errno values to nfs error numbers.
165  * Use NFSERR_IO as the catch all for ones not specifically defined in
166  * RFC 1094.
167  */
168 static u_char nfsrv_v2errmap[ELAST] = {
169   NFSERR_PERM,  NFSERR_NOENT,   NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
170   NFSERR_NXIO,  NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
171   NFSERR_IO,    NFSERR_IO,      NFSERR_ACCES,   NFSERR_IO,      NFSERR_IO,
172   NFSERR_IO,    NFSERR_EXIST,   NFSERR_IO,      NFSERR_NODEV,   NFSERR_NOTDIR,
173   NFSERR_ISDIR, NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
174   NFSERR_IO,    NFSERR_FBIG,    NFSERR_NOSPC,   NFSERR_IO,      NFSERR_ROFS,
175   NFSERR_IO,    NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
176   NFSERR_IO,    NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
177   NFSERR_IO,    NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
178   NFSERR_IO,    NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
179   NFSERR_IO,    NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
180   NFSERR_IO,    NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
181   NFSERR_IO,    NFSERR_IO,      NFSERR_NAMETOL, NFSERR_IO,      NFSERR_IO,
182   NFSERR_NOTEMPTY, NFSERR_IO,   NFSERR_IO,      NFSERR_DQUOT,   NFSERR_STALE,
183   NFSERR_IO,    NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
184   NFSERR_IO,    NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
185   NFSERR_IO,    NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
186   NFSERR_IO /* << Last is 86 */
187 };
188
189 /*
190  * Maps errno values to nfs error numbers.
191  * Although it is not obvious whether or not NFS clients really care if
192  * a returned error value is in the specified list for the procedure, the
193  * safest thing to do is filter them appropriately. For Version 2, the
194  * X/Open XNFS document is the only specification that defines error values
195  * for each RPC (The RFC simply lists all possible error values for all RPCs),
196  * so I have decided to not do this for Version 2.
197  * The first entry is the default error return and the rest are the valid
198  * errors for that RPC in increasing numeric order.
199  */
200 static short nfsv3err_null[] = {
201         0,
202         0,
203 };
204
205 static short nfsv3err_getattr[] = {
206         NFSERR_IO,
207         NFSERR_IO,
208         NFSERR_STALE,
209         NFSERR_BADHANDLE,
210         NFSERR_SERVERFAULT,
211         0,
212 };
213
214 static short nfsv3err_setattr[] = {
215         NFSERR_IO,
216         NFSERR_PERM,
217         NFSERR_IO,
218         NFSERR_ACCES,
219         NFSERR_INVAL,
220         NFSERR_NOSPC,
221         NFSERR_ROFS,
222         NFSERR_DQUOT,
223         NFSERR_STALE,
224         NFSERR_BADHANDLE,
225         NFSERR_NOT_SYNC,
226         NFSERR_SERVERFAULT,
227         0,
228 };
229
230 static short nfsv3err_lookup[] = {
231         NFSERR_IO,
232         NFSERR_NOENT,
233         NFSERR_IO,
234         NFSERR_ACCES,
235         NFSERR_NOTDIR,
236         NFSERR_NAMETOL,
237         NFSERR_STALE,
238         NFSERR_BADHANDLE,
239         NFSERR_SERVERFAULT,
240         0,
241 };
242
243 static short nfsv3err_access[] = {
244         NFSERR_IO,
245         NFSERR_IO,
246         NFSERR_STALE,
247         NFSERR_BADHANDLE,
248         NFSERR_SERVERFAULT,
249         0,
250 };
251
252 static short nfsv3err_readlink[] = {
253         NFSERR_IO,
254         NFSERR_IO,
255         NFSERR_ACCES,
256         NFSERR_INVAL,
257         NFSERR_STALE,
258         NFSERR_BADHANDLE,
259         NFSERR_NOTSUPP,
260         NFSERR_SERVERFAULT,
261         0,
262 };
263
264 static short nfsv3err_read[] = {
265         NFSERR_IO,
266         NFSERR_IO,
267         NFSERR_NXIO,
268         NFSERR_ACCES,
269         NFSERR_INVAL,
270         NFSERR_STALE,
271         NFSERR_BADHANDLE,
272         NFSERR_SERVERFAULT,
273         0,
274 };
275
276 static short nfsv3err_write[] = {
277         NFSERR_IO,
278         NFSERR_IO,
279         NFSERR_ACCES,
280         NFSERR_INVAL,
281         NFSERR_FBIG,
282         NFSERR_NOSPC,
283         NFSERR_ROFS,
284         NFSERR_DQUOT,
285         NFSERR_STALE,
286         NFSERR_BADHANDLE,
287         NFSERR_SERVERFAULT,
288         0,
289 };
290
291 static short nfsv3err_create[] = {
292         NFSERR_IO,
293         NFSERR_IO,
294         NFSERR_ACCES,
295         NFSERR_EXIST,
296         NFSERR_NOTDIR,
297         NFSERR_NOSPC,
298         NFSERR_ROFS,
299         NFSERR_NAMETOL,
300         NFSERR_DQUOT,
301         NFSERR_STALE,
302         NFSERR_BADHANDLE,
303         NFSERR_NOTSUPP,
304         NFSERR_SERVERFAULT,
305         0,
306 };
307
308 static short nfsv3err_mkdir[] = {
309         NFSERR_IO,
310         NFSERR_IO,
311         NFSERR_ACCES,
312         NFSERR_EXIST,
313         NFSERR_NOTDIR,
314         NFSERR_NOSPC,
315         NFSERR_ROFS,
316         NFSERR_NAMETOL,
317         NFSERR_DQUOT,
318         NFSERR_STALE,
319         NFSERR_BADHANDLE,
320         NFSERR_NOTSUPP,
321         NFSERR_SERVERFAULT,
322         0,
323 };
324
325 static short nfsv3err_symlink[] = {
326         NFSERR_IO,
327         NFSERR_IO,
328         NFSERR_ACCES,
329         NFSERR_EXIST,
330         NFSERR_NOTDIR,
331         NFSERR_NOSPC,
332         NFSERR_ROFS,
333         NFSERR_NAMETOL,
334         NFSERR_DQUOT,
335         NFSERR_STALE,
336         NFSERR_BADHANDLE,
337         NFSERR_NOTSUPP,
338         NFSERR_SERVERFAULT,
339         0,
340 };
341
342 static short nfsv3err_mknod[] = {
343         NFSERR_IO,
344         NFSERR_IO,
345         NFSERR_ACCES,
346         NFSERR_EXIST,
347         NFSERR_NOTDIR,
348         NFSERR_NOSPC,
349         NFSERR_ROFS,
350         NFSERR_NAMETOL,
351         NFSERR_DQUOT,
352         NFSERR_STALE,
353         NFSERR_BADHANDLE,
354         NFSERR_NOTSUPP,
355         NFSERR_SERVERFAULT,
356         NFSERR_BADTYPE,
357         0,
358 };
359
360 static short nfsv3err_remove[] = {
361         NFSERR_IO,
362         NFSERR_NOENT,
363         NFSERR_IO,
364         NFSERR_ACCES,
365         NFSERR_NOTDIR,
366         NFSERR_ROFS,
367         NFSERR_NAMETOL,
368         NFSERR_STALE,
369         NFSERR_BADHANDLE,
370         NFSERR_SERVERFAULT,
371         0,
372 };
373
374 static short nfsv3err_rmdir[] = {
375         NFSERR_IO,
376         NFSERR_NOENT,
377         NFSERR_IO,
378         NFSERR_ACCES,
379         NFSERR_EXIST,
380         NFSERR_NOTDIR,
381         NFSERR_INVAL,
382         NFSERR_ROFS,
383         NFSERR_NAMETOL,
384         NFSERR_NOTEMPTY,
385         NFSERR_STALE,
386         NFSERR_BADHANDLE,
387         NFSERR_NOTSUPP,
388         NFSERR_SERVERFAULT,
389         0,
390 };
391
392 static short nfsv3err_rename[] = {
393         NFSERR_IO,
394         NFSERR_NOENT,
395         NFSERR_IO,
396         NFSERR_ACCES,
397         NFSERR_EXIST,
398         NFSERR_XDEV,
399         NFSERR_NOTDIR,
400         NFSERR_ISDIR,
401         NFSERR_INVAL,
402         NFSERR_NOSPC,
403         NFSERR_ROFS,
404         NFSERR_MLINK,
405         NFSERR_NAMETOL,
406         NFSERR_NOTEMPTY,
407         NFSERR_DQUOT,
408         NFSERR_STALE,
409         NFSERR_BADHANDLE,
410         NFSERR_NOTSUPP,
411         NFSERR_SERVERFAULT,
412         0,
413 };
414
415 static short nfsv3err_link[] = {
416         NFSERR_IO,
417         NFSERR_IO,
418         NFSERR_ACCES,
419         NFSERR_EXIST,
420         NFSERR_XDEV,
421         NFSERR_NOTDIR,
422         NFSERR_INVAL,
423         NFSERR_NOSPC,
424         NFSERR_ROFS,
425         NFSERR_MLINK,
426         NFSERR_NAMETOL,
427         NFSERR_DQUOT,
428         NFSERR_STALE,
429         NFSERR_BADHANDLE,
430         NFSERR_NOTSUPP,
431         NFSERR_SERVERFAULT,
432         0,
433 };
434
435 static short nfsv3err_readdir[] = {
436         NFSERR_IO,
437         NFSERR_IO,
438         NFSERR_ACCES,
439         NFSERR_NOTDIR,
440         NFSERR_STALE,
441         NFSERR_BADHANDLE,
442         NFSERR_BAD_COOKIE,
443         NFSERR_TOOSMALL,
444         NFSERR_SERVERFAULT,
445         0,
446 };
447
448 static short nfsv3err_readdirplus[] = {
449         NFSERR_IO,
450         NFSERR_IO,
451         NFSERR_ACCES,
452         NFSERR_NOTDIR,
453         NFSERR_STALE,
454         NFSERR_BADHANDLE,
455         NFSERR_BAD_COOKIE,
456         NFSERR_NOTSUPP,
457         NFSERR_TOOSMALL,
458         NFSERR_SERVERFAULT,
459         0,
460 };
461
462 static short nfsv3err_fsstat[] = {
463         NFSERR_IO,
464         NFSERR_IO,
465         NFSERR_STALE,
466         NFSERR_BADHANDLE,
467         NFSERR_SERVERFAULT,
468         0,
469 };
470
471 static short nfsv3err_fsinfo[] = {
472         NFSERR_STALE,
473         NFSERR_STALE,
474         NFSERR_BADHANDLE,
475         NFSERR_SERVERFAULT,
476         0,
477 };
478
479 static short nfsv3err_pathconf[] = {
480         NFSERR_STALE,
481         NFSERR_STALE,
482         NFSERR_BADHANDLE,
483         NFSERR_SERVERFAULT,
484         0,
485 };
486
487 static short nfsv3err_commit[] = {
488         NFSERR_IO,
489         NFSERR_IO,
490         NFSERR_STALE,
491         NFSERR_BADHANDLE,
492         NFSERR_SERVERFAULT,
493         0,
494 };
495
496 static short *nfsrv_v3errmap[] = {
497         nfsv3err_null,
498         nfsv3err_getattr,
499         nfsv3err_setattr,
500         nfsv3err_lookup,
501         nfsv3err_access,
502         nfsv3err_readlink,
503         nfsv3err_read,
504         nfsv3err_write,
505         nfsv3err_create,
506         nfsv3err_mkdir,
507         nfsv3err_symlink,
508         nfsv3err_mknod,
509         nfsv3err_remove,
510         nfsv3err_rmdir,
511         nfsv3err_rename,
512         nfsv3err_link,
513         nfsv3err_readdir,
514         nfsv3err_readdirplus,
515         nfsv3err_fsstat,
516         nfsv3err_fsinfo,
517         nfsv3err_pathconf,
518         nfsv3err_commit,
519 };
520
521 /*
522  * Called once to initialize data structures...
523  */
524 static int
525 nfsrv_modevent(module_t mod, int type, void *data)
526 {
527
528         switch (type) {
529         case MOD_LOAD:
530                 rpc_vers = txdr_unsigned(RPC_VER2);
531                 rpc_call = txdr_unsigned(RPC_CALL);
532                 rpc_reply = txdr_unsigned(RPC_REPLY);
533                 rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
534                 rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
535                 rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
536                 rpc_autherr = txdr_unsigned(RPC_AUTHERR);
537                 rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
538                 nfs_prog = txdr_unsigned(NFS_PROG);
539                 nfs_true = txdr_unsigned(TRUE);
540                 nfs_false = txdr_unsigned(FALSE);
541                 nfs_xdrneg1 = txdr_unsigned(-1);
542                 nfs_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
543                 if (nfs_ticks < 1)
544                         nfs_ticks = 1;
545
546                 nfsrv_init(0);          /* Init server data structures */
547                 nfsrv_initcache();      /* Init the server request cache */
548
549                 nfsrv_timer(0);
550
551                 nfs_prev_nfssvc_sy_narg = sysent[SYS_nfssvc].sy_narg;
552                 sysent[SYS_nfssvc].sy_narg = 2;
553                 nfs_prev_nfssvc_sy_call = sysent[SYS_nfssvc].sy_call;
554                 sysent[SYS_nfssvc].sy_call = (sy_call_t *)nfssvc;
555                 break;
556
557                 case MOD_UNLOAD:
558
559                 untimeout(nfsrv_timer, (void *)NULL, nfsrv_timer_handle);
560                 sysent[SYS_nfssvc].sy_narg = nfs_prev_nfssvc_sy_narg;
561                 sysent[SYS_nfssvc].sy_call = nfs_prev_nfssvc_sy_call;
562                 break;
563         }
564         return 0;
565 }
566 static moduledata_t nfsserver_mod = {
567         "nfsserver",
568         nfsrv_modevent,
569         NULL,
570 };
571 DECLARE_MODULE(nfsserver, nfsserver_mod, SI_SUB_VFS, SI_ORDER_ANY);
572
573 /* So that loader and kldload(2) can find us, wherever we are.. */
574 MODULE_VERSION(nfsserver, 1);
575
576 /*
577  * Set up nameidata for a lookup() call and do it.
578  *
579  * If pubflag is set, this call is done for a lookup operation on the
580  * public filehandle. In that case we allow crossing mountpoints and
581  * absolute pathnames. However, the caller is expected to check that
582  * the lookup result is within the public fs, and deny access if
583  * it is not.
584  *
585  * nfs_namei() clears out garbage fields that namei() might leave garbage.
586  * This is mainly ni_vp and ni_dvp when an error occurs, and ni_dvp when no
587  * error occurs but the parent was not requested.
588  *
589  * dirp may be set whether an error is returned or not, and must be
590  * released by the caller.
591  */
592 int
593 nfs_namei(struct nameidata *ndp, fhandle_t *fhp, int len,
594     struct nfssvc_sock *slp, struct sockaddr *nam, struct mbuf **mdp,
595     caddr_t *dposp, struct vnode **retdirp, struct thread *td, int pubflag)
596 {
597         int i, rem;
598         struct mbuf *md;
599         char *fromcp, *tocp, *cp;
600         struct iovec aiov;
601         struct uio auio;
602         struct vnode *dp;
603         int error, rdonly, linklen;
604         struct componentname *cnp = &ndp->ni_cnd;
605
606         *retdirp = (struct vnode *)0;
607         cnp->cn_pnbuf = zalloc(namei_zone);
608
609         /*
610          * Copy the name from the mbuf list to ndp->ni_pnbuf
611          * and set the various ndp fields appropriately.
612          */
613         fromcp = *dposp;
614         tocp = cnp->cn_pnbuf;
615         md = *mdp;
616         rem = mtod(md, caddr_t) + md->m_len - fromcp;
617         for (i = 0; i < len; i++) {
618                 while (rem == 0) {
619                         md = md->m_next;
620                         if (md == NULL) {
621                                 error = EBADRPC;
622                                 goto out;
623                         }
624                         fromcp = mtod(md, caddr_t);
625                         rem = md->m_len;
626                 }
627                 if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) {
628                         error = EACCES;
629                         goto out;
630                 }
631                 *tocp++ = *fromcp++;
632                 rem--;
633         }
634         *tocp = '\0';
635         *mdp = md;
636         *dposp = fromcp;
637         len = nfsm_rndup(len)-len;
638         if (len > 0) {
639                 if (rem >= len)
640                         *dposp += len;
641                 else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0)
642                         goto out;
643         }
644
645         /*
646          * Extract and set starting directory.
647          */
648         error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp,
649             nam, &rdonly, pubflag);
650         if (error)
651                 goto out;
652         if (dp->v_type != VDIR) {
653                 vrele(dp);
654                 error = ENOTDIR;
655                 goto out;
656         }
657
658         if (rdonly)
659                 cnp->cn_flags |= RDONLY;
660
661         /*
662          * Set return directory.  Reference to dp is implicitly transfered
663          * to the returned pointer
664          */
665         *retdirp = dp;
666
667         if (pubflag) {
668                 /*
669                  * Oh joy. For WebNFS, handle those pesky '%' escapes,
670                  * and the 'native path' indicator.
671                  */
672                 cp = zalloc(namei_zone);
673                 fromcp = cnp->cn_pnbuf;
674                 tocp = cp;
675                 if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) {
676                         switch ((unsigned char)*fromcp) {
677                         case WEBNFS_NATIVE_CHAR:
678                                 /*
679                                  * 'Native' path for us is the same
680                                  * as a path according to the NFS spec,
681                                  * just skip the escape char.
682                                  */
683                                 fromcp++;
684                                 break;
685                         /*
686                          * More may be added in the future, range 0x80-0xff
687                          */
688                         default:
689                                 error = EIO;
690                                 zfree(namei_zone, cp);
691                                 goto out;
692                         }
693                 }
694                 /*
695                  * Translate the '%' escapes, URL-style.
696                  */
697                 while (*fromcp != '\0') {
698                         if (*fromcp == WEBNFS_ESC_CHAR) {
699                                 if (fromcp[1] != '\0' && fromcp[2] != '\0') {
700                                         fromcp++;
701                                         *tocp++ = HEXSTRTOI(fromcp);
702                                         fromcp += 2;
703                                         continue;
704                                 } else {
705                                         error = ENOENT;
706                                         zfree(namei_zone, cp);
707                                         goto out;
708                                 }
709                         } else
710                                 *tocp++ = *fromcp++;
711                 }
712                 *tocp = '\0';
713                 zfree(namei_zone, cnp->cn_pnbuf);
714                 cnp->cn_pnbuf = cp;
715         }
716
717         ndp->ni_pathlen = (tocp - cnp->cn_pnbuf) + 1;
718         ndp->ni_segflg = UIO_SYSSPACE;
719
720         if (pubflag) {
721                 ndp->ni_rootdir = rootvnode;
722                 ndp->ni_loopcnt = 0;
723                 if (cnp->cn_pnbuf[0] == '/')
724                         dp = rootvnode;
725         } else {
726                 cnp->cn_flags |= NOCROSSMOUNT;
727         }
728
729         /*
730          * Initialize for scan, set ni_startdir and bump ref on dp again
731          * becuase lookup() will dereference ni_startdir.
732          */
733
734         cnp->cn_thread = td;
735         VREF(dp);
736         ndp->ni_startdir = dp;
737
738         for (;;) {
739                 cnp->cn_nameptr = cnp->cn_pnbuf;
740                 /*
741                  * Call lookup() to do the real work.  If an error occurs,
742                  * ndp->ni_vp and ni_dvp are left uninitialized or NULL and
743                  * we do not have to dereference anything before returning.
744                  * In either case ni_startdir will be dereferenced and NULLed
745                  * out.
746                  */
747                 error = lookup(ndp);
748                 if (error)
749                         break;
750
751                 /*
752                  * Check for encountering a symbolic link.  Trivial
753                  * termination occurs if no symlink encountered.
754                  * Note: zfree is safe because error is 0, so we will
755                  * not zfree it again when we break.
756                  */
757                 if ((cnp->cn_flags & ISSYMLINK) == 0) {
758                         nfsrv_object_create(ndp->ni_vp);
759                         if (cnp->cn_flags & (SAVENAME | SAVESTART))
760                                 cnp->cn_flags |= HASBUF;
761                         else
762                                 zfree(namei_zone, cnp->cn_pnbuf);
763                         break;
764                 }
765
766                 /*
767                  * Validate symlink
768                  */
769                 if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
770                         VOP_UNLOCK(ndp->ni_dvp, 0, td);
771                 if (!pubflag) {
772                         error = EINVAL;
773                         goto badlink2;
774                 }
775
776                 if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
777                         error = ELOOP;
778                         goto badlink2;
779                 }
780                 if (ndp->ni_pathlen > 1)
781                         cp = zalloc(namei_zone);
782                 else
783                         cp = cnp->cn_pnbuf;
784                 aiov.iov_base = cp;
785                 aiov.iov_len = MAXPATHLEN;
786                 auio.uio_iov = &aiov;
787                 auio.uio_iovcnt = 1;
788                 auio.uio_offset = 0;
789                 auio.uio_rw = UIO_READ;
790                 auio.uio_segflg = UIO_SYSSPACE;
791                 auio.uio_td = (struct thread *)0;
792                 auio.uio_resid = MAXPATHLEN;
793                 error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
794                 if (error) {
795                 badlink1:
796                         if (ndp->ni_pathlen > 1)
797                                 zfree(namei_zone, cp);
798                 badlink2:
799                         vrele(ndp->ni_dvp);
800                         vput(ndp->ni_vp);
801                         break;
802                 }
803                 linklen = MAXPATHLEN - auio.uio_resid;
804                 if (linklen == 0) {
805                         error = ENOENT;
806                         goto badlink1;
807                 }
808                 if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
809                         error = ENAMETOOLONG;
810                         goto badlink1;
811                 }
812
813                 /*
814                  * Adjust or replace path
815                  */
816                 if (ndp->ni_pathlen > 1) {
817                         bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
818                         zfree(namei_zone, cnp->cn_pnbuf);
819                         cnp->cn_pnbuf = cp;
820                 } else
821                         cnp->cn_pnbuf[linklen] = '\0';
822                 ndp->ni_pathlen += linklen;
823
824                 /*
825                  * Cleanup refs for next loop and check if root directory
826                  * should replace current directory.  Normally ni_dvp
827                  * becomes the new base directory and is cleaned up when
828                  * we loop.  Explicitly null pointers after invalidation
829                  * to clarify operation.
830                  */
831                 vput(ndp->ni_vp);
832                 ndp->ni_vp = NULL;
833
834                 if (cnp->cn_pnbuf[0] == '/') {
835                         vrele(ndp->ni_dvp);
836                         ndp->ni_dvp = ndp->ni_rootdir;
837                         VREF(ndp->ni_dvp);
838                 }
839                 ndp->ni_startdir = ndp->ni_dvp;
840                 ndp->ni_dvp = NULL;
841         }
842
843         /*
844          * nfs_namei() guarentees that fields will not contain garbage
845          * whether an error occurs or not.  This allows the caller to track
846          * cleanup state trivially.
847          */
848 out:
849         if (error) {
850                 zfree(namei_zone, cnp->cn_pnbuf);
851                 ndp->ni_vp = NULL;
852                 ndp->ni_dvp = NULL;
853                 ndp->ni_startdir = NULL;
854                 cnp->cn_flags &= ~HASBUF;
855         } else if ((ndp->ni_cnd.cn_flags & (WANTPARENT|LOCKPARENT)) == 0) {
856                 ndp->ni_dvp = NULL;
857         }
858         return (error);
859 }
860
861 /*
862  * A fiddled version of m_adj() that ensures null fill to a long
863  * boundary and only trims off the back end
864  */
865 void
866 nfsm_adj(struct mbuf *mp, int len, int nul)
867 {
868         struct mbuf *m;
869         int count, i;
870         char *cp;
871
872         /*
873          * Trim from tail.  Scan the mbuf chain,
874          * calculating its length and finding the last mbuf.
875          * If the adjustment only affects this mbuf, then just
876          * adjust and return.  Otherwise, rescan and truncate
877          * after the remaining size.
878          */
879         count = 0;
880         m = mp;
881         for (;;) {
882                 count += m->m_len;
883                 if (m->m_next == (struct mbuf *)0)
884                         break;
885                 m = m->m_next;
886         }
887         if (m->m_len > len) {
888                 m->m_len -= len;
889                 if (nul > 0) {
890                         cp = mtod(m, caddr_t)+m->m_len-nul;
891                         for (i = 0; i < nul; i++)
892                                 *cp++ = '\0';
893                 }
894                 return;
895         }
896         count -= len;
897         if (count < 0)
898                 count = 0;
899         /*
900          * Correct length for chain is "count".
901          * Find the mbuf with last data, adjust its length,
902          * and toss data from remaining mbufs on chain.
903          */
904         for (m = mp; m; m = m->m_next) {
905                 if (m->m_len >= count) {
906                         m->m_len = count;
907                         if (nul > 0) {
908                                 cp = mtod(m, caddr_t)+m->m_len-nul;
909                                 for (i = 0; i < nul; i++)
910                                         *cp++ = '\0';
911                         }
912                         break;
913                 }
914                 count -= m->m_len;
915         }
916         for (m = m->m_next;m;m = m->m_next)
917                 m->m_len = 0;
918 }
919
920 /*
921  * Make these functions instead of macros, so that the kernel text size
922  * doesn't get too big...
923  */
924 void
925 nfsm_srvwcc(struct nfsrv_descript *nfsd, int before_ret,
926     struct vattr *before_vap, int after_ret, struct vattr *after_vap,
927     struct mbuf **mbp, char **bposp)
928 {
929         struct mbuf *mb = *mbp;
930         char *bpos = *bposp;
931         u_int32_t *tl;
932
933         if (before_ret) {
934                 tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED);
935                 *tl = nfs_false;
936         } else {
937                 tl = nfsm_build(u_int32_t *, 7 * NFSX_UNSIGNED);
938                 *tl++ = nfs_true;
939                 txdr_hyper(before_vap->va_size, tl);
940                 tl += 2;
941                 txdr_nfsv3time(&(before_vap->va_mtime), tl);
942                 tl += 2;
943                 txdr_nfsv3time(&(before_vap->va_ctime), tl);
944         }
945         *bposp = bpos;
946         *mbp = mb;
947         nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp);
948 }
949
950 void
951 nfsm_srvpostopattr(struct nfsrv_descript *nfsd, int after_ret,
952     struct vattr *after_vap, struct mbuf **mbp, char **bposp)
953 {
954         struct mbuf *mb = *mbp;
955         char *bpos = *bposp;
956         u_int32_t *tl;
957         struct nfs_fattr *fp;
958
959         if (after_ret) {
960                 tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED);
961                 *tl = nfs_false;
962         } else {
963                 tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR);
964                 *tl++ = nfs_true;
965                 fp = (struct nfs_fattr *)tl;
966                 nfsm_srvfattr(nfsd, after_vap, fp);
967         }
968         *mbp = mb;
969         *bposp = bpos;
970 }
971
972 void
973 nfsm_srvfattr(struct nfsrv_descript *nfsd, struct vattr *vap,
974     struct nfs_fattr *fp)
975 {
976
977         fp->fa_nlink = txdr_unsigned(vap->va_nlink);
978         fp->fa_uid = txdr_unsigned(vap->va_uid);
979         fp->fa_gid = txdr_unsigned(vap->va_gid);
980         if (nfsd->nd_flag & ND_NFSV3) {
981                 fp->fa_type = vtonfsv3_type(vap->va_type);
982                 fp->fa_mode = vtonfsv3_mode(vap->va_mode);
983                 txdr_hyper(vap->va_size, &fp->fa3_size);
984                 txdr_hyper(vap->va_bytes, &fp->fa3_used);
985                 fp->fa3_rdev.specdata1 = txdr_unsigned(umajor(vap->va_rdev));
986                 fp->fa3_rdev.specdata2 = txdr_unsigned(uminor(vap->va_rdev));
987                 fp->fa3_fsid.nfsuquad[0] = 0;
988                 fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
989                 fp->fa3_fileid.nfsuquad[0] = 0;
990                 fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid);
991                 txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
992                 txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
993                 txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
994         } else {
995                 fp->fa_type = vtonfsv2_type(vap->va_type);
996                 fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
997                 fp->fa2_size = txdr_unsigned(vap->va_size);
998                 fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
999                 if (vap->va_type == VFIFO)
1000                         fp->fa2_rdev = 0xffffffff;
1001                 else
1002                         fp->fa2_rdev = txdr_unsigned(vap->va_rdev);
1003                 fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
1004                 fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
1005                 fp->fa2_fileid = txdr_unsigned(vap->va_fileid);
1006                 txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
1007                 txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
1008                 txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);
1009         }
1010 }
1011
1012 /*
1013  * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
1014  *      - look up fsid in mount list (if not found ret error)
1015  *      - get vp and export rights by calling VFS_FHTOVP()
1016  *      - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
1017  *      - if not lockflag unlock it with VOP_UNLOCK()
1018  */
1019 int
1020 nfsrv_fhtovp(fhandle_t *fhp, int lockflag, struct vnode **vpp,
1021     struct ucred *cred, struct nfssvc_sock *slp, struct sockaddr *nam,
1022     int *rdonlyp, int pubflag)
1023 {
1024         struct thread *td = curthread; /* XXX */
1025         struct mount *mp;
1026         int i;
1027         struct ucred *credanon;
1028         int error, exflags;
1029 #ifdef MNT_EXNORESPORT          /* XXX needs mountd and /etc/exports help yet */
1030         struct sockaddr_int *saddr;
1031 #endif
1032
1033         *vpp = (struct vnode *)0;
1034
1035         if (nfs_ispublicfh(fhp)) {
1036                 if (!pubflag || !nfs_pub.np_valid)
1037                         return (ESTALE);
1038                 fhp = &nfs_pub.np_handle;
1039         }
1040
1041         mp = vfs_getvfs(&fhp->fh_fsid);
1042         if (!mp)
1043                 return (ESTALE);
1044         error = VFS_CHECKEXP(mp, nam, &exflags, &credanon);
1045         if (error)
1046                 return (error);
1047         error = VFS_FHTOVP(mp, &fhp->fh_fid, vpp);
1048         if (error)
1049                 return (error);
1050 #ifdef MNT_EXNORESPORT
1051         if (!(exflags & (MNT_EXNORESPORT|MNT_EXPUBLIC))) {
1052                 saddr = (struct sockaddr_in *)nam;
1053                 if (saddr->sin_family == AF_INET &&
1054                     ntohs(saddr->sin_port) >= IPPORT_RESERVED) {
1055                         vput(*vpp);
1056                         *vpp = NULL;
1057                         return (NFSERR_AUTHERR | AUTH_TOOWEAK);
1058                 }
1059         }
1060 #endif
1061         /*
1062          * Check/setup credentials.
1063          */
1064         if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) {
1065                 cred->cr_uid = credanon->cr_uid;
1066                 for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++)
1067                         cred->cr_groups[i] = credanon->cr_groups[i];
1068                 cred->cr_ngroups = i;
1069         }
1070         if (exflags & MNT_EXRDONLY)
1071                 *rdonlyp = 1;
1072         else
1073                 *rdonlyp = 0;
1074
1075         nfsrv_object_create(*vpp);
1076
1077         if (!lockflag)
1078                 VOP_UNLOCK(*vpp, 0, td);
1079         return (0);
1080 }
1081
1082
1083 /*
1084  * WebNFS: check if a filehandle is a public filehandle. For v3, this
1085  * means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has
1086  * transformed this to all zeroes in both cases, so check for it.
1087  */
1088 int
1089 nfs_ispublicfh(fhandle_t *fhp)
1090 {
1091         char *cp = (char *)fhp;
1092         int i;
1093
1094         for (i = 0; i < NFSX_V3FH; i++)
1095                 if (*cp++ != 0)
1096                         return (FALSE);
1097         return (TRUE);
1098 }
1099
1100 /*
1101  * This function compares two net addresses by family and returns TRUE
1102  * if they are the same host.
1103  * If there is any doubt, return FALSE.
1104  * The AF_INET family is handled as a special case so that address mbufs
1105  * don't need to be saved to store "struct in_addr", which is only 4 bytes.
1106  */
1107 int
1108 netaddr_match(int family, union nethostaddr *haddr, struct sockaddr *nam)
1109 {
1110         struct sockaddr_in *inetaddr;
1111
1112         switch (family) {
1113         case AF_INET:
1114                 inetaddr = (struct sockaddr_in *)nam;
1115                 if (inetaddr->sin_family == AF_INET &&
1116                     inetaddr->sin_addr.s_addr == haddr->had_inetaddr)
1117                         return (1);
1118                 break;
1119         default:
1120                 break;
1121         };
1122         return (0);
1123 }
1124
1125 /*
1126  * Map errnos to NFS error numbers. For Version 3 also filter out error
1127  * numbers not specified for the associated procedure.
1128  */
1129 int
1130 nfsrv_errmap(struct nfsrv_descript *nd, int err)
1131 {
1132         short *defaulterrp, *errp;
1133
1134         if (nd->nd_flag & ND_NFSV3) {
1135             if (nd->nd_procnum <= NFSPROC_COMMIT) {
1136                 errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum];
1137                 while (*++errp) {
1138                         if (*errp == err)
1139                                 return (err);
1140                         else if (*errp > err)
1141                                 break;
1142                 }
1143                 return ((int)*defaulterrp);
1144             } else
1145                 return (err & 0xffff);
1146         }
1147         if (err <= ELAST)
1148                 return ((int)nfsrv_v2errmap[err - 1]);
1149         return (NFSERR_IO);
1150 }
1151
1152 int
1153 nfsrv_object_create(struct vnode *vp)
1154 {
1155
1156         if (vp == NULL || vp->v_type != VREG)
1157                 return (1);
1158         return (vfs_object_create(vp, curthread,
1159                           curthread ? curthread->td_proc->p_ucred : NULL));
1160 }
1161
1162 /*
1163  * Sort the group list in increasing numerical order.
1164  * (Insertion sort by Chris Torek, who was grossed out by the bubble sort
1165  *  that used to be here.)
1166  */
1167 void
1168 nfsrvw_sort(gid_t *list, int num)
1169 {
1170         int i, j;
1171         gid_t v;
1172
1173         /* Insertion sort. */
1174         for (i = 1; i < num; i++) {
1175                 v = list[i];
1176                 /* find correct slot for value v, moving others up */
1177                 for (j = i; --j >= 0 && v < list[j];)
1178                         list[j + 1] = list[j];
1179                 list[j + 1] = v;
1180         }
1181 }
1182
1183 /*
1184  * copy credentials making sure that the result can be compared with bcmp().
1185  */
1186 void
1187 nfsrv_setcred(struct ucred *incred, struct ucred *outcred)
1188 {
1189         int i;
1190
1191         bzero((caddr_t)outcred, sizeof (struct ucred));
1192         outcred->cr_ref = 1;
1193         outcred->cr_uid = incred->cr_uid;
1194         outcred->cr_ngroups = incred->cr_ngroups;
1195         for (i = 0; i < incred->cr_ngroups; i++)
1196                 outcred->cr_groups[i] = incred->cr_groups[i];
1197         nfsrvw_sort(outcred->cr_groups, outcred->cr_ngroups);
1198 }
1199
1200 /*
1201  * Helper functions for macros.
1202  */
1203
1204 void
1205 nfsm_srvfhtom_xx(fhandle_t *f, int v3,
1206     u_int32_t **tl, struct mbuf **mb, caddr_t *bpos)
1207 {
1208         u_int32_t *cp;
1209
1210         if (v3) {
1211                 *tl = nfsm_build_xx(NFSX_UNSIGNED + NFSX_V3FH, mb, bpos);
1212                 *(*tl)++ = txdr_unsigned(NFSX_V3FH);
1213                 bcopy(f, (*tl), NFSX_V3FH);
1214         } else {
1215                 cp = nfsm_build_xx(NFSX_V2FH, mb, bpos);
1216                 bcopy(f, cp, NFSX_V2FH);
1217         }
1218 }
1219
1220 void
1221 nfsm_srvpostop_fh_xx(fhandle_t *f,
1222     u_int32_t **tl, struct mbuf **mb, caddr_t *bpos)
1223 {
1224
1225         *tl = nfsm_build_xx(2 * NFSX_UNSIGNED + NFSX_V3FH, mb, bpos);
1226         *(*tl)++ = nfs_true;
1227         *(*tl)++ = txdr_unsigned(NFSX_V3FH);
1228         bcopy(f, (*tl), NFSX_V3FH);
1229 }
1230
1231 int
1232 nfsm_srvstrsiz_xx(int *s, int m,
1233     u_int32_t **tl, struct mbuf **md, caddr_t *dpos)
1234 {
1235
1236         *tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
1237         if (*tl == NULL)
1238                 return EBADRPC;
1239         *s = fxdr_unsigned(int32_t, **tl);
1240         if (*s > m || *s <= 0)
1241                 return EBADRPC;
1242         return 0;
1243 }
1244
1245 int
1246 nfsm_srvnamesiz_xx(int *s,
1247     u_int32_t **tl, struct mbuf **md, caddr_t *dpos)
1248 {
1249
1250         *tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
1251         if (*tl == NULL)
1252                 return EBADRPC;
1253         *s = fxdr_unsigned(int32_t, **tl);
1254         if (*s > NFS_MAXNAMLEN)
1255                 return NFSERR_NAMETOL;
1256         if (*s <= 0)
1257                 return EBADRPC;
1258         return 0;
1259 }
1260
1261 void
1262 nfsm_clget_xx(u_int32_t **tl, struct mbuf *mb, struct mbuf **mp,
1263     char **bp, char **be, caddr_t bpos)
1264 {
1265         struct mbuf *nmp;
1266
1267         if (*bp >= *be) {
1268                 if (*mp == mb)
1269                         (*mp)->m_len += *bp - bpos;
1270                 MGET(nmp, M_TRYWAIT, MT_DATA);
1271                 MCLGET(nmp, M_TRYWAIT);
1272                 nmp->m_len = NFSMSIZ(nmp);
1273                 (*mp)->m_next = nmp;
1274                 *mp = nmp;
1275                 *bp = mtod(*mp, caddr_t);
1276                 *be = *bp + (*mp)->m_len;
1277         }
1278         *tl = (u_int32_t *)*bp;
1279 }
1280
1281 int
1282 nfsm_srvmtofh_xx(fhandle_t *f, struct nfsrv_descript *nfsd,
1283     u_int32_t **tl, struct mbuf **md, caddr_t *dpos)
1284 {
1285         int fhlen;
1286
1287         if (nfsd->nd_flag & ND_NFSV3) {
1288                 *tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
1289                 if (*tl == NULL)
1290                         return EBADRPC;
1291                 fhlen = fxdr_unsigned(int, **tl);
1292                 if (fhlen != 0 && fhlen != NFSX_V3FH)
1293                         return EBADRPC;
1294         } else {
1295                 fhlen = NFSX_V2FH;
1296         }
1297         if (fhlen != 0) {
1298                 *tl = nfsm_dissect_xx(fhlen, md, dpos);
1299                 if (*tl == NULL)
1300                         return EBADRPC;
1301                 bcopy((caddr_t)*tl, (caddr_t)(f), fhlen);
1302         } else {
1303                 bzero((caddr_t)(f), NFSX_V3FH);
1304         }
1305         return 0;
1306 }
1307
1308 int
1309 nfsm_srvsattr_xx(struct vattr *a,
1310     u_int32_t **tl, struct mbuf **md, caddr_t *dpos)
1311 {
1312
1313         *tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
1314         if (*tl == NULL)
1315                 return EBADRPC;
1316         if (**tl == nfs_true) {
1317                 *tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
1318                 if (*tl == NULL)
1319                         return EBADRPC;
1320                 (a)->va_mode = nfstov_mode(**tl);
1321         }
1322         *tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
1323         if (*tl == NULL)
1324                 return EBADRPC;
1325         if (**tl == nfs_true) {
1326                 *tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
1327                 if (*tl == NULL)
1328                         return EBADRPC;
1329                 (a)->va_uid = fxdr_unsigned(uid_t, **tl);
1330         }
1331         *tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
1332         if (*tl == NULL)
1333                 return EBADRPC;
1334         if (**tl == nfs_true) {
1335                 *tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
1336                 if (*tl == NULL)
1337                         return EBADRPC;
1338                 (a)->va_gid = fxdr_unsigned(gid_t, **tl);
1339         }
1340         *tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
1341         if (*tl == NULL)
1342                 return EBADRPC;
1343         if (**tl == nfs_true) {
1344                 *tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos);
1345                 if (*tl == NULL)
1346                         return EBADRPC;
1347                 (a)->va_size = fxdr_hyper(*tl);
1348         }
1349         *tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
1350         if (*tl == NULL)
1351                 return EBADRPC;
1352         switch (fxdr_unsigned(int, **tl)) {
1353         case NFSV3SATTRTIME_TOCLIENT:
1354                 *tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos);
1355                 if (*tl == NULL)
1356                         return EBADRPC;
1357                 fxdr_nfsv3time(*tl, &(a)->va_atime);
1358                 break;
1359         case NFSV3SATTRTIME_TOSERVER:
1360                 getnanotime(&(a)->va_atime);
1361                 break;
1362         }
1363         *tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
1364         if (*tl == NULL)
1365                 return EBADRPC;
1366         switch (fxdr_unsigned(int, **tl)) {
1367         case NFSV3SATTRTIME_TOCLIENT:
1368                 *tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos);
1369                 if (*tl == NULL)
1370                         return EBADRPC;
1371                 fxdr_nfsv3time(*tl, &(a)->va_mtime);
1372                 break;
1373         case NFSV3SATTRTIME_TOSERVER:
1374                 getnanotime(&(a)->va_mtime);
1375                 break;
1376         }
1377         return 0;
1378 }