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