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