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