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.39 1997/09/21 04:22:40 dyson 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/sysctl.h>
48#include <sys/buf.h>
49#include <sys/mount.h>
50#include <sys/vnode.h>
51#include <miscfs/specfs/specdev.h>
52#include <miscfs/fifofs/fifo.h>
53#include <sys/malloc.h>
54#include <sys/dirent.h>
55#include <sys/unistd.h>
56
57#include <isofs/cd9660/iso.h>
58#include <isofs/cd9660/cd9660_node.h>
59#include <isofs/cd9660/iso_rrip.h>
60
61static int cd9660_setattr __P((struct vop_setattr_args *));
62static int cd9660_open __P((struct vop_open_args *));
63static int cd9660_close __P((struct vop_close_args *));
64static int cd9660_access __P((struct vop_access_args *));
65static int cd9660_getattr __P((struct vop_getattr_args *));
66static int cd9660_read __P((struct vop_read_args *));
67static int cd9660_ioctl __P((struct vop_ioctl_args *));
68static int cd9660_mmap __P((struct vop_mmap_args *));
69static int cd9660_seek __P((struct vop_seek_args *));
70struct isoreaddir;
71static int iso_uiodir __P((struct isoreaddir *idp, struct dirent *dp,
72 off_t off));
73static int iso_shipdir __P((struct isoreaddir *idp));
74static int cd9660_readdir __P((struct vop_readdir_args *));
75static int cd9660_readlink __P((struct vop_readlink_args *ap));
76static int cd9660_abortop __P((struct vop_abortop_args *));
77static int cd9660_lock __P((struct vop_lock_args *));
78static int cd9660_unlock __P((struct vop_unlock_args *));
79static int cd9660_strategy __P((struct vop_strategy_args *));
80static int cd9660_print __P((struct vop_print_args *));
81static int cd9660_islocked __P((struct vop_islocked_args *));
82
83/*
84 * Setattr call. Only allowed for block and character special devices.
85 */
86int
87cd9660_setattr(ap)
88 struct vop_setattr_args /* {
89 struct vnodeop_desc *a_desc;
90 struct vnode *a_vp;
91 struct vattr *a_vap;
92 struct ucred *a_cred;
93 struct proc *a_p;
94 } */ *ap;
95{
96 struct vnode *vp = ap->a_vp;
97 struct vattr *vap = ap->a_vap;
98
99 if (vap->va_flags != (u_long)VNOVAL || vap->va_uid != (uid_t)VNOVAL ||
100 vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL ||
101 vap->va_mtime.tv_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL)
102 return (EROFS);
103 if (vap->va_size != (u_quad_t)VNOVAL) {
104 switch (vp->v_type) {
105 case VDIR:
106 return (EISDIR);
107 case VLNK:
108 case VREG:
109 return (EROFS);
110 case VCHR:
111 case VBLK:
112 case VSOCK:
113 case VFIFO:
114 return (0);
115 }
116 }
117 return (0);
118}
119
120/*
121 * Open called.
122 *
123 * Nothing to do.
124 */
125/* ARGSUSED */
126static int
127cd9660_open(ap)
128 struct vop_open_args /* {
129 struct vnode *a_vp;
130 int a_mode;
131 struct ucred *a_cred;
132 struct proc *a_p;
133 } */ *ap;
134{
135 return (0);
136}
137
138/*
139 * Close called
140 *
141 * Update the times on the inode on writeable file systems.
142 */
143/* ARGSUSED */
144static int
145cd9660_close(ap)
146 struct vop_close_args /* {
147 struct vnode *a_vp;
148 int a_fflag;
149 struct ucred *a_cred;
150 struct proc *a_p;
151 } */ *ap;
152{
153 return (0);
154}
155
156/*
157 * Check mode permission on inode pointer. Mode is READ, WRITE or EXEC.
158 * The mode is shifted to select the owner/group/other fields. The
159 * super user is granted all permissions.
160 */
161/* ARGSUSED */
162static int
163cd9660_access(ap)
164 struct vop_access_args /* {
165 struct vnode *a_vp;
166 int a_mode;
167 struct ucred *a_cred;
168 struct proc *a_p;
169 } */ *ap;
170{
171 struct vnode *vp = ap->a_vp;
172 struct iso_node *ip = VTOI(vp);
173 struct ucred *cred = ap->a_cred;
174 mode_t mask, mode = ap->a_mode;
175 gid_t *gp;
176 int i;
177
178 /*
179 * Disallow write attempts unless the file is a socket,
180 * fifo, or a block or character device resident on the
181 * file system.
182 */
183 if (mode & VWRITE) {
184 switch (vp->v_type) {
185 case VDIR:
186 case VLNK:
187 case VREG:
188 return (EROFS);
189 }
190 }
191
192 /* User id 0 always gets access. */
193 if (cred->cr_uid == 0)
194 return (0);
195
196 mask = 0;
197
198 /* Otherwise, check the owner. */
199 if (cred->cr_uid == ip->inode.iso_uid) {
200 if (mode & VEXEC)
201 mask |= S_IXUSR;
202 if (mode & VREAD)
203 mask |= S_IRUSR;
204 if (mode & VWRITE)
205 mask |= S_IWUSR;
206 return ((ip->inode.iso_mode & mask) == mask ? 0 : EACCES);
207 }
208
209 /* Otherwise, check the groups. */
210 for (i = 0, gp = cred->cr_groups; i < cred->cr_ngroups; i++, gp++)
211 if (ip->inode.iso_gid == *gp) {
212 if (mode & VEXEC)
213 mask |= S_IXGRP;
214 if (mode & VREAD)
215 mask |= S_IRGRP;
216 if (mode & VWRITE)
217 mask |= S_IWGRP;
218 return ((ip->inode.iso_mode & mask) == mask ?
219 0 : EACCES);
220 }
221
222 /* Otherwise, check everyone else. */
223 if (mode & VEXEC)
224 mask |= S_IXOTH;
225 if (mode & VREAD)
226 mask |= S_IROTH;
227 if (mode & VWRITE)
228 mask |= S_IWOTH;
229 return ((ip->inode.iso_mode & mask) == mask ? 0 : EACCES);
230}
231
232static int
233cd9660_getattr(ap)
234 struct vop_getattr_args /* {
235 struct vnode *a_vp;
236 struct vattr *a_vap;
237 struct ucred *a_cred;
238 struct proc *a_p;
239 } */ *ap;
240
241{
242 struct vnode *vp = ap->a_vp;
243 register struct vattr *vap = ap->a_vap;
244 register struct iso_node *ip = VTOI(vp);
245
246 vap->va_fsid = ip->i_dev;
247 vap->va_fileid = ip->i_number;
248
249 vap->va_mode = ip->inode.iso_mode;
250 vap->va_nlink = ip->inode.iso_links;
251 vap->va_uid = ip->inode.iso_uid;
252 vap->va_gid = ip->inode.iso_gid;
253 vap->va_atime = ip->inode.iso_atime;
254 vap->va_mtime = ip->inode.iso_mtime;
255 vap->va_ctime = ip->inode.iso_ctime;
256 vap->va_rdev = ip->inode.iso_rdev;
257
258 vap->va_size = (u_quad_t) ip->i_size;
259 if (ip->i_size == 0 && (vap->va_mode & S_IFMT) == S_IFLNK) {
260 struct vop_readlink_args rdlnk;
261 struct iovec aiov;
262 struct uio auio;
263 char *cp;
264
265 MALLOC(cp, char *, MAXPATHLEN, M_TEMP, M_WAITOK);
266 aiov.iov_base = cp;
267 aiov.iov_len = MAXPATHLEN;
268 auio.uio_iov = &aiov;
269 auio.uio_iovcnt = 1;
270 auio.uio_offset = 0;
271 auio.uio_rw = UIO_READ;
272 auio.uio_segflg = UIO_SYSSPACE;
273 auio.uio_procp = ap->a_p;
274 auio.uio_resid = MAXPATHLEN;
275 rdlnk.a_uio = &auio;
276 rdlnk.a_vp = ap->a_vp;
277 rdlnk.a_cred = ap->a_cred;
278 if (cd9660_readlink(&rdlnk) == 0)
279 vap->va_size = MAXPATHLEN - auio.uio_resid;
280 FREE(cp, M_TEMP);
281 }
282 vap->va_flags = 0;
283 vap->va_gen = 1;
284 vap->va_blocksize = ip->i_mnt->logical_block_size;
285 vap->va_bytes = (u_quad_t) ip->i_size;
286 vap->va_type = vp->v_type;
287 vap->va_filerev = 0;
288 return (0);
289}
290
291/*
292 * Vnode op for reading.
293 */
294static int
295cd9660_read(ap)
296 struct vop_read_args /* {
297 struct vnode *a_vp;
298 struct uio *a_uio;
299 int a_ioflag;
300 struct ucred *a_cred;
301 } */ *ap;
302{
303 struct vnode *vp = ap->a_vp;
304 register struct uio *uio = ap->a_uio;
305 register struct iso_node *ip = VTOI(vp);
306 register struct iso_mnt *imp;
307 struct buf *bp;
308 daddr_t lbn, rablock;
309 off_t diff;
310 int rasize, error = 0;
311 long size, n, on;
312
313 if (uio->uio_resid == 0)
314 return (0);
315 if (uio->uio_offset < 0)
316 return (EINVAL);
317 ip->i_flag |= IN_ACCESS;
318 imp = ip->i_mnt;
319 do {
320 lbn = lblkno(imp, uio->uio_offset);
321 on = blkoff(imp, uio->uio_offset);
322 n = min((u_int)(imp->logical_block_size - on),
323 uio->uio_resid);
324 diff = (off_t)ip->i_size - uio->uio_offset;
325 if (diff <= 0)
326 return (0);
327 if (diff < n)
328 n = diff;
329 size = blksize(imp, ip, lbn);
330 rablock = lbn + 1;
331 if ((vp->v_mount->mnt_flag & MNT_NOCLUSTERR) == 0) {
332 if (lblktosize(imp, rablock) <= ip->i_size)
333 error = cluster_read(vp, (off_t)ip->i_size,
334 lbn, size, NOCRED, uio->uio_resid,
335 (ap->a_ioflag >> 16), &bp);
336 else
337 error = bread(vp, lbn, size, NOCRED, &bp);
338 } else {
339 if (vp->v_lastr + 1 == lbn &&
340 lblktosize(imp, rablock) < ip->i_size) {
341 rasize = blksize(imp, ip, rablock);
342 error = breadn(vp, lbn, size, &rablock,
343 &rasize, 1, NOCRED, &bp);
344 } else
345 error = bread(vp, lbn, size, NOCRED, &bp);
346 }
347 vp->v_lastr = lbn;
348 n = min(n, size - bp->b_resid);
349 if (error) {
350 brelse(bp);
351 return (error);
352 }
353
354 error = uiomove(bp->b_data + on, (int)n, uio);
355 brelse(bp);
356 } while (error == 0 && uio->uio_resid > 0 && n != 0);
357 return (error);
358}
359
360/* ARGSUSED */
361static int
362cd9660_ioctl(ap)
363 struct vop_ioctl_args /* {
364 struct vnode *a_vp;
365 u_long a_command;
366 caddr_t a_data;
367 int a_fflag;
368 struct ucred *a_cred;
369 struct proc *a_p;
370 } */ *ap;
371{
372 printf("You did ioctl for isofs !!\n");
373 return (ENOTTY);
374}
375
376/*
377 * Mmap a file
378 *
379 * NB Currently unsupported.
380 */
381/* ARGSUSED */
382static int
383cd9660_mmap(ap)
384 struct vop_mmap_args /* {
385 struct vnode *a_vp;
386 int a_fflags;
387 struct ucred *a_cred;
388 struct proc *a_p;
389 } */ *ap;
390{
391
392 return (EINVAL);
393}
394
395/*
396 * Seek on a file
397 *
398 * Nothing to do, so just return.
399 */
400/* ARGSUSED */
401static int
402cd9660_seek(ap)
403 struct vop_seek_args /* {
404 struct vnode *a_vp;
405 off_t a_oldoff;
406 off_t a_newoff;
407 struct ucred *a_cred;
408 } */ *ap;
409{
410
411 return (0);
412}
413
414/*
415 * Structure for reading directories
416 */
417struct isoreaddir {
418 struct dirent saveent;
419 struct dirent assocent;
420 struct dirent current;
421 off_t saveoff;
422 off_t assocoff;
423 off_t curroff;
424 struct uio *uio;
425 off_t uio_off;
426 int eofflag;
427 u_long *cookies;
428 int ncookies;
429};
430
431int
432iso_uiodir(idp,dp,off)
433 struct isoreaddir *idp;
434 struct dirent *dp;
435 off_t off;
436{
437 int error;
438
439 dp->d_name[dp->d_namlen] = 0;
440 dp->d_reclen = GENERIC_DIRSIZ(dp);
441
442 if (idp->uio->uio_resid < dp->d_reclen) {
443 idp->eofflag = 0;
444 return (-1);
445 }
446
447 if (idp->cookies) {
448 if (idp->ncookies <= 0) {
449 idp->eofflag = 0;
450 return (-1);
451 }
452
453 *idp->cookies++ = off;
454 --idp->ncookies;
455 }
456
457 if (error = uiomove((caddr_t) dp,dp->d_reclen,idp->uio))
458 return (error);
459 idp->uio_off = off;
460 return (0);
461}
462
463int
464iso_shipdir(idp)
465 struct isoreaddir *idp;
466{
467 struct dirent *dp;
468 int cl, sl, assoc;
469 int error;
470 char *cname, *sname;
471
472 cl = idp->current.d_namlen;
473 cname = idp->current.d_name;
474assoc = (cl > 1) && (*cname == ASSOCCHAR);
475 if (assoc) {
476 cl--;
477 cname++;
478 }
479
480 dp = &idp->saveent;
481 sname = dp->d_name;
482 if (!(sl = dp->d_namlen)) {
483 dp = &idp->assocent;
484 sname = dp->d_name + 1;
485 sl = dp->d_namlen - 1;
486 }
487 if (sl > 0) {
488 if (sl != cl
489 || bcmp(sname,cname,sl)) {
490 if (idp->assocent.d_namlen) {
491 if (error = iso_uiodir(idp,&idp->assocent,idp->assocoff))
492 return (error);
493 idp->assocent.d_namlen = 0;
494 }
495 if (idp->saveent.d_namlen) {
496 if (error = iso_uiodir(idp,&idp->saveent,idp->saveoff))
497 return (error);
498 idp->saveent.d_namlen = 0;
499 }
500 }
501 }
502 idp->current.d_reclen = GENERIC_DIRSIZ(&idp->current);
503 if (assoc) {
504 idp->assocoff = idp->curroff;
505 bcopy(&idp->current,&idp->assocent,idp->current.d_reclen);
506 } else {
507 idp->saveoff = idp->curroff;
508 bcopy(&idp->current,&idp->saveent,idp->current.d_reclen);
509 }
510 return (0);
511}
512
513/*
514 * Vnode op for readdir
515 */
516static int
517cd9660_readdir(ap)
518 struct vop_readdir_args /* {
519 struct vnode *a_vp;
520 struct uio *a_uio;
521 struct ucred *a_cred;
522 int *a_eofflag;
523 int *a_ncookies;
524 u_long *a_cookies;
525 } */ *ap;
526{
527 register struct uio *uio = ap->a_uio;
528 struct isoreaddir *idp;
529 struct vnode *vdp = ap->a_vp;
530 struct iso_node *dp;
531 struct iso_mnt *imp;
532 struct buf *bp = NULL;
533 struct iso_directory_record *ep;
534 int entryoffsetinblock;
535 doff_t endsearch;
536 u_long bmask;
537 int error = 0;
538 int reclen;
539 u_short namelen;
540 int ncookies = 0;
541 u_long *cookies = NULL;
542
543 dp = VTOI(vdp);
544 imp = dp->i_mnt;
545 bmask = imp->im_bmask;
546
547 MALLOC(idp, struct isoreaddir *, sizeof(*idp), M_TEMP, M_WAITOK);
548 idp->saveent.d_namlen = idp->assocent.d_namlen = 0;
549 /*
550 * XXX
551 * Is it worth trying to figure out the type?
552 */
553 idp->saveent.d_type = idp->assocent.d_type = idp->current.d_type =
554 DT_UNKNOWN;
555 idp->uio = uio;
556 if (ap->a_ncookies == NULL) {
557 idp->cookies = NULL;
558 } else {
559 /*
560 * Guess the number of cookies needed.
561 */
562 ncookies = uio->uio_resid / 16;
563 MALLOC(cookies, u_long *, ncookies * sizeof(u_int), M_TEMP,
564 M_WAITOK);
565 idp->cookies = cookies;
566 idp->ncookies = ncookies;
567 }
568 idp->eofflag = 1;
569 idp->curroff = uio->uio_offset;
570
571 if ((entryoffsetinblock = idp->curroff & bmask) &&
572 (error = VOP_BLKATOFF(vdp, (off_t)idp->curroff, NULL, &bp))) {
573 FREE(idp, M_TEMP);
574 return (error);
575 }
576 endsearch = dp->i_size;
577
578 while (idp->curroff < endsearch) {
579 /*
580 * If offset is on a block boundary,
581 * read the next directory block.
582 * Release previous if it exists.
583 */
584 if ((idp->curroff & bmask) == 0) {
585 if (bp != NULL)
586 brelse(bp);
587 if (error =
588 VOP_BLKATOFF(vdp, (off_t)idp->curroff, NULL, &bp))
589 break;
590 entryoffsetinblock = 0;
591 }
592 /*
593 * Get pointer to next entry.
594 */
595 ep = (struct iso_directory_record *)
596 ((char *)bp->b_data + entryoffsetinblock);
597
598 reclen = isonum_711(ep->length);
599 if (reclen == 0) {
600 /* skip to next block, if any */
601 idp->curroff =
602 (idp->curroff & ~bmask) + imp->logical_block_size;
603 continue;
604 }
605
606 if (reclen < ISO_DIRECTORY_RECORD_SIZE) {
607 error = EINVAL;
608 /* illegal entry, stop */
609 break;
610 }
611
612 if (entryoffsetinblock + reclen > imp->logical_block_size) {
613 error = EINVAL;
614 /* illegal directory, so stop looking */
615 break;
616 }
617
618 idp->current.d_namlen = isonum_711(ep->name_len);
619
620 if (reclen < ISO_DIRECTORY_RECORD_SIZE + idp->current.d_namlen) {
621 error = EINVAL;
622 /* illegal entry, stop */
623 break;
624 }
625
626 if (isonum_711(ep->flags)&2)
627 idp->current.d_fileno = isodirino(ep, imp);
628 else
629 idp->current.d_fileno = dbtob(bp->b_blkno) +
630 entryoffsetinblock;
631
632 idp->curroff += reclen;
633
634 switch (imp->iso_ftype) {
635 case ISO_FTYPE_RRIP:
636 cd9660_rrip_getname(ep,idp->current.d_name, &namelen,
637 &idp->current.d_fileno,imp);
638 idp->current.d_namlen = (u_char)namelen;
639 if (idp->current.d_namlen)
640 error = iso_uiodir(idp,&idp->current,idp->curroff);
641 break;
642 default: /* ISO_FTYPE_DEFAULT || ISO_FTYPE_9660 || ISO_FTYPE_HIGH_SIERRA*/
643 strcpy(idp->current.d_name,"..");
644 switch (ep->name[0]) {
645 case 0:
646 idp->current.d_namlen = 1;
647 error = iso_uiodir(idp,&idp->current,idp->curroff);
648 break;
649 case 1:
650 idp->current.d_namlen = 2;
651 error = iso_uiodir(idp,&idp->current,idp->curroff);
652 break;
653 default:
654 isofntrans(ep->name,idp->current.d_namlen,
655 idp->current.d_name, &namelen,
656 imp->iso_ftype == ISO_FTYPE_9660,
657 isonum_711(ep->flags)&4);
658 idp->current.d_namlen = (u_char)namelen;
659 if (imp->iso_ftype == ISO_FTYPE_DEFAULT)
660 error = iso_shipdir(idp);
661 else
662 error = iso_uiodir(idp,&idp->current,idp->curroff);
663 break;
664 }
665 }
666 if (error)
667 break;
668
669 entryoffsetinblock += reclen;
670 }
671
672 if (!error && imp->iso_ftype == ISO_FTYPE_DEFAULT) {
673 idp->current.d_namlen = 0;
674 error = iso_shipdir(idp);
675 }
676 if (error < 0)
677 error = 0;
678
679 if (ap->a_ncookies != NULL) {
680 if (error)
681 free(cookies, M_TEMP);
682 else {
683 /*
684 * Work out the number of cookies actually used.
685 */
686 *ap->a_ncookies = ncookies - idp->ncookies;
687 *ap->a_cookies = cookies;
688 }
689 }
690
691 if (bp)
692 brelse (bp);
693
694 uio->uio_offset = idp->uio_off;
695 *ap->a_eofflag = idp->eofflag;
696
697 FREE(idp, M_TEMP);
698
699 return (error);
700}
701
702/*
703 * Return target name of a symbolic link
704 * Shouldn't we get the parent vnode and read the data from there?
705 * This could eventually result in deadlocks in cd9660_lookup.
706 * But otherwise the block read here is in the block buffer two times.
707 */
708typedef struct iso_directory_record ISODIR;
709typedef struct iso_node ISONODE;
710typedef struct iso_mnt ISOMNT;
711static int
712cd9660_readlink(ap)
713 struct vop_readlink_args /* {
714 struct vnode *a_vp;
715 struct uio *a_uio;
716 struct ucred *a_cred;
717 } */ *ap;
718{
719 ISONODE *ip;
720 ISODIR *dirp;
721 ISOMNT *imp;
722 struct buf *bp;
723 struct uio *uio;
724 u_short symlen;
725 int error;
726 char *symname;
727
728 ip = VTOI(ap->a_vp);
729 imp = ip->i_mnt;
730 uio = ap->a_uio;
731
732 if (imp->iso_ftype != ISO_FTYPE_RRIP)
733 return (EINVAL);
734
735 /*
736 * Get parents directory record block that this inode included.
737 */
738 error = bread(imp->im_devvp,
739 (ip->i_number >> imp->im_bshift) <<
740 (imp->im_bshift - DEV_BSHIFT),
741 imp->logical_block_size, NOCRED, &bp);
742 if (error) {
743 brelse(bp);
744 return (EINVAL);
745 }
746
747 /*
748 * Setup the directory pointer for this inode
749 */
750 dirp = (ISODIR *)(bp->b_data + (ip->i_number & imp->im_bmask));
751
752 /*
753 * Just make sure, we have a right one....
754 * 1: Check not cross boundary on block
755 */
756 if ((ip->i_number & imp->im_bmask) + isonum_711(dirp->length)
757 > (unsigned)imp->logical_block_size) {
758 brelse(bp);
759 return (EINVAL);
760 }
761
762 /*
763 * Now get a buffer
764 * Abuse a namei buffer for now.
765 */
766 if (uio->uio_segflg == UIO_SYSSPACE)
767 symname = uio->uio_iov->iov_base;
768 else
769 symname = zalloc(namei_zone);
770
771 /*
772 * Ok, we just gathering a symbolic name in SL record.
773 */
774 if (cd9660_rrip_getsymname(dirp, symname, &symlen, imp) == 0) {
775 if (uio->uio_segflg != UIO_SYSSPACE)
776 zfree(namei_zone, symname);
777 brelse(bp);
778 return (EINVAL);
779 }
780 /*
781 * Don't forget before you leave from home ;-)
782 */
783 brelse(bp);
784
785 /*
786 * return with the symbolic name to caller's.
787 */
788 if (uio->uio_segflg != UIO_SYSSPACE) {
789 error = uiomove(symname, symlen, uio);
790 zfree(namei_zone, symname);
791 return (error);
792 }
793 uio->uio_resid -= symlen;
794 uio->uio_iov->iov_base += symlen;
795 uio->uio_iov->iov_len -= symlen;
796 return (0);
797}
798
799/*
800 * Ufs abort op, called after namei() when a CREATE/DELETE isn't actually
801 * done. If a buffer has been saved in anticipation of a CREATE, delete it.
802 */
803static int
804cd9660_abortop(ap)
805 struct vop_abortop_args /* {
806 struct vnode *a_dvp;
807 struct componentname *a_cnp;
808 } */ *ap;
809{
810 if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF)
811 zfree(namei_zone, ap->a_cnp->cn_pnbuf);
812 return (0);
813}
814
815/*
816 * Lock an inode.
817 */
818static int
819cd9660_lock(ap)
820 struct vop_lock_args /* {
821 struct vnode *a_vp;
822 int a_flags;
823 struct proc *a_p;
824 } */ *ap;
825{
826 struct vnode *vp = ap->a_vp;
827
828 return (lockmgr(&VTOI(vp)->i_lock, ap->a_flags, &vp->v_interlock,
829 ap->a_p));
830}
831
832/*
833 * Unlock an inode.
834 */
835static int
836cd9660_unlock(ap)
837 struct vop_unlock_args /* {
838 struct vnode *a_vp;
839 int a_flags;
840 struct proc *a_p;
841 } */ *ap;
842{
843 struct vnode *vp = ap->a_vp;
844
845 return (lockmgr(&VTOI(vp)->i_lock, ap->a_flags | LK_RELEASE,
846 &vp->v_interlock, ap->a_p));
847}
848
849/*
850 * Calculate the logical to physical mapping if not done already,
851 * then call the device strategy routine.
852 */
853static int
854cd9660_strategy(ap)
855 struct vop_strategy_args /* {
856 struct buf *a_bp;
857 } */ *ap;
858{
859 register struct buf *bp = ap->a_bp;
860 register struct vnode *vp = bp->b_vp;
861 register struct iso_node *ip;
862 int error;
863
864 ip = VTOI(vp);
865 if (vp->v_type == VBLK || vp->v_type == VCHR)
866 panic("cd9660_strategy: spec");
867 if (bp->b_blkno == bp->b_lblkno) {
868 if ((error =
869 VOP_BMAP(vp, bp->b_lblkno, NULL, &bp->b_blkno, NULL, NULL))) {
870 bp->b_error = error;
871 bp->b_flags |= B_ERROR;
872 biodone(bp);
873 return (error);
874 }
875 if ((long)bp->b_blkno == -1)
876 clrbuf(bp);
877 }
878 if ((long)bp->b_blkno == -1) {
879 biodone(bp);
880 return (0);
881 }
882 vp = ip->i_devvp;
883 bp->b_dev = vp->v_rdev;
884 VOCALL (vp->v_op, VOFFSET(vop_strategy), ap);
885 return (0);
886}
887
888/*
889 * Print out the contents of an inode.
890 */
891static int
892cd9660_print(ap)
893 struct vop_print_args /* {
894 struct vnode *a_vp;
895 } */ *ap;
896{
897
898 printf("tag VT_ISOFS, isofs vnode\n");
899 return (0);
900}
901
902/*
903 * Check for a locked inode.
904 */
905int
906cd9660_islocked(ap)
907 struct vop_islocked_args /* {
908 struct vnode *a_vp;
909 } */ *ap;
910{
911
912 return (lockstatus(&VTOI(ap->a_vp)->i_lock));
913}
914
915/*
916 * Return POSIX pathconf information applicable to cd9660 filesystems.
917 */
918int
919cd9660_pathconf(ap)
920 struct vop_pathconf_args /* {
921 struct vnode *a_vp;
922 int a_name;
923 register_t *a_retval;
924 } */ *ap;
925{
926
927 switch (ap->a_name) {
928 case _PC_LINK_MAX:
929 *ap->a_retval = 1;
930 return (0);
931 case _PC_NAME_MAX:
932 if (VTOI(ap->a_vp)->i_mnt->iso_ftype == ISO_FTYPE_RRIP)
933 *ap->a_retval = NAME_MAX;
934 else
935 *ap->a_retval = 37;
936 return (0);
937 case _PC_PATH_MAX:
938 *ap->a_retval = PATH_MAX;
939 return (0);
940 case _PC_PIPE_BUF:
941 *ap->a_retval = PIPE_BUF;
942 return (0);
943 case _PC_CHOWN_RESTRICTED:
944 *ap->a_retval = 1;
945 return (0);
946 case _PC_NO_TRUNC:
947 *ap->a_retval = 1;
948 return (0);
949 default:
950 return (EINVAL);
951 }
952 /* NOTREACHED */
953}
954
955/*
956 * Global vfs data structures for isofs
957 */
958#define cd9660_create \
959 ((int (*) __P((struct vop_create_args *)))eopnotsupp)
960#define cd9660_mknod ((int (*) __P((struct vop_mknod_args *)))eopnotsupp)
961#define cd9660_write ((int (*) __P((struct vop_write_args *)))eopnotsupp)
962#ifdef NFS
963#define cd9660_lease_check lease_check
964#else
965#define cd9660_lease_check ((int (*) __P((struct vop_lease_args *)))nullop)
966#endif
967#define cd9660_poll vop_nopoll
968#define cd9660_fsync ((int (*) __P((struct vop_fsync_args *)))nullop)
969#define cd9660_remove \
970 ((int (*) __P((struct vop_remove_args *)))eopnotsupp)
971#define cd9660_link ((int (*) __P((struct vop_link_args *)))eopnotsupp)
972#define cd9660_rename \
973 ((int (*) __P((struct vop_rename_args *)))eopnotsupp)
974#define cd9660_mkdir ((int (*) __P((struct vop_mkdir_args *)))eopnotsupp)
975#define cd9660_rmdir ((int (*) __P((struct vop_rmdir_args *)))eopnotsupp)
976#define cd9660_symlink \
977 ((int (*) __P((struct vop_symlink_args *)))eopnotsupp)
978#define cd9660_advlock \
979 ((int (*) __P((struct vop_advlock_args *)))eopnotsupp)
980#define cd9660_valloc ((int(*) __P(( \
981 struct vnode *pvp, \
982 int mode, \
983 struct ucred *cred, \
984 struct vnode **vpp))) eopnotsupp)
985#define cd9660_vfree ((int (*) __P((struct vop_vfree_args *)))eopnotsupp)
986#define cd9660_truncate \
987 ((int (*) __P((struct vop_truncate_args *)))eopnotsupp)
988#define cd9660_update \
989 ((int (*) __P((struct vop_update_args *)))eopnotsupp)
990#define cd9660_bwrite \
991 ((int (*) __P((struct vop_bwrite_args *)))eopnotsupp)
992
993/*
994 * Global vfs data structures for cd9660
995 */
996vop_t **cd9660_vnodeop_p;
997struct vnodeopv_entry_desc cd9660_vnodeop_entries[] = {
998
999 { &vop_default_desc, (vop_t *)vn_default_error },
1000 { &vop_lookup_desc, (vop_t *)vfs_cache_lookup }, /* lookup */
1001 { &vop_cachedlookup_desc, (vop_t *)cd9660_lookup }, /* lookup */
1002 { &vop_create_desc, (vop_t *)cd9660_create }, /* create */
1003/* XXX: vop_whiteout */
1004 { &vop_mknod_desc, (vop_t *)cd9660_mknod }, /* mknod */
1005 { &vop_open_desc, (vop_t *)cd9660_open }, /* open */
1006 { &vop_close_desc, (vop_t *)cd9660_close }, /* close */
1007 { &vop_access_desc, (vop_t *)cd9660_access }, /* access */
1008 { &vop_getattr_desc, (vop_t *)cd9660_getattr }, /* getattr */
1009 { &vop_setattr_desc, (vop_t *)cd9660_setattr }, /* setattr */
1010 { &vop_read_desc, (vop_t *)cd9660_read }, /* read */
1011 { &vop_write_desc, (vop_t *)cd9660_write }, /* write */
1012 { &vop_lease_desc, (vop_t *)cd9660_lease_check },/* lease */
1013 { &vop_ioctl_desc, (vop_t *)cd9660_ioctl }, /* ioctl */
1014 { &vop_poll_desc, (vop_t *)cd9660_poll }, /* poll */
1015 { &vop_revoke_desc, (vop_t *)cd9660_revoke }, /* revoke */
1016 { &vop_mmap_desc, (vop_t *)cd9660_mmap }, /* mmap */
1017 { &vop_fsync_desc, (vop_t *)cd9660_fsync }, /* fsync */
1018 { &vop_seek_desc, (vop_t *)cd9660_seek }, /* seek */
1019 { &vop_remove_desc, (vop_t *)cd9660_remove }, /* remove */
1020 { &vop_link_desc, (vop_t *)cd9660_link }, /* link */
1021 { &vop_rename_desc, (vop_t *)cd9660_rename }, /* rename */
1022 { &vop_mkdir_desc, (vop_t *)cd9660_mkdir }, /* mkdir */
1023 { &vop_rmdir_desc, (vop_t *)cd9660_rmdir }, /* rmdir */
1024 { &vop_symlink_desc, (vop_t *)cd9660_symlink }, /* symlink */
1025 { &vop_readdir_desc, (vop_t *)cd9660_readdir }, /* readdir */
1026 { &vop_readlink_desc, (vop_t *)cd9660_readlink },/* readlink */
1027 { &vop_abortop_desc, (vop_t *)cd9660_abortop }, /* abortop */
1028 { &vop_inactive_desc, (vop_t *)cd9660_inactive },/* inactive */
1029 { &vop_reclaim_desc, (vop_t *)cd9660_reclaim }, /* reclaim */
1030 { &vop_lock_desc, (vop_t *)cd9660_lock }, /* lock */
1031 { &vop_unlock_desc, (vop_t *)cd9660_unlock }, /* unlock */
1032 { &vop_bmap_desc, (vop_t *)cd9660_bmap }, /* bmap */
1033 { &vop_strategy_desc, (vop_t *)cd9660_strategy },/* strategy */
1034 { &vop_print_desc, (vop_t *)cd9660_print }, /* print */
1035 { &vop_islocked_desc, (vop_t *)cd9660_islocked },/* islocked */
1036 { &vop_pathconf_desc, (vop_t *)cd9660_pathconf },/* pathconf */
1037 { &vop_advlock_desc, (vop_t *)cd9660_advlock }, /* advlock */
1038 { &vop_blkatoff_desc, (vop_t *)cd9660_blkatoff },/* blkatoff */
1039 { &vop_valloc_desc, (vop_t *)cd9660_valloc }, /* valloc */
1040/* XXX: vop_reallocblks */
1041 { &vop_vfree_desc, (vop_t *)cd9660_vfree }, /* vfree */
1042 { &vop_truncate_desc, (vop_t *)cd9660_truncate },/* truncate */
1043 { &vop_update_desc, (vop_t *)cd9660_update }, /* update */
1044/* XXX: vop_getpages */
1045/* XXX: vop_putpages */
1046 { &vop_bwrite_desc, (vop_t *)vn_bwrite },
1047 { NULL, NULL }
1048};
1049static struct vnodeopv_desc cd9660_vnodeop_opv_desc =
1050 { &cd9660_vnodeop_p, cd9660_vnodeop_entries };
1051VNODEOP_SET(cd9660_vnodeop_opv_desc);
1052
1053/*
1054 * Special device vnode ops
1055 */
1056vop_t **cd9660_specop_p;
1057struct vnodeopv_entry_desc cd9660_specop_entries[] = {
1058 { &vop_default_desc, (vop_t *)vn_default_error },
1059 { &vop_lookup_desc, (vop_t *)spec_lookup }, /* lookup */
1060/* XXX: vop_cachedlookup */
1061 { &vop_create_desc, (vop_t *)spec_create }, /* create */
1062/* XXX: vop_whiteout */
1063 { &vop_mknod_desc, (vop_t *)spec_mknod }, /* mknod */
1064 { &vop_open_desc, (vop_t *)spec_open }, /* open */
1065 { &vop_close_desc, (vop_t *)spec_close }, /* close */
1066 { &vop_access_desc, (vop_t *)cd9660_access }, /* access */
1067 { &vop_getattr_desc, (vop_t *)cd9660_getattr }, /* getattr */
1068 { &vop_setattr_desc, (vop_t *)cd9660_setattr }, /* setattr */
1069 { &vop_read_desc, (vop_t *)spec_read }, /* read */
1070 { &vop_write_desc, (vop_t *)spec_write }, /* write */
1071 { &vop_lease_desc, (vop_t *)spec_lease_check }, /* lease */
1072 { &vop_ioctl_desc, (vop_t *)spec_ioctl }, /* ioctl */
1073 { &vop_poll_desc, (vop_t *)spec_poll }, /* poll */
1074 { &vop_revoke_desc, (vop_t *)spec_revoke }, /* revoke */
1075 { &vop_mmap_desc, (vop_t *)spec_mmap }, /* mmap */
1076 { &vop_fsync_desc, (vop_t *)spec_fsync }, /* fsync */
1077 { &vop_seek_desc, (vop_t *)spec_seek }, /* seek */
1078 { &vop_remove_desc, (vop_t *)spec_remove }, /* remove */
1079 { &vop_link_desc, (vop_t *)spec_link }, /* link */
1080 { &vop_rename_desc, (vop_t *)spec_rename }, /* rename */
1081 { &vop_mkdir_desc, (vop_t *)spec_mkdir }, /* mkdir */
1082 { &vop_rmdir_desc, (vop_t *)spec_rmdir }, /* rmdir */
1083 { &vop_symlink_desc, (vop_t *)spec_symlink }, /* symlink */
1084 { &vop_readdir_desc, (vop_t *)spec_readdir }, /* readdir */
1085 { &vop_readlink_desc, (vop_t *)spec_readlink }, /* readlink */
1086 { &vop_abortop_desc, (vop_t *)spec_abortop }, /* abortop */
1087 { &vop_inactive_desc, (vop_t *)cd9660_inactive },/* inactive */
1088 { &vop_reclaim_desc, (vop_t *)cd9660_reclaim }, /* reclaim */
1089 { &vop_lock_desc, (vop_t *)cd9660_lock }, /* lock */
1090 { &vop_unlock_desc, (vop_t *)cd9660_unlock }, /* unlock */
1091 { &vop_bmap_desc, (vop_t *)spec_bmap }, /* bmap */
1092 { &vop_strategy_desc, (vop_t *)spec_strategy }, /* strategy */
1093 { &vop_print_desc, (vop_t *)cd9660_print }, /* print */
1094 { &vop_islocked_desc, (vop_t *)cd9660_islocked },/* islocked */
1095 { &vop_pathconf_desc, (vop_t *)spec_pathconf }, /* pathconf */
1096 { &vop_advlock_desc, (vop_t *)spec_advlock }, /* advlock */
1097 { &vop_blkatoff_desc, (vop_t *)spec_blkatoff }, /* blkatoff */
1098 { &vop_valloc_desc, (vop_t *)spec_valloc }, /* valloc */
1099/* XXX: vop_reallocblks */
1100 { &vop_vfree_desc, (vop_t *)spec_vfree }, /* vfree */
1101 { &vop_truncate_desc, (vop_t *)spec_truncate }, /* truncate */
1102 { &vop_update_desc, (vop_t *)cd9660_update }, /* update */
1103/* XXX: vop_getpages */
1104/* XXX: vop_putpages */
1105 { &vop_bwrite_desc, (vop_t *)vn_bwrite },
1106 { NULL, NULL }
1107};
1108static struct vnodeopv_desc cd9660_specop_opv_desc =
1109 { &cd9660_specop_p, cd9660_specop_entries };
1110VNODEOP_SET(cd9660_specop_opv_desc);
1111
1112vop_t **cd9660_fifoop_p;
1113struct vnodeopv_entry_desc cd9660_fifoop_entries[] = {
1114 { &vop_default_desc, (vop_t *)vn_default_error },
1115 { &vop_lookup_desc, (vop_t *)fifo_lookup }, /* lookup */
1116/* XXX: vop_cachedlookup */
1117 { &vop_create_desc, (vop_t *)fifo_create }, /* create */
1118/* XXX: vop_whiteout */
1119 { &vop_mknod_desc, (vop_t *)fifo_mknod }, /* mknod */
1120 { &vop_open_desc, (vop_t *)fifo_open }, /* open */
1121 { &vop_close_desc, (vop_t *)fifo_close }, /* close */
1122 { &vop_access_desc, (vop_t *)cd9660_access }, /* access */
1123 { &vop_getattr_desc, (vop_t *)cd9660_getattr }, /* getattr */
1124 { &vop_setattr_desc, (vop_t *)cd9660_setattr }, /* setattr */
1125 { &vop_read_desc, (vop_t *)fifo_read }, /* read */
1126 { &vop_write_desc, (vop_t *)fifo_write }, /* write */
1127 { &vop_lease_desc, (vop_t *)fifo_lease_check }, /* lease */
1128 { &vop_ioctl_desc, (vop_t *)fifo_ioctl }, /* ioctl */
1129 { &vop_poll_desc, (vop_t *)fifo_poll }, /* poll */
1130 { &vop_revoke_desc, (vop_t *)fifo_revoke }, /* revoke */
1131 { &vop_mmap_desc, (vop_t *)fifo_mmap }, /* mmap */
1132 { &vop_fsync_desc, (vop_t *)fifo_fsync }, /* fsync */
1133 { &vop_seek_desc, (vop_t *)fifo_seek }, /* seek */
1134 { &vop_remove_desc, (vop_t *)fifo_remove }, /* remove */
1135 { &vop_link_desc, (vop_t *)fifo_link } , /* link */
1136 { &vop_rename_desc, (vop_t *)fifo_rename }, /* rename */
1137 { &vop_mkdir_desc, (vop_t *)fifo_mkdir }, /* mkdir */
1138 { &vop_rmdir_desc, (vop_t *)fifo_rmdir }, /* rmdir */
1139 { &vop_symlink_desc, (vop_t *)fifo_symlink }, /* symlink */
1140 { &vop_readdir_desc, (vop_t *)fifo_readdir }, /* readdir */
1141 { &vop_readlink_desc, (vop_t *)fifo_readlink }, /* readlink */
1142 { &vop_abortop_desc, (vop_t *)fifo_abortop }, /* abortop */
1143 { &vop_inactive_desc, (vop_t *)cd9660_inactive },/* inactive */
1144 { &vop_reclaim_desc, (vop_t *)cd9660_reclaim }, /* reclaim */
1145 { &vop_lock_desc, (vop_t *)cd9660_lock }, /* lock */
1146 { &vop_unlock_desc, (vop_t *)cd9660_unlock }, /* unlock */
1147 { &vop_bmap_desc, (vop_t *)fifo_bmap }, /* bmap */
1148 { &vop_strategy_desc, (vop_t *)fifo_strategy }, /* strategy */
1149 { &vop_print_desc, (vop_t *)cd9660_print }, /* print */
1150 { &vop_islocked_desc, (vop_t *)cd9660_islocked },/* islocked */
1151 { &vop_pathconf_desc, (vop_t *)fifo_pathconf }, /* pathconf */
1152 { &vop_advlock_desc, (vop_t *)fifo_advlock }, /* advlock */
1153 { &vop_blkatoff_desc, (vop_t *)fifo_blkatoff }, /* blkatoff */
1154 { &vop_valloc_desc, (vop_t *)fifo_valloc }, /* valloc */
1155/* XXX: vop_reallocpages */
1156 { &vop_vfree_desc, (vop_t *)fifo_vfree }, /* vfree */
1157 { &vop_truncate_desc, (vop_t *)fifo_truncate }, /* truncate */
1158 { &vop_update_desc, (vop_t *)cd9660_update }, /* update */
1159/* XXX: vop_getpages */
1160/* XXX: vop_putpages */
1161 { &vop_bwrite_desc, (vop_t *)vn_bwrite },
1162 { NULL, NULL }
1163};
1164static struct vnodeopv_desc cd9660_fifoop_opv_desc =
1165 { &cd9660_fifoop_p, cd9660_fifoop_entries };
1166
1167VNODEOP_SET(cd9660_fifoop_opv_desc);
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.39 1997/09/21 04:22:40 dyson 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/sysctl.h>
48#include <sys/buf.h>
49#include <sys/mount.h>
50#include <sys/vnode.h>
51#include <miscfs/specfs/specdev.h>
52#include <miscfs/fifofs/fifo.h>
53#include <sys/malloc.h>
54#include <sys/dirent.h>
55#include <sys/unistd.h>
56
57#include <isofs/cd9660/iso.h>
58#include <isofs/cd9660/cd9660_node.h>
59#include <isofs/cd9660/iso_rrip.h>
60
61static int cd9660_setattr __P((struct vop_setattr_args *));
62static int cd9660_open __P((struct vop_open_args *));
63static int cd9660_close __P((struct vop_close_args *));
64static int cd9660_access __P((struct vop_access_args *));
65static int cd9660_getattr __P((struct vop_getattr_args *));
66static int cd9660_read __P((struct vop_read_args *));
67static int cd9660_ioctl __P((struct vop_ioctl_args *));
68static int cd9660_mmap __P((struct vop_mmap_args *));
69static int cd9660_seek __P((struct vop_seek_args *));
70struct isoreaddir;
71static int iso_uiodir __P((struct isoreaddir *idp, struct dirent *dp,
72 off_t off));
73static int iso_shipdir __P((struct isoreaddir *idp));
74static int cd9660_readdir __P((struct vop_readdir_args *));
75static int cd9660_readlink __P((struct vop_readlink_args *ap));
76static int cd9660_abortop __P((struct vop_abortop_args *));
77static int cd9660_lock __P((struct vop_lock_args *));
78static int cd9660_unlock __P((struct vop_unlock_args *));
79static int cd9660_strategy __P((struct vop_strategy_args *));
80static int cd9660_print __P((struct vop_print_args *));
81static int cd9660_islocked __P((struct vop_islocked_args *));
82
83/*
84 * Setattr call. Only allowed for block and character special devices.
85 */
86int
87cd9660_setattr(ap)
88 struct vop_setattr_args /* {
89 struct vnodeop_desc *a_desc;
90 struct vnode *a_vp;
91 struct vattr *a_vap;
92 struct ucred *a_cred;
93 struct proc *a_p;
94 } */ *ap;
95{
96 struct vnode *vp = ap->a_vp;
97 struct vattr *vap = ap->a_vap;
98
99 if (vap->va_flags != (u_long)VNOVAL || vap->va_uid != (uid_t)VNOVAL ||
100 vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL ||
101 vap->va_mtime.tv_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL)
102 return (EROFS);
103 if (vap->va_size != (u_quad_t)VNOVAL) {
104 switch (vp->v_type) {
105 case VDIR:
106 return (EISDIR);
107 case VLNK:
108 case VREG:
109 return (EROFS);
110 case VCHR:
111 case VBLK:
112 case VSOCK:
113 case VFIFO:
114 return (0);
115 }
116 }
117 return (0);
118}
119
120/*
121 * Open called.
122 *
123 * Nothing to do.
124 */
125/* ARGSUSED */
126static int
127cd9660_open(ap)
128 struct vop_open_args /* {
129 struct vnode *a_vp;
130 int a_mode;
131 struct ucred *a_cred;
132 struct proc *a_p;
133 } */ *ap;
134{
135 return (0);
136}
137
138/*
139 * Close called
140 *
141 * Update the times on the inode on writeable file systems.
142 */
143/* ARGSUSED */
144static int
145cd9660_close(ap)
146 struct vop_close_args /* {
147 struct vnode *a_vp;
148 int a_fflag;
149 struct ucred *a_cred;
150 struct proc *a_p;
151 } */ *ap;
152{
153 return (0);
154}
155
156/*
157 * Check mode permission on inode pointer. Mode is READ, WRITE or EXEC.
158 * The mode is shifted to select the owner/group/other fields. The
159 * super user is granted all permissions.
160 */
161/* ARGSUSED */
162static int
163cd9660_access(ap)
164 struct vop_access_args /* {
165 struct vnode *a_vp;
166 int a_mode;
167 struct ucred *a_cred;
168 struct proc *a_p;
169 } */ *ap;
170{
171 struct vnode *vp = ap->a_vp;
172 struct iso_node *ip = VTOI(vp);
173 struct ucred *cred = ap->a_cred;
174 mode_t mask, mode = ap->a_mode;
175 gid_t *gp;
176 int i;
177
178 /*
179 * Disallow write attempts unless the file is a socket,
180 * fifo, or a block or character device resident on the
181 * file system.
182 */
183 if (mode & VWRITE) {
184 switch (vp->v_type) {
185 case VDIR:
186 case VLNK:
187 case VREG:
188 return (EROFS);
189 }
190 }
191
192 /* User id 0 always gets access. */
193 if (cred->cr_uid == 0)
194 return (0);
195
196 mask = 0;
197
198 /* Otherwise, check the owner. */
199 if (cred->cr_uid == ip->inode.iso_uid) {
200 if (mode & VEXEC)
201 mask |= S_IXUSR;
202 if (mode & VREAD)
203 mask |= S_IRUSR;
204 if (mode & VWRITE)
205 mask |= S_IWUSR;
206 return ((ip->inode.iso_mode & mask) == mask ? 0 : EACCES);
207 }
208
209 /* Otherwise, check the groups. */
210 for (i = 0, gp = cred->cr_groups; i < cred->cr_ngroups; i++, gp++)
211 if (ip->inode.iso_gid == *gp) {
212 if (mode & VEXEC)
213 mask |= S_IXGRP;
214 if (mode & VREAD)
215 mask |= S_IRGRP;
216 if (mode & VWRITE)
217 mask |= S_IWGRP;
218 return ((ip->inode.iso_mode & mask) == mask ?
219 0 : EACCES);
220 }
221
222 /* Otherwise, check everyone else. */
223 if (mode & VEXEC)
224 mask |= S_IXOTH;
225 if (mode & VREAD)
226 mask |= S_IROTH;
227 if (mode & VWRITE)
228 mask |= S_IWOTH;
229 return ((ip->inode.iso_mode & mask) == mask ? 0 : EACCES);
230}
231
232static int
233cd9660_getattr(ap)
234 struct vop_getattr_args /* {
235 struct vnode *a_vp;
236 struct vattr *a_vap;
237 struct ucred *a_cred;
238 struct proc *a_p;
239 } */ *ap;
240
241{
242 struct vnode *vp = ap->a_vp;
243 register struct vattr *vap = ap->a_vap;
244 register struct iso_node *ip = VTOI(vp);
245
246 vap->va_fsid = ip->i_dev;
247 vap->va_fileid = ip->i_number;
248
249 vap->va_mode = ip->inode.iso_mode;
250 vap->va_nlink = ip->inode.iso_links;
251 vap->va_uid = ip->inode.iso_uid;
252 vap->va_gid = ip->inode.iso_gid;
253 vap->va_atime = ip->inode.iso_atime;
254 vap->va_mtime = ip->inode.iso_mtime;
255 vap->va_ctime = ip->inode.iso_ctime;
256 vap->va_rdev = ip->inode.iso_rdev;
257
258 vap->va_size = (u_quad_t) ip->i_size;
259 if (ip->i_size == 0 && (vap->va_mode & S_IFMT) == S_IFLNK) {
260 struct vop_readlink_args rdlnk;
261 struct iovec aiov;
262 struct uio auio;
263 char *cp;
264
265 MALLOC(cp, char *, MAXPATHLEN, M_TEMP, M_WAITOK);
266 aiov.iov_base = cp;
267 aiov.iov_len = MAXPATHLEN;
268 auio.uio_iov = &aiov;
269 auio.uio_iovcnt = 1;
270 auio.uio_offset = 0;
271 auio.uio_rw = UIO_READ;
272 auio.uio_segflg = UIO_SYSSPACE;
273 auio.uio_procp = ap->a_p;
274 auio.uio_resid = MAXPATHLEN;
275 rdlnk.a_uio = &auio;
276 rdlnk.a_vp = ap->a_vp;
277 rdlnk.a_cred = ap->a_cred;
278 if (cd9660_readlink(&rdlnk) == 0)
279 vap->va_size = MAXPATHLEN - auio.uio_resid;
280 FREE(cp, M_TEMP);
281 }
282 vap->va_flags = 0;
283 vap->va_gen = 1;
284 vap->va_blocksize = ip->i_mnt->logical_block_size;
285 vap->va_bytes = (u_quad_t) ip->i_size;
286 vap->va_type = vp->v_type;
287 vap->va_filerev = 0;
288 return (0);
289}
290
291/*
292 * Vnode op for reading.
293 */
294static int
295cd9660_read(ap)
296 struct vop_read_args /* {
297 struct vnode *a_vp;
298 struct uio *a_uio;
299 int a_ioflag;
300 struct ucred *a_cred;
301 } */ *ap;
302{
303 struct vnode *vp = ap->a_vp;
304 register struct uio *uio = ap->a_uio;
305 register struct iso_node *ip = VTOI(vp);
306 register struct iso_mnt *imp;
307 struct buf *bp;
308 daddr_t lbn, rablock;
309 off_t diff;
310 int rasize, error = 0;
311 long size, n, on;
312
313 if (uio->uio_resid == 0)
314 return (0);
315 if (uio->uio_offset < 0)
316 return (EINVAL);
317 ip->i_flag |= IN_ACCESS;
318 imp = ip->i_mnt;
319 do {
320 lbn = lblkno(imp, uio->uio_offset);
321 on = blkoff(imp, uio->uio_offset);
322 n = min((u_int)(imp->logical_block_size - on),
323 uio->uio_resid);
324 diff = (off_t)ip->i_size - uio->uio_offset;
325 if (diff <= 0)
326 return (0);
327 if (diff < n)
328 n = diff;
329 size = blksize(imp, ip, lbn);
330 rablock = lbn + 1;
331 if ((vp->v_mount->mnt_flag & MNT_NOCLUSTERR) == 0) {
332 if (lblktosize(imp, rablock) <= ip->i_size)
333 error = cluster_read(vp, (off_t)ip->i_size,
334 lbn, size, NOCRED, uio->uio_resid,
335 (ap->a_ioflag >> 16), &bp);
336 else
337 error = bread(vp, lbn, size, NOCRED, &bp);
338 } else {
339 if (vp->v_lastr + 1 == lbn &&
340 lblktosize(imp, rablock) < ip->i_size) {
341 rasize = blksize(imp, ip, rablock);
342 error = breadn(vp, lbn, size, &rablock,
343 &rasize, 1, NOCRED, &bp);
344 } else
345 error = bread(vp, lbn, size, NOCRED, &bp);
346 }
347 vp->v_lastr = lbn;
348 n = min(n, size - bp->b_resid);
349 if (error) {
350 brelse(bp);
351 return (error);
352 }
353
354 error = uiomove(bp->b_data + on, (int)n, uio);
355 brelse(bp);
356 } while (error == 0 && uio->uio_resid > 0 && n != 0);
357 return (error);
358}
359
360/* ARGSUSED */
361static int
362cd9660_ioctl(ap)
363 struct vop_ioctl_args /* {
364 struct vnode *a_vp;
365 u_long a_command;
366 caddr_t a_data;
367 int a_fflag;
368 struct ucred *a_cred;
369 struct proc *a_p;
370 } */ *ap;
371{
372 printf("You did ioctl for isofs !!\n");
373 return (ENOTTY);
374}
375
376/*
377 * Mmap a file
378 *
379 * NB Currently unsupported.
380 */
381/* ARGSUSED */
382static int
383cd9660_mmap(ap)
384 struct vop_mmap_args /* {
385 struct vnode *a_vp;
386 int a_fflags;
387 struct ucred *a_cred;
388 struct proc *a_p;
389 } */ *ap;
390{
391
392 return (EINVAL);
393}
394
395/*
396 * Seek on a file
397 *
398 * Nothing to do, so just return.
399 */
400/* ARGSUSED */
401static int
402cd9660_seek(ap)
403 struct vop_seek_args /* {
404 struct vnode *a_vp;
405 off_t a_oldoff;
406 off_t a_newoff;
407 struct ucred *a_cred;
408 } */ *ap;
409{
410
411 return (0);
412}
413
414/*
415 * Structure for reading directories
416 */
417struct isoreaddir {
418 struct dirent saveent;
419 struct dirent assocent;
420 struct dirent current;
421 off_t saveoff;
422 off_t assocoff;
423 off_t curroff;
424 struct uio *uio;
425 off_t uio_off;
426 int eofflag;
427 u_long *cookies;
428 int ncookies;
429};
430
431int
432iso_uiodir(idp,dp,off)
433 struct isoreaddir *idp;
434 struct dirent *dp;
435 off_t off;
436{
437 int error;
438
439 dp->d_name[dp->d_namlen] = 0;
440 dp->d_reclen = GENERIC_DIRSIZ(dp);
441
442 if (idp->uio->uio_resid < dp->d_reclen) {
443 idp->eofflag = 0;
444 return (-1);
445 }
446
447 if (idp->cookies) {
448 if (idp->ncookies <= 0) {
449 idp->eofflag = 0;
450 return (-1);
451 }
452
453 *idp->cookies++ = off;
454 --idp->ncookies;
455 }
456
457 if (error = uiomove((caddr_t) dp,dp->d_reclen,idp->uio))
458 return (error);
459 idp->uio_off = off;
460 return (0);
461}
462
463int
464iso_shipdir(idp)
465 struct isoreaddir *idp;
466{
467 struct dirent *dp;
468 int cl, sl, assoc;
469 int error;
470 char *cname, *sname;
471
472 cl = idp->current.d_namlen;
473 cname = idp->current.d_name;
474assoc = (cl > 1) && (*cname == ASSOCCHAR);
475 if (assoc) {
476 cl--;
477 cname++;
478 }
479
480 dp = &idp->saveent;
481 sname = dp->d_name;
482 if (!(sl = dp->d_namlen)) {
483 dp = &idp->assocent;
484 sname = dp->d_name + 1;
485 sl = dp->d_namlen - 1;
486 }
487 if (sl > 0) {
488 if (sl != cl
489 || bcmp(sname,cname,sl)) {
490 if (idp->assocent.d_namlen) {
491 if (error = iso_uiodir(idp,&idp->assocent,idp->assocoff))
492 return (error);
493 idp->assocent.d_namlen = 0;
494 }
495 if (idp->saveent.d_namlen) {
496 if (error = iso_uiodir(idp,&idp->saveent,idp->saveoff))
497 return (error);
498 idp->saveent.d_namlen = 0;
499 }
500 }
501 }
502 idp->current.d_reclen = GENERIC_DIRSIZ(&idp->current);
503 if (assoc) {
504 idp->assocoff = idp->curroff;
505 bcopy(&idp->current,&idp->assocent,idp->current.d_reclen);
506 } else {
507 idp->saveoff = idp->curroff;
508 bcopy(&idp->current,&idp->saveent,idp->current.d_reclen);
509 }
510 return (0);
511}
512
513/*
514 * Vnode op for readdir
515 */
516static int
517cd9660_readdir(ap)
518 struct vop_readdir_args /* {
519 struct vnode *a_vp;
520 struct uio *a_uio;
521 struct ucred *a_cred;
522 int *a_eofflag;
523 int *a_ncookies;
524 u_long *a_cookies;
525 } */ *ap;
526{
527 register struct uio *uio = ap->a_uio;
528 struct isoreaddir *idp;
529 struct vnode *vdp = ap->a_vp;
530 struct iso_node *dp;
531 struct iso_mnt *imp;
532 struct buf *bp = NULL;
533 struct iso_directory_record *ep;
534 int entryoffsetinblock;
535 doff_t endsearch;
536 u_long bmask;
537 int error = 0;
538 int reclen;
539 u_short namelen;
540 int ncookies = 0;
541 u_long *cookies = NULL;
542
543 dp = VTOI(vdp);
544 imp = dp->i_mnt;
545 bmask = imp->im_bmask;
546
547 MALLOC(idp, struct isoreaddir *, sizeof(*idp), M_TEMP, M_WAITOK);
548 idp->saveent.d_namlen = idp->assocent.d_namlen = 0;
549 /*
550 * XXX
551 * Is it worth trying to figure out the type?
552 */
553 idp->saveent.d_type = idp->assocent.d_type = idp->current.d_type =
554 DT_UNKNOWN;
555 idp->uio = uio;
556 if (ap->a_ncookies == NULL) {
557 idp->cookies = NULL;
558 } else {
559 /*
560 * Guess the number of cookies needed.
561 */
562 ncookies = uio->uio_resid / 16;
563 MALLOC(cookies, u_long *, ncookies * sizeof(u_int), M_TEMP,
564 M_WAITOK);
565 idp->cookies = cookies;
566 idp->ncookies = ncookies;
567 }
568 idp->eofflag = 1;
569 idp->curroff = uio->uio_offset;
570
571 if ((entryoffsetinblock = idp->curroff & bmask) &&
572 (error = VOP_BLKATOFF(vdp, (off_t)idp->curroff, NULL, &bp))) {
573 FREE(idp, M_TEMP);
574 return (error);
575 }
576 endsearch = dp->i_size;
577
578 while (idp->curroff < endsearch) {
579 /*
580 * If offset is on a block boundary,
581 * read the next directory block.
582 * Release previous if it exists.
583 */
584 if ((idp->curroff & bmask) == 0) {
585 if (bp != NULL)
586 brelse(bp);
587 if (error =
588 VOP_BLKATOFF(vdp, (off_t)idp->curroff, NULL, &bp))
589 break;
590 entryoffsetinblock = 0;
591 }
592 /*
593 * Get pointer to next entry.
594 */
595 ep = (struct iso_directory_record *)
596 ((char *)bp->b_data + entryoffsetinblock);
597
598 reclen = isonum_711(ep->length);
599 if (reclen == 0) {
600 /* skip to next block, if any */
601 idp->curroff =
602 (idp->curroff & ~bmask) + imp->logical_block_size;
603 continue;
604 }
605
606 if (reclen < ISO_DIRECTORY_RECORD_SIZE) {
607 error = EINVAL;
608 /* illegal entry, stop */
609 break;
610 }
611
612 if (entryoffsetinblock + reclen > imp->logical_block_size) {
613 error = EINVAL;
614 /* illegal directory, so stop looking */
615 break;
616 }
617
618 idp->current.d_namlen = isonum_711(ep->name_len);
619
620 if (reclen < ISO_DIRECTORY_RECORD_SIZE + idp->current.d_namlen) {
621 error = EINVAL;
622 /* illegal entry, stop */
623 break;
624 }
625
626 if (isonum_711(ep->flags)&2)
627 idp->current.d_fileno = isodirino(ep, imp);
628 else
629 idp->current.d_fileno = dbtob(bp->b_blkno) +
630 entryoffsetinblock;
631
632 idp->curroff += reclen;
633
634 switch (imp->iso_ftype) {
635 case ISO_FTYPE_RRIP:
636 cd9660_rrip_getname(ep,idp->current.d_name, &namelen,
637 &idp->current.d_fileno,imp);
638 idp->current.d_namlen = (u_char)namelen;
639 if (idp->current.d_namlen)
640 error = iso_uiodir(idp,&idp->current,idp->curroff);
641 break;
642 default: /* ISO_FTYPE_DEFAULT || ISO_FTYPE_9660 || ISO_FTYPE_HIGH_SIERRA*/
643 strcpy(idp->current.d_name,"..");
644 switch (ep->name[0]) {
645 case 0:
646 idp->current.d_namlen = 1;
647 error = iso_uiodir(idp,&idp->current,idp->curroff);
648 break;
649 case 1:
650 idp->current.d_namlen = 2;
651 error = iso_uiodir(idp,&idp->current,idp->curroff);
652 break;
653 default:
654 isofntrans(ep->name,idp->current.d_namlen,
655 idp->current.d_name, &namelen,
656 imp->iso_ftype == ISO_FTYPE_9660,
657 isonum_711(ep->flags)&4);
658 idp->current.d_namlen = (u_char)namelen;
659 if (imp->iso_ftype == ISO_FTYPE_DEFAULT)
660 error = iso_shipdir(idp);
661 else
662 error = iso_uiodir(idp,&idp->current,idp->curroff);
663 break;
664 }
665 }
666 if (error)
667 break;
668
669 entryoffsetinblock += reclen;
670 }
671
672 if (!error && imp->iso_ftype == ISO_FTYPE_DEFAULT) {
673 idp->current.d_namlen = 0;
674 error = iso_shipdir(idp);
675 }
676 if (error < 0)
677 error = 0;
678
679 if (ap->a_ncookies != NULL) {
680 if (error)
681 free(cookies, M_TEMP);
682 else {
683 /*
684 * Work out the number of cookies actually used.
685 */
686 *ap->a_ncookies = ncookies - idp->ncookies;
687 *ap->a_cookies = cookies;
688 }
689 }
690
691 if (bp)
692 brelse (bp);
693
694 uio->uio_offset = idp->uio_off;
695 *ap->a_eofflag = idp->eofflag;
696
697 FREE(idp, M_TEMP);
698
699 return (error);
700}
701
702/*
703 * Return target name of a symbolic link
704 * Shouldn't we get the parent vnode and read the data from there?
705 * This could eventually result in deadlocks in cd9660_lookup.
706 * But otherwise the block read here is in the block buffer two times.
707 */
708typedef struct iso_directory_record ISODIR;
709typedef struct iso_node ISONODE;
710typedef struct iso_mnt ISOMNT;
711static int
712cd9660_readlink(ap)
713 struct vop_readlink_args /* {
714 struct vnode *a_vp;
715 struct uio *a_uio;
716 struct ucred *a_cred;
717 } */ *ap;
718{
719 ISONODE *ip;
720 ISODIR *dirp;
721 ISOMNT *imp;
722 struct buf *bp;
723 struct uio *uio;
724 u_short symlen;
725 int error;
726 char *symname;
727
728 ip = VTOI(ap->a_vp);
729 imp = ip->i_mnt;
730 uio = ap->a_uio;
731
732 if (imp->iso_ftype != ISO_FTYPE_RRIP)
733 return (EINVAL);
734
735 /*
736 * Get parents directory record block that this inode included.
737 */
738 error = bread(imp->im_devvp,
739 (ip->i_number >> imp->im_bshift) <<
740 (imp->im_bshift - DEV_BSHIFT),
741 imp->logical_block_size, NOCRED, &bp);
742 if (error) {
743 brelse(bp);
744 return (EINVAL);
745 }
746
747 /*
748 * Setup the directory pointer for this inode
749 */
750 dirp = (ISODIR *)(bp->b_data + (ip->i_number & imp->im_bmask));
751
752 /*
753 * Just make sure, we have a right one....
754 * 1: Check not cross boundary on block
755 */
756 if ((ip->i_number & imp->im_bmask) + isonum_711(dirp->length)
757 > (unsigned)imp->logical_block_size) {
758 brelse(bp);
759 return (EINVAL);
760 }
761
762 /*
763 * Now get a buffer
764 * Abuse a namei buffer for now.
765 */
766 if (uio->uio_segflg == UIO_SYSSPACE)
767 symname = uio->uio_iov->iov_base;
768 else
769 symname = zalloc(namei_zone);
770
771 /*
772 * Ok, we just gathering a symbolic name in SL record.
773 */
774 if (cd9660_rrip_getsymname(dirp, symname, &symlen, imp) == 0) {
775 if (uio->uio_segflg != UIO_SYSSPACE)
776 zfree(namei_zone, symname);
777 brelse(bp);
778 return (EINVAL);
779 }
780 /*
781 * Don't forget before you leave from home ;-)
782 */
783 brelse(bp);
784
785 /*
786 * return with the symbolic name to caller's.
787 */
788 if (uio->uio_segflg != UIO_SYSSPACE) {
789 error = uiomove(symname, symlen, uio);
790 zfree(namei_zone, symname);
791 return (error);
792 }
793 uio->uio_resid -= symlen;
794 uio->uio_iov->iov_base += symlen;
795 uio->uio_iov->iov_len -= symlen;
796 return (0);
797}
798
799/*
800 * Ufs abort op, called after namei() when a CREATE/DELETE isn't actually
801 * done. If a buffer has been saved in anticipation of a CREATE, delete it.
802 */
803static int
804cd9660_abortop(ap)
805 struct vop_abortop_args /* {
806 struct vnode *a_dvp;
807 struct componentname *a_cnp;
808 } */ *ap;
809{
810 if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF)
811 zfree(namei_zone, ap->a_cnp->cn_pnbuf);
812 return (0);
813}
814
815/*
816 * Lock an inode.
817 */
818static int
819cd9660_lock(ap)
820 struct vop_lock_args /* {
821 struct vnode *a_vp;
822 int a_flags;
823 struct proc *a_p;
824 } */ *ap;
825{
826 struct vnode *vp = ap->a_vp;
827
828 return (lockmgr(&VTOI(vp)->i_lock, ap->a_flags, &vp->v_interlock,
829 ap->a_p));
830}
831
832/*
833 * Unlock an inode.
834 */
835static int
836cd9660_unlock(ap)
837 struct vop_unlock_args /* {
838 struct vnode *a_vp;
839 int a_flags;
840 struct proc *a_p;
841 } */ *ap;
842{
843 struct vnode *vp = ap->a_vp;
844
845 return (lockmgr(&VTOI(vp)->i_lock, ap->a_flags | LK_RELEASE,
846 &vp->v_interlock, ap->a_p));
847}
848
849/*
850 * Calculate the logical to physical mapping if not done already,
851 * then call the device strategy routine.
852 */
853static int
854cd9660_strategy(ap)
855 struct vop_strategy_args /* {
856 struct buf *a_bp;
857 } */ *ap;
858{
859 register struct buf *bp = ap->a_bp;
860 register struct vnode *vp = bp->b_vp;
861 register struct iso_node *ip;
862 int error;
863
864 ip = VTOI(vp);
865 if (vp->v_type == VBLK || vp->v_type == VCHR)
866 panic("cd9660_strategy: spec");
867 if (bp->b_blkno == bp->b_lblkno) {
868 if ((error =
869 VOP_BMAP(vp, bp->b_lblkno, NULL, &bp->b_blkno, NULL, NULL))) {
870 bp->b_error = error;
871 bp->b_flags |= B_ERROR;
872 biodone(bp);
873 return (error);
874 }
875 if ((long)bp->b_blkno == -1)
876 clrbuf(bp);
877 }
878 if ((long)bp->b_blkno == -1) {
879 biodone(bp);
880 return (0);
881 }
882 vp = ip->i_devvp;
883 bp->b_dev = vp->v_rdev;
884 VOCALL (vp->v_op, VOFFSET(vop_strategy), ap);
885 return (0);
886}
887
888/*
889 * Print out the contents of an inode.
890 */
891static int
892cd9660_print(ap)
893 struct vop_print_args /* {
894 struct vnode *a_vp;
895 } */ *ap;
896{
897
898 printf("tag VT_ISOFS, isofs vnode\n");
899 return (0);
900}
901
902/*
903 * Check for a locked inode.
904 */
905int
906cd9660_islocked(ap)
907 struct vop_islocked_args /* {
908 struct vnode *a_vp;
909 } */ *ap;
910{
911
912 return (lockstatus(&VTOI(ap->a_vp)->i_lock));
913}
914
915/*
916 * Return POSIX pathconf information applicable to cd9660 filesystems.
917 */
918int
919cd9660_pathconf(ap)
920 struct vop_pathconf_args /* {
921 struct vnode *a_vp;
922 int a_name;
923 register_t *a_retval;
924 } */ *ap;
925{
926
927 switch (ap->a_name) {
928 case _PC_LINK_MAX:
929 *ap->a_retval = 1;
930 return (0);
931 case _PC_NAME_MAX:
932 if (VTOI(ap->a_vp)->i_mnt->iso_ftype == ISO_FTYPE_RRIP)
933 *ap->a_retval = NAME_MAX;
934 else
935 *ap->a_retval = 37;
936 return (0);
937 case _PC_PATH_MAX:
938 *ap->a_retval = PATH_MAX;
939 return (0);
940 case _PC_PIPE_BUF:
941 *ap->a_retval = PIPE_BUF;
942 return (0);
943 case _PC_CHOWN_RESTRICTED:
944 *ap->a_retval = 1;
945 return (0);
946 case _PC_NO_TRUNC:
947 *ap->a_retval = 1;
948 return (0);
949 default:
950 return (EINVAL);
951 }
952 /* NOTREACHED */
953}
954
955/*
956 * Global vfs data structures for isofs
957 */
958#define cd9660_create \
959 ((int (*) __P((struct vop_create_args *)))eopnotsupp)
960#define cd9660_mknod ((int (*) __P((struct vop_mknod_args *)))eopnotsupp)
961#define cd9660_write ((int (*) __P((struct vop_write_args *)))eopnotsupp)
962#ifdef NFS
963#define cd9660_lease_check lease_check
964#else
965#define cd9660_lease_check ((int (*) __P((struct vop_lease_args *)))nullop)
966#endif
967#define cd9660_poll vop_nopoll
968#define cd9660_fsync ((int (*) __P((struct vop_fsync_args *)))nullop)
969#define cd9660_remove \
970 ((int (*) __P((struct vop_remove_args *)))eopnotsupp)
971#define cd9660_link ((int (*) __P((struct vop_link_args *)))eopnotsupp)
972#define cd9660_rename \
973 ((int (*) __P((struct vop_rename_args *)))eopnotsupp)
974#define cd9660_mkdir ((int (*) __P((struct vop_mkdir_args *)))eopnotsupp)
975#define cd9660_rmdir ((int (*) __P((struct vop_rmdir_args *)))eopnotsupp)
976#define cd9660_symlink \
977 ((int (*) __P((struct vop_symlink_args *)))eopnotsupp)
978#define cd9660_advlock \
979 ((int (*) __P((struct vop_advlock_args *)))eopnotsupp)
980#define cd9660_valloc ((int(*) __P(( \
981 struct vnode *pvp, \
982 int mode, \
983 struct ucred *cred, \
984 struct vnode **vpp))) eopnotsupp)
985#define cd9660_vfree ((int (*) __P((struct vop_vfree_args *)))eopnotsupp)
986#define cd9660_truncate \
987 ((int (*) __P((struct vop_truncate_args *)))eopnotsupp)
988#define cd9660_update \
989 ((int (*) __P((struct vop_update_args *)))eopnotsupp)
990#define cd9660_bwrite \
991 ((int (*) __P((struct vop_bwrite_args *)))eopnotsupp)
992
993/*
994 * Global vfs data structures for cd9660
995 */
996vop_t **cd9660_vnodeop_p;
997struct vnodeopv_entry_desc cd9660_vnodeop_entries[] = {
998
999 { &vop_default_desc, (vop_t *)vn_default_error },
1000 { &vop_lookup_desc, (vop_t *)vfs_cache_lookup }, /* lookup */
1001 { &vop_cachedlookup_desc, (vop_t *)cd9660_lookup }, /* lookup */
1002 { &vop_create_desc, (vop_t *)cd9660_create }, /* create */
1003/* XXX: vop_whiteout */
1004 { &vop_mknod_desc, (vop_t *)cd9660_mknod }, /* mknod */
1005 { &vop_open_desc, (vop_t *)cd9660_open }, /* open */
1006 { &vop_close_desc, (vop_t *)cd9660_close }, /* close */
1007 { &vop_access_desc, (vop_t *)cd9660_access }, /* access */
1008 { &vop_getattr_desc, (vop_t *)cd9660_getattr }, /* getattr */
1009 { &vop_setattr_desc, (vop_t *)cd9660_setattr }, /* setattr */
1010 { &vop_read_desc, (vop_t *)cd9660_read }, /* read */
1011 { &vop_write_desc, (vop_t *)cd9660_write }, /* write */
1012 { &vop_lease_desc, (vop_t *)cd9660_lease_check },/* lease */
1013 { &vop_ioctl_desc, (vop_t *)cd9660_ioctl }, /* ioctl */
1014 { &vop_poll_desc, (vop_t *)cd9660_poll }, /* poll */
1015 { &vop_revoke_desc, (vop_t *)cd9660_revoke }, /* revoke */
1016 { &vop_mmap_desc, (vop_t *)cd9660_mmap }, /* mmap */
1017 { &vop_fsync_desc, (vop_t *)cd9660_fsync }, /* fsync */
1018 { &vop_seek_desc, (vop_t *)cd9660_seek }, /* seek */
1019 { &vop_remove_desc, (vop_t *)cd9660_remove }, /* remove */
1020 { &vop_link_desc, (vop_t *)cd9660_link }, /* link */
1021 { &vop_rename_desc, (vop_t *)cd9660_rename }, /* rename */
1022 { &vop_mkdir_desc, (vop_t *)cd9660_mkdir }, /* mkdir */
1023 { &vop_rmdir_desc, (vop_t *)cd9660_rmdir }, /* rmdir */
1024 { &vop_symlink_desc, (vop_t *)cd9660_symlink }, /* symlink */
1025 { &vop_readdir_desc, (vop_t *)cd9660_readdir }, /* readdir */
1026 { &vop_readlink_desc, (vop_t *)cd9660_readlink },/* readlink */
1027 { &vop_abortop_desc, (vop_t *)cd9660_abortop }, /* abortop */
1028 { &vop_inactive_desc, (vop_t *)cd9660_inactive },/* inactive */
1029 { &vop_reclaim_desc, (vop_t *)cd9660_reclaim }, /* reclaim */
1030 { &vop_lock_desc, (vop_t *)cd9660_lock }, /* lock */
1031 { &vop_unlock_desc, (vop_t *)cd9660_unlock }, /* unlock */
1032 { &vop_bmap_desc, (vop_t *)cd9660_bmap }, /* bmap */
1033 { &vop_strategy_desc, (vop_t *)cd9660_strategy },/* strategy */
1034 { &vop_print_desc, (vop_t *)cd9660_print }, /* print */
1035 { &vop_islocked_desc, (vop_t *)cd9660_islocked },/* islocked */
1036 { &vop_pathconf_desc, (vop_t *)cd9660_pathconf },/* pathconf */
1037 { &vop_advlock_desc, (vop_t *)cd9660_advlock }, /* advlock */
1038 { &vop_blkatoff_desc, (vop_t *)cd9660_blkatoff },/* blkatoff */
1039 { &vop_valloc_desc, (vop_t *)cd9660_valloc }, /* valloc */
1040/* XXX: vop_reallocblks */
1041 { &vop_vfree_desc, (vop_t *)cd9660_vfree }, /* vfree */
1042 { &vop_truncate_desc, (vop_t *)cd9660_truncate },/* truncate */
1043 { &vop_update_desc, (vop_t *)cd9660_update }, /* update */
1044/* XXX: vop_getpages */
1045/* XXX: vop_putpages */
1046 { &vop_bwrite_desc, (vop_t *)vn_bwrite },
1047 { NULL, NULL }
1048};
1049static struct vnodeopv_desc cd9660_vnodeop_opv_desc =
1050 { &cd9660_vnodeop_p, cd9660_vnodeop_entries };
1051VNODEOP_SET(cd9660_vnodeop_opv_desc);
1052
1053/*
1054 * Special device vnode ops
1055 */
1056vop_t **cd9660_specop_p;
1057struct vnodeopv_entry_desc cd9660_specop_entries[] = {
1058 { &vop_default_desc, (vop_t *)vn_default_error },
1059 { &vop_lookup_desc, (vop_t *)spec_lookup }, /* lookup */
1060/* XXX: vop_cachedlookup */
1061 { &vop_create_desc, (vop_t *)spec_create }, /* create */
1062/* XXX: vop_whiteout */
1063 { &vop_mknod_desc, (vop_t *)spec_mknod }, /* mknod */
1064 { &vop_open_desc, (vop_t *)spec_open }, /* open */
1065 { &vop_close_desc, (vop_t *)spec_close }, /* close */
1066 { &vop_access_desc, (vop_t *)cd9660_access }, /* access */
1067 { &vop_getattr_desc, (vop_t *)cd9660_getattr }, /* getattr */
1068 { &vop_setattr_desc, (vop_t *)cd9660_setattr }, /* setattr */
1069 { &vop_read_desc, (vop_t *)spec_read }, /* read */
1070 { &vop_write_desc, (vop_t *)spec_write }, /* write */
1071 { &vop_lease_desc, (vop_t *)spec_lease_check }, /* lease */
1072 { &vop_ioctl_desc, (vop_t *)spec_ioctl }, /* ioctl */
1073 { &vop_poll_desc, (vop_t *)spec_poll }, /* poll */
1074 { &vop_revoke_desc, (vop_t *)spec_revoke }, /* revoke */
1075 { &vop_mmap_desc, (vop_t *)spec_mmap }, /* mmap */
1076 { &vop_fsync_desc, (vop_t *)spec_fsync }, /* fsync */
1077 { &vop_seek_desc, (vop_t *)spec_seek }, /* seek */
1078 { &vop_remove_desc, (vop_t *)spec_remove }, /* remove */
1079 { &vop_link_desc, (vop_t *)spec_link }, /* link */
1080 { &vop_rename_desc, (vop_t *)spec_rename }, /* rename */
1081 { &vop_mkdir_desc, (vop_t *)spec_mkdir }, /* mkdir */
1082 { &vop_rmdir_desc, (vop_t *)spec_rmdir }, /* rmdir */
1083 { &vop_symlink_desc, (vop_t *)spec_symlink }, /* symlink */
1084 { &vop_readdir_desc, (vop_t *)spec_readdir }, /* readdir */
1085 { &vop_readlink_desc, (vop_t *)spec_readlink }, /* readlink */
1086 { &vop_abortop_desc, (vop_t *)spec_abortop }, /* abortop */
1087 { &vop_inactive_desc, (vop_t *)cd9660_inactive },/* inactive */
1088 { &vop_reclaim_desc, (vop_t *)cd9660_reclaim }, /* reclaim */
1089 { &vop_lock_desc, (vop_t *)cd9660_lock }, /* lock */
1090 { &vop_unlock_desc, (vop_t *)cd9660_unlock }, /* unlock */
1091 { &vop_bmap_desc, (vop_t *)spec_bmap }, /* bmap */
1092 { &vop_strategy_desc, (vop_t *)spec_strategy }, /* strategy */
1093 { &vop_print_desc, (vop_t *)cd9660_print }, /* print */
1094 { &vop_islocked_desc, (vop_t *)cd9660_islocked },/* islocked */
1095 { &vop_pathconf_desc, (vop_t *)spec_pathconf }, /* pathconf */
1096 { &vop_advlock_desc, (vop_t *)spec_advlock }, /* advlock */
1097 { &vop_blkatoff_desc, (vop_t *)spec_blkatoff }, /* blkatoff */
1098 { &vop_valloc_desc, (vop_t *)spec_valloc }, /* valloc */
1099/* XXX: vop_reallocblks */
1100 { &vop_vfree_desc, (vop_t *)spec_vfree }, /* vfree */
1101 { &vop_truncate_desc, (vop_t *)spec_truncate }, /* truncate */
1102 { &vop_update_desc, (vop_t *)cd9660_update }, /* update */
1103/* XXX: vop_getpages */
1104/* XXX: vop_putpages */
1105 { &vop_bwrite_desc, (vop_t *)vn_bwrite },
1106 { NULL, NULL }
1107};
1108static struct vnodeopv_desc cd9660_specop_opv_desc =
1109 { &cd9660_specop_p, cd9660_specop_entries };
1110VNODEOP_SET(cd9660_specop_opv_desc);
1111
1112vop_t **cd9660_fifoop_p;
1113struct vnodeopv_entry_desc cd9660_fifoop_entries[] = {
1114 { &vop_default_desc, (vop_t *)vn_default_error },
1115 { &vop_lookup_desc, (vop_t *)fifo_lookup }, /* lookup */
1116/* XXX: vop_cachedlookup */
1117 { &vop_create_desc, (vop_t *)fifo_create }, /* create */
1118/* XXX: vop_whiteout */
1119 { &vop_mknod_desc, (vop_t *)fifo_mknod }, /* mknod */
1120 { &vop_open_desc, (vop_t *)fifo_open }, /* open */
1121 { &vop_close_desc, (vop_t *)fifo_close }, /* close */
1122 { &vop_access_desc, (vop_t *)cd9660_access }, /* access */
1123 { &vop_getattr_desc, (vop_t *)cd9660_getattr }, /* getattr */
1124 { &vop_setattr_desc, (vop_t *)cd9660_setattr }, /* setattr */
1125 { &vop_read_desc, (vop_t *)fifo_read }, /* read */
1126 { &vop_write_desc, (vop_t *)fifo_write }, /* write */
1127 { &vop_lease_desc, (vop_t *)fifo_lease_check }, /* lease */
1128 { &vop_ioctl_desc, (vop_t *)fifo_ioctl }, /* ioctl */
1129 { &vop_poll_desc, (vop_t *)fifo_poll }, /* poll */
1130 { &vop_revoke_desc, (vop_t *)fifo_revoke }, /* revoke */
1131 { &vop_mmap_desc, (vop_t *)fifo_mmap }, /* mmap */
1132 { &vop_fsync_desc, (vop_t *)fifo_fsync }, /* fsync */
1133 { &vop_seek_desc, (vop_t *)fifo_seek }, /* seek */
1134 { &vop_remove_desc, (vop_t *)fifo_remove }, /* remove */
1135 { &vop_link_desc, (vop_t *)fifo_link } , /* link */
1136 { &vop_rename_desc, (vop_t *)fifo_rename }, /* rename */
1137 { &vop_mkdir_desc, (vop_t *)fifo_mkdir }, /* mkdir */
1138 { &vop_rmdir_desc, (vop_t *)fifo_rmdir }, /* rmdir */
1139 { &vop_symlink_desc, (vop_t *)fifo_symlink }, /* symlink */
1140 { &vop_readdir_desc, (vop_t *)fifo_readdir }, /* readdir */
1141 { &vop_readlink_desc, (vop_t *)fifo_readlink }, /* readlink */
1142 { &vop_abortop_desc, (vop_t *)fifo_abortop }, /* abortop */
1143 { &vop_inactive_desc, (vop_t *)cd9660_inactive },/* inactive */
1144 { &vop_reclaim_desc, (vop_t *)cd9660_reclaim }, /* reclaim */
1145 { &vop_lock_desc, (vop_t *)cd9660_lock }, /* lock */
1146 { &vop_unlock_desc, (vop_t *)cd9660_unlock }, /* unlock */
1147 { &vop_bmap_desc, (vop_t *)fifo_bmap }, /* bmap */
1148 { &vop_strategy_desc, (vop_t *)fifo_strategy }, /* strategy */
1149 { &vop_print_desc, (vop_t *)cd9660_print }, /* print */
1150 { &vop_islocked_desc, (vop_t *)cd9660_islocked },/* islocked */
1151 { &vop_pathconf_desc, (vop_t *)fifo_pathconf }, /* pathconf */
1152 { &vop_advlock_desc, (vop_t *)fifo_advlock }, /* advlock */
1153 { &vop_blkatoff_desc, (vop_t *)fifo_blkatoff }, /* blkatoff */
1154 { &vop_valloc_desc, (vop_t *)fifo_valloc }, /* valloc */
1155/* XXX: vop_reallocpages */
1156 { &vop_vfree_desc, (vop_t *)fifo_vfree }, /* vfree */
1157 { &vop_truncate_desc, (vop_t *)fifo_truncate }, /* truncate */
1158 { &vop_update_desc, (vop_t *)cd9660_update }, /* update */
1159/* XXX: vop_getpages */
1160/* XXX: vop_putpages */
1161 { &vop_bwrite_desc, (vop_t *)vn_bwrite },
1162 { NULL, NULL }
1163};
1164static struct vnodeopv_desc cd9660_fifoop_opv_desc =
1165 { &cd9660_fifoop_p, cd9660_fifoop_entries };
1166
1167VNODEOP_SET(cd9660_fifoop_opv_desc);