]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/fs/nwfs/nwfs_vnops.c
This commit was generated by cvs2svn to compensate for changes in r138296,
[FreeBSD/FreeBSD.git] / sys / fs / nwfs / nwfs_vnops.c
1 /*
2  * Copyright (c) 1999, 2000, 2001 Boris Popov
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *    This product includes software developed by Boris Popov.
16  * 4. Neither the name of the author nor the names of any co-contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  * $FreeBSD$
33  */
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/namei.h>
37 #include <sys/kernel.h>
38 #include <sys/bio.h>
39 #include <sys/buf.h>
40 #include <sys/fcntl.h>
41 #include <sys/mount.h>
42 #include <sys/unistd.h>
43 #include <sys/vnode.h>
44
45 #include <vm/vm.h>
46 #include <vm/vm_extern.h>
47
48 #include <machine/mutex.h>
49
50 #include <netncp/ncp.h>
51 #include <netncp/ncp_conn.h>
52 #include <netncp/ncp_subr.h>
53 #include <netncp/nwerror.h>
54 #include <netncp/ncp_nls.h>
55
56 #include <fs/nwfs/nwfs.h>
57 #include <fs/nwfs/nwfs_node.h>
58 #include <fs/nwfs/nwfs_subr.h>
59
60 /*
61  * Prototypes for NWFS vnode operations
62  */
63 static vop_create_t     nwfs_create;
64 static vop_mknod_t      nwfs_mknod;
65 static vop_open_t       nwfs_open;
66 static vop_close_t      nwfs_close;
67 static vop_access_t     nwfs_access;
68 static vop_getattr_t    nwfs_getattr;
69 static vop_setattr_t    nwfs_setattr;
70 static vop_read_t       nwfs_read;
71 static vop_write_t      nwfs_write;
72 static vop_fsync_t      nwfs_fsync;
73 static vop_remove_t     nwfs_remove;
74 static vop_link_t       nwfs_link;
75 static vop_lookup_t     nwfs_lookup;
76 static vop_rename_t     nwfs_rename;
77 static vop_mkdir_t      nwfs_mkdir;
78 static vop_rmdir_t      nwfs_rmdir;
79 static vop_symlink_t    nwfs_symlink;
80 static vop_readdir_t    nwfs_readdir;
81 static vop_strategy_t   nwfs_strategy;
82 static vop_print_t      nwfs_print;
83 static vop_pathconf_t   nwfs_pathconf;
84
85 /* Global vfs data structures for nwfs */
86 static struct vop_vector nwfs_vnodeops = {
87         .vop_default =          &default_vnodeops,
88         .vop_access =           nwfs_access,
89         .vop_open =             nwfs_open,
90         .vop_close =            nwfs_close,
91         .vop_create =           nwfs_create,
92         .vop_fsync =            nwfs_fsync,
93         .vop_getattr =          nwfs_getattr,
94         .vop_getpages =         nwfs_getpages,
95         .vop_putpages =         nwfs_putpages,
96         .vop_ioctl =            nwfs_ioctl,
97         .vop_inactive =         nwfs_inactive,
98         .vop_link =             nwfs_link,
99         .vop_lookup =           nwfs_lookup,
100         .vop_mkdir =            nwfs_mkdir,
101         .vop_mknod =            nwfs_mknod,
102         .vop_pathconf =         nwfs_pathconf,
103         .vop_print =            nwfs_print,
104         .vop_read =             nwfs_read,
105         .vop_readdir =          nwfs_readdir,
106         .vop_reclaim =          nwfs_reclaim,
107         .vop_remove =           nwfs_remove,
108         .vop_rename =           nwfs_rename,
109         .vop_rmdir =            nwfs_rmdir,
110         .vop_setattr =          nwfs_setattr,
111         .vop_strategy =         nwfs_strategy,
112         .vop_symlink =          nwfs_symlink,
113         .vop_write =            nwfs_write,
114 };
115
116 /*
117  * nwfs_access vnode op
118  */
119 static int
120 nwfs_access(ap)
121         struct vop_access_args /* {
122                 struct vnode *a_vp;
123                 int  a_mode;
124                 struct ucred *a_cred;
125                 struct thread *td;
126         } */ *ap;
127 {
128         struct vnode *vp = ap->a_vp;
129         mode_t mpmode;
130         struct nwmount *nmp = VTONWFS(vp);
131
132         NCPVNDEBUG("\n");
133         if ((ap->a_mode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY)) {
134                 switch (vp->v_type) {
135                     case VREG: case VDIR: case VLNK:
136                         return (EROFS);
137                     default:
138                         break;
139                 }
140         }
141         mpmode = vp->v_type == VREG ? nmp->m.file_mode :
142             nmp->m.dir_mode;
143         return (vaccess(vp->v_type, mpmode, nmp->m.uid,
144             nmp->m.gid, ap->a_mode, ap->a_cred, NULL));
145 }
146 /*
147  * nwfs_open vnode op
148  */
149 /* ARGSUSED */
150 static int
151 nwfs_open(ap)
152         struct vop_open_args /* {
153                 struct vnode *a_vp;
154                 int  a_mode;
155                 struct ucred *a_cred;
156                 struct thread *td;
157         } */ *ap;
158 {
159         struct vnode *vp = ap->a_vp;
160         int mode = ap->a_mode;
161         struct nwnode *np = VTONW(vp);
162         struct ncp_open_info no;
163         struct nwmount *nmp = VTONWFS(vp);
164         struct vattr vattr;
165         int error, nwm;
166
167         NCPVNDEBUG("%s,%d\n", np->n_name, np->opened);
168         if (vp->v_type != VREG && vp->v_type != VDIR) { 
169                 NCPFATAL("open vtype = %d\n", vp->v_type);
170                 return (EACCES);
171         }
172         if (vp->v_type == VDIR) return 0;       /* nothing to do now */
173         if (np->n_flag & NMODIFIED) {
174                 if ((error = nwfs_vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_td, 1)) == EINTR)
175                         return (error);
176                 np->n_atime = 0;
177                 error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_td);
178                 if (error) return (error);
179                 np->n_mtime = vattr.va_mtime.tv_sec;
180         } else {
181                 error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_td);
182                 if (error) return (error);
183                 if (np->n_mtime != vattr.va_mtime.tv_sec) {
184                         if ((error = nwfs_vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_td, 1)) == EINTR)
185                                 return (error);
186                         np->n_mtime = vattr.va_mtime.tv_sec;
187                 }
188         }
189         if (np->opened) {
190                 np->opened++;
191                 return 0;
192         }
193         nwm = AR_READ;
194         if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0)
195                 nwm |= AR_WRITE;
196         error = ncp_open_create_file_or_subdir(nmp, vp, 0, NULL, OC_MODE_OPEN,
197                                                0, nwm, &no, ap->a_td, ap->a_cred);
198         if (error) {
199                 if (mode & FWRITE)
200                         return EACCES;
201                 nwm = AR_READ;
202                 error = ncp_open_create_file_or_subdir(nmp, vp, 0, NULL, OC_MODE_OPEN, 0,
203                                                    nwm, &no, ap->a_td, ap->a_cred);
204         }
205         if (!error) {
206                 np->opened++;
207                 np->n_fh = no.fh;
208                 np->n_origfh = no.origfh;
209         }
210         np->n_atime = 0;
211         return (error);
212 }
213
214 static int
215 nwfs_close(ap)
216         struct vop_close_args /* {
217                 struct vnodeop_desc *a_desc;
218                 struct vnode *a_vp;
219                 int  a_fflag;
220                 struct ucred *a_cred;
221                 struct thread *td;
222         } */ *ap;
223 {
224         struct vnode *vp = ap->a_vp;
225         struct nwnode *np = VTONW(vp);
226         int error;
227
228         NCPVNDEBUG("name=%s,pid=%d,c=%d\n", np->n_name, ap->a_td->td_proc->p_pid,
229                         np->opened);
230
231         if (vp->v_type == VDIR) return 0;       /* nothing to do now */
232         error = 0;
233         mtx_lock(&vp->v_interlock);
234         if (np->opened == 0) {
235                 mtx_unlock(&vp->v_interlock);
236                 return 0;
237         }
238         mtx_unlock(&vp->v_interlock);
239         error = nwfs_vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_td, 1);
240         mtx_lock(&vp->v_interlock);
241         if (np->opened == 0) {
242                 mtx_unlock(&vp->v_interlock);
243                 return 0;
244         }
245         if (--np->opened == 0) {
246                 mtx_unlock(&vp->v_interlock);
247                 error = ncp_close_file(NWFSTOCONN(VTONWFS(vp)), &np->n_fh, 
248                    ap->a_td, ap->a_cred);
249         } else
250                 mtx_unlock(&vp->v_interlock);
251         np->n_atime = 0;
252         return (error);
253 }
254
255 /*
256  * nwfs_getattr call from vfs.
257  */
258 static int
259 nwfs_getattr(ap)
260         struct vop_getattr_args /* {
261                 struct vnode *a_vp;
262                 struct vattr *a_vap;
263                 struct ucred *a_cred;
264                 struct thread *td;
265         } */ *ap;
266 {
267         struct vnode *vp = ap->a_vp;
268         struct nwnode *np = VTONW(vp);
269         struct vattr *va=ap->a_vap;
270         struct nwmount *nmp = VTONWFS(vp);
271         struct nw_entry_info fattr;
272         int error;
273         u_int32_t oldsize;
274
275         NCPVNDEBUG("%lx:%d: '%s' %d\n", (long)vp, nmp->n_volume, np->n_name, (vp->v_vflag & VV_ROOT) != 0);
276         error = nwfs_attr_cachelookup(vp, va);
277         if (!error) return 0;
278         NCPVNDEBUG("not in cache\n");
279         oldsize = np->n_size;
280         if (np->n_flag & NVOLUME) {
281                 error = ncp_obtain_info(nmp, np->n_fid.f_id, 0, NULL, &fattr,
282                     ap->a_td, ap->a_cred);
283         } else {
284                 error = ncp_obtain_info(nmp, np->n_fid.f_parent, np->n_nmlen, 
285                     np->n_name, &fattr, ap->a_td, ap->a_cred);
286         }
287         if (error) {
288                 NCPVNDEBUG("error %d\n", error);
289                 return error;
290         }
291         nwfs_attr_cacheenter(vp, &fattr);
292         *va = np->n_vattr;
293         if (np->opened)
294                 np->n_size = oldsize;
295         return (0);
296 }
297 /*
298  * nwfs_setattr call from vfs.
299  */
300 static int
301 nwfs_setattr(ap)
302         struct vop_setattr_args /* {
303                 struct vnode *a_vp;
304                 struct vattr *a_vap;
305                 struct ucred *a_cred;
306                 struct thread *td;
307         } */ *ap;
308 {
309         struct vnode *vp = ap->a_vp;
310         struct nwnode *np = VTONW(vp);
311         struct vattr *vap = ap->a_vap;
312         u_quad_t tsize=0;
313         int error = 0;
314
315         NCPVNDEBUG("\n");
316         if (vap->va_flags != VNOVAL)
317                 return (EOPNOTSUPP);
318         /*
319          * Disallow write attempts if the filesystem is mounted read-only.
320          */
321         if ((vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL || 
322              vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL ||
323              vap->va_mode != (mode_t)VNOVAL) &&(vp->v_mount->mnt_flag & MNT_RDONLY))
324                 return (EROFS);
325         if (vap->va_size != VNOVAL) {
326                 switch (vp->v_type) {
327                 case VDIR:
328                         return (EISDIR);
329                 case VREG:
330                         /*
331                          * Disallow write attempts if the filesystem is
332                          * mounted read-only.
333                          */
334                         if (vp->v_mount->mnt_flag & MNT_RDONLY)
335                                 return (EROFS);
336                         vnode_pager_setsize(vp, (u_long)vap->va_size);
337                         tsize = np->n_size;
338                         np->n_size = vap->va_size;
339                         break;
340                 default:
341                         return EINVAL;
342                 };
343         }
344         error = ncp_setattr(vp, vap, ap->a_cred, ap->a_td);
345         if (error && vap->va_size != VNOVAL) {
346                 np->n_size = tsize;
347                 vnode_pager_setsize(vp, (u_long)tsize);
348         }
349         np->n_atime = 0;        /* invalidate cache */
350         VOP_GETATTR(vp, vap, ap->a_cred, ap->a_td);
351         np->n_mtime = vap->va_mtime.tv_sec;
352         return (0);
353 }
354 /*
355  * nwfs_read call.
356  */
357 static int
358 nwfs_read(ap)
359         struct vop_read_args /* {
360                 struct vnode *a_vp;
361                 struct uio *a_uio;
362                 int  a_ioflag;
363                 struct ucred *a_cred;
364         } */ *ap;
365 {
366         struct vnode *vp = ap->a_vp;
367         struct uio *uio=ap->a_uio;
368         int error;
369         NCPVNDEBUG("nwfs_read:\n");
370
371         if (vp->v_type != VREG && vp->v_type != VDIR)
372                 return (EPERM);
373         error = nwfs_readvnode(vp, uio, ap->a_cred);
374         return error;
375 }
376
377 static int
378 nwfs_write(ap)
379         struct vop_write_args /* {
380                 struct vnode *a_vp;
381                 struct uio *a_uio;
382                 int  a_ioflag;
383                 struct ucred *a_cred;
384         } */ *ap;
385 {
386         struct vnode *vp = ap->a_vp;
387         struct uio *uio = ap->a_uio;
388         int error;
389
390         NCPVNDEBUG("%d,ofs=%d,sz=%d\n", vp->v_type, (int)uio->uio_offset, uio->uio_resid);
391
392         if (vp->v_type != VREG)
393                 return (EPERM);
394         error = nwfs_writevnode(vp, uio, ap->a_cred, ap->a_ioflag);
395         return(error);
396 }
397 /*
398  * nwfs_create call
399  * Create a regular file. On entry the directory to contain the file being
400  * created is locked.  We must release before we return. We must also free
401  * the pathname buffer pointed at by cnp->cn_pnbuf, always on error, or
402  * only if the SAVESTART bit in cn_flags is clear on success.
403  */
404 static int
405 nwfs_create(ap)
406         struct vop_create_args /* {
407                 struct vnode *a_dvp;
408                 struct vnode **a_vpp;
409                 struct componentname *a_cnp;
410                 struct vattr *a_vap;
411         } */ *ap;
412 {
413         struct vnode *dvp = ap->a_dvp;
414         struct vattr *vap = ap->a_vap;
415         struct vnode **vpp=ap->a_vpp;
416         struct componentname *cnp = ap->a_cnp;
417         struct vnode *vp = (struct vnode *)0;
418         int error = 0, fmode;
419         struct vattr vattr;
420         struct nwnode *np;
421         struct ncp_open_info no;
422         struct nwmount *nmp=VTONWFS(dvp);
423         ncpfid fid;
424         
425
426         NCPVNDEBUG("\n");
427         *vpp = NULL;
428         if (vap->va_type == VSOCK)
429                 return (EOPNOTSUPP);
430         if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_thread))) {
431                 return (error);
432         }
433         fmode = AR_READ | AR_WRITE;
434 /*      if (vap->va_vaflags & VA_EXCLUSIVE)
435                 fmode |= AR_DENY_READ | AR_DENY_WRITE;*/
436         
437         error = ncp_open_create_file_or_subdir(nmp, dvp, cnp->cn_namelen, cnp->cn_nameptr, 
438                            OC_MODE_CREATE | OC_MODE_OPEN | OC_MODE_REPLACE,
439                            0, fmode, &no, cnp->cn_thread, cnp->cn_cred);
440         if (!error) {
441                 error = ncp_close_file(NWFSTOCONN(nmp), &no.fh, cnp->cn_thread, cnp->cn_cred);
442                 fid.f_parent = VTONW(dvp)->n_fid.f_id;
443                 fid.f_id = no.fattr.dirEntNum;
444                 error = nwfs_nget(VTOVFS(dvp), fid, &no.fattr, dvp, &vp);
445                 if (!error) {
446                         np = VTONW(vp);
447                         np->opened = 0;
448                         *vpp = vp;
449                 }
450                 if (cnp->cn_flags & MAKEENTRY)
451                         cache_enter(dvp, vp, cnp);
452         }
453         return (error);
454 }
455
456 /*
457  * nwfs_remove call. It isn't possible to emulate UFS behaivour because
458  * NetWare doesn't allow delete/rename operations on an opened file.
459  */
460 static int
461 nwfs_remove(ap)
462         struct vop_remove_args /* {
463                 struct vnodeop_desc *a_desc;
464                 struct vnode * a_dvp;
465                 struct vnode * a_vp;
466                 struct componentname * a_cnp;
467         } */ *ap;
468 {
469         struct vnode *vp = ap->a_vp;
470         struct vnode *dvp = ap->a_dvp;
471         struct componentname *cnp = ap->a_cnp;
472         struct nwnode *np = VTONW(vp);
473         struct nwmount *nmp = VTONWFS(vp);
474         int error;
475
476         if (vp->v_type == VDIR || np->opened || vrefcnt(vp) != 1)
477                 return EPERM;
478         cache_purge(vp);
479         error = ncp_DeleteNSEntry(nmp, VTONW(dvp)->n_fid.f_id,
480             cnp->cn_namelen, cnp->cn_nameptr, cnp->cn_thread, cnp->cn_cred);
481         if (error == 0)
482                 np->n_flag |= NSHOULDFREE;
483         else if (error == 0x899c)
484                 error = EACCES;
485         return (error);
486 }
487
488 /*
489  * nwfs_file rename call
490  */
491 static int
492 nwfs_rename(ap)
493         struct vop_rename_args  /* {
494                 struct vnode *a_fdvp;
495                 struct vnode *a_fvp;
496                 struct componentname *a_fcnp;
497                 struct vnode *a_tdvp;
498                 struct vnode *a_tvp;
499                 struct componentname *a_tcnp;
500         } */ *ap;
501 {
502         struct vnode *fvp = ap->a_fvp;
503         struct vnode *tvp = ap->a_tvp;
504         struct vnode *fdvp = ap->a_fdvp;
505         struct vnode *tdvp = ap->a_tdvp;
506         struct componentname *tcnp = ap->a_tcnp;
507         struct componentname *fcnp = ap->a_fcnp;
508         struct nwmount *nmp=VTONWFS(fvp);
509         u_int16_t oldtype = 6;
510         int error=0;
511
512         /* Check for cross-device rename */
513         if ((fvp->v_mount != tdvp->v_mount) ||
514             (tvp && (fvp->v_mount != tvp->v_mount))) {
515                 error = EXDEV;
516                 goto out;
517         }
518
519         if (tvp && vrefcnt(tvp) > 1) {
520                 error = EBUSY;
521                 goto out;
522         }
523         if (fvp->v_type == VDIR) {
524                 oldtype |= NW_TYPE_SUBDIR;
525         } else if (fvp->v_type == VREG) {
526                 oldtype |= NW_TYPE_FILE;
527         } else {
528                 error = EINVAL;
529                 goto out;
530         }
531         if (tvp && tvp != fvp) {
532                 error = ncp_DeleteNSEntry(nmp, VTONW(tdvp)->n_fid.f_id,
533                     tcnp->cn_namelen, tcnp->cn_nameptr, 
534                     tcnp->cn_thread, tcnp->cn_cred);
535                 if (error == 0x899c) error = EACCES;
536                 if (error)
537                         goto out_cacherem;
538         }
539         error = ncp_nsrename(NWFSTOCONN(nmp), nmp->n_volume, nmp->name_space, 
540                 oldtype, &nmp->m.nls,
541                 VTONW(fdvp)->n_fid.f_id, fcnp->cn_nameptr, fcnp->cn_namelen,
542                 VTONW(tdvp)->n_fid.f_id, tcnp->cn_nameptr, tcnp->cn_namelen,
543                 tcnp->cn_thread, tcnp->cn_cred);
544
545         if (error == 0x8992)
546                 error = EEXIST;
547         if (fvp->v_type == VDIR) {
548                 if (tvp != NULL && tvp->v_type == VDIR)
549                         cache_purge(tdvp);
550                 cache_purge(fdvp);
551         }
552 out_cacherem:
553         nwfs_attr_cacheremove(fdvp);
554         nwfs_attr_cacheremove(tdvp);
555         nwfs_attr_cacheremove(fvp);
556 out:
557         if (tdvp == tvp)
558                 vrele(tdvp);
559         else
560                 vput(tdvp);
561         if (tvp)
562                 vput(tvp);
563         vrele(fdvp);
564         vrele(fvp);
565         if (tvp)
566                 nwfs_attr_cacheremove(tvp);
567         /*
568          * Kludge: Map ENOENT => 0 assuming that it is a reply to a retry.
569          */
570         if (error == ENOENT)
571                 error = 0;
572         return (error);
573 }
574
575 /*
576  * nwfs hard link create call
577  * Netware filesystems don't know what links are.
578  */
579 static int
580 nwfs_link(ap)
581         struct vop_link_args /* {
582                 struct vnode *a_tdvp;
583                 struct vnode *a_vp;
584                 struct componentname *a_cnp;
585         } */ *ap;
586 {
587         return EOPNOTSUPP;
588 }
589
590 /*
591  * nwfs_symlink link create call
592  * Netware filesystems don't know what symlinks are.
593  */
594 static int
595 nwfs_symlink(ap)
596         struct vop_symlink_args /* {
597                 struct vnode *a_dvp;
598                 struct vnode **a_vpp;
599                 struct componentname *a_cnp;
600                 struct vattr *a_vap;
601                 char *a_target;
602         } */ *ap;
603 {
604         return (EOPNOTSUPP);
605 }
606
607 static int nwfs_mknod(ap) 
608         struct vop_mknod_args /* {
609         } */ *ap;
610 {
611         return (EOPNOTSUPP);
612 }
613
614 /*
615  * nwfs_mkdir call
616  */
617 static int
618 nwfs_mkdir(ap)
619         struct vop_mkdir_args /* {
620                 struct vnode *a_dvp;
621                 struct vnode **a_vpp;
622                 struct componentname *a_cnp;
623                 struct vattr *a_vap;
624         } */ *ap;
625 {
626         struct vnode *dvp = ap->a_dvp;
627 /*      struct vattr *vap = ap->a_vap;*/
628         struct componentname *cnp = ap->a_cnp;
629         int len=cnp->cn_namelen;
630         struct ncp_open_info no;
631         struct nwnode *np;
632         struct vnode *newvp = (struct vnode *)0;
633         ncpfid fid;
634         int error = 0;
635         struct vattr vattr;
636         char *name=cnp->cn_nameptr;
637
638         if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_thread))) {
639                 return (error);
640         }       
641         if ((name[0] == '.') && ((len == 1) || ((len == 2) && (name[1] == '.')))) {
642                 return EEXIST;
643         }
644         if (ncp_open_create_file_or_subdir(VTONWFS(dvp), dvp, cnp->cn_namelen,
645                         cnp->cn_nameptr, OC_MODE_CREATE, aDIR, 0xffff,
646                         &no, cnp->cn_thread, cnp->cn_cred) != 0) {
647                 error = EACCES;
648         } else {
649                 error = 0;
650         }
651         if (!error) {
652                 fid.f_parent = VTONW(dvp)->n_fid.f_id;
653                 fid.f_id = no.fattr.dirEntNum;
654                 error = nwfs_nget(VTOVFS(dvp), fid, &no.fattr, dvp, &newvp);
655                 if (!error) {
656                         np = VTONW(newvp);
657                         newvp->v_type = VDIR;
658                         *ap->a_vpp = newvp;
659                 }
660         }
661         return (error);
662 }
663
664 /*
665  * nwfs_remove directory call
666  */
667 static int
668 nwfs_rmdir(ap)
669         struct vop_rmdir_args /* {
670                 struct vnode *a_dvp;
671                 struct vnode *a_vp;
672                 struct componentname *a_cnp;
673         } */ *ap;
674 {
675         struct vnode *vp = ap->a_vp;
676         struct vnode *dvp = ap->a_dvp;
677         struct componentname *cnp = ap->a_cnp;
678         struct nwnode *np = VTONW(vp);
679         struct nwmount *nmp = VTONWFS(vp);
680         struct nwnode *dnp = VTONW(dvp);
681         int error = EIO;
682
683         if (dvp == vp)
684                 return EINVAL;
685
686         error = ncp_DeleteNSEntry(nmp, dnp->n_fid.f_id, 
687                 cnp->cn_namelen, cnp->cn_nameptr, cnp->cn_thread, cnp->cn_cred);
688         if (error == 0)
689                 np->n_flag |= NSHOULDFREE;
690         else if (error == NWE_DIR_NOT_EMPTY)
691                 error = ENOTEMPTY;
692         dnp->n_flag |= NMODIFIED;
693         nwfs_attr_cacheremove(dvp);
694         cache_purge(dvp);
695         cache_purge(vp);
696         return (error);
697 }
698
699 /*
700  * nwfs_readdir call
701  */
702 static int
703 nwfs_readdir(ap)
704         struct vop_readdir_args /* {
705                 struct vnode *a_vp;
706                 struct uio *a_uio;
707                 struct ucred *a_cred;
708                 int *a_eofflag;
709                 u_long *a_cookies;
710                 int a_ncookies;
711         } */ *ap;
712 {
713         struct vnode *vp = ap->a_vp;
714         struct uio *uio = ap->a_uio;
715         int error;
716
717         if (vp->v_type != VDIR)
718                 return (EPERM);
719         if (ap->a_ncookies) {
720                 printf("nwfs_readdir: no support for cookies now...");
721                 return (EOPNOTSUPP);
722         }
723
724         error = nwfs_readvnode(vp, uio, ap->a_cred);
725         return error;
726 }
727 /* ARGSUSED */
728 static int
729 nwfs_fsync(ap)
730         struct vop_fsync_args /* {
731                 struct vnodeop_desc *a_desc;
732                 struct vnode * a_vp;
733                 struct ucred * a_cred;
734                 int  a_waitfor;
735                 struct thread *a_td;
736         } */ *ap;
737 {
738 /*      return (nfs_flush(ap->a_vp, ap->a_cred, ap->a_waitfor, ap->a_td, 1));*/
739     return (0);
740 }
741
742 /* ARGSUSED */
743 static 
744 int nwfs_print (ap) 
745         struct vop_print_args /* {
746                 struct vnode *a_vp;
747         } */ *ap;
748 {
749         struct vnode *vp = ap->a_vp;
750         struct nwnode *np = VTONW(vp);
751
752         printf("\tnwfs node: name = '%s', fid = %d, pfid = %d\n",
753             np->n_name, np->n_fid.f_id, np->n_fid.f_parent);
754         return (0);
755 }
756
757 static int nwfs_pathconf (ap)
758         struct vop_pathconf_args  /* {
759         struct vnode *vp;
760         int name;
761         register_t *retval;
762         } */ *ap;
763 {
764         int name=ap->a_name, error=0;
765         register_t *retval=ap->a_retval;
766         
767         switch(name){
768                 case _PC_LINK_MAX:
769                         *retval=0;
770                         break;
771                 case _PC_NAME_MAX:
772                         *retval=NCP_MAX_FILENAME; /* XXX from nwfsnode */
773                         break;
774                 case _PC_PATH_MAX:
775                         *retval=NCP_MAXPATHLEN; /* XXX from nwfsnode */
776                         break;
777                 default:
778                         error=EINVAL;
779         }
780         return(error);
781 }
782
783 static int nwfs_strategy (ap) 
784         struct vop_strategy_args /* {
785         struct buf *a_bp
786         } */ *ap;
787 {
788         struct buf *bp=ap->a_bp;
789         struct ucred *cr;
790         struct thread *td;
791         int error = 0;
792
793         NCPVNDEBUG("\n");
794         if (bp->b_flags & B_ASYNC)
795                 td = (struct thread *)0;
796         else
797                 td = curthread; /* XXX */
798         if (bp->b_iocmd == BIO_READ)
799                 cr = bp->b_rcred;
800         else
801                 cr = bp->b_wcred;
802         /*
803          * If the op is asynchronous and an i/o daemon is waiting
804          * queue the request, wake it up and wait for completion
805          * otherwise just do it ourselves.
806          */
807         if ((bp->b_flags & B_ASYNC) == 0 )
808                 error = nwfs_doio(ap->a_vp, bp, cr, td);
809         return (error);
810 }
811
812
813 /*
814  * How to keep the brain busy ...
815  * Currently lookup routine can make two lookup for vnode. This can be
816  * avoided by reorg the code.
817  */
818 int
819 nwfs_lookup(ap)
820         struct vop_lookup_args /* {
821                 struct vnodeop_desc *a_desc;
822                 struct vnode *a_dvp;
823                 struct vnode **a_vpp;
824                 struct componentname *a_cnp;
825         } */ *ap;
826 {
827         struct componentname *cnp = ap->a_cnp;
828         struct vnode *dvp = ap->a_dvp;
829         struct vnode **vpp = ap->a_vpp;
830         int flags = cnp->cn_flags;
831         struct vnode *vp;
832         struct nwmount *nmp;
833         struct mount *mp = dvp->v_mount;
834         struct nwnode *dnp, *npp;
835         struct nw_entry_info fattr, *fap;
836         ncpfid fid;
837         int nameiop=cnp->cn_nameiop, islastcn;
838         int lockparent, wantparent, error = 0, notfound;
839         struct thread *td = cnp->cn_thread;
840         char _name[cnp->cn_namelen+1];
841         bcopy(cnp->cn_nameptr, _name, cnp->cn_namelen);
842         _name[cnp->cn_namelen]=0;
843         
844         if (dvp->v_type != VDIR)
845                 return (ENOTDIR);
846         if ((flags & ISDOTDOT) && (dvp->v_vflag & VV_ROOT)) {
847                 printf("nwfs_lookup: invalid '..'\n");
848                 return EIO;
849         }
850
851         NCPVNDEBUG("%d '%s' in '%s' id=d\n", nameiop, _name, 
852                 VTONW(dvp)->n_name/*, VTONW(dvp)->n_name*/);
853
854         islastcn = flags & ISLASTCN;
855         if (islastcn && (mp->mnt_flag & MNT_RDONLY) && (nameiop != LOOKUP))
856                 return (EROFS);
857         if ((error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, td)))
858                 return (error);
859         lockparent = flags & LOCKPARENT;
860         wantparent = flags & (LOCKPARENT|WANTPARENT);
861         nmp = VFSTONWFS(mp);
862         dnp = VTONW(dvp);
863 /*
864 printf("dvp %d:%d:%d\n", (int)mp, (int)dvp->v_vflag & VV_ROOT, (int)flags & ISDOTDOT);
865 */
866         error = ncp_pathcheck(cnp->cn_nameptr, cnp->cn_namelen, &nmp->m.nls, 
867             (nameiop == CREATE || nameiop == RENAME) && (nmp->m.nls.opt & NWHP_NOSTRICT) == 0);
868         if (error) 
869             return ENOENT;
870
871         error = cache_lookup(dvp, vpp, cnp);
872         NCPVNDEBUG("cache_lookup returned %d\n", error);
873         if (error > 0)
874                 return error;
875         if (error) {            /* name was found */
876                 struct vattr vattr;
877                 int vpid;
878
879                 vp = *vpp;
880                 vpid = vp->v_id;
881                 if (dvp == vp) {        /* lookup on current */
882                         vref(vp);
883                         error = 0;
884                         NCPVNDEBUG("cached '.'");
885                 } else if (flags & ISDOTDOT) {
886                         VOP_UNLOCK(dvp, 0, td); /* unlock parent */
887                         error = vget(vp, LK_EXCLUSIVE, td);
888                         if (!error && lockparent && islastcn)
889                                 error = vn_lock(dvp, LK_EXCLUSIVE, td);
890                 } else {
891                         error = vget(vp, LK_EXCLUSIVE, td);
892                         if (!lockparent || error || !islastcn)
893                                 VOP_UNLOCK(dvp, 0, td);
894                 }
895                 if (!error) {
896                         if (vpid == vp->v_id) {
897                            if (!VOP_GETATTR(vp, &vattr, cnp->cn_cred, td)
898                             && vattr.va_ctime.tv_sec == VTONW(vp)->n_ctime) {
899                                 if (nameiop != LOOKUP && islastcn)
900                                         cnp->cn_flags |= SAVENAME;
901                                 NCPVNDEBUG("use cached vnode");
902                                 return (0);
903                            }
904                            cache_purge(vp);
905                         }
906                         vput(vp);
907                         if (lockparent && dvp != vp && islastcn)
908                                 VOP_UNLOCK(dvp, 0, td);
909                 }
910                 error = vn_lock(dvp, LK_EXCLUSIVE, td);
911                 *vpp = NULLVP;
912                 if (error)
913                         return (error);
914         }
915         /* not in cache, so ...  */
916         error = 0;
917         *vpp = NULLVP;
918         fap = NULL;
919         if (flags & ISDOTDOT) {
920                 if (NWCMPF(&dnp->n_parent, &nmp->n_rootent)) {
921                         fid = nmp->n_rootent;
922                         fap = NULL;
923                         notfound = 0;
924                 } else {
925                         error = nwfs_lookupnp(nmp, dnp->n_parent, td, &npp);
926                         if (error) {
927                                 return error;
928                         }
929                         fid = dnp->n_parent;
930                         fap = &fattr;
931                         /*np = *npp;*/
932                         notfound = ncp_obtain_info(nmp, npp->n_dosfid,
933                             0, NULL, fap, td, cnp->cn_cred);
934                 }
935         } else {
936                 fap = &fattr;
937                 notfound = ncp_lookup(dvp, cnp->cn_namelen, cnp->cn_nameptr,
938                         fap, td, cnp->cn_cred);
939                 fid.f_id = fap->dirEntNum;
940                 if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') {
941                         fid.f_parent = dnp->n_fid.f_parent;
942                 } else
943                         fid.f_parent = dnp->n_fid.f_id;
944                 NCPVNDEBUG("call to ncp_lookup returned=%d\n", notfound);
945         }
946         if (notfound && notfound < 0x80 )
947                 return (notfound);      /* hard error */
948         if (notfound) { /* entry not found */
949                 /* Handle RENAME or CREATE case... */
950                 if ((nameiop == CREATE || nameiop == RENAME) && wantparent && islastcn) {
951                         cnp->cn_flags |= SAVENAME;
952                         if (!lockparent)
953                                 VOP_UNLOCK(dvp, 0, td);
954                         return (EJUSTRETURN);
955                 }
956                 return ENOENT;
957         }/* else {
958                 NCPVNDEBUG("Found entry %s with id=%d\n", fap->entryName, fap->dirEntNum);
959         }*/
960         /* handle DELETE case ... */
961         if (nameiop == DELETE && islastcn) {    /* delete last component */
962                 error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, cnp->cn_thread);
963                 if (error) return (error);
964                 if (NWCMPF(&dnp->n_fid, &fid)) {        /* we found ourselfs */
965                         VREF(dvp);
966                         *vpp = dvp;
967                         return 0;
968                 }
969                 error = nwfs_nget(mp, fid, fap, dvp, &vp);
970                 if (error) return (error);
971                 *vpp = vp;
972                 cnp->cn_flags |= SAVENAME;      /* I free it later */
973                 if (!lockparent) VOP_UNLOCK(dvp, 0, td);
974                 return (0);
975         }
976         if (nameiop == RENAME && islastcn && wantparent) {
977                 error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, cnp->cn_thread);
978                 if (error) return (error);
979                 if (NWCMPF(&dnp->n_fid, &fid)) return EISDIR;
980                 error = nwfs_nget(mp, fid, fap, dvp, &vp);
981                 if (error) return (error);
982                 *vpp = vp;
983                 cnp->cn_flags |= SAVENAME;
984                 if (!lockparent)
985                         VOP_UNLOCK(dvp, 0, td);
986                 return (0);
987         }
988         if (flags & ISDOTDOT) {
989                 VOP_UNLOCK(dvp, 0, td);         /* race to get the inode */
990                 error = nwfs_nget(mp, fid, NULL, NULL, &vp);
991                 if (error) {
992                         vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, td);
993                         return (error);
994                 }
995                 if (lockparent && islastcn &&
996                     (error = vn_lock(dvp, LK_EXCLUSIVE, td))) {
997                         vput(vp);
998                         return (error);
999                 }
1000                 *vpp = vp;
1001         } else if (NWCMPF(&dnp->n_fid, &fid)) {
1002                 vref(dvp);
1003                 *vpp = dvp;
1004         } else {
1005                 error = nwfs_nget(mp, fid, fap, dvp, &vp);
1006                 if (error) return (error);
1007                 *vpp = vp;
1008                 NCPVNDEBUG("lookup: getnewvp!\n");
1009                 if (!lockparent || !islastcn)
1010                         VOP_UNLOCK(dvp, 0, td);
1011         }
1012         if ((cnp->cn_flags & MAKEENTRY)/* && !islastcn*/) {
1013                 VTONW(*vpp)->n_ctime = VTONW(*vpp)->n_vattr.va_ctime.tv_sec;
1014                 cache_enter(dvp, *vpp, cnp);
1015         }
1016         return (0);
1017 }