Deleted Added
full compact
cd9660_vnops.c (34096) cd9660_vnops.c (37384)
1/*-
2 * Copyright (c) 1994
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley
6 * by Pace Willisson (pace@blitz.com). The Rock Ridge Extension
7 * Support code is derived from software contributed to Berkeley
8 * by Atsushi Murai (amurai@spec.co.jp).
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 *
38 * @(#)cd9660_vnops.c 8.19 (Berkeley) 5/27/95
1/*-
2 * Copyright (c) 1994
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley
6 * by Pace Willisson (pace@blitz.com). The Rock Ridge Extension
7 * Support code is derived from software contributed to Berkeley
8 * by Atsushi Murai (amurai@spec.co.jp).
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 *
38 * @(#)cd9660_vnops.c 8.19 (Berkeley) 5/27/95
39 * $Id: cd9660_vnops.c,v 1.51 1997/12/27 02:56:20 bde Exp $
39 * $Id: cd9660_vnops.c,v 1.52 1998/03/06 09:46:14 msmith Exp $
40 */
41
42#include <sys/param.h>
43#include <sys/systm.h>
44#include <sys/namei.h>
45#include <sys/kernel.h>
46#include <sys/stat.h>
47#include <sys/buf.h>
48#include <sys/mount.h>
49#include <sys/vnode.h>
50#include <miscfs/specfs/specdev.h>
51#include <miscfs/fifofs/fifo.h>
52#include <sys/malloc.h>
53#include <sys/dirent.h>
54#include <sys/unistd.h>
55
56#include <vm/vm.h>
57#include <vm/vm_zone.h>
58#include <vm/vnode_pager.h>
59
60#include <isofs/cd9660/iso.h>
61#include <isofs/cd9660/cd9660_node.h>
62#include <isofs/cd9660/iso_rrip.h>
63
64static int cd9660_setattr __P((struct vop_setattr_args *));
65static int cd9660_access __P((struct vop_access_args *));
66static int cd9660_getattr __P((struct vop_getattr_args *));
67static int cd9660_pathconf __P((struct vop_pathconf_args *));
68static int cd9660_read __P((struct vop_read_args *));
69struct isoreaddir;
70static int iso_uiodir __P((struct isoreaddir *idp, struct dirent *dp,
71 off_t off));
72static int iso_shipdir __P((struct isoreaddir *idp));
73static int cd9660_readdir __P((struct vop_readdir_args *));
74static int cd9660_readlink __P((struct vop_readlink_args *ap));
75static int cd9660_abortop __P((struct vop_abortop_args *));
76static int cd9660_strategy __P((struct vop_strategy_args *));
77static int cd9660_print __P((struct vop_print_args *));
78static int cd9660_getpages __P((struct vop_getpages_args *));
79static int cd9660_putpages __P((struct vop_putpages_args *));
80
81/*
82 * Setattr call. Only allowed for block and character special devices.
83 */
84int
85cd9660_setattr(ap)
86 struct vop_setattr_args /* {
87 struct vnodeop_desc *a_desc;
88 struct vnode *a_vp;
89 struct vattr *a_vap;
90 struct ucred *a_cred;
91 struct proc *a_p;
92 } */ *ap;
93{
94 struct vnode *vp = ap->a_vp;
95 struct vattr *vap = ap->a_vap;
96
97 if (vap->va_flags != (u_long)VNOVAL || vap->va_uid != (uid_t)VNOVAL ||
98 vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL ||
99 vap->va_mtime.tv_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL)
100 return (EROFS);
101 if (vap->va_size != (u_quad_t)VNOVAL) {
102 switch (vp->v_type) {
103 case VDIR:
104 return (EISDIR);
105 case VLNK:
106 case VREG:
107 return (EROFS);
108 case VCHR:
109 case VBLK:
110 case VSOCK:
111 case VFIFO:
112 return (0);
113 }
114 }
115 return (0);
116}
117
118/*
119 * Check mode permission on inode pointer. Mode is READ, WRITE or EXEC.
120 * The mode is shifted to select the owner/group/other fields. The
121 * super user is granted all permissions.
122 */
123/* ARGSUSED */
124static int
125cd9660_access(ap)
126 struct vop_access_args /* {
127 struct vnode *a_vp;
128 int a_mode;
129 struct ucred *a_cred;
130 struct proc *a_p;
131 } */ *ap;
132{
133 struct vnode *vp = ap->a_vp;
134 struct iso_node *ip = VTOI(vp);
135 struct ucred *cred = ap->a_cred;
136 mode_t mask, mode = ap->a_mode;
137 gid_t *gp;
138 int i;
139
140 /*
141 * Disallow write attempts unless the file is a socket,
142 * fifo, or a block or character device resident on the
143 * file system.
144 */
145 if (mode & VWRITE) {
146 switch (vp->v_type) {
147 case VDIR:
148 case VLNK:
149 case VREG:
150 return (EROFS);
151 }
152 }
153
154 /* User id 0 always gets access. */
155 if (cred->cr_uid == 0)
156 return (0);
157
158 mask = 0;
159
160 /* Otherwise, check the owner. */
161 if (cred->cr_uid == ip->inode.iso_uid) {
162 if (mode & VEXEC)
163 mask |= S_IXUSR;
164 if (mode & VREAD)
165 mask |= S_IRUSR;
166 if (mode & VWRITE)
167 mask |= S_IWUSR;
168 return ((ip->inode.iso_mode & mask) == mask ? 0 : EACCES);
169 }
170
171 /* Otherwise, check the groups. */
172 for (i = 0, gp = cred->cr_groups; i < cred->cr_ngroups; i++, gp++)
173 if (ip->inode.iso_gid == *gp) {
174 if (mode & VEXEC)
175 mask |= S_IXGRP;
176 if (mode & VREAD)
177 mask |= S_IRGRP;
178 if (mode & VWRITE)
179 mask |= S_IWGRP;
180 return ((ip->inode.iso_mode & mask) == mask ?
181 0 : EACCES);
182 }
183
184 /* Otherwise, check everyone else. */
185 if (mode & VEXEC)
186 mask |= S_IXOTH;
187 if (mode & VREAD)
188 mask |= S_IROTH;
189 if (mode & VWRITE)
190 mask |= S_IWOTH;
191 return ((ip->inode.iso_mode & mask) == mask ? 0 : EACCES);
192}
193
194static int
195cd9660_getattr(ap)
196 struct vop_getattr_args /* {
197 struct vnode *a_vp;
198 struct vattr *a_vap;
199 struct ucred *a_cred;
200 struct proc *a_p;
201 } */ *ap;
202
203{
204 struct vnode *vp = ap->a_vp;
205 register struct vattr *vap = ap->a_vap;
206 register struct iso_node *ip = VTOI(vp);
207
208 vap->va_fsid = ip->i_dev;
209 vap->va_fileid = ip->i_number;
210
211 vap->va_mode = ip->inode.iso_mode;
212 vap->va_nlink = ip->inode.iso_links;
213 vap->va_uid = ip->inode.iso_uid;
214 vap->va_gid = ip->inode.iso_gid;
215 vap->va_atime = ip->inode.iso_atime;
216 vap->va_mtime = ip->inode.iso_mtime;
217 vap->va_ctime = ip->inode.iso_ctime;
218 vap->va_rdev = ip->inode.iso_rdev;
219
220 vap->va_size = (u_quad_t) ip->i_size;
221 if (ip->i_size == 0 && (vap->va_mode & S_IFMT) == S_IFLNK) {
222 struct vop_readlink_args rdlnk;
223 struct iovec aiov;
224 struct uio auio;
225 char *cp;
226
227 MALLOC(cp, char *, MAXPATHLEN, M_TEMP, M_WAITOK);
228 aiov.iov_base = cp;
229 aiov.iov_len = MAXPATHLEN;
230 auio.uio_iov = &aiov;
231 auio.uio_iovcnt = 1;
232 auio.uio_offset = 0;
233 auio.uio_rw = UIO_READ;
234 auio.uio_segflg = UIO_SYSSPACE;
235 auio.uio_procp = ap->a_p;
236 auio.uio_resid = MAXPATHLEN;
237 rdlnk.a_uio = &auio;
238 rdlnk.a_vp = ap->a_vp;
239 rdlnk.a_cred = ap->a_cred;
240 if (cd9660_readlink(&rdlnk) == 0)
241 vap->va_size = MAXPATHLEN - auio.uio_resid;
242 FREE(cp, M_TEMP);
243 }
244 vap->va_flags = 0;
245 vap->va_gen = 1;
246 vap->va_blocksize = ip->i_mnt->logical_block_size;
247 vap->va_bytes = (u_quad_t) ip->i_size;
248 vap->va_type = vp->v_type;
249 vap->va_filerev = 0;
250 return (0);
251}
252
253/*
254 * Vnode op for reading.
255 */
256static int
257cd9660_read(ap)
258 struct vop_read_args /* {
259 struct vnode *a_vp;
260 struct uio *a_uio;
261 int a_ioflag;
262 struct ucred *a_cred;
263 } */ *ap;
264{
265 struct vnode *vp = ap->a_vp;
266 register struct uio *uio = ap->a_uio;
267 register struct iso_node *ip = VTOI(vp);
268 register struct iso_mnt *imp;
269 struct buf *bp;
270 daddr_t lbn, rablock;
271 off_t diff;
272 int rasize, error = 0;
273 long size, n, on;
274
275 if (uio->uio_resid == 0)
276 return (0);
277 if (uio->uio_offset < 0)
278 return (EINVAL);
279 ip->i_flag |= IN_ACCESS;
280 imp = ip->i_mnt;
281 do {
282 lbn = lblkno(imp, uio->uio_offset);
283 on = blkoff(imp, uio->uio_offset);
284 n = min((u_int)(imp->logical_block_size - on),
285 uio->uio_resid);
286 diff = (off_t)ip->i_size - uio->uio_offset;
287 if (diff <= 0)
288 return (0);
289 if (diff < n)
290 n = diff;
291 size = blksize(imp, ip, lbn);
292 rablock = lbn + 1;
293 if ((vp->v_mount->mnt_flag & MNT_NOCLUSTERR) == 0) {
294 if (lblktosize(imp, rablock) < ip->i_size)
295 error = cluster_read(vp, (off_t)ip->i_size,
296 lbn, size, NOCRED, uio->uio_resid,
297 (ap->a_ioflag >> 16), &bp);
298 else
299 error = bread(vp, lbn, size, NOCRED, &bp);
300 } else {
301 if (vp->v_lastr + 1 == lbn &&
302 lblktosize(imp, rablock) < ip->i_size) {
303 rasize = blksize(imp, ip, rablock);
304 error = breadn(vp, lbn, size, &rablock,
305 &rasize, 1, NOCRED, &bp);
306 } else
307 error = bread(vp, lbn, size, NOCRED, &bp);
308 }
309 vp->v_lastr = lbn;
310 n = min(n, size - bp->b_resid);
311 if (error) {
312 brelse(bp);
313 return (error);
314 }
315
316 error = uiomove(bp->b_data + on, (int)n, uio);
317 brelse(bp);
318 } while (error == 0 && uio->uio_resid > 0 && n != 0);
319 return (error);
320}
321
322/*
323 * Structure for reading directories
324 */
325struct isoreaddir {
326 struct dirent saveent;
327 struct dirent assocent;
328 struct dirent current;
329 off_t saveoff;
330 off_t assocoff;
331 off_t curroff;
332 struct uio *uio;
333 off_t uio_off;
334 int eofflag;
335 u_long *cookies;
336 int ncookies;
337};
338
339int
340iso_uiodir(idp,dp,off)
341 struct isoreaddir *idp;
342 struct dirent *dp;
343 off_t off;
344{
345 int error;
346
347 dp->d_name[dp->d_namlen] = 0;
348 dp->d_reclen = GENERIC_DIRSIZ(dp);
349
350 if (idp->uio->uio_resid < dp->d_reclen) {
351 idp->eofflag = 0;
352 return (-1);
353 }
354
355 if (idp->cookies) {
356 if (idp->ncookies <= 0) {
357 idp->eofflag = 0;
358 return (-1);
359 }
360
361 *idp->cookies++ = off;
362 --idp->ncookies;
363 }
364
365 if (error = uiomove((caddr_t) dp,dp->d_reclen,idp->uio))
366 return (error);
367 idp->uio_off = off;
368 return (0);
369}
370
371int
372iso_shipdir(idp)
373 struct isoreaddir *idp;
374{
375 struct dirent *dp;
376 int cl, sl, assoc;
377 int error;
378 char *cname, *sname;
379
380 cl = idp->current.d_namlen;
381 cname = idp->current.d_name;
382assoc = (cl > 1) && (*cname == ASSOCCHAR);
383 if (assoc) {
384 cl--;
385 cname++;
386 }
387
388 dp = &idp->saveent;
389 sname = dp->d_name;
390 if (!(sl = dp->d_namlen)) {
391 dp = &idp->assocent;
392 sname = dp->d_name + 1;
393 sl = dp->d_namlen - 1;
394 }
395 if (sl > 0) {
396 if (sl != cl
397 || bcmp(sname,cname,sl)) {
398 if (idp->assocent.d_namlen) {
399 if (error = iso_uiodir(idp,&idp->assocent,idp->assocoff))
400 return (error);
401 idp->assocent.d_namlen = 0;
402 }
403 if (idp->saveent.d_namlen) {
404 if (error = iso_uiodir(idp,&idp->saveent,idp->saveoff))
405 return (error);
406 idp->saveent.d_namlen = 0;
407 }
408 }
409 }
410 idp->current.d_reclen = GENERIC_DIRSIZ(&idp->current);
411 if (assoc) {
412 idp->assocoff = idp->curroff;
413 bcopy(&idp->current,&idp->assocent,idp->current.d_reclen);
414 } else {
415 idp->saveoff = idp->curroff;
416 bcopy(&idp->current,&idp->saveent,idp->current.d_reclen);
417 }
418 return (0);
419}
420
421/*
422 * Vnode op for readdir
423 */
424static int
425cd9660_readdir(ap)
426 struct vop_readdir_args /* {
427 struct vnode *a_vp;
428 struct uio *a_uio;
429 struct ucred *a_cred;
430 int *a_eofflag;
431 int *a_ncookies;
432 u_long *a_cookies;
433 } */ *ap;
434{
435 register struct uio *uio = ap->a_uio;
436 struct isoreaddir *idp;
437 struct vnode *vdp = ap->a_vp;
438 struct iso_node *dp;
439 struct iso_mnt *imp;
440 struct buf *bp = NULL;
441 struct iso_directory_record *ep;
442 int entryoffsetinblock;
443 doff_t endsearch;
444 u_long bmask;
445 int error = 0;
446 int reclen;
447 u_short namelen;
448 int ncookies = 0;
449 u_long *cookies = NULL;
450
451 dp = VTOI(vdp);
452 imp = dp->i_mnt;
453 bmask = imp->im_bmask;
454
455 MALLOC(idp, struct isoreaddir *, sizeof(*idp), M_TEMP, M_WAITOK);
456 idp->saveent.d_namlen = idp->assocent.d_namlen = 0;
457 /*
458 * XXX
459 * Is it worth trying to figure out the type?
460 */
461 idp->saveent.d_type = idp->assocent.d_type = idp->current.d_type =
462 DT_UNKNOWN;
463 idp->uio = uio;
464 if (ap->a_ncookies == NULL) {
465 idp->cookies = NULL;
466 } else {
467 /*
468 * Guess the number of cookies needed.
469 */
470 ncookies = uio->uio_resid / 16;
471 MALLOC(cookies, u_long *, ncookies * sizeof(u_int), M_TEMP,
472 M_WAITOK);
473 idp->cookies = cookies;
474 idp->ncookies = ncookies;
475 }
476 idp->eofflag = 1;
477 idp->curroff = uio->uio_offset;
478
479 if ((entryoffsetinblock = idp->curroff & bmask) &&
480 (error = cd9660_blkatoff(vdp, (off_t)idp->curroff, NULL, &bp))) {
481 FREE(idp, M_TEMP);
482 return (error);
483 }
484 endsearch = dp->i_size;
485
486 while (idp->curroff < endsearch) {
487 /*
488 * If offset is on a block boundary,
489 * read the next directory block.
490 * Release previous if it exists.
491 */
492 if ((idp->curroff & bmask) == 0) {
493 if (bp != NULL)
494 brelse(bp);
495 if (error =
496 cd9660_blkatoff(vdp, (off_t)idp->curroff, NULL, &bp))
497 break;
498 entryoffsetinblock = 0;
499 }
500 /*
501 * Get pointer to next entry.
502 */
503 ep = (struct iso_directory_record *)
504 ((char *)bp->b_data + entryoffsetinblock);
505
506 reclen = isonum_711(ep->length);
507 if (reclen == 0) {
508 /* skip to next block, if any */
509 idp->curroff =
510 (idp->curroff & ~bmask) + imp->logical_block_size;
511 continue;
512 }
513
514 if (reclen < ISO_DIRECTORY_RECORD_SIZE) {
515 error = EINVAL;
516 /* illegal entry, stop */
517 break;
518 }
519
520 if (entryoffsetinblock + reclen > imp->logical_block_size) {
521 error = EINVAL;
522 /* illegal directory, so stop looking */
523 break;
524 }
525
526 idp->current.d_namlen = isonum_711(ep->name_len);
527
528 if (reclen < ISO_DIRECTORY_RECORD_SIZE + idp->current.d_namlen) {
529 error = EINVAL;
530 /* illegal entry, stop */
531 break;
532 }
533
534 if (isonum_711(ep->flags)&2)
535 idp->current.d_fileno = isodirino(ep, imp);
536 else
537 idp->current.d_fileno = dbtob(bp->b_blkno) +
538 entryoffsetinblock;
539
540 idp->curroff += reclen;
541
542 switch (imp->iso_ftype) {
543 case ISO_FTYPE_RRIP:
544 cd9660_rrip_getname(ep,idp->current.d_name, &namelen,
545 &idp->current.d_fileno,imp);
546 idp->current.d_namlen = (u_char)namelen;
547 if (idp->current.d_namlen)
548 error = iso_uiodir(idp,&idp->current,idp->curroff);
549 break;
550 default: /* ISO_FTYPE_DEFAULT || ISO_FTYPE_9660 || ISO_FTYPE_HIGH_SIERRA*/
551 strcpy(idp->current.d_name,"..");
552 switch (ep->name[0]) {
553 case 0:
554 idp->current.d_namlen = 1;
555 error = iso_uiodir(idp,&idp->current,idp->curroff);
556 break;
557 case 1:
558 idp->current.d_namlen = 2;
559 error = iso_uiodir(idp,&idp->current,idp->curroff);
560 break;
561 default:
562 isofntrans(ep->name,idp->current.d_namlen,
563 idp->current.d_name, &namelen,
564 imp->iso_ftype == ISO_FTYPE_9660,
565 isonum_711(ep->flags)&4);
566 idp->current.d_namlen = (u_char)namelen;
567 if (imp->iso_ftype == ISO_FTYPE_DEFAULT)
568 error = iso_shipdir(idp);
569 else
570 error = iso_uiodir(idp,&idp->current,idp->curroff);
571 break;
572 }
573 }
574 if (error)
575 break;
576
577 entryoffsetinblock += reclen;
578 }
579
580 if (!error && imp->iso_ftype == ISO_FTYPE_DEFAULT) {
581 idp->current.d_namlen = 0;
582 error = iso_shipdir(idp);
583 }
584 if (error < 0)
585 error = 0;
586
587 if (ap->a_ncookies != NULL) {
588 if (error)
589 free(cookies, M_TEMP);
590 else {
591 /*
592 * Work out the number of cookies actually used.
593 */
594 *ap->a_ncookies = ncookies - idp->ncookies;
595 *ap->a_cookies = cookies;
596 }
597 }
598
599 if (bp)
600 brelse (bp);
601
602 uio->uio_offset = idp->uio_off;
603 *ap->a_eofflag = idp->eofflag;
604
605 FREE(idp, M_TEMP);
606
607 return (error);
608}
609
610/*
611 * Return target name of a symbolic link
612 * Shouldn't we get the parent vnode and read the data from there?
613 * This could eventually result in deadlocks in cd9660_lookup.
614 * But otherwise the block read here is in the block buffer two times.
615 */
616typedef struct iso_directory_record ISODIR;
617typedef struct iso_node ISONODE;
618typedef struct iso_mnt ISOMNT;
619static int
620cd9660_readlink(ap)
621 struct vop_readlink_args /* {
622 struct vnode *a_vp;
623 struct uio *a_uio;
624 struct ucred *a_cred;
625 } */ *ap;
626{
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
636 ip = VTOI(ap->a_vp);
637 imp = ip->i_mnt;
638 uio = ap->a_uio;
639
640 if (imp->iso_ftype != ISO_FTYPE_RRIP)
641 return (EINVAL);
642
643 /*
644 * Get parents directory record block that this inode included.
645 */
646 error = bread(imp->im_devvp,
647 (ip->i_number >> imp->im_bshift) <<
648 (imp->im_bshift - DEV_BSHIFT),
649 imp->logical_block_size, NOCRED, &bp);
650 if (error) {
651 brelse(bp);
652 return (EINVAL);
653 }
654
655 /*
656 * Setup the directory pointer for this inode
657 */
658 dirp = (ISODIR *)(bp->b_data + (ip->i_number & imp->im_bmask));
659
660 /*
661 * Just make sure, we have a right one....
662 * 1: Check not cross boundary on block
663 */
664 if ((ip->i_number & imp->im_bmask) + isonum_711(dirp->length)
665 > (unsigned)imp->logical_block_size) {
666 brelse(bp);
667 return (EINVAL);
668 }
669
670 /*
671 * Now get a buffer
672 * Abuse a namei buffer for now.
673 */
674 if (uio->uio_segflg == UIO_SYSSPACE)
675 symname = uio->uio_iov->iov_base;
676 else
677 symname = zalloc(namei_zone);
678
679 /*
680 * Ok, we just gathering a symbolic name in SL record.
681 */
682 if (cd9660_rrip_getsymname(dirp, symname, &symlen, imp) == 0) {
683 if (uio->uio_segflg != UIO_SYSSPACE)
684 zfree(namei_zone, symname);
685 brelse(bp);
686 return (EINVAL);
687 }
688 /*
689 * Don't forget before you leave from home ;-)
690 */
691 brelse(bp);
692
693 /*
694 * return with the symbolic name to caller's.
695 */
696 if (uio->uio_segflg != UIO_SYSSPACE) {
697 error = uiomove(symname, symlen, uio);
698 zfree(namei_zone, symname);
699 return (error);
700 }
701 uio->uio_resid -= symlen;
702 uio->uio_iov->iov_base += symlen;
703 uio->uio_iov->iov_len -= symlen;
704 return (0);
705}
706
707/*
708 * Ufs abort op, called after namei() when a CREATE/DELETE isn't actually
709 * done. If a buffer has been saved in anticipation of a CREATE, delete it.
710 */
711static int
712cd9660_abortop(ap)
713 struct vop_abortop_args /* {
714 struct vnode *a_dvp;
715 struct componentname *a_cnp;
716 } */ *ap;
717{
718 if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF)
719 zfree(namei_zone, ap->a_cnp->cn_pnbuf);
720 return (0);
721}
722
723/*
724 * Calculate the logical to physical mapping if not done already,
725 * then call the device strategy routine.
726 */
727static int
728cd9660_strategy(ap)
729 struct vop_strategy_args /* {
40 */
41
42#include <sys/param.h>
43#include <sys/systm.h>
44#include <sys/namei.h>
45#include <sys/kernel.h>
46#include <sys/stat.h>
47#include <sys/buf.h>
48#include <sys/mount.h>
49#include <sys/vnode.h>
50#include <miscfs/specfs/specdev.h>
51#include <miscfs/fifofs/fifo.h>
52#include <sys/malloc.h>
53#include <sys/dirent.h>
54#include <sys/unistd.h>
55
56#include <vm/vm.h>
57#include <vm/vm_zone.h>
58#include <vm/vnode_pager.h>
59
60#include <isofs/cd9660/iso.h>
61#include <isofs/cd9660/cd9660_node.h>
62#include <isofs/cd9660/iso_rrip.h>
63
64static int cd9660_setattr __P((struct vop_setattr_args *));
65static int cd9660_access __P((struct vop_access_args *));
66static int cd9660_getattr __P((struct vop_getattr_args *));
67static int cd9660_pathconf __P((struct vop_pathconf_args *));
68static int cd9660_read __P((struct vop_read_args *));
69struct isoreaddir;
70static int iso_uiodir __P((struct isoreaddir *idp, struct dirent *dp,
71 off_t off));
72static int iso_shipdir __P((struct isoreaddir *idp));
73static int cd9660_readdir __P((struct vop_readdir_args *));
74static int cd9660_readlink __P((struct vop_readlink_args *ap));
75static int cd9660_abortop __P((struct vop_abortop_args *));
76static int cd9660_strategy __P((struct vop_strategy_args *));
77static int cd9660_print __P((struct vop_print_args *));
78static int cd9660_getpages __P((struct vop_getpages_args *));
79static int cd9660_putpages __P((struct vop_putpages_args *));
80
81/*
82 * Setattr call. Only allowed for block and character special devices.
83 */
84int
85cd9660_setattr(ap)
86 struct vop_setattr_args /* {
87 struct vnodeop_desc *a_desc;
88 struct vnode *a_vp;
89 struct vattr *a_vap;
90 struct ucred *a_cred;
91 struct proc *a_p;
92 } */ *ap;
93{
94 struct vnode *vp = ap->a_vp;
95 struct vattr *vap = ap->a_vap;
96
97 if (vap->va_flags != (u_long)VNOVAL || vap->va_uid != (uid_t)VNOVAL ||
98 vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL ||
99 vap->va_mtime.tv_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL)
100 return (EROFS);
101 if (vap->va_size != (u_quad_t)VNOVAL) {
102 switch (vp->v_type) {
103 case VDIR:
104 return (EISDIR);
105 case VLNK:
106 case VREG:
107 return (EROFS);
108 case VCHR:
109 case VBLK:
110 case VSOCK:
111 case VFIFO:
112 return (0);
113 }
114 }
115 return (0);
116}
117
118/*
119 * Check mode permission on inode pointer. Mode is READ, WRITE or EXEC.
120 * The mode is shifted to select the owner/group/other fields. The
121 * super user is granted all permissions.
122 */
123/* ARGSUSED */
124static int
125cd9660_access(ap)
126 struct vop_access_args /* {
127 struct vnode *a_vp;
128 int a_mode;
129 struct ucred *a_cred;
130 struct proc *a_p;
131 } */ *ap;
132{
133 struct vnode *vp = ap->a_vp;
134 struct iso_node *ip = VTOI(vp);
135 struct ucred *cred = ap->a_cred;
136 mode_t mask, mode = ap->a_mode;
137 gid_t *gp;
138 int i;
139
140 /*
141 * Disallow write attempts unless the file is a socket,
142 * fifo, or a block or character device resident on the
143 * file system.
144 */
145 if (mode & VWRITE) {
146 switch (vp->v_type) {
147 case VDIR:
148 case VLNK:
149 case VREG:
150 return (EROFS);
151 }
152 }
153
154 /* User id 0 always gets access. */
155 if (cred->cr_uid == 0)
156 return (0);
157
158 mask = 0;
159
160 /* Otherwise, check the owner. */
161 if (cred->cr_uid == ip->inode.iso_uid) {
162 if (mode & VEXEC)
163 mask |= S_IXUSR;
164 if (mode & VREAD)
165 mask |= S_IRUSR;
166 if (mode & VWRITE)
167 mask |= S_IWUSR;
168 return ((ip->inode.iso_mode & mask) == mask ? 0 : EACCES);
169 }
170
171 /* Otherwise, check the groups. */
172 for (i = 0, gp = cred->cr_groups; i < cred->cr_ngroups; i++, gp++)
173 if (ip->inode.iso_gid == *gp) {
174 if (mode & VEXEC)
175 mask |= S_IXGRP;
176 if (mode & VREAD)
177 mask |= S_IRGRP;
178 if (mode & VWRITE)
179 mask |= S_IWGRP;
180 return ((ip->inode.iso_mode & mask) == mask ?
181 0 : EACCES);
182 }
183
184 /* Otherwise, check everyone else. */
185 if (mode & VEXEC)
186 mask |= S_IXOTH;
187 if (mode & VREAD)
188 mask |= S_IROTH;
189 if (mode & VWRITE)
190 mask |= S_IWOTH;
191 return ((ip->inode.iso_mode & mask) == mask ? 0 : EACCES);
192}
193
194static int
195cd9660_getattr(ap)
196 struct vop_getattr_args /* {
197 struct vnode *a_vp;
198 struct vattr *a_vap;
199 struct ucred *a_cred;
200 struct proc *a_p;
201 } */ *ap;
202
203{
204 struct vnode *vp = ap->a_vp;
205 register struct vattr *vap = ap->a_vap;
206 register struct iso_node *ip = VTOI(vp);
207
208 vap->va_fsid = ip->i_dev;
209 vap->va_fileid = ip->i_number;
210
211 vap->va_mode = ip->inode.iso_mode;
212 vap->va_nlink = ip->inode.iso_links;
213 vap->va_uid = ip->inode.iso_uid;
214 vap->va_gid = ip->inode.iso_gid;
215 vap->va_atime = ip->inode.iso_atime;
216 vap->va_mtime = ip->inode.iso_mtime;
217 vap->va_ctime = ip->inode.iso_ctime;
218 vap->va_rdev = ip->inode.iso_rdev;
219
220 vap->va_size = (u_quad_t) ip->i_size;
221 if (ip->i_size == 0 && (vap->va_mode & S_IFMT) == S_IFLNK) {
222 struct vop_readlink_args rdlnk;
223 struct iovec aiov;
224 struct uio auio;
225 char *cp;
226
227 MALLOC(cp, char *, MAXPATHLEN, M_TEMP, M_WAITOK);
228 aiov.iov_base = cp;
229 aiov.iov_len = MAXPATHLEN;
230 auio.uio_iov = &aiov;
231 auio.uio_iovcnt = 1;
232 auio.uio_offset = 0;
233 auio.uio_rw = UIO_READ;
234 auio.uio_segflg = UIO_SYSSPACE;
235 auio.uio_procp = ap->a_p;
236 auio.uio_resid = MAXPATHLEN;
237 rdlnk.a_uio = &auio;
238 rdlnk.a_vp = ap->a_vp;
239 rdlnk.a_cred = ap->a_cred;
240 if (cd9660_readlink(&rdlnk) == 0)
241 vap->va_size = MAXPATHLEN - auio.uio_resid;
242 FREE(cp, M_TEMP);
243 }
244 vap->va_flags = 0;
245 vap->va_gen = 1;
246 vap->va_blocksize = ip->i_mnt->logical_block_size;
247 vap->va_bytes = (u_quad_t) ip->i_size;
248 vap->va_type = vp->v_type;
249 vap->va_filerev = 0;
250 return (0);
251}
252
253/*
254 * Vnode op for reading.
255 */
256static int
257cd9660_read(ap)
258 struct vop_read_args /* {
259 struct vnode *a_vp;
260 struct uio *a_uio;
261 int a_ioflag;
262 struct ucred *a_cred;
263 } */ *ap;
264{
265 struct vnode *vp = ap->a_vp;
266 register struct uio *uio = ap->a_uio;
267 register struct iso_node *ip = VTOI(vp);
268 register struct iso_mnt *imp;
269 struct buf *bp;
270 daddr_t lbn, rablock;
271 off_t diff;
272 int rasize, error = 0;
273 long size, n, on;
274
275 if (uio->uio_resid == 0)
276 return (0);
277 if (uio->uio_offset < 0)
278 return (EINVAL);
279 ip->i_flag |= IN_ACCESS;
280 imp = ip->i_mnt;
281 do {
282 lbn = lblkno(imp, uio->uio_offset);
283 on = blkoff(imp, uio->uio_offset);
284 n = min((u_int)(imp->logical_block_size - on),
285 uio->uio_resid);
286 diff = (off_t)ip->i_size - uio->uio_offset;
287 if (diff <= 0)
288 return (0);
289 if (diff < n)
290 n = diff;
291 size = blksize(imp, ip, lbn);
292 rablock = lbn + 1;
293 if ((vp->v_mount->mnt_flag & MNT_NOCLUSTERR) == 0) {
294 if (lblktosize(imp, rablock) < ip->i_size)
295 error = cluster_read(vp, (off_t)ip->i_size,
296 lbn, size, NOCRED, uio->uio_resid,
297 (ap->a_ioflag >> 16), &bp);
298 else
299 error = bread(vp, lbn, size, NOCRED, &bp);
300 } else {
301 if (vp->v_lastr + 1 == lbn &&
302 lblktosize(imp, rablock) < ip->i_size) {
303 rasize = blksize(imp, ip, rablock);
304 error = breadn(vp, lbn, size, &rablock,
305 &rasize, 1, NOCRED, &bp);
306 } else
307 error = bread(vp, lbn, size, NOCRED, &bp);
308 }
309 vp->v_lastr = lbn;
310 n = min(n, size - bp->b_resid);
311 if (error) {
312 brelse(bp);
313 return (error);
314 }
315
316 error = uiomove(bp->b_data + on, (int)n, uio);
317 brelse(bp);
318 } while (error == 0 && uio->uio_resid > 0 && n != 0);
319 return (error);
320}
321
322/*
323 * Structure for reading directories
324 */
325struct isoreaddir {
326 struct dirent saveent;
327 struct dirent assocent;
328 struct dirent current;
329 off_t saveoff;
330 off_t assocoff;
331 off_t curroff;
332 struct uio *uio;
333 off_t uio_off;
334 int eofflag;
335 u_long *cookies;
336 int ncookies;
337};
338
339int
340iso_uiodir(idp,dp,off)
341 struct isoreaddir *idp;
342 struct dirent *dp;
343 off_t off;
344{
345 int error;
346
347 dp->d_name[dp->d_namlen] = 0;
348 dp->d_reclen = GENERIC_DIRSIZ(dp);
349
350 if (idp->uio->uio_resid < dp->d_reclen) {
351 idp->eofflag = 0;
352 return (-1);
353 }
354
355 if (idp->cookies) {
356 if (idp->ncookies <= 0) {
357 idp->eofflag = 0;
358 return (-1);
359 }
360
361 *idp->cookies++ = off;
362 --idp->ncookies;
363 }
364
365 if (error = uiomove((caddr_t) dp,dp->d_reclen,idp->uio))
366 return (error);
367 idp->uio_off = off;
368 return (0);
369}
370
371int
372iso_shipdir(idp)
373 struct isoreaddir *idp;
374{
375 struct dirent *dp;
376 int cl, sl, assoc;
377 int error;
378 char *cname, *sname;
379
380 cl = idp->current.d_namlen;
381 cname = idp->current.d_name;
382assoc = (cl > 1) && (*cname == ASSOCCHAR);
383 if (assoc) {
384 cl--;
385 cname++;
386 }
387
388 dp = &idp->saveent;
389 sname = dp->d_name;
390 if (!(sl = dp->d_namlen)) {
391 dp = &idp->assocent;
392 sname = dp->d_name + 1;
393 sl = dp->d_namlen - 1;
394 }
395 if (sl > 0) {
396 if (sl != cl
397 || bcmp(sname,cname,sl)) {
398 if (idp->assocent.d_namlen) {
399 if (error = iso_uiodir(idp,&idp->assocent,idp->assocoff))
400 return (error);
401 idp->assocent.d_namlen = 0;
402 }
403 if (idp->saveent.d_namlen) {
404 if (error = iso_uiodir(idp,&idp->saveent,idp->saveoff))
405 return (error);
406 idp->saveent.d_namlen = 0;
407 }
408 }
409 }
410 idp->current.d_reclen = GENERIC_DIRSIZ(&idp->current);
411 if (assoc) {
412 idp->assocoff = idp->curroff;
413 bcopy(&idp->current,&idp->assocent,idp->current.d_reclen);
414 } else {
415 idp->saveoff = idp->curroff;
416 bcopy(&idp->current,&idp->saveent,idp->current.d_reclen);
417 }
418 return (0);
419}
420
421/*
422 * Vnode op for readdir
423 */
424static int
425cd9660_readdir(ap)
426 struct vop_readdir_args /* {
427 struct vnode *a_vp;
428 struct uio *a_uio;
429 struct ucred *a_cred;
430 int *a_eofflag;
431 int *a_ncookies;
432 u_long *a_cookies;
433 } */ *ap;
434{
435 register struct uio *uio = ap->a_uio;
436 struct isoreaddir *idp;
437 struct vnode *vdp = ap->a_vp;
438 struct iso_node *dp;
439 struct iso_mnt *imp;
440 struct buf *bp = NULL;
441 struct iso_directory_record *ep;
442 int entryoffsetinblock;
443 doff_t endsearch;
444 u_long bmask;
445 int error = 0;
446 int reclen;
447 u_short namelen;
448 int ncookies = 0;
449 u_long *cookies = NULL;
450
451 dp = VTOI(vdp);
452 imp = dp->i_mnt;
453 bmask = imp->im_bmask;
454
455 MALLOC(idp, struct isoreaddir *, sizeof(*idp), M_TEMP, M_WAITOK);
456 idp->saveent.d_namlen = idp->assocent.d_namlen = 0;
457 /*
458 * XXX
459 * Is it worth trying to figure out the type?
460 */
461 idp->saveent.d_type = idp->assocent.d_type = idp->current.d_type =
462 DT_UNKNOWN;
463 idp->uio = uio;
464 if (ap->a_ncookies == NULL) {
465 idp->cookies = NULL;
466 } else {
467 /*
468 * Guess the number of cookies needed.
469 */
470 ncookies = uio->uio_resid / 16;
471 MALLOC(cookies, u_long *, ncookies * sizeof(u_int), M_TEMP,
472 M_WAITOK);
473 idp->cookies = cookies;
474 idp->ncookies = ncookies;
475 }
476 idp->eofflag = 1;
477 idp->curroff = uio->uio_offset;
478
479 if ((entryoffsetinblock = idp->curroff & bmask) &&
480 (error = cd9660_blkatoff(vdp, (off_t)idp->curroff, NULL, &bp))) {
481 FREE(idp, M_TEMP);
482 return (error);
483 }
484 endsearch = dp->i_size;
485
486 while (idp->curroff < endsearch) {
487 /*
488 * If offset is on a block boundary,
489 * read the next directory block.
490 * Release previous if it exists.
491 */
492 if ((idp->curroff & bmask) == 0) {
493 if (bp != NULL)
494 brelse(bp);
495 if (error =
496 cd9660_blkatoff(vdp, (off_t)idp->curroff, NULL, &bp))
497 break;
498 entryoffsetinblock = 0;
499 }
500 /*
501 * Get pointer to next entry.
502 */
503 ep = (struct iso_directory_record *)
504 ((char *)bp->b_data + entryoffsetinblock);
505
506 reclen = isonum_711(ep->length);
507 if (reclen == 0) {
508 /* skip to next block, if any */
509 idp->curroff =
510 (idp->curroff & ~bmask) + imp->logical_block_size;
511 continue;
512 }
513
514 if (reclen < ISO_DIRECTORY_RECORD_SIZE) {
515 error = EINVAL;
516 /* illegal entry, stop */
517 break;
518 }
519
520 if (entryoffsetinblock + reclen > imp->logical_block_size) {
521 error = EINVAL;
522 /* illegal directory, so stop looking */
523 break;
524 }
525
526 idp->current.d_namlen = isonum_711(ep->name_len);
527
528 if (reclen < ISO_DIRECTORY_RECORD_SIZE + idp->current.d_namlen) {
529 error = EINVAL;
530 /* illegal entry, stop */
531 break;
532 }
533
534 if (isonum_711(ep->flags)&2)
535 idp->current.d_fileno = isodirino(ep, imp);
536 else
537 idp->current.d_fileno = dbtob(bp->b_blkno) +
538 entryoffsetinblock;
539
540 idp->curroff += reclen;
541
542 switch (imp->iso_ftype) {
543 case ISO_FTYPE_RRIP:
544 cd9660_rrip_getname(ep,idp->current.d_name, &namelen,
545 &idp->current.d_fileno,imp);
546 idp->current.d_namlen = (u_char)namelen;
547 if (idp->current.d_namlen)
548 error = iso_uiodir(idp,&idp->current,idp->curroff);
549 break;
550 default: /* ISO_FTYPE_DEFAULT || ISO_FTYPE_9660 || ISO_FTYPE_HIGH_SIERRA*/
551 strcpy(idp->current.d_name,"..");
552 switch (ep->name[0]) {
553 case 0:
554 idp->current.d_namlen = 1;
555 error = iso_uiodir(idp,&idp->current,idp->curroff);
556 break;
557 case 1:
558 idp->current.d_namlen = 2;
559 error = iso_uiodir(idp,&idp->current,idp->curroff);
560 break;
561 default:
562 isofntrans(ep->name,idp->current.d_namlen,
563 idp->current.d_name, &namelen,
564 imp->iso_ftype == ISO_FTYPE_9660,
565 isonum_711(ep->flags)&4);
566 idp->current.d_namlen = (u_char)namelen;
567 if (imp->iso_ftype == ISO_FTYPE_DEFAULT)
568 error = iso_shipdir(idp);
569 else
570 error = iso_uiodir(idp,&idp->current,idp->curroff);
571 break;
572 }
573 }
574 if (error)
575 break;
576
577 entryoffsetinblock += reclen;
578 }
579
580 if (!error && imp->iso_ftype == ISO_FTYPE_DEFAULT) {
581 idp->current.d_namlen = 0;
582 error = iso_shipdir(idp);
583 }
584 if (error < 0)
585 error = 0;
586
587 if (ap->a_ncookies != NULL) {
588 if (error)
589 free(cookies, M_TEMP);
590 else {
591 /*
592 * Work out the number of cookies actually used.
593 */
594 *ap->a_ncookies = ncookies - idp->ncookies;
595 *ap->a_cookies = cookies;
596 }
597 }
598
599 if (bp)
600 brelse (bp);
601
602 uio->uio_offset = idp->uio_off;
603 *ap->a_eofflag = idp->eofflag;
604
605 FREE(idp, M_TEMP);
606
607 return (error);
608}
609
610/*
611 * Return target name of a symbolic link
612 * Shouldn't we get the parent vnode and read the data from there?
613 * This could eventually result in deadlocks in cd9660_lookup.
614 * But otherwise the block read here is in the block buffer two times.
615 */
616typedef struct iso_directory_record ISODIR;
617typedef struct iso_node ISONODE;
618typedef struct iso_mnt ISOMNT;
619static int
620cd9660_readlink(ap)
621 struct vop_readlink_args /* {
622 struct vnode *a_vp;
623 struct uio *a_uio;
624 struct ucred *a_cred;
625 } */ *ap;
626{
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
636 ip = VTOI(ap->a_vp);
637 imp = ip->i_mnt;
638 uio = ap->a_uio;
639
640 if (imp->iso_ftype != ISO_FTYPE_RRIP)
641 return (EINVAL);
642
643 /*
644 * Get parents directory record block that this inode included.
645 */
646 error = bread(imp->im_devvp,
647 (ip->i_number >> imp->im_bshift) <<
648 (imp->im_bshift - DEV_BSHIFT),
649 imp->logical_block_size, NOCRED, &bp);
650 if (error) {
651 brelse(bp);
652 return (EINVAL);
653 }
654
655 /*
656 * Setup the directory pointer for this inode
657 */
658 dirp = (ISODIR *)(bp->b_data + (ip->i_number & imp->im_bmask));
659
660 /*
661 * Just make sure, we have a right one....
662 * 1: Check not cross boundary on block
663 */
664 if ((ip->i_number & imp->im_bmask) + isonum_711(dirp->length)
665 > (unsigned)imp->logical_block_size) {
666 brelse(bp);
667 return (EINVAL);
668 }
669
670 /*
671 * Now get a buffer
672 * Abuse a namei buffer for now.
673 */
674 if (uio->uio_segflg == UIO_SYSSPACE)
675 symname = uio->uio_iov->iov_base;
676 else
677 symname = zalloc(namei_zone);
678
679 /*
680 * Ok, we just gathering a symbolic name in SL record.
681 */
682 if (cd9660_rrip_getsymname(dirp, symname, &symlen, imp) == 0) {
683 if (uio->uio_segflg != UIO_SYSSPACE)
684 zfree(namei_zone, symname);
685 brelse(bp);
686 return (EINVAL);
687 }
688 /*
689 * Don't forget before you leave from home ;-)
690 */
691 brelse(bp);
692
693 /*
694 * return with the symbolic name to caller's.
695 */
696 if (uio->uio_segflg != UIO_SYSSPACE) {
697 error = uiomove(symname, symlen, uio);
698 zfree(namei_zone, symname);
699 return (error);
700 }
701 uio->uio_resid -= symlen;
702 uio->uio_iov->iov_base += symlen;
703 uio->uio_iov->iov_len -= symlen;
704 return (0);
705}
706
707/*
708 * Ufs abort op, called after namei() when a CREATE/DELETE isn't actually
709 * done. If a buffer has been saved in anticipation of a CREATE, delete it.
710 */
711static int
712cd9660_abortop(ap)
713 struct vop_abortop_args /* {
714 struct vnode *a_dvp;
715 struct componentname *a_cnp;
716 } */ *ap;
717{
718 if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF)
719 zfree(namei_zone, ap->a_cnp->cn_pnbuf);
720 return (0);
721}
722
723/*
724 * Calculate the logical to physical mapping if not done already,
725 * then call the device strategy routine.
726 */
727static int
728cd9660_strategy(ap)
729 struct vop_strategy_args /* {
730 struct buf *a_vp;
730 struct buf *a_bp;
731 } */ *ap;
732{
733 register struct buf *bp = ap->a_bp;
734 register struct vnode *vp = bp->b_vp;
735 register struct iso_node *ip;
736 int error;
737
738 ip = VTOI(vp);
739 if (vp->v_type == VBLK || vp->v_type == VCHR)
740 panic("cd9660_strategy: spec");
741 if (bp->b_blkno == bp->b_lblkno) {
742 if ((error =
743 VOP_BMAP(vp, bp->b_lblkno, NULL, &bp->b_blkno, NULL, NULL))) {
744 bp->b_error = error;
745 bp->b_flags |= B_ERROR;
746 biodone(bp);
747 return (error);
748 }
749 if ((long)bp->b_blkno == -1)
750 clrbuf(bp);
751 }
752 if ((long)bp->b_blkno == -1) {
753 biodone(bp);
754 return (0);
755 }
756 vp = ip->i_devvp;
757 bp->b_dev = vp->v_rdev;
731 struct buf *a_bp;
732 } */ *ap;
733{
734 register struct buf *bp = ap->a_bp;
735 register struct vnode *vp = bp->b_vp;
736 register struct iso_node *ip;
737 int error;
738
739 ip = VTOI(vp);
740 if (vp->v_type == VBLK || vp->v_type == VCHR)
741 panic("cd9660_strategy: spec");
742 if (bp->b_blkno == bp->b_lblkno) {
743 if ((error =
744 VOP_BMAP(vp, bp->b_lblkno, NULL, &bp->b_blkno, NULL, NULL))) {
745 bp->b_error = error;
746 bp->b_flags |= B_ERROR;
747 biodone(bp);
748 return (error);
749 }
750 if ((long)bp->b_blkno == -1)
751 clrbuf(bp);
752 }
753 if ((long)bp->b_blkno == -1) {
754 biodone(bp);
755 return (0);
756 }
757 vp = ip->i_devvp;
758 bp->b_dev = vp->v_rdev;
758 VOCALL (vp->v_op, VOFFSET(vop_strategy), ap);
759 VOP_STRATEGY(vp, bp);
759 return (0);
760}
761
762/*
763 * Print out the contents of an inode.
764 */
765static int
766cd9660_print(ap)
767 struct vop_print_args /* {
768 struct vnode *a_vp;
769 } */ *ap;
770{
771
772 printf("tag VT_ISOFS, isofs vnode\n");
773 return (0);
774}
775
776/*
777 * Return POSIX pathconf information applicable to cd9660 filesystems.
778 */
779static int
780cd9660_pathconf(ap)
781 struct vop_pathconf_args /* {
782 struct vnode *a_vp;
783 int a_name;
784 register_t *a_retval;
785 } */ *ap;
786{
787
788 switch (ap->a_name) {
789 case _PC_LINK_MAX:
790 *ap->a_retval = 1;
791 return (0);
792 case _PC_NAME_MAX:
793 if (VTOI(ap->a_vp)->i_mnt->iso_ftype == ISO_FTYPE_RRIP)
794 *ap->a_retval = NAME_MAX;
795 else
796 *ap->a_retval = 37;
797 return (0);
798 case _PC_PATH_MAX:
799 *ap->a_retval = PATH_MAX;
800 return (0);
801 case _PC_PIPE_BUF:
802 *ap->a_retval = PIPE_BUF;
803 return (0);
804 case _PC_CHOWN_RESTRICTED:
805 *ap->a_retval = 1;
806 return (0);
807 case _PC_NO_TRUNC:
808 *ap->a_retval = 1;
809 return (0);
810 default:
811 return (EINVAL);
812 }
813 /* NOTREACHED */
814}
815
816/*
817 * get page routine
818 *
819 * XXX By default, wimp out... note that a_offset is ignored (and always
820 * XXX has been).
821 */
822int
823cd9660_getpages(ap)
824 struct vop_getpages_args *ap;
825{
826 return vnode_pager_generic_getpages(ap->a_vp, ap->a_m, ap->a_count,
827 ap->a_reqpage);
828}
829
830/*
831 * put page routine
832 *
833 * XXX By default, wimp out... note that a_offset is ignored (and always
834 * XXX has been).
835 */
836int
837cd9660_putpages(ap)
838 struct vop_putpages_args *ap;
839{
840 return vnode_pager_generic_putpages(ap->a_vp, ap->a_m, ap->a_count,
841 ap->a_sync, ap->a_rtvals);
842}
843
844/*
845 * Global vfs data structures for cd9660
846 */
847vop_t **cd9660_vnodeop_p;
848static struct vnodeopv_entry_desc cd9660_vnodeop_entries[] = {
849 { &vop_default_desc, (vop_t *) vop_defaultop },
850 { &vop_abortop_desc, (vop_t *) cd9660_abortop },
851 { &vop_access_desc, (vop_t *) cd9660_access },
852 { &vop_bmap_desc, (vop_t *) cd9660_bmap },
853 { &vop_cachedlookup_desc, (vop_t *) cd9660_lookup },
854 { &vop_getattr_desc, (vop_t *) cd9660_getattr },
855 { &vop_inactive_desc, (vop_t *) cd9660_inactive },
856 { &vop_islocked_desc, (vop_t *) vop_stdislocked },
857 { &vop_lock_desc, (vop_t *) vop_stdlock },
858 { &vop_lookup_desc, (vop_t *) vfs_cache_lookup },
859 { &vop_pathconf_desc, (vop_t *) cd9660_pathconf },
860 { &vop_print_desc, (vop_t *) cd9660_print },
861 { &vop_read_desc, (vop_t *) cd9660_read },
862 { &vop_readdir_desc, (vop_t *) cd9660_readdir },
863 { &vop_readlink_desc, (vop_t *) cd9660_readlink },
864 { &vop_reclaim_desc, (vop_t *) cd9660_reclaim },
865 { &vop_setattr_desc, (vop_t *) cd9660_setattr },
866 { &vop_strategy_desc, (vop_t *) cd9660_strategy },
867 { &vop_unlock_desc, (vop_t *) vop_stdunlock },
868 { &vop_getpages_desc, (vop_t *) cd9660_getpages },
869 { &vop_putpages_desc, (vop_t *) cd9660_putpages },
870 { NULL, NULL }
871};
872static struct vnodeopv_desc cd9660_vnodeop_opv_desc =
873 { &cd9660_vnodeop_p, cd9660_vnodeop_entries };
874VNODEOP_SET(cd9660_vnodeop_opv_desc);
875
876/*
877 * Special device vnode ops
878 */
879vop_t **cd9660_specop_p;
880static struct vnodeopv_entry_desc cd9660_specop_entries[] = {
881 { &vop_default_desc, (vop_t *) spec_vnoperate },
882 { &vop_access_desc, (vop_t *) cd9660_access },
883 { &vop_getattr_desc, (vop_t *) cd9660_getattr },
884 { &vop_inactive_desc, (vop_t *) cd9660_inactive },
885 { &vop_islocked_desc, (vop_t *) vop_stdislocked },
886 { &vop_lock_desc, (vop_t *) vop_stdlock },
887 { &vop_print_desc, (vop_t *) cd9660_print },
888 { &vop_reclaim_desc, (vop_t *) cd9660_reclaim },
889 { &vop_setattr_desc, (vop_t *) cd9660_setattr },
890 { &vop_unlock_desc, (vop_t *) vop_stdunlock },
891 { NULL, NULL }
892};
893static struct vnodeopv_desc cd9660_specop_opv_desc =
894 { &cd9660_specop_p, cd9660_specop_entries };
895VNODEOP_SET(cd9660_specop_opv_desc);
896
897vop_t **cd9660_fifoop_p;
898static struct vnodeopv_entry_desc cd9660_fifoop_entries[] = {
899 { &vop_default_desc, (vop_t *) fifo_vnoperate },
900 { &vop_access_desc, (vop_t *) cd9660_access },
901 { &vop_getattr_desc, (vop_t *) cd9660_getattr },
902 { &vop_inactive_desc, (vop_t *) cd9660_inactive },
903 { &vop_islocked_desc, (vop_t *) vop_stdislocked },
904 { &vop_lock_desc, (vop_t *) vop_stdlock },
905 { &vop_print_desc, (vop_t *) cd9660_print },
906 { &vop_reclaim_desc, (vop_t *) cd9660_reclaim },
907 { &vop_setattr_desc, (vop_t *) cd9660_setattr },
908 { &vop_unlock_desc, (vop_t *) vop_stdunlock },
909 { NULL, NULL }
910};
911static struct vnodeopv_desc cd9660_fifoop_opv_desc =
912 { &cd9660_fifoop_p, cd9660_fifoop_entries };
913
914VNODEOP_SET(cd9660_fifoop_opv_desc);
760 return (0);
761}
762
763/*
764 * Print out the contents of an inode.
765 */
766static int
767cd9660_print(ap)
768 struct vop_print_args /* {
769 struct vnode *a_vp;
770 } */ *ap;
771{
772
773 printf("tag VT_ISOFS, isofs vnode\n");
774 return (0);
775}
776
777/*
778 * Return POSIX pathconf information applicable to cd9660 filesystems.
779 */
780static int
781cd9660_pathconf(ap)
782 struct vop_pathconf_args /* {
783 struct vnode *a_vp;
784 int a_name;
785 register_t *a_retval;
786 } */ *ap;
787{
788
789 switch (ap->a_name) {
790 case _PC_LINK_MAX:
791 *ap->a_retval = 1;
792 return (0);
793 case _PC_NAME_MAX:
794 if (VTOI(ap->a_vp)->i_mnt->iso_ftype == ISO_FTYPE_RRIP)
795 *ap->a_retval = NAME_MAX;
796 else
797 *ap->a_retval = 37;
798 return (0);
799 case _PC_PATH_MAX:
800 *ap->a_retval = PATH_MAX;
801 return (0);
802 case _PC_PIPE_BUF:
803 *ap->a_retval = PIPE_BUF;
804 return (0);
805 case _PC_CHOWN_RESTRICTED:
806 *ap->a_retval = 1;
807 return (0);
808 case _PC_NO_TRUNC:
809 *ap->a_retval = 1;
810 return (0);
811 default:
812 return (EINVAL);
813 }
814 /* NOTREACHED */
815}
816
817/*
818 * get page routine
819 *
820 * XXX By default, wimp out... note that a_offset is ignored (and always
821 * XXX has been).
822 */
823int
824cd9660_getpages(ap)
825 struct vop_getpages_args *ap;
826{
827 return vnode_pager_generic_getpages(ap->a_vp, ap->a_m, ap->a_count,
828 ap->a_reqpage);
829}
830
831/*
832 * put page routine
833 *
834 * XXX By default, wimp out... note that a_offset is ignored (and always
835 * XXX has been).
836 */
837int
838cd9660_putpages(ap)
839 struct vop_putpages_args *ap;
840{
841 return vnode_pager_generic_putpages(ap->a_vp, ap->a_m, ap->a_count,
842 ap->a_sync, ap->a_rtvals);
843}
844
845/*
846 * Global vfs data structures for cd9660
847 */
848vop_t **cd9660_vnodeop_p;
849static struct vnodeopv_entry_desc cd9660_vnodeop_entries[] = {
850 { &vop_default_desc, (vop_t *) vop_defaultop },
851 { &vop_abortop_desc, (vop_t *) cd9660_abortop },
852 { &vop_access_desc, (vop_t *) cd9660_access },
853 { &vop_bmap_desc, (vop_t *) cd9660_bmap },
854 { &vop_cachedlookup_desc, (vop_t *) cd9660_lookup },
855 { &vop_getattr_desc, (vop_t *) cd9660_getattr },
856 { &vop_inactive_desc, (vop_t *) cd9660_inactive },
857 { &vop_islocked_desc, (vop_t *) vop_stdislocked },
858 { &vop_lock_desc, (vop_t *) vop_stdlock },
859 { &vop_lookup_desc, (vop_t *) vfs_cache_lookup },
860 { &vop_pathconf_desc, (vop_t *) cd9660_pathconf },
861 { &vop_print_desc, (vop_t *) cd9660_print },
862 { &vop_read_desc, (vop_t *) cd9660_read },
863 { &vop_readdir_desc, (vop_t *) cd9660_readdir },
864 { &vop_readlink_desc, (vop_t *) cd9660_readlink },
865 { &vop_reclaim_desc, (vop_t *) cd9660_reclaim },
866 { &vop_setattr_desc, (vop_t *) cd9660_setattr },
867 { &vop_strategy_desc, (vop_t *) cd9660_strategy },
868 { &vop_unlock_desc, (vop_t *) vop_stdunlock },
869 { &vop_getpages_desc, (vop_t *) cd9660_getpages },
870 { &vop_putpages_desc, (vop_t *) cd9660_putpages },
871 { NULL, NULL }
872};
873static struct vnodeopv_desc cd9660_vnodeop_opv_desc =
874 { &cd9660_vnodeop_p, cd9660_vnodeop_entries };
875VNODEOP_SET(cd9660_vnodeop_opv_desc);
876
877/*
878 * Special device vnode ops
879 */
880vop_t **cd9660_specop_p;
881static struct vnodeopv_entry_desc cd9660_specop_entries[] = {
882 { &vop_default_desc, (vop_t *) spec_vnoperate },
883 { &vop_access_desc, (vop_t *) cd9660_access },
884 { &vop_getattr_desc, (vop_t *) cd9660_getattr },
885 { &vop_inactive_desc, (vop_t *) cd9660_inactive },
886 { &vop_islocked_desc, (vop_t *) vop_stdislocked },
887 { &vop_lock_desc, (vop_t *) vop_stdlock },
888 { &vop_print_desc, (vop_t *) cd9660_print },
889 { &vop_reclaim_desc, (vop_t *) cd9660_reclaim },
890 { &vop_setattr_desc, (vop_t *) cd9660_setattr },
891 { &vop_unlock_desc, (vop_t *) vop_stdunlock },
892 { NULL, NULL }
893};
894static struct vnodeopv_desc cd9660_specop_opv_desc =
895 { &cd9660_specop_p, cd9660_specop_entries };
896VNODEOP_SET(cd9660_specop_opv_desc);
897
898vop_t **cd9660_fifoop_p;
899static struct vnodeopv_entry_desc cd9660_fifoop_entries[] = {
900 { &vop_default_desc, (vop_t *) fifo_vnoperate },
901 { &vop_access_desc, (vop_t *) cd9660_access },
902 { &vop_getattr_desc, (vop_t *) cd9660_getattr },
903 { &vop_inactive_desc, (vop_t *) cd9660_inactive },
904 { &vop_islocked_desc, (vop_t *) vop_stdislocked },
905 { &vop_lock_desc, (vop_t *) vop_stdlock },
906 { &vop_print_desc, (vop_t *) cd9660_print },
907 { &vop_reclaim_desc, (vop_t *) cd9660_reclaim },
908 { &vop_setattr_desc, (vop_t *) cd9660_setattr },
909 { &vop_unlock_desc, (vop_t *) vop_stdunlock },
910 { NULL, NULL }
911};
912static struct vnodeopv_desc cd9660_fifoop_opv_desc =
913 { &cd9660_fifoop_p, cd9660_fifoop_entries };
914
915VNODEOP_SET(cd9660_fifoop_opv_desc);