1 /*-
2 * Copyright (c) 1998, 1999 Semen Ustimenko (semenu@FreeBSD.org)
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
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/kernel.h>
32 #include <sys/proc.h>
33 #include <sys/time.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <sys/vnode.h>
37 #include <sys/mount.h>
38 #include <sys/namei.h>
39 #include <sys/malloc.h>
40 #include <sys/bio.h>
41 #include <sys/buf.h>
42 #include <sys/dirent.h>
43
44 #include <vm/vm.h>
45 #include <vm/vm_param.h>
46 #include <vm/vm_page.h>
47 #include <vm/vm_object.h>
48 #include <vm/vm_pager.h>
49 #include <vm/vnode_pager.h>
50 #include <vm/vm_extern.h>
51
52 #include <sys/unistd.h> /* for pathconf(2) constants */
53
54 #include <fs/hpfs/hpfs.h>
55 #include <fs/hpfs/hpfsmount.h>
56 #include <fs/hpfs/hpfs_subr.h>
57 #include <fs/hpfs/hpfs_ioctl.h>
58
59 static int hpfs_de_uiomove(struct hpfsmount *, struct hpfsdirent *,
60 struct uio *);
61 static int hpfs_ioctl(struct vop_ioctl_args *ap);
62 static int hpfs_read(struct vop_read_args *);
63 static int hpfs_write(struct vop_write_args *ap);
64 static int hpfs_getattr(struct vop_getattr_args *ap);
65 static int hpfs_setattr(struct vop_setattr_args *ap);
66 static int hpfs_inactive(struct vop_inactive_args *ap);
67 static int hpfs_print(struct vop_print_args *ap);
68 static int hpfs_reclaim(struct vop_reclaim_args *ap);
69 static int hpfs_strategy(struct vop_strategy_args *ap);
70 static int hpfs_access(struct vop_access_args *ap);
71 static int hpfs_open(struct vop_open_args *ap);
72 static int hpfs_close(struct vop_close_args *ap);
73 static int hpfs_readdir(struct vop_readdir_args *ap);
74 static int hpfs_lookup(struct vop_lookup_args *ap);
75 static int hpfs_create(struct vop_create_args *);
76 static int hpfs_remove(struct vop_remove_args *);
77 static int hpfs_bmap(struct vop_bmap_args *ap);
78 static int hpfs_fsync(struct vop_fsync_args *ap);
79 static int hpfs_pathconf(struct vop_pathconf_args *ap);
80
81 static int
82 hpfs_fsync(ap)
83 struct vop_fsync_args /* {
84 struct vnode *a_vp;
85 struct ucred *a_cred;
86 int a_waitfor;
87 struct thread *a_td;
88 } */ *ap;
89 {
90 /*
91 * Flush our dirty buffers.
92 */
93 vop_stdfsync(ap);
94
95 /*
96 * Write out the on-disc version of the vnode.
97 */
98 return hpfs_update(VTOHP(ap->a_vp));
99 }
100
101 static int
102 hpfs_ioctl (
103 struct vop_ioctl_args /* {
104 struct vnode *a_vp;
105 u_long a_command;
106 caddr_t a_data;
107 int a_fflag;
108 struct ucred *a_cred;
109 struct thread *a_td;
110 } */ *ap)
111 {
112 register struct vnode *vp = ap->a_vp;
113 register struct hpfsnode *hp = VTOHP(vp);
114 int error;
115
116 printf("hpfs_ioctl(0x%x, 0x%lx, 0x%p, 0x%x): ",
117 hp->h_no, ap->a_command, ap->a_data, ap->a_fflag);
118
119 switch (ap->a_command) {
120 case HPFSIOCGEANUM: {
121 u_long eanum;
122 u_long passed;
123 struct ea *eap;
124
125 eanum = 0;
126
127 if (hp->h_fn.fn_ealen > 0) {
128 eap = (struct ea *)&(hp->h_fn.fn_int);
129 passed = 0;
130
131 while (passed < hp->h_fn.fn_ealen) {
132
133 printf("EAname: %s\n", EA_NAME(eap));
134
135 eanum++;
136 passed += sizeof(struct ea) +
137 eap->ea_namelen + 1 + eap->ea_vallen;
138 eap = (struct ea *)((caddr_t)hp->h_fn.fn_int +
139 passed);
140 }
141 error = 0;
142 } else {
143 error = ENOENT;
144 }
145
146 printf("%lu eas\n", eanum);
147
148 *(u_long *)ap->a_data = eanum;
149
150 break;
151 }
152 case HPFSIOCGEASZ: {
153 u_long eanum;
154 u_long passed;
155 struct ea *eap;
156
157 printf("EA%ld\n", *(u_long *)ap->a_data);
158
159 eanum = 0;
160 if (hp->h_fn.fn_ealen > 0) {
161 eap = (struct ea *)&(hp->h_fn.fn_int);
162 passed = 0;
163
164 error = ENOENT;
165 while (passed < hp->h_fn.fn_ealen) {
166 printf("EAname: %s\n", EA_NAME(eap));
167
168 if (eanum == *(u_long *)ap->a_data) {
169 *(u_long *)ap->a_data =
170 eap->ea_namelen + 1 +
171 eap->ea_vallen;
172
173 error = 0;
174 break;
175 }
176
177 eanum++;
178 passed += sizeof(struct ea) +
179 eap->ea_namelen + 1 + eap->ea_vallen;
180 eap = (struct ea *)((caddr_t)hp->h_fn.fn_int +
181 passed);
182 }
183 } else {
184 error = ENOENT;
185 }
186
187 break;
188 }
189 case HPFSIOCRDEA: {
190 u_long eanum;
191 u_long passed;
192 struct hpfs_rdea *rdeap;
193 struct ea *eap;
194
195 rdeap = (struct hpfs_rdea *)ap->a_data;
196 printf("EA%ld\n", rdeap->ea_no);
197
198 eanum = 0;
199 if (hp->h_fn.fn_ealen > 0) {
200 eap = (struct ea *)&(hp->h_fn.fn_int);
201 passed = 0;
202
203 error = ENOENT;
204 while (passed < hp->h_fn.fn_ealen) {
205 printf("EAname: %s\n", EA_NAME(eap));
206
207 if (eanum == rdeap->ea_no) {
208 rdeap->ea_sz = eap->ea_namelen + 1 +
209 eap->ea_vallen;
210 copyout(EA_NAME(eap),rdeap->ea_data,
211 rdeap->ea_sz);
212 error = 0;
213 break;
214 }
215
216 eanum++;
217 passed += sizeof(struct ea) +
218 eap->ea_namelen + 1 + eap->ea_vallen;
219 eap = (struct ea *)((caddr_t)hp->h_fn.fn_int +
220 passed);
221 }
222 } else {
223 error = ENOENT;
224 }
225
226 break;
227 }
228 default:
229 error = ENOTTY;
230 break;
231 }
232 return (error);
233 }
234
235 /*
236 * Map file offset to disk offset.
237 */
238 int
239 hpfs_bmap(ap)
240 struct vop_bmap_args /* {
241 struct vnode *a_vp;
242 daddr_t a_bn;
243 struct vnode **a_vpp;
244 daddr_t *a_bnp;
245 int *a_runp;
246 int *a_runb;
247 } */ *ap;
248 {
249 register struct hpfsnode *hp = VTOHP(ap->a_vp);
250 daddr_t blkno;
251 int error;
252
253 if (ap->a_vpp != NULL)
254 *ap->a_vpp = hp->h_devvp;
255 if (ap->a_runb != NULL)
256 *ap->a_runb = 0;
257 if (ap->a_bnp == NULL)
258 return (0);
259
260 dprintf(("hpfs_bmap(0x%x, 0x%x): ",hp->h_no, ap->a_bn));
261
262 error = hpfs_hpbmap (hp, ap->a_bn, &blkno, ap->a_runp);
263 *ap->a_bnp = blkno;
264
265 return (error);
266 }
267
268 static int
269 hpfs_read(ap)
270 struct vop_read_args /* {
271 struct vnode *a_vp;
272 struct uio *a_uio;
273 int a_ioflag;
274 struct ucred *a_cred;
275 } */ *ap;
276 {
277 register struct vnode *vp = ap->a_vp;
278 register struct hpfsnode *hp = VTOHP(vp);
279 struct uio *uio = ap->a_uio;
280 struct buf *bp;
281 u_int xfersz, toread;
282 u_int off;
283 daddr_t lbn, bn;
284 int resid;
285 int runl;
286 int error = 0;
287
288 resid = min (uio->uio_resid, hp->h_fn.fn_size - uio->uio_offset);
289
290 dprintf(("hpfs_read(0x%x, off: %d resid: %d, segflg: %d): [resid: 0x%x]\n",hp->h_no,(u_int32_t)uio->uio_offset,uio->uio_resid,uio->uio_segflg, resid));
291
292 while (resid) {
293 lbn = uio->uio_offset >> DEV_BSHIFT;
294 off = uio->uio_offset & (DEV_BSIZE - 1);
295 dprintf(("hpfs_read: resid: 0x%x lbn: 0x%x off: 0x%x\n",
296 uio->uio_resid, lbn, off));
297 error = hpfs_hpbmap(hp, lbn, &bn, &runl);
298 if (error)
299 return (error);
300
301 toread = min(off + resid, min(DFLTPHYS, (runl+1)*DEV_BSIZE));
302 xfersz = (toread + DEV_BSIZE - 1) & ~(DEV_BSIZE - 1);
303 dprintf(("hpfs_read: bn: 0x%x (0x%x) toread: 0x%x (0x%x)\n",
304 bn, runl, toread, xfersz));
305
306 if (toread == 0)
307 break;
308
309 error = bread(hp->h_devvp, bn, xfersz, NOCRED, &bp);
310 if (error) {
311 brelse(bp);
312 break;
313 }
314
315 error = uiomove(bp->b_data + off, toread - off, uio);
316 if(error) {
317 brelse(bp);
318 break;
319 }
320 brelse(bp);
321 resid -= toread;
322 }
323 dprintf(("hpfs_read: successful\n"));
324 return (error);
325 }
326
327 static int
328 hpfs_write(ap)
329 struct vop_write_args /* {
330 struct vnode *a_vp;
331 struct uio *a_uio;
332 int a_ioflag;
333 struct ucred *a_cred;
334 } */ *ap;
335 {
336 register struct vnode *vp = ap->a_vp;
337 register struct hpfsnode *hp = VTOHP(vp);
338 struct uio *uio = ap->a_uio;
339 struct buf *bp;
340 u_int xfersz, towrite;
341 u_int off;
342 daddr_t lbn, bn;
343 int runl;
344 int error = 0;
345
346 dprintf(("hpfs_write(0x%x, off: %d resid: %d, segflg: %d):\n",hp->h_no,(u_int32_t)uio->uio_offset,uio->uio_resid,uio->uio_segflg));
347
348 if (ap->a_ioflag & IO_APPEND) {
349 dprintf(("hpfs_write: APPEND mode\n"));
350 uio->uio_offset = hp->h_fn.fn_size;
351 }
352 if (uio->uio_offset + uio->uio_resid > hp->h_fn.fn_size) {
353 error = hpfs_extend (hp, uio->uio_offset + uio->uio_resid);
354 if (error) {
355 printf("hpfs_write: hpfs_extend FAILED %d\n", error);
356 return (error);
357 }
358 }
359
360 while (uio->uio_resid) {
361 lbn = uio->uio_offset >> DEV_BSHIFT;
362 off = uio->uio_offset & (DEV_BSIZE - 1);
363 dprintf(("hpfs_write: resid: 0x%x lbn: 0x%x off: 0x%x\n",
364 uio->uio_resid, lbn, off));
365 error = hpfs_hpbmap(hp, lbn, &bn, &runl);
366 if (error)
367 return (error);
368
369 towrite = min(off + uio->uio_resid, min(DFLTPHYS, (runl+1)*DEV_BSIZE));
370 xfersz = (towrite + DEV_BSIZE - 1) & ~(DEV_BSIZE - 1);
371 dprintf(("hpfs_write: bn: 0x%x (0x%x) towrite: 0x%x (0x%x)\n",
372 bn, runl, towrite, xfersz));
373
374 if ((off == 0) && (towrite == xfersz)) {
375 bp = getblk(hp->h_devvp, bn, xfersz, 0, 0, 0);
376 clrbuf(bp);
377 } else {
378 error = bread(hp->h_devvp, bn, xfersz, NOCRED, &bp);
379 if (error) {
380 brelse(bp);
381 return (error);
382 }
383 }
384
385 error = uiomove(bp->b_data + off, towrite - off, uio);
386 if(error) {
387 brelse(bp);
388 return (error);
389 }
390
391 if (ap->a_ioflag & IO_SYNC)
392 bwrite(bp);
393 else
394 bawrite(bp);
395 }
396
397 dprintf(("hpfs_write: successful\n"));
398 return (0);
399 }
400
401 /*
402 * XXXXX do we need hpfsnode locking inside?
403 */
404 static int
405 hpfs_getattr(ap)
406 struct vop_getattr_args /* {
407 struct vnode *a_vp;
408 struct vattr *a_vap;
409 struct ucred *a_cred;
410 struct thread *a_td;
411 } */ *ap;
412 {
413 register struct vnode *vp = ap->a_vp;
414 register struct hpfsnode *hp = VTOHP(vp);
415 register struct vattr *vap = ap->a_vap;
416 int error;
417
418 dprintf(("hpfs_getattr(0x%x):\n", hp->h_no));
419
420 vap->va_fsid = dev2udev(hp->h_dev);
421 vap->va_fileid = hp->h_no;
422 vap->va_mode = hp->h_mode;
423 vap->va_nlink = 1;
424 vap->va_uid = hp->h_uid;
425 vap->va_gid = hp->h_gid;
426 vap->va_rdev = 0; /* XXX UNODEV ? */
427 vap->va_size = hp->h_fn.fn_size;
428 vap->va_bytes = ((hp->h_fn.fn_size + DEV_BSIZE-1) & ~(DEV_BSIZE-1)) +
429 DEV_BSIZE;
430
431 if (!(hp->h_flag & H_PARVALID)) {
432 error = hpfs_validateparent(hp);
433 if (error)
434 return (error);
435 }
436 vap->va_atime = hpfstimetounix(hp->h_atime);
437 vap->va_mtime = hpfstimetounix(hp->h_mtime);
438 vap->va_ctime = hpfstimetounix(hp->h_ctime);
439
440 vap->va_flags = 0;
441 vap->va_gen = 0;
442 vap->va_blocksize = DEV_BSIZE;
443 vap->va_type = vp->v_type;
444 vap->va_filerev = 0;
445
446 return (0);
447 }
448
449 /*
450 * XXXXX do we need hpfsnode locking inside?
451 */
452 static int
453 hpfs_setattr(ap)
454 struct vop_setattr_args /* {
455 struct vnode *a_vp;
456 struct vattr *a_vap;
457 struct ucred *a_cred;
458 struct thread *a_td;
459 } */ *ap;
460 {
461 struct vnode *vp = ap->a_vp;
462 struct hpfsnode *hp = VTOHP(vp);
463 struct vattr *vap = ap->a_vap;
464 struct ucred *cred = ap->a_cred;
465 struct thread *td = ap->a_td;
466 int error;
467
468 dprintf(("hpfs_setattr(0x%x):\n", hp->h_no));
469
470 /*
471 * Check for unsettable attributes.
472 */
473 if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
474 (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
475 (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
476 (vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
477 dprintf(("hpfs_setattr: changing nonsettable attr\n"));
478 return (EINVAL);
479 }
480
481 /* Can't change flags XXX Could be implemented */
482 if (vap->va_flags != VNOVAL) {
483 printf("hpfs_setattr: FLAGS CANNOT BE SET\n");
484 return (EINVAL);
485 }
486
487 /* Can't change uid/gid XXX Could be implemented */
488 if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
489 printf("hpfs_setattr: UID/GID CANNOT BE SET\n");
490 return (EINVAL);
491 }
492
493 /* Can't change mode XXX Could be implemented */
494 if (vap->va_mode != (mode_t)VNOVAL) {
495 printf("hpfs_setattr: MODE CANNOT BE SET\n");
496 return (EINVAL);
497 }
498
499 /* Update times */
500 if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
501 if (vp->v_mount->mnt_flag & MNT_RDONLY)
502 return (EROFS);
503 if (cred->cr_uid != hp->h_uid &&
504 (error = suser_cred(cred, SUSER_ALLOWJAIL)) &&
505 ((vap->va_vaflags & VA_UTIMES_NULL) == 0 ||
506 (error = VOP_ACCESS(vp, VWRITE, cred, td))))
507 return (error);
508 if (vap->va_atime.tv_sec != VNOVAL)
509 hp->h_atime = vap->va_atime.tv_sec;
510 if (vap->va_mtime.tv_sec != VNOVAL)
511 hp->h_mtime = vap->va_mtime.tv_sec;
512
513 hp->h_flag |= H_PARCHANGE;
514 }
515
516 if (vap->va_size != VNOVAL) {
517 switch (vp->v_type) {
518 case VDIR:
519 return (EISDIR);
520 case VREG:
521 if (vp->v_mount->mnt_flag & MNT_RDONLY)
522 return (EROFS);
523 break;
524 default:
525 printf("hpfs_setattr: WRONG v_type\n");
526 return (EINVAL);
527 }
528
529 if (vap->va_size < hp->h_fn.fn_size) {
530 error = vtruncbuf(vp, cred, td, vap->va_size, DEV_BSIZE);
531 if (error)
532 return (error);
533 error = hpfs_truncate(hp, vap->va_size);
534 if (error)
535 return (error);
536
537 } else if (vap->va_size > hp->h_fn.fn_size) {
538 vnode_pager_setsize(vp, vap->va_size);
539 error = hpfs_extend(hp, vap->va_size);
540 if (error)
541 return (error);
542 }
543 }
544
545 return (0);
546 }
547
548 /*
549 * Last reference to a node. If necessary, write or delete it.
550 */
551 int
552 hpfs_inactive(ap)
553 struct vop_inactive_args /* {
554 struct vnode *a_vp;
555 } */ *ap;
556 {
557 register struct vnode *vp = ap->a_vp;
558 register struct hpfsnode *hp = VTOHP(vp);
559 int error;
560
561 dprintf(("hpfs_inactive(0x%x): \n", hp->h_no));
562
563 if (hp->h_flag & H_CHANGE) {
564 dprintf(("hpfs_inactive: node changed, update\n"));
565 error = hpfs_update (hp);
566 if (error)
567 return (error);
568 }
569
570 if (hp->h_flag & H_PARCHANGE) {
571 dprintf(("hpfs_inactive: parent node changed, update\n"));
572 error = hpfs_updateparent (hp);
573 if (error)
574 return (error);
575 }
576
577 if (prtactive && vrefcnt(vp) != 0)
578 vprint("hpfs_inactive: pushing active", vp);
579
580 if (hp->h_flag & H_INVAL) {
581 VOP_UNLOCK(vp,0,ap->a_td);
582 vrecycle(vp, NULL, ap->a_td);
583 return (0);
584 }
585
586 VOP_UNLOCK(vp,0,ap->a_td);
587 return (0);
588 }
589
590 /*
591 * Reclaim an inode so that it can be used for other purposes.
592 */
593 int
594 hpfs_reclaim(ap)
595 struct vop_reclaim_args /* {
596 struct vnode *a_vp;
597 } */ *ap;
598 {
599 register struct vnode *vp = ap->a_vp;
600 register struct hpfsnode *hp = VTOHP(vp);
601
602 dprintf(("hpfs_reclaim(0x%x0): \n", hp->h_no));
603
604 hpfs_hphashrem(hp);
605
606 /* Purge old data structures associated with the inode. */
607 if (hp->h_devvp) {
608 vrele(hp->h_devvp);
609 hp->h_devvp = NULL;
610 }
611
612 mtx_destroy(&hp->h_interlock);
613
614 vp->v_data = NULL;
615
616 FREE(hp, M_HPFSNO);
617
618 return (0);
619 }
620
621 static int
622 hpfs_print(ap)
623 struct vop_print_args /* {
624 struct vnode *a_vp;
625 } */ *ap;
626 {
627 register struct vnode *vp = ap->a_vp;
628 register struct hpfsnode *hp = VTOHP(vp);
629
630 printf("\tino 0x%x\n", hp->h_no);
631 return (0);
632 }
633
634 /*
635 * Calculate the logical to physical mapping if not done already,
636 * then call the device strategy routine.
637 *
638 * In order to be able to swap to a file, the hpfs_hpbmap operation may not
639 * deadlock on memory. See hpfs_bmap() for details. XXXXXXX (not impl)
640 */
641 int
642 hpfs_strategy(ap)
643 struct vop_strategy_args /* {
644 struct buf *a_bp;
645 } */ *ap;
646 {
647 register struct buf *bp = ap->a_bp;
648 register struct vnode *vp = ap->a_vp;
649 register struct hpfsnode *hp = VTOHP(ap->a_vp);
650 daddr_t blkno;
651 int error;
652
653 KASSERT(ap->a_vp == ap->a_bp->b_vp, ("%s(%p != %p)",
654 __func__, ap->a_vp, ap->a_bp->b_vp));
655 dprintf(("hpfs_strategy(): \n"));
656
657 if (vp->v_type == VBLK || vp->v_type == VCHR)
658 panic("hpfs_strategy: spec");
659 if (bp->b_blkno == bp->b_lblkno) {
660 error = hpfs_hpbmap (hp, bp->b_lblkno, &blkno, NULL);
661 bp->b_blkno = blkno;
662 if (error) {
663 printf("hpfs_strategy: hpfs_bpbmap FAILED %d\n", error);
664 bp->b_error = error;
665 bp->b_ioflags |= BIO_ERROR;
666 bufdone(bp);
667 return (error);
668 }
669 if ((long)bp->b_blkno == -1)
670 vfs_bio_clrbuf(bp);
671 }
672 if ((long)bp->b_blkno == -1) {
673 bufdone(bp);
674 return (0);
675 }
676 bp->b_dev = hp->h_devvp->v_rdev;
677 bp->b_iooffset = dbtob(bp->b_blkno);
678 VOP_SPECSTRATEGY(hp->h_devvp, bp);
679 return (0);
680 }
681
682 /*
683 * XXXXX do we need hpfsnode locking inside?
684 */
685 int
686 hpfs_access(ap)
687 struct vop_access_args /* {
688 struct vnode *a_vp;
689 int a_mode;
690 struct ucred *a_cred;
691 struct thread *a_td;
692 } */ *ap;
693 {
694 struct vnode *vp = ap->a_vp;
695 struct hpfsnode *hp = VTOHP(vp);
696 mode_t mode = ap->a_mode;
697
698 dprintf(("hpfs_access(0x%x):\n", hp->h_no));
699
700 /*
701 * Disallow write attempts on read-only filesystems;
702 * unless the file is a socket, fifo, or a block or
703 * character device resident on the filesystem.
704 */
705 if (mode & VWRITE) {
706 switch ((int)vp->v_type) {
707 case VDIR:
708 case VLNK:
709 case VREG:
710 if (vp->v_mount->mnt_flag & MNT_RDONLY)
711 return (EROFS);
712 break;
713 }
714 }
715
716 return (vaccess(vp->v_type, hp->h_mode, hp->h_uid, hp->h_gid,
717 ap->a_mode, ap->a_cred, NULL));
718 }
719
720 /*
721 * Open called.
722 *
723 * Nothing to do.
724 */
725 /* ARGSUSED */
726 static int
727 hpfs_open(ap)
728 struct vop_open_args /* {
729 struct vnode *a_vp;
730 int a_mode;
731 struct ucred *a_cred;
732 struct thread *a_td;
733 } */ *ap;
734 {
735 #if HPFS_DEBUG
736 register struct vnode *vp = ap->a_vp;
737 register struct hpfsnode *hp = VTOHP(vp);
738
739 printf("hpfs_open(0x%x):\n",hp->h_no);
740 #endif
741
742 /*
743 * Files marked append-only must be opened for appending.
744 */
745
746 return (0);
747 }
748
749 /*
750 * Close called.
751 *
752 * Update the times on the inode.
753 */
754 /* ARGSUSED */
755 static int
756 hpfs_close(ap)
757 struct vop_close_args /* {
758 struct vnode *a_vp;
759 int a_fflag;
760 struct ucred *a_cred;
761 struct thread *a_td;
762 } */ *ap;
763 {
764 #if HPFS_DEBUG
765 register struct vnode *vp = ap->a_vp;
766 register struct hpfsnode *hp = VTOHP(vp);
767
768 printf("hpfs_close: %d\n",hp->h_no);
769 #endif
770
771 return (0);
772 }
773
774 static int
775 hpfs_de_uiomove (
776 struct hpfsmount *hpmp,
777 struct hpfsdirent *dep,
778 struct uio *uio)
779 {
780 struct dirent cde;
781 int i, error;
782
783 dprintf(("[no: 0x%x, size: %d, name: %2d:%.*s, flag: 0x%x] ",
784 dep->de_fnode, dep->de_size, dep->de_namelen,
785 dep->de_namelen, dep->de_name, dep->de_flag));
786
787 /*strncpy(cde.d_name, dep->de_name, dep->de_namelen);*/
788 for (i=0; i<dep->de_namelen; i++)
789 cde.d_name[i] = hpfs_d2u(hpmp, dep->de_name[i]);
790
791 cde.d_name[dep->de_namelen] = '\0';
792 cde.d_namlen = dep->de_namelen;
793 cde.d_fileno = dep->de_fnode;
794 cde.d_type = (dep->de_flag & DE_DIR) ? DT_DIR : DT_REG;
795 cde.d_reclen = sizeof(struct dirent);
796
797 error = uiomove((char *)&cde, sizeof(struct dirent), uio);
798 if (error)
799 return (error);
800
801 dprintf(("[0x%x] ", uio->uio_resid));
802 return (error);
803 }
804
805
806 static struct dirent hpfs_de_dot =
807 { 0, sizeof(struct dirent), DT_DIR, 1, "." };
808 static struct dirent hpfs_de_dotdot =
809 { 0, sizeof(struct dirent), DT_DIR, 2, ".." };
810 int
811 hpfs_readdir(ap)
812 struct vop_readdir_args /* {
813 struct vnode *a_vp;
814 struct uio *a_uio;
815 struct ucred *a_cred;
816 int *a_ncookies;
817 u_int **cookies;
818 } */ *ap;
819 {
820 register struct vnode *vp = ap->a_vp;
821 register struct hpfsnode *hp = VTOHP(vp);
822 struct hpfsmount *hpmp = hp->h_hpmp;
823 struct uio *uio = ap->a_uio;
824 int ncookies = 0, i, num, cnum;
825 int error = 0;
826 off_t off;
827 struct buf *bp;
828 struct dirblk *dp;
829 struct hpfsdirent *dep;
830 lsn_t olsn;
831 lsn_t lsn;
832 int level;
833
834 dprintf(("hpfs_readdir(0x%x, 0x%x, 0x%x): ",hp->h_no,(u_int32_t)uio->uio_offset,uio->uio_resid));
835
836 off = uio->uio_offset;
837
838 if( uio->uio_offset < sizeof(struct dirent) ) {
839 dprintf((". faked, "));
840 hpfs_de_dot.d_fileno = hp->h_no;
841 error = uiomove((char *)&hpfs_de_dot,sizeof(struct dirent),uio);
842 if(error) {
843 return (error);
844 }
845
846 ncookies ++;
847 }
848
849 if( uio->uio_offset < 2 * sizeof(struct dirent) ) {
850 dprintf((".. faked, "));
851 hpfs_de_dotdot.d_fileno = hp->h_fn.fn_parent;
852
853 error = uiomove((char *)&hpfs_de_dotdot, sizeof(struct dirent),
854 uio);
855 if(error) {
856 return (error);
857 }
858
859 ncookies ++;
860 }
861
862 num = uio->uio_offset / sizeof(struct dirent) - 2;
863 cnum = 0;
864
865 lsn = ((alleaf_t *)hp->h_fn.fn_abd)->al_lsn;
866
867 olsn = 0;
868 level = 1;
869
870 dive:
871 dprintf(("[dive 0x%x] ", lsn));
872 error = bread(hp->h_devvp, lsn, D_BSIZE, NOCRED, &bp);
873 if (error) {
874 brelse(bp);
875 return (error);
876 }
877
878 dp = (struct dirblk *) bp->b_data;
879 if (dp->d_magic != D_MAGIC) {
880 printf("hpfs_readdir: MAGIC DOESN'T MATCH\n");
881 brelse(bp);
882 return (EINVAL);
883 }
884
885 dep = D_DIRENT(dp);
886
887 if (olsn) {
888 dprintf(("[restore 0x%x] ", olsn));
889
890 while(!(dep->de_flag & DE_END) ) {
891 if((dep->de_flag & DE_DOWN) &&
892 (olsn == DE_DOWNLSN(dep)))
893 break;
894 dep = (hpfsdirent_t *)((caddr_t)dep + dep->de_reclen);
895 }
896
897 if((dep->de_flag & DE_DOWN) && (olsn == DE_DOWNLSN(dep))) {
898 if (dep->de_flag & DE_END)
899 goto blockdone;
900
901 if (!(dep->de_flag & DE_SPECIAL)) {
902 if (num <= cnum) {
903 if (uio->uio_resid < sizeof(struct dirent)) {
904 brelse(bp);
905 dprintf(("[resid] "));
906 goto readdone;
907 }
908
909 error = hpfs_de_uiomove(hpmp, dep, uio);
910 if (error) {
911 brelse (bp);
912 return (error);
913 }
914 ncookies++;
915
916 if (uio->uio_resid < sizeof(struct dirent)) {
917 brelse(bp);
918 dprintf(("[resid] "));
919 goto readdone;
920 }
921 }
922 cnum++;
923 }
924
925 dep = (hpfsdirent_t *)((caddr_t)dep + dep->de_reclen);
926 } else {
927 printf("hpfs_readdir: ERROR! oLSN not found\n");
928 brelse(bp);
929 return (EINVAL);
930 }
931 }
932
933 olsn = 0;
934
935 while(!(dep->de_flag & DE_END)) {
936 if(dep->de_flag & DE_DOWN) {
937 lsn = DE_DOWNLSN(dep);
938 brelse(bp);
939 level++;
940 goto dive;
941 }
942
943 if (!(dep->de_flag & DE_SPECIAL)) {
944 if (num <= cnum) {
945 if (uio->uio_resid < sizeof(struct dirent)) {
946 brelse(bp);
947 dprintf(("[resid] "));
948 goto readdone;
949 }
950
951 error = hpfs_de_uiomove(hpmp, dep, uio);
952 if (error) {
953 brelse (bp);
954 return (error);
955 }
956 ncookies++;
957
958 if (uio->uio_resid < sizeof(struct dirent)) {
959 brelse(bp);
960 dprintf(("[resid] "));
961 goto readdone;
962 }
963 }
964 cnum++;
965 }
966
967 dep = (hpfsdirent_t *)((caddr_t)dep + dep->de_reclen);
968 }
969
970 if(dep->de_flag & DE_DOWN) {
971 dprintf(("[enddive] "));
972 lsn = DE_DOWNLSN(dep);
973 brelse(bp);
974 level++;
975 goto dive;
976 }
977
978 blockdone:
979 dprintf(("[EOB] "));
980 olsn = lsn;
981 lsn = dp->d_parent;
982 brelse(bp);
983 level--;
984
985 dprintf(("[level %d] ", level));
986
987 if (level > 0)
988 goto dive; /* undive really */
989
990 if (ap->a_eofflag) {
991 dprintf(("[EOF] "));
992 *ap->a_eofflag = 1;
993 }
994
995 readdone:
996 dprintf(("[readdone]\n"));
997 if (!error && ap->a_ncookies != NULL) {
998 struct dirent* dpStart;
999 struct dirent* dp;
1000 u_long *cookies;
1001 u_long *cookiep;
1002
1003 dprintf(("%d cookies, ",ncookies));
1004 if (uio->uio_segflg != UIO_SYSSPACE || uio->uio_iovcnt != 1)
1005 panic("hpfs_readdir: unexpected uio from NFS server");
1006 dpStart = (struct dirent *)
1007 ((caddr_t)uio->uio_iov->iov_base -
1008 (uio->uio_offset - off));
1009 MALLOC(cookies, u_long *, ncookies * sizeof(u_long),
1010 M_TEMP, M_WAITOK);
1011 for (dp = dpStart, cookiep = cookies, i=0;
1012 i < ncookies;
1013 dp = (struct dirent *)((caddr_t) dp + dp->d_reclen), i++) {
1014 off += dp->d_reclen;
1015 *cookiep++ = (u_int) off;
1016 }
1017 *ap->a_ncookies = ncookies;
1018 *ap->a_cookies = cookies;
1019 }
1020
1021 return (0);
1022 }
1023
1024 int
1025 hpfs_lookup(ap)
1026 struct vop_lookup_args /* {
1027 struct vnode *a_dvp;
1028 struct vnode **a_vpp;
1029 struct componentname *a_cnp;
1030 } */ *ap;
1031 {
1032 register struct vnode *dvp = ap->a_dvp;
1033 register struct hpfsnode *dhp = VTOHP(dvp);
1034 struct hpfsmount *hpmp = dhp->h_hpmp;
1035 struct componentname *cnp = ap->a_cnp;
1036 struct ucred *cred = cnp->cn_cred;
1037 int error;
1038 int nameiop = cnp->cn_nameiop;
1039 int flags = cnp->cn_flags;
1040 int lockparent = flags & LOCKPARENT;
1041 #if HPFS_DEBUG
1042 int wantparent = flags & (LOCKPARENT|WANTPARENT);
1043 #endif
1044 dprintf(("hpfs_lookup(0x%x, %s, %ld, %d, %d): \n",
1045 dhp->h_no, cnp->cn_nameptr, cnp->cn_namelen,
1046 lockparent, wantparent));
1047
1048 if (nameiop != CREATE && nameiop != DELETE && nameiop != LOOKUP) {
1049 printf("hpfs_lookup: LOOKUP, DELETE and CREATE are only supported\n");
1050 return (EOPNOTSUPP);
1051 }
1052
1053 error = VOP_ACCESS(dvp, VEXEC, cred, cnp->cn_thread);
1054 if(error)
1055 return (error);
1056
1057 if( (cnp->cn_namelen == 1) &&
1058 !strncmp(cnp->cn_nameptr,".",1) ) {
1059 dprintf(("hpfs_lookup(0x%x,...): . faked\n",dhp->h_no));
1060
1061 VREF(dvp);
1062 *ap->a_vpp = dvp;
1063
1064 return (0);
1065 } else if( (cnp->cn_namelen == 2) &&
1066 !strncmp(cnp->cn_nameptr,"..",2) && (flags & ISDOTDOT) ) {
1067 dprintf(("hpfs_lookup(0x%x,...): .. faked (0x%x)\n",
1068 dhp->h_no, dhp->h_fn.fn_parent));
1069
1070 if (VFS_VGET(hpmp->hpm_mp, dhp->h_fn.fn_parent,
1071 LK_NOWAIT | LK_EXCLUSIVE, ap->a_vpp)) {
1072 VOP_UNLOCK(dvp,0,cnp->cn_thread);
1073 error = VFS_VGET(hpmp->hpm_mp,
1074 dhp->h_fn.fn_parent, LK_EXCLUSIVE, ap->a_vpp);
1075 VOP_LOCK(dvp, 0, cnp->cn_thread);
1076 if(error)
1077 return(error);
1078 }
1079 if (!lockparent || !(flags & ISLASTCN))
1080 VOP_UNLOCK(dvp,0,cnp->cn_thread);
1081 return (0);
1082 } else {
1083 struct buf *bp;
1084 struct hpfsdirent *dep;
1085 struct hpfsnode *hp;
1086
1087 error = hpfs_genlookupbyname(dhp,
1088 cnp->cn_nameptr, cnp->cn_namelen, &bp, &dep);
1089 if (error) {
1090 if ((error == ENOENT) && (flags & ISLASTCN) &&
1091 (nameiop == CREATE || nameiop == RENAME)) {
1092 if(!lockparent)
1093 VOP_UNLOCK(dvp, 0, cnp->cn_thread);
1094 cnp->cn_flags |= SAVENAME;
1095 return (EJUSTRETURN);
1096 }
1097
1098 return (error);
1099 }
1100
1101 dprintf(("hpfs_lookup: fnode: 0x%x, CPID: 0x%x\n",
1102 dep->de_fnode, dep->de_cpid));
1103
1104 if (nameiop == DELETE && (flags & ISLASTCN)) {
1105 error = VOP_ACCESS(dvp, VWRITE, cred, cnp->cn_thread);
1106 if (error) {
1107 brelse(bp);
1108 return (error);
1109 }
1110 }
1111
1112 if (dhp->h_no == dep->de_fnode) {
1113 brelse(bp);
1114 VREF(dvp);
1115 *ap->a_vpp = dvp;
1116 return (0);
1117 }
1118
1119 error = VFS_VGET(hpmp->hpm_mp, dep->de_fnode, LK_EXCLUSIVE,
1120 ap->a_vpp);
1121 if (error) {
1122 printf("hpfs_lookup: VFS_VGET FAILED %d\n", error);
1123 brelse(bp);
1124 return(error);
1125 }
1126
1127 hp = VTOHP(*ap->a_vpp);
1128
1129 hp->h_mtime = dep->de_mtime;
1130 hp->h_ctime = dep->de_ctime;
1131 hp->h_atime = dep->de_atime;
1132 bcopy(dep->de_name, hp->h_name, dep->de_namelen);
1133 hp->h_name[dep->de_namelen] = '\0';
1134 hp->h_namelen = dep->de_namelen;
1135 hp->h_flag |= H_PARVALID;
1136
1137 brelse(bp);
1138
1139 if(!lockparent || !(flags & ISLASTCN))
1140 VOP_UNLOCK(dvp, 0, cnp->cn_thread);
1141 if ((flags & MAKEENTRY) &&
1142 (!(flags & ISLASTCN) ||
1143 (nameiop != DELETE && nameiop != CREATE)))
1144 cache_enter(dvp, *ap->a_vpp, cnp);
1145 }
1146 return (error);
1147 }
1148
1149 int
1150 hpfs_remove(ap)
1151 struct vop_remove_args /* {
1152 struct vnode *a_dvp;
1153 struct vnode *a_vp;
1154 struct componentname *a_cnp;
1155 } */ *ap;
1156 {
1157 int error;
1158
1159 dprintf(("hpfs_remove(0x%x, %s, %ld): \n", VTOHP(ap->a_vp)->h_no,
1160 ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen));
1161
1162 if (ap->a_vp->v_type == VDIR)
1163 return (EPERM);
1164
1165 error = hpfs_removefnode (ap->a_dvp, ap->a_vp, ap->a_cnp);
1166 return (error);
1167 }
1168
1169 int
1170 hpfs_create(ap)
1171 struct vop_create_args /* {
1172 struct vnode *a_dvp;
1173 struct vnode **a_vpp;
1174 struct componentname *a_cnp;
1175 struct vattr *a_vap;
1176 } */ *ap;
1177 {
1178 int error;
1179
1180 dprintf(("hpfs_create(0x%x, %s, %ld): \n", VTOHP(ap->a_dvp)->h_no,
1181 ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen));
1182
1183 if (!(ap->a_cnp->cn_flags & HASBUF))
1184 panic ("hpfs_create: no name\n");
1185
1186 error = hpfs_makefnode (ap->a_dvp, ap->a_vpp, ap->a_cnp, ap->a_vap);
1187
1188 return (error);
1189 }
1190
1191 /*
1192 * Return POSIX pathconf information applicable to NTFS filesystem
1193 */
1194 int
1195 hpfs_pathconf(ap)
1196 struct vop_pathconf_args /* {
1197 struct vnode *a_vp;
1198 int a_name;
1199 register_t *a_retval;
1200 } */ *ap;
1201 {
1202 switch (ap->a_name) {
1203 case _PC_LINK_MAX:
1204 *ap->a_retval = 1;
1205 return (0);
1206 case _PC_NAME_MAX:
1207 *ap->a_retval = HPFS_MAXFILENAME;
1208 return (0);
1209 case _PC_PATH_MAX:
1210 *ap->a_retval = PATH_MAX;
1211 return (0);
1212 case _PC_CHOWN_RESTRICTED:
1213 *ap->a_retval = 1;
1214 return (0);
1215 case _PC_NO_TRUNC:
1216 *ap->a_retval = 0;
1217 return (0);
1218 default:
1219 return (EINVAL);
1220 }
1221 /* NOTREACHED */
1222 }
1223
1224
1225 /*
1226 * Global vfs data structures
1227 */
1228 vop_t **hpfs_vnodeop_p;
1229 struct vnodeopv_entry_desc hpfs_vnodeop_entries[] = {
1230 { &vop_default_desc, (vop_t *)vop_defaultop },
1231
1232 { &vop_getattr_desc, (vop_t *)hpfs_getattr },
1233 { &vop_setattr_desc, (vop_t *)hpfs_setattr },
1234 { &vop_inactive_desc, (vop_t *)hpfs_inactive },
1235 { &vop_reclaim_desc, (vop_t *)hpfs_reclaim },
1236 { &vop_print_desc, (vop_t *)hpfs_print },
1237 { &vop_create_desc, (vop_t *)hpfs_create },
1238 { &vop_remove_desc, (vop_t *)hpfs_remove },
1239 { &vop_cachedlookup_desc, (vop_t *)hpfs_lookup },
1240 { &vop_lookup_desc, (vop_t *)vfs_cache_lookup },
1241 { &vop_access_desc, (vop_t *)hpfs_access },
1242 { &vop_close_desc, (vop_t *)hpfs_close },
1243 { &vop_open_desc, (vop_t *)hpfs_open },
1244 { &vop_readdir_desc, (vop_t *)hpfs_readdir },
1245 { &vop_fsync_desc, (vop_t *)hpfs_fsync },
1246 { &vop_bmap_desc, (vop_t *)hpfs_bmap },
1247 { &vop_strategy_desc, (vop_t *)hpfs_strategy },
1248 { &vop_read_desc, (vop_t *)hpfs_read },
1249 { &vop_write_desc, (vop_t *)hpfs_write },
1250 { &vop_ioctl_desc, (vop_t *)hpfs_ioctl },
1251 { &vop_pathconf_desc, (vop_t *)hpfs_pathconf },
1252 { NULL, NULL }
1253 };
1254
1255 static
1256 struct vnodeopv_desc hpfs_vnodeop_opv_desc =
1257 { &hpfs_vnodeop_p, hpfs_vnodeop_entries };
1258
1259 VNODEOP_SET(hpfs_vnodeop_opv_desc);
Cache object: c25c1aa7bf905e0c78da2dd5effc8d93
|