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