cd9660_vnops.c revision 1.29.4.1 1 /* $NetBSD: cd9660_vnops.c,v 1.29.4.1 2007/12/08 18:20:13 mjf Exp $ */
2
3 /*-
4 * Copyright (c) 1994
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley
8 * by Pace Willisson (pace (at) blitz.com). The Rock Ridge Extension
9 * Support code is derived from software contributed to Berkeley
10 * by Atsushi Murai (amurai (at) spec.co.jp).
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * @(#)cd9660_vnops.c 8.15 (Berkeley) 5/27/95
37 */
38
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: cd9660_vnops.c,v 1.29.4.1 2007/12/08 18:20:13 mjf Exp $");
41
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/namei.h>
45 #include <sys/resourcevar.h>
46 #include <sys/kernel.h>
47 #include <sys/file.h>
48 #include <sys/stat.h>
49 #include <sys/buf.h>
50 #include <sys/proc.h>
51 #include <sys/mount.h>
52 #include <sys/vnode.h>
53 #include <sys/malloc.h>
54 #include <sys/dirent.h>
55 #include <sys/kauth.h>
56
57 #include <miscfs/fifofs/fifo.h>
58 #include <miscfs/genfs/genfs.h>
59 #include <miscfs/specfs/specdev.h>
60
61 #include <fs/cd9660/iso.h>
62 #include <fs/cd9660/cd9660_extern.h>
63 #include <fs/cd9660/cd9660_node.h>
64 #include <fs/cd9660/iso_rrip.h>
65 #include <fs/cd9660/cd9660_mount.h>
66
67 /*
68 * Structure for reading directories
69 */
70 struct isoreaddir {
71 struct dirent saveent;
72 struct dirent assocent;
73 struct dirent current;
74 off_t saveoff;
75 off_t assocoff;
76 off_t curroff;
77 struct uio *uio;
78 off_t uio_off;
79 int eofflag;
80 off_t *cookies;
81 int ncookies;
82 };
83
84 int iso_uiodir(struct isoreaddir *, struct dirent *, off_t);
85 int iso_shipdir(struct isoreaddir *);
86
87 #if 0
88 /*
89 * Mknod vnode call
90 * Actually remap the device number
91 */
92 int
93 cd9660_mknod(ndp, vap, cred, p)
94 struct nameidata *ndp;
95 kauth_cred_t cred;
96 struct vattr *vap;
97 struct proc *p;
98 {
99 #ifndef ISODEVMAP
100 PNBUF_PUT(ndp->ni_pnbuf);
101 vput(ndp->ni_dvp);
102 vput(ndp->ni_vp);
103 return (EINVAL);
104 #else
105 struct vnode *vp;
106 struct iso_node *ip;
107 struct iso_dnode *dp;
108
109 vp = ndp->ni_vp;
110 ip = VTOI(vp);
111
112 if (ip->i_mnt->iso_ftype != ISO_FTYPE_RRIP
113 || vap->va_type != vp->v_type
114 || (vap->va_type != VCHR && vap->va_type != VBLK)) {
115 PNBUF_PUT(ndp->ni_pnbuf);
116 vput(ndp->ni_dvp);
117 vput(ndp->ni_vp);
118 return (EINVAL);
119 }
120
121 dp = iso_dmap(ip->i_dev, ip->i_number, 1);
122 if (ip->inode.iso_rdev == vap->va_rdev ||
123 vap->va_rdev == (dev_t)VNOVAL) {
124 /* same as the unmapped one, delete the mapping */
125 LIST_REMOVE(dp, d_hash);
126 FREE(dp, M_CACHE);
127 } else
128 /* enter new mapping */
129 dp->d_dev = vap->va_rdev;
130
131 /*
132 * Remove inode so that it will be reloaded by iget and
133 * checked to see if it is an alias of an existing entry
134 * in the inode cache.
135 */
136 vput(vp);
137 vp->v_type = VNON;
138 vgone(vp);
139 return (0);
140 #endif
141 }
142 #endif
143
144 /*
145 * Check mode permission on inode pointer. Mode is READ, WRITE or EXEC.
146 * The mode is shifted to select the owner/group/other fields. The
147 * super user is granted all permissions.
148 */
149 int
150 cd9660_access(v)
151 void *v;
152 {
153 struct vop_access_args /* {
154 struct vnode *a_vp;
155 int a_mode;
156 kauth_cred_t a_cred;
157 } */ *ap = v;
158 struct vnode *vp = ap->a_vp;
159 struct iso_node *ip = VTOI(vp);
160
161 /*
162 * Disallow write attempts unless the file is a socket,
163 * fifo, or a block or character device resident on the
164 * file system.
165 */
166 if (ap->a_mode & VWRITE) {
167 switch (vp->v_type) {
168 case VDIR:
169 case VLNK:
170 case VREG:
171 return (EROFS);
172 default:
173 break;
174 }
175 }
176
177 return (vaccess(vp->v_type, ip->inode.iso_mode & ALLPERMS,
178 ip->inode.iso_uid, ip->inode.iso_gid, ap->a_mode, ap->a_cred));
179 }
180
181 int
182 cd9660_getattr(v)
183 void *v;
184 {
185 struct vop_getattr_args /* {
186 struct vnode *a_vp;
187 struct vattr *a_vap;
188 kauth_cred_t a_cred;
189 } */ *ap = v;
190 struct vnode *vp = ap->a_vp;
191 struct iso_node *ip = VTOI(vp);
192 struct vattr *vap = ap->a_vap;
193
194 vap->va_fsid = ip->i_dev;
195 vap->va_fileid = ip->i_number;
196
197 vap->va_mode = ip->inode.iso_mode & ALLPERMS;
198 vap->va_nlink = ip->inode.iso_links;
199 vap->va_uid = ip->inode.iso_uid;
200 vap->va_gid = ip->inode.iso_gid;
201 vap->va_atime = ip->inode.iso_atime;
202 vap->va_mtime = ip->inode.iso_mtime;
203 vap->va_ctime = ip->inode.iso_ctime;
204 vap->va_rdev = ip->inode.iso_rdev;
205
206 vap->va_size = (u_quad_t) ip->i_size;
207 if (ip->i_size == 0 && vp->v_type == VLNK) {
208 struct vop_readlink_args rdlnk;
209 struct iovec aiov;
210 struct uio auio;
211 char *cp;
212
213 MALLOC(cp, char *, MAXPATHLEN, M_TEMP, M_WAITOK);
214 aiov.iov_base = cp;
215 aiov.iov_len = MAXPATHLEN;
216 auio.uio_iov = &aiov;
217 auio.uio_iovcnt = 1;
218 auio.uio_offset = 0;
219 auio.uio_rw = UIO_READ;
220 auio.uio_resid = MAXPATHLEN;
221 UIO_SETUP_SYSSPACE(&auio);
222 rdlnk.a_uio = &auio;
223 rdlnk.a_vp = ap->a_vp;
224 rdlnk.a_cred = ap->a_cred;
225 if (cd9660_readlink(&rdlnk) == 0)
226 vap->va_size = MAXPATHLEN - auio.uio_resid;
227 FREE(cp, M_TEMP);
228 }
229 vap->va_flags = 0;
230 vap->va_gen = 1;
231 vap->va_blocksize = ip->i_mnt->logical_block_size;
232 vap->va_bytes = (u_quad_t) ip->i_size;
233 vap->va_type = vp->v_type;
234 return (0);
235 }
236
237 /*
238 * Vnode op for reading.
239 */
240 int
241 cd9660_read(v)
242 void *v;
243 {
244 struct vop_read_args /* {
245 struct vnode *a_vp;
246 struct uio *a_uio;
247 int a_ioflag;
248 kauth_cred_t a_cred;
249 } */ *ap = v;
250 struct vnode *vp = ap->a_vp;
251 struct uio *uio = ap->a_uio;
252 struct iso_node *ip = VTOI(vp);
253 struct iso_mnt *imp;
254 struct buf *bp;
255 daddr_t lbn, rablock;
256 off_t diff;
257 int rasize, error = 0;
258 long size, n, on;
259
260 if (uio->uio_resid == 0)
261 return (0);
262 if (uio->uio_offset < 0)
263 return (EINVAL);
264 if (uio->uio_offset >= ip->i_size)
265 return 0;
266 ip->i_flag |= IN_ACCESS;
267 imp = ip->i_mnt;
268
269 if (vp->v_type == VREG) {
270 const int advice = IO_ADV_DECODE(ap->a_ioflag);
271 error = 0;
272
273 while (uio->uio_resid > 0) {
274 void *win;
275 int flags;
276 vsize_t bytelen = MIN(ip->i_size - uio->uio_offset,
277 uio->uio_resid);
278
279 if (bytelen == 0)
280 break;
281 win = ubc_alloc(&vp->v_uobj, uio->uio_offset,
282 &bytelen, advice, UBC_READ);
283 error = uiomove(win, bytelen, uio);
284 flags = UBC_WANT_UNMAP(vp) ? UBC_UNMAP : 0;
285 ubc_release(win, flags);
286 if (error)
287 break;
288 }
289 goto out;
290 }
291
292 do {
293 lbn = lblkno(imp, uio->uio_offset);
294 on = blkoff(imp, uio->uio_offset);
295 n = MIN(imp->logical_block_size - on, uio->uio_resid);
296 diff = (off_t)ip->i_size - uio->uio_offset;
297 if (diff <= 0)
298 return (0);
299 if (diff < n)
300 n = diff;
301 size = blksize(imp, ip, lbn);
302 rablock = lbn + 1;
303 if (lblktosize(imp, rablock) < ip->i_size) {
304 rasize = blksize(imp, ip, rablock);
305 error = breadn(vp, lbn, size, &rablock,
306 &rasize, 1, NOCRED, &bp);
307 } else {
308 error = bread(vp, lbn, size, NOCRED, &bp);
309 }
310 n = MIN(n, size - bp->b_resid);
311 if (error) {
312 brelse(bp, 0);
313 return (error);
314 }
315
316 error = uiomove((char *)bp->b_data + on, (int)n, uio);
317 brelse(bp, 0);
318 } while (error == 0 && uio->uio_resid > 0 && n != 0);
319
320 out:
321 return (error);
322 }
323
324 int
325 iso_uiodir(idp, dp, off)
326 struct isoreaddir *idp;
327 struct dirent *dp;
328 off_t off;
329 {
330 int error;
331
332 dp->d_name[dp->d_namlen] = 0;
333 dp->d_reclen = _DIRENT_SIZE(dp);
334
335 if (idp->uio->uio_resid < dp->d_reclen) {
336 idp->eofflag = 0;
337 return (-1);
338 }
339
340 if (idp->cookies) {
341 if (idp->ncookies <= 0) {
342 idp->eofflag = 0;
343 return (-1);
344 }
345
346 *idp->cookies++ = off;
347 --idp->ncookies;
348 }
349
350 if ((error = uiomove(dp, dp->d_reclen, idp->uio)) != 0)
351 return (error);
352 idp->uio_off = off;
353 return (0);
354 }
355
356 int
357 iso_shipdir(idp)
358 struct isoreaddir *idp;
359 {
360 struct dirent *dp;
361 int cl, sl, assoc;
362 int error;
363 char *cname, *sname;
364
365 cl = idp->current.d_namlen;
366 cname = idp->current.d_name;
367
368 if ((assoc = cl > 1 && *cname == ASSOCCHAR)) {
369 cl--;
370 cname++;
371 }
372
373 dp = &idp->saveent;
374 sname = dp->d_name;
375 if (!(sl = dp->d_namlen)) {
376 dp = &idp->assocent;
377 sname = dp->d_name + 1;
378 sl = dp->d_namlen - 1;
379 }
380 if (sl > 0) {
381 if (sl != cl
382 || memcmp(sname, cname, sl)) {
383 if (idp->assocent.d_namlen) {
384 error = iso_uiodir(idp, &idp->assocent,
385 idp->assocoff);
386 if (error)
387 return (error);
388 idp->assocent.d_namlen = 0;
389 }
390 if (idp->saveent.d_namlen) {
391 error = iso_uiodir(idp, &idp->saveent,
392 idp->saveoff);
393 if (error)
394 return (error);
395 idp->saveent.d_namlen = 0;
396 }
397 }
398 }
399 idp->current.d_reclen = _DIRENT_SIZE(&idp->current);
400 if (assoc) {
401 idp->assocoff = idp->curroff;
402 memcpy(&idp->assocent, &idp->current, idp->current.d_reclen);
403 } else {
404 idp->saveoff = idp->curroff;
405 memcpy(&idp->saveent, &idp->current, idp->current.d_reclen);
406 }
407 return (0);
408 }
409
410 /*
411 * Vnode op for readdir
412 */
413 int
414 cd9660_readdir(v)
415 void *v;
416 {
417 struct vop_readdir_args /* {
418 struct vnode *a_vp;
419 struct uio *a_uio;
420 kauth_cred_t a_cred;
421 int *a_eofflag;
422 off_t **a_cookies;
423 int *a_ncookies;
424 } */ *ap = v;
425 struct uio *uio = ap->a_uio;
426 struct isoreaddir *idp;
427 struct vnode *vdp = ap->a_vp;
428 struct iso_node *dp;
429 struct iso_mnt *imp;
430 struct buf *bp = NULL;
431 struct iso_directory_record *ep;
432 int entryoffsetinblock;
433 doff_t endsearch;
434 u_long bmask;
435 int error = 0;
436 int reclen;
437 u_short namelen;
438 off_t *cookies = NULL;
439 int ncookies = 0;
440
441 if (vdp->v_type != VDIR)
442 return (ENOTDIR);
443
444 dp = VTOI(vdp);
445 imp = dp->i_mnt;
446 bmask = imp->im_bmask;
447
448 MALLOC(idp, struct isoreaddir *, sizeof(*idp), M_TEMP, M_WAITOK);
449 idp->saveent.d_namlen = idp->assocent.d_namlen = 0;
450 /*
451 * XXX
452 * Is it worth trying to figure out the type?
453 */
454 idp->saveent.d_type = idp->assocent.d_type = idp->current.d_type =
455 DT_UNKNOWN;
456 idp->uio = uio;
457 if (ap->a_ncookies == NULL)
458 idp->cookies = NULL;
459 else {
460 ncookies = uio->uio_resid / _DIRENT_MINSIZE((struct dirent *)0);
461 cookies = malloc(ncookies * sizeof(off_t), M_TEMP, M_WAITOK);
462 idp->cookies = cookies;
463 idp->ncookies = ncookies;
464 }
465 idp->eofflag = 1;
466 idp->curroff = uio->uio_offset;
467
468 if ((entryoffsetinblock = idp->curroff & bmask) &&
469 (error = cd9660_blkatoff(vdp, (off_t)idp->curroff, NULL, &bp))) {
470 FREE(idp, M_TEMP);
471 return (error);
472 }
473 endsearch = dp->i_size;
474
475 while (idp->curroff < endsearch) {
476 /*
477 * If offset is on a block boundary,
478 * read the next directory block.
479 * Release previous if it exists.
480 */
481 if ((idp->curroff & bmask) == 0) {
482 if (bp != NULL)
483 brelse(bp, 0);
484 error = cd9660_blkatoff(vdp, (off_t)idp->curroff,
485 NULL, &bp);
486 if (error)
487 break;
488 entryoffsetinblock = 0;
489 }
490 /*
491 * Get pointer to next entry.
492 */
493 KASSERT(bp != NULL);
494 ep = (struct iso_directory_record *)
495 ((char *)bp->b_data + entryoffsetinblock);
496
497 reclen = isonum_711(ep->length);
498 if (reclen == 0) {
499 /* skip to next block, if any */
500 idp->curroff =
501 (idp->curroff & ~bmask) + imp->logical_block_size;
502 continue;
503 }
504
505 if (reclen < ISO_DIRECTORY_RECORD_SIZE) {
506 error = EINVAL;
507 /* illegal entry, stop */
508 break;
509 }
510
511 if (entryoffsetinblock + reclen > imp->logical_block_size) {
512 error = EINVAL;
513 /* illegal directory, so stop looking */
514 break;
515 }
516
517 idp->current.d_namlen = isonum_711(ep->name_len);
518
519 if (reclen < ISO_DIRECTORY_RECORD_SIZE + idp->current.d_namlen) {
520 error = EINVAL;
521 /* illegal entry, stop */
522 break;
523 }
524
525 if (isonum_711(ep->flags)&2)
526 idp->current.d_fileno = isodirino(ep, imp);
527 else
528 idp->current.d_fileno = dbtob(bp->b_blkno) +
529 entryoffsetinblock;
530
531 idp->curroff += reclen;
532
533 switch (imp->iso_ftype) {
534 case ISO_FTYPE_RRIP:
535 cd9660_rrip_getname(ep, idp->current.d_name, &namelen,
536 &idp->current.d_fileno, imp);
537 idp->current.d_namlen = (u_char)namelen;
538 if (idp->current.d_namlen)
539 error = iso_uiodir(idp, &idp->current,
540 idp->curroff);
541 break;
542 default: /* ISO_FTYPE_DEFAULT || ISO_FTYPE_9660 */
543 isofntrans(ep->name, idp->current.d_namlen,
544 idp->current.d_name, &namelen,
545 imp->iso_ftype == ISO_FTYPE_9660,
546 (imp->im_flags & ISOFSMNT_NOCASETRANS) == 0,
547 isonum_711(ep->flags)&4,
548 imp->im_joliet_level);
549 switch (idp->current.d_name[0]) {
550 case 0:
551 idp->current.d_name[0] = '.';
552 idp->current.d_namlen = 1;
553 error = iso_uiodir(idp, &idp->current,
554 idp->curroff);
555 break;
556 case 1:
557 strlcpy(idp->current.d_name, "..",
558 sizeof(idp->current.d_name));
559 idp->current.d_namlen = 2;
560 error = iso_uiodir(idp, &idp->current,
561 idp->curroff);
562 break;
563 default:
564 idp->current.d_namlen = (u_char)namelen;
565 if (imp->iso_ftype == ISO_FTYPE_DEFAULT)
566 error = iso_shipdir(idp);
567 else
568 error = iso_uiodir(idp, &idp->current,
569 idp->curroff);
570 break;
571 }
572 }
573 if (error)
574 break;
575
576 entryoffsetinblock += reclen;
577 }
578
579 if (!error && imp->iso_ftype == ISO_FTYPE_DEFAULT) {
580 idp->current.d_namlen = 0;
581 error = iso_shipdir(idp);
582 }
583 if (error < 0)
584 error = 0;
585
586 if (ap->a_ncookies != NULL) {
587 if (error)
588 free(cookies, M_TEMP);
589 else {
590 /*
591 * Work out the number of cookies actually used.
592 */
593 *ap->a_ncookies = ncookies - idp->ncookies;
594 *ap->a_cookies = cookies;
595 }
596 }
597
598 if (bp)
599 brelse(bp, 0);
600
601 uio->uio_offset = idp->uio_off;
602 *ap->a_eofflag = idp->eofflag;
603
604 FREE(idp, M_TEMP);
605
606 return (error);
607 }
608
609 /*
610 * Return target name of a symbolic link
611 * Shouldn't we get the parent vnode and read the data from there?
612 * This could eventually result in deadlocks in cd9660_lookup.
613 * But otherwise the block read here is in the block buffer two times.
614 */
615 typedef struct iso_directory_record ISODIR;
616 typedef struct iso_node ISONODE;
617 typedef struct iso_mnt ISOMNT;
618 int
619 cd9660_readlink(v)
620 void *v;
621 {
622 struct vop_readlink_args /* {
623 struct vnode *a_vp;
624 struct uio *a_uio;
625 kauth_cred_t a_cred;
626 } */ *ap = v;
627 ISONODE *ip;
628 ISODIR *dirp;
629 ISOMNT *imp;
630 struct buf *bp;
631 struct uio *uio;
632 u_short symlen;
633 int error;
634 char *symname;
635 bool use_pnbuf;
636
637 ip = VTOI(ap->a_vp);
638 imp = ip->i_mnt;
639 uio = ap->a_uio;
640
641 if (imp->iso_ftype != ISO_FTYPE_RRIP)
642 return (EINVAL);
643
644 /*
645 * Get parents directory record block that this inode included.
646 */
647 error = bread(imp->im_devvp,
648 (ip->i_number >> imp->im_bshift) <<
649 (imp->im_bshift - DEV_BSHIFT),
650 imp->logical_block_size, NOCRED, &bp);
651 if (error) {
652 brelse(bp, 0);
653 return (EINVAL);
654 }
655
656 /*
657 * Setup the directory pointer for this inode
658 */
659 dirp = (ISODIR *)((char *)bp->b_data + (ip->i_number & imp->im_bmask));
660
661 /*
662 * Just make sure, we have a right one....
663 * 1: Check not cross boundary on block
664 */
665 if ((ip->i_number & imp->im_bmask) + isonum_711(dirp->length)
666 > imp->logical_block_size) {
667 brelse(bp, 0);
668 return (EINVAL);
669 }
670
671 /*
672 * Now get a buffer
673 * Abuse a namei buffer for now.
674 */
675 use_pnbuf = !VMSPACE_IS_KERNEL_P(uio->uio_vmspace) ||
676 uio->uio_iov->iov_len < MAXPATHLEN;
677 if (use_pnbuf) {
678 symname = PNBUF_GET();
679 } else {
680 symname = uio->uio_iov->iov_base;
681 }
682
683 /*
684 * Ok, we just gathering a symbolic name in SL record.
685 */
686 if (cd9660_rrip_getsymname(dirp, symname, &symlen, imp) == 0) {
687 if (use_pnbuf) {
688 PNBUF_PUT(symname);
689 }
690 brelse(bp, 0);
691 return (EINVAL);
692 }
693 /*
694 * Don't forget before you leave from home ;-)
695 */
696 brelse(bp, 0);
697
698 /*
699 * return with the symbolic name to caller's.
700 */
701 if (use_pnbuf) {
702 error = uiomove(symname, symlen, uio);
703 PNBUF_PUT(symname);
704 return (error);
705 }
706 uio->uio_resid -= symlen;
707 uio->uio_iov->iov_base = (char *)uio->uio_iov->iov_base + symlen;
708 uio->uio_iov->iov_len -= symlen;
709 return (0);
710 }
711
712 int
713 cd9660_link(v)
714 void *v;
715 {
716 struct vop_link_args /* {
717 struct vnode *a_dvp;
718 struct vnode *a_vp;
719 struct componentname *a_cnp;
720 } */ *ap = v;
721
722 VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
723 vput(ap->a_dvp);
724 return (EROFS);
725 }
726
727 int
728 cd9660_symlink(v)
729 void *v;
730 {
731 struct vop_symlink_args /* {
732 struct vnode *a_dvp;
733 struct vnode **a_vpp;
734 struct componentname *a_cnp;
735 struct vattr *a_vap;
736 char *a_target;
737 } */ *ap = v;
738
739 VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
740 vput(ap->a_dvp);
741 return (EROFS);
742 }
743
744 /*
745 * Calculate the logical to physical mapping if not done already,
746 * then call the device strategy routine.
747 */
748 int
749 cd9660_strategy(v)
750 void *v;
751 {
752 struct vop_strategy_args /* {
753 struct vnode *a_vp;
754 struct buf *a_bp;
755 } */ *ap = v;
756 struct buf *bp = ap->a_bp;
757 struct vnode *vp = ap->a_vp;
758 struct iso_node *ip;
759 int error;
760
761 ip = VTOI(vp);
762 if (vp->v_type == VBLK || vp->v_type == VCHR)
763 panic("cd9660_strategy: spec");
764 if (bp->b_blkno == bp->b_lblkno) {
765 error = VOP_BMAP(vp, bp->b_lblkno, NULL, &bp->b_blkno, NULL);
766 if (error) {
767 bp->b_error = error;
768 biodone(bp);
769 return (error);
770 }
771 if ((long)bp->b_blkno == -1)
772 clrbuf(bp);
773 }
774 if ((long)bp->b_blkno == -1) {
775 biodone(bp);
776 return (0);
777 }
778 vp = ip->i_devvp;
779 return (VOP_STRATEGY(vp, bp));
780 }
781
782 /*
783 * Print out the contents of an inode.
784 */
785 /*ARGSUSED*/
786 int
787 cd9660_print(void *v)
788 {
789
790 printf("tag VT_ISOFS, isofs vnode\n");
791 return (0);
792 }
793
794 /*
795 * Return POSIX pathconf information applicable to cd9660 filesystems.
796 */
797 int
798 cd9660_pathconf(v)
799 void *v;
800 {
801 struct vop_pathconf_args /* {
802 struct vnode *a_vp;
803 int a_name;
804 register_t *a_retval;
805 } */ *ap = v;
806 switch (ap->a_name) {
807 case _PC_LINK_MAX:
808 *ap->a_retval = 1;
809 return (0);
810 case _PC_NAME_MAX:
811 if (VTOI(ap->a_vp)->i_mnt->iso_ftype == ISO_FTYPE_RRIP)
812 *ap->a_retval = NAME_MAX;
813 else
814 *ap->a_retval = 37;
815 return (0);
816 case _PC_PATH_MAX:
817 *ap->a_retval = PATH_MAX;
818 return (0);
819 case _PC_PIPE_BUF:
820 *ap->a_retval = PIPE_BUF;
821 return (0);
822 case _PC_CHOWN_RESTRICTED:
823 *ap->a_retval = 1;
824 return (0);
825 case _PC_NO_TRUNC:
826 *ap->a_retval = 1;
827 return (0);
828 case _PC_SYNC_IO:
829 *ap->a_retval = 1;
830 return (0);
831 case _PC_FILESIZEBITS:
832 *ap->a_retval = 32;
833 return (0);
834 default:
835 return (EINVAL);
836 }
837 /* NOTREACHED */
838 }
839
840 /*
841 * Allow changing the size for special files (and fifos).
842 */
843 int
844 cd9660_setattr(v)
845 void *v;
846 {
847 struct vop_setattr_args /* {
848 struct vnodeop_desc *a_desc;
849 struct vnode *a_vp;
850 struct vattr *a_vap;
851 kauth_cred_t a_cred;
852 struct proc *a_p;
853 } */ *ap = v;
854 struct vattr *vap = ap->a_vap;
855 struct vnode *vp = ap->a_vp;
856
857 /*
858 * Only size is changeable.
859 */
860 if (vap->va_type != VNON
861 || vap->va_nlink != (nlink_t)VNOVAL
862 || vap->va_fsid != VNOVAL
863 || vap->va_fileid != VNOVAL
864 || vap->va_blocksize != VNOVAL
865 || vap->va_rdev != (dev_t)VNOVAL
866 || (int)vap->va_bytes != VNOVAL
867 || vap->va_gen != VNOVAL
868 || vap->va_flags != VNOVAL
869 || vap->va_uid != (uid_t)VNOVAL
870 || vap->va_gid != (gid_t)VNOVAL
871 || vap->va_atime.tv_sec != VNOVAL
872 || vap->va_mtime.tv_sec != VNOVAL
873 || vap->va_mode != (mode_t)VNOVAL)
874 return EOPNOTSUPP;
875
876 if (vap->va_size != VNOVAL
877 && vp->v_type != VCHR
878 && vp->v_type != VBLK
879 && vp->v_type != VFIFO)
880 return EOPNOTSUPP;
881
882 return 0;
883 }
884
885 /*
886 * Global vfs data structures for isofs
887 */
888 #define cd9660_create genfs_eopnotsupp
889 #define cd9660_mknod genfs_eopnotsupp
890 #define cd9660_write genfs_eopnotsupp
891 #define cd9660_lease_check genfs_lease_check
892 #define cd9660_fsync genfs_nullop
893 #define cd9660_remove genfs_eopnotsupp
894 #define cd9660_rename genfs_eopnotsupp
895 #define cd9660_mkdir genfs_eopnotsupp
896 #define cd9660_rmdir genfs_eopnotsupp
897 #define cd9660_advlock genfs_einval
898 #define cd9660_bwrite genfs_eopnotsupp
899 #define cd9660_revoke genfs_revoke
900
901 /*
902 * Global vfs data structures for cd9660
903 */
904 int (**cd9660_vnodeop_p)(void *);
905 const struct vnodeopv_entry_desc cd9660_vnodeop_entries[] = {
906 { &vop_default_desc, vn_default_error },
907 { &vop_lookup_desc, cd9660_lookup }, /* lookup */
908 { &vop_create_desc, cd9660_create }, /* create */
909 { &vop_mknod_desc, cd9660_mknod }, /* mknod */
910 { &vop_open_desc, cd9660_open }, /* open */
911 { &vop_close_desc, cd9660_close }, /* close */
912 { &vop_access_desc, cd9660_access }, /* access */
913 { &vop_getattr_desc, cd9660_getattr }, /* getattr */
914 { &vop_setattr_desc, cd9660_setattr }, /* setattr */
915 { &vop_read_desc, cd9660_read }, /* read */
916 { &vop_write_desc, cd9660_write }, /* write */
917 { &vop_lease_desc, cd9660_lease_check }, /* lease */
918 { &vop_fcntl_desc, genfs_fcntl }, /* fcntl */
919 { &vop_ioctl_desc, cd9660_ioctl }, /* ioctl */
920 { &vop_poll_desc, cd9660_poll }, /* poll */
921 { &vop_revoke_desc, cd9660_revoke }, /* revoke */
922 { &vop_mmap_desc, cd9660_mmap }, /* mmap */
923 { &vop_fsync_desc, cd9660_fsync }, /* fsync */
924 { &vop_seek_desc, cd9660_seek }, /* seek */
925 { &vop_remove_desc, cd9660_remove }, /* remove */
926 { &vop_link_desc, cd9660_link }, /* link */
927 { &vop_rename_desc, cd9660_rename }, /* rename */
928 { &vop_mkdir_desc, cd9660_mkdir }, /* mkdir */
929 { &vop_rmdir_desc, cd9660_rmdir }, /* rmdir */
930 { &vop_symlink_desc, cd9660_symlink }, /* symlink */
931 { &vop_readdir_desc, cd9660_readdir }, /* readdir */
932 { &vop_readlink_desc, cd9660_readlink }, /* readlink */
933 { &vop_abortop_desc, cd9660_abortop }, /* abortop */
934 { &vop_inactive_desc, cd9660_inactive }, /* inactive */
935 { &vop_reclaim_desc, cd9660_reclaim }, /* reclaim */
936 { &vop_lock_desc, genfs_lock }, /* lock */
937 { &vop_unlock_desc, genfs_unlock }, /* unlock */
938 { &vop_bmap_desc, cd9660_bmap }, /* bmap */
939 { &vop_strategy_desc, cd9660_strategy }, /* strategy */
940 { &vop_print_desc, cd9660_print }, /* print */
941 { &vop_islocked_desc, genfs_islocked }, /* islocked */
942 { &vop_pathconf_desc, cd9660_pathconf }, /* pathconf */
943 { &vop_advlock_desc, cd9660_advlock }, /* advlock */
944 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */
945 { &vop_getpages_desc, genfs_getpages }, /* getpages */
946 { &vop_putpages_desc, genfs_putpages }, /* putpages */
947 { NULL, NULL }
948 };
949 const struct vnodeopv_desc cd9660_vnodeop_opv_desc =
950 { &cd9660_vnodeop_p, cd9660_vnodeop_entries };
951
952 /*
953 * Special device vnode ops
954 */
955 int (**cd9660_specop_p)(void *);
956 const struct vnodeopv_entry_desc cd9660_specop_entries[] = {
957 { &vop_default_desc, vn_default_error },
958 { &vop_lookup_desc, spec_lookup }, /* lookup */
959 { &vop_create_desc, spec_create }, /* create */
960 { &vop_mknod_desc, spec_mknod }, /* mknod */
961 { &vop_open_desc, spec_open }, /* open */
962 { &vop_close_desc, spec_close }, /* close */
963 { &vop_access_desc, cd9660_access }, /* access */
964 { &vop_getattr_desc, cd9660_getattr }, /* getattr */
965 { &vop_setattr_desc, cd9660_setattr }, /* setattr */
966 { &vop_read_desc, spec_read }, /* read */
967 { &vop_write_desc, spec_write }, /* write */
968 { &vop_lease_desc, spec_lease_check }, /* lease */
969 { &vop_fcntl_desc, genfs_fcntl }, /* fcntl */
970 { &vop_ioctl_desc, spec_ioctl }, /* ioctl */
971 { &vop_poll_desc, spec_poll }, /* poll */
972 { &vop_kqfilter_desc, spec_kqfilter }, /* kqfilter */
973 { &vop_revoke_desc, spec_revoke }, /* revoke */
974 { &vop_mmap_desc, spec_mmap }, /* mmap */
975 { &vop_fsync_desc, spec_fsync }, /* fsync */
976 { &vop_seek_desc, spec_seek }, /* seek */
977 { &vop_remove_desc, spec_remove }, /* remove */
978 { &vop_link_desc, spec_link }, /* link */
979 { &vop_rename_desc, spec_rename }, /* rename */
980 { &vop_mkdir_desc, spec_mkdir }, /* mkdir */
981 { &vop_rmdir_desc, spec_rmdir }, /* rmdir */
982 { &vop_symlink_desc, spec_symlink }, /* symlink */
983 { &vop_readdir_desc, spec_readdir }, /* readdir */
984 { &vop_readlink_desc, spec_readlink }, /* readlink */
985 { &vop_abortop_desc, spec_abortop }, /* abortop */
986 { &vop_inactive_desc, cd9660_inactive }, /* inactive */
987 { &vop_reclaim_desc, cd9660_reclaim }, /* reclaim */
988 { &vop_lock_desc, genfs_lock }, /* lock */
989 { &vop_unlock_desc, genfs_unlock }, /* unlock */
990 { &vop_bmap_desc, spec_bmap }, /* bmap */
991 { &vop_strategy_desc, spec_strategy }, /* strategy */
992 { &vop_print_desc, cd9660_print }, /* print */
993 { &vop_islocked_desc, genfs_islocked }, /* islocked */
994 { &vop_pathconf_desc, spec_pathconf }, /* pathconf */
995 { &vop_advlock_desc, spec_advlock }, /* advlock */
996 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */
997 { &vop_getpages_desc, spec_getpages }, /* getpages */
998 { &vop_putpages_desc, spec_putpages }, /* putpages */
999 { NULL, NULL }
1000 };
1001 const struct vnodeopv_desc cd9660_specop_opv_desc =
1002 { &cd9660_specop_p, cd9660_specop_entries };
1003
1004 int (**cd9660_fifoop_p)(void *);
1005 const struct vnodeopv_entry_desc cd9660_fifoop_entries[] = {
1006 { &vop_default_desc, vn_default_error },
1007 { &vop_lookup_desc, fifo_lookup }, /* lookup */
1008 { &vop_create_desc, fifo_create }, /* create */
1009 { &vop_mknod_desc, fifo_mknod }, /* mknod */
1010 { &vop_open_desc, fifo_open }, /* open */
1011 { &vop_close_desc, fifo_close }, /* close */
1012 { &vop_access_desc, cd9660_access }, /* access */
1013 { &vop_getattr_desc, cd9660_getattr }, /* getattr */
1014 { &vop_setattr_desc, cd9660_setattr }, /* setattr */
1015 { &vop_read_desc, fifo_read }, /* read */
1016 { &vop_write_desc, fifo_write }, /* write */
1017 { &vop_lease_desc, fifo_lease_check }, /* lease */
1018 { &vop_fcntl_desc, genfs_fcntl }, /* fcntl */
1019 { &vop_ioctl_desc, fifo_ioctl }, /* ioctl */
1020 { &vop_poll_desc, fifo_poll }, /* poll */
1021 { &vop_kqfilter_desc, fifo_kqfilter }, /* kqfilter */
1022 { &vop_revoke_desc, fifo_revoke }, /* revoke */
1023 { &vop_mmap_desc, fifo_mmap }, /* mmap */
1024 { &vop_fsync_desc, fifo_fsync }, /* fsync */
1025 { &vop_seek_desc, fifo_seek }, /* seek */
1026 { &vop_remove_desc, fifo_remove }, /* remove */
1027 { &vop_link_desc, fifo_link } , /* link */
1028 { &vop_rename_desc, fifo_rename }, /* rename */
1029 { &vop_mkdir_desc, fifo_mkdir }, /* mkdir */
1030 { &vop_rmdir_desc, fifo_rmdir }, /* rmdir */
1031 { &vop_symlink_desc, fifo_symlink }, /* symlink */
1032 { &vop_readdir_desc, fifo_readdir }, /* readdir */
1033 { &vop_readlink_desc, fifo_readlink }, /* readlink */
1034 { &vop_abortop_desc, fifo_abortop }, /* abortop */
1035 { &vop_inactive_desc, cd9660_inactive }, /* inactive */
1036 { &vop_reclaim_desc, cd9660_reclaim }, /* reclaim */
1037 { &vop_lock_desc, genfs_lock }, /* lock */
1038 { &vop_unlock_desc, genfs_unlock }, /* unlock */
1039 { &vop_bmap_desc, fifo_bmap }, /* bmap */
1040 { &vop_strategy_desc, fifo_strategy }, /* strategy */
1041 { &vop_print_desc, cd9660_print }, /* print */
1042 { &vop_islocked_desc, genfs_islocked }, /* islocked */
1043 { &vop_pathconf_desc, fifo_pathconf }, /* pathconf */
1044 { &vop_advlock_desc, fifo_advlock }, /* advlock */
1045 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */
1046 { &vop_putpages_desc, fifo_putpages }, /* putpages */
1047 { NULL, NULL }
1048 };
1049 const struct vnodeopv_desc cd9660_fifoop_opv_desc =
1050 { &cd9660_fifoop_p, cd9660_fifoop_entries };
1051