]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/fs/cd9660/cd9660_vnops.c
This commit was generated by cvs2svn to compensate for changes in r171825,
[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  * 4. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  *
34  *      @(#)cd9660_vnops.c      8.19 (Berkeley) 5/27/95
35  */
36
37 #include <sys/cdefs.h>
38 __FBSDID("$FreeBSD$");
39
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/namei.h>
43 #include <sys/kernel.h>
44 #include <sys/conf.h>
45 #include <sys/stat.h>
46 #include <sys/bio.h>
47 #include <sys/buf.h>
48 #include <sys/mount.h>
49 #include <sys/vnode.h>
50 #include <fs/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/vnode_pager.h>
58 #include <vm/uma.h>
59
60 #include <fs/cd9660/iso.h>
61 #include <fs/cd9660/cd9660_node.h>
62 #include <fs/cd9660/iso_rrip.h>
63
64 static vop_setattr_t    cd9660_setattr;
65 static vop_open_t       cd9660_open;
66 static vop_access_t     cd9660_access;
67 static vop_getattr_t    cd9660_getattr;
68 static vop_ioctl_t      cd9660_ioctl;
69 static vop_pathconf_t   cd9660_pathconf;
70 static vop_read_t       cd9660_read;
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 vop_readdir_t    cd9660_readdir;
75 static vop_readlink_t   cd9660_readlink;
76 static vop_strategy_t   cd9660_strategy;
77 static vop_vptofh_t     cd9660_vptofh;
78
79 /*
80  * Setattr call. Only allowed for block and character special devices.
81  */
82 static int
83 cd9660_setattr(ap)
84         struct vop_setattr_args /* {
85                 struct vnodeop_desc *a_desc;
86                 struct vnode *a_vp;
87                 struct vattr *a_vap;
88                 struct ucred *a_cred;
89                 struct thread *a_td;
90         } */ *ap;
91 {
92         struct vnode *vp = ap->a_vp;
93         struct vattr *vap = ap->a_vap;
94
95         if (vap->va_flags != (u_long)VNOVAL || vap->va_uid != (uid_t)VNOVAL ||
96             vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL ||
97             vap->va_mtime.tv_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL)
98                 return (EROFS);
99         if (vap->va_size != (u_quad_t)VNOVAL) {
100                 switch (vp->v_type) {
101                 case VDIR:
102                         return (EISDIR);
103                 case VLNK:
104                 case VREG:
105                         return (EROFS);
106                 case VCHR:
107                 case VBLK:
108                 case VSOCK:
109                 case VFIFO:
110                 case VNON:
111                 case VBAD:
112                 case VMARKER:
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         if (vp->v_type == VCHR || vp->v_type == VBLK)
139                 return (EOPNOTSUPP);
140
141         /*
142          * Disallow write attempts unless the file is a socket,
143          * fifo, or a block or character device resident on the
144          * filesystem.
145          */
146         if (mode & VWRITE) {
147                 switch (vp->v_type) {
148                 case VDIR:
149                 case VLNK:
150                 case VREG:
151                         return (EROFS);
152                         /* NOT REACHED */
153                 default:
154                         break;
155                 }
156         }
157
158         return (vaccess(vp->v_type, ip->inode.iso_mode, ip->inode.iso_uid,
159             ip->inode.iso_gid, ap->a_mode, ap->a_cred, NULL));
160 }
161
162 static int
163 cd9660_open(ap)
164         struct vop_open_args /* {
165                 struct vnode *a_vp;
166                 int a_mode;
167                 struct ucred *a_cred;
168                 struct thread *a_td;
169                 int a_fdidx;
170         } */ *ap;
171 {
172         struct iso_node *ip = VTOI(ap->a_vp);
173
174         vnode_create_vobject(ap->a_vp, ip->i_size, ap->a_td);
175         return 0;
176 }
177
178
179 static int
180 cd9660_getattr(ap)
181         struct vop_getattr_args /* {
182                 struct vnode *a_vp;
183                 struct vattr *a_vap;
184                 struct ucred *a_cred;
185                 struct thread *a_td;
186         } */ *ap;
187
188 {
189         struct vnode *vp = ap->a_vp;
190         struct vattr *vap = ap->a_vap;
191         struct iso_node *ip = VTOI(vp);
192
193         vap->va_fsid    = dev2udev(ip->i_mnt->im_dev);
194         vap->va_fileid  = ip->i_number;
195
196         vap->va_mode    = ip->inode.iso_mode;
197         vap->va_nlink   = ip->inode.iso_links;
198         vap->va_uid     = ip->inode.iso_uid;
199         vap->va_gid     = ip->inode.iso_gid;
200         vap->va_atime   = ip->inode.iso_atime;
201         vap->va_mtime   = ip->inode.iso_mtime;
202         vap->va_ctime   = ip->inode.iso_ctime;
203         vap->va_rdev    = ip->inode.iso_rdev;
204
205         vap->va_size    = (u_quad_t) ip->i_size;
206         if (ip->i_size == 0 && (vap->va_mode & S_IFMT) == S_IFLNK) {
207                 struct vop_readlink_args rdlnk;
208                 struct iovec aiov;
209                 struct uio auio;
210                 char *cp;
211
212                 MALLOC(cp, char *, MAXPATHLEN, M_TEMP, M_WAITOK);
213                 aiov.iov_base = cp;
214                 aiov.iov_len = MAXPATHLEN;
215                 auio.uio_iov = &aiov;
216                 auio.uio_iovcnt = 1;
217                 auio.uio_offset = 0;
218                 auio.uio_rw = UIO_READ;
219                 auio.uio_segflg = UIO_SYSSPACE;
220                 auio.uio_td = ap->a_td;
221                 auio.uio_resid = MAXPATHLEN;
222                 rdlnk.a_uio = &auio;
223                 rdlnk.a_vp = ap->a_vp;
224                 rdlnk.a_cred = ap->a_cred;
225                 if (cd9660_readlink(&rdlnk) == 0)
226                         vap->va_size = MAXPATHLEN - auio.uio_resid;
227                 FREE(cp, M_TEMP);
228         }
229         vap->va_flags   = 0;
230         vap->va_gen = 1;
231         vap->va_blocksize = ip->i_mnt->logical_block_size;
232         vap->va_bytes   = (u_quad_t) ip->i_size;
233         vap->va_type    = vp->v_type;
234         vap->va_filerev = 0;
235         return (0);
236 }
237
238 /*
239  * Vnode op for ioctl.
240  */
241 static int
242 cd9660_ioctl(ap)
243         struct vop_ioctl_args /* {
244                 struct vnode *a_vp;
245                 u_long  a_command;
246                 caddr_t  a_data;
247                 int  a_fflag;
248                 struct ucred *a_cred;
249                 struct thread *a_td;
250         } */ *ap;
251 {
252         struct vnode *vp = ap->a_vp;
253         struct iso_node *ip = VTOI(vp);
254
255         if (vp->v_type == VCHR || vp->v_type == VBLK)
256                 return (EOPNOTSUPP);
257
258         switch (ap->a_command) {
259
260         case FIOGETLBA:
261                 *(int *)(ap->a_data) = ip->iso_start;
262                 return 0;
263         default:
264                 return (ENOTTY);
265         }
266 }
267
268 /*
269  * Vnode op for reading.
270  */
271 static int
272 cd9660_read(ap)
273         struct vop_read_args /* {
274                 struct vnode *a_vp;
275                 struct uio *a_uio;
276                 int a_ioflag;
277                 struct ucred *a_cred;
278         } */ *ap;
279 {
280         struct vnode *vp = ap->a_vp;
281         struct uio *uio = ap->a_uio;
282         struct iso_node *ip = VTOI(vp);
283         struct iso_mnt *imp;
284         struct buf *bp;
285         daddr_t lbn, rablock;
286         off_t diff;
287         int rasize, error = 0;
288         int seqcount;
289         long size, n, on;
290
291         if (vp->v_type == VCHR || vp->v_type == VBLK)
292                 return (EOPNOTSUPP);
293
294         seqcount = ap->a_ioflag >> IO_SEQSHIFT;
295
296         if (uio->uio_resid == 0)
297                 return (0);
298         if (uio->uio_offset < 0)
299                 return (EINVAL);
300         ip->i_flag |= IN_ACCESS;
301         imp = ip->i_mnt;
302         do {
303                 lbn = lblkno(imp, uio->uio_offset);
304                 on = blkoff(imp, uio->uio_offset);
305                 n = min((u_int)(imp->logical_block_size - on),
306                         uio->uio_resid);
307                 diff = (off_t)ip->i_size - uio->uio_offset;
308                 if (diff <= 0)
309                         return (0);
310                 if (diff < n)
311                         n = diff;
312                 size = blksize(imp, ip, lbn);
313                 rablock = lbn + 1;
314                 if ((vp->v_mount->mnt_flag & MNT_NOCLUSTERR) == 0) {
315                         if (lblktosize(imp, rablock) < ip->i_size)
316                                 error = cluster_read(vp, (off_t)ip->i_size,
317                                          lbn, size, NOCRED, uio->uio_resid,
318                                          (ap->a_ioflag >> 16), &bp);
319                         else
320                                 error = bread(vp, lbn, size, NOCRED, &bp);
321                 } else {
322                         if (seqcount > 1 &&
323                             lblktosize(imp, rablock) < ip->i_size) {
324                                 rasize = blksize(imp, ip, rablock);
325                                 error = breadn(vp, lbn, size, &rablock,
326                                                &rasize, 1, NOCRED, &bp);
327                         } else
328                                 error = bread(vp, lbn, size, NOCRED, &bp);
329                 }
330                 n = min(n, size - bp->b_resid);
331                 if (error) {
332                         brelse(bp);
333                         return (error);
334                 }
335
336                 error = uiomove(bp->b_data + on, (int)n, uio);
337                 brelse(bp);
338         } while (error == 0 && uio->uio_resid > 0 && n != 0);
339         return (error);
340 }
341
342 /*
343  * Structure for reading directories
344  */
345 struct isoreaddir {
346         struct dirent saveent;
347         struct dirent assocent;
348         struct dirent current;
349         off_t saveoff;
350         off_t assocoff;
351         off_t curroff;
352         struct uio *uio;
353         off_t uio_off;
354         int eofflag;
355         u_long *cookies;
356         int ncookies;
357 };
358
359 static int
360 iso_uiodir(idp,dp,off)
361         struct isoreaddir *idp;
362         struct dirent *dp;
363         off_t off;
364 {
365         int error;
366
367         dp->d_name[dp->d_namlen] = 0;
368         dp->d_reclen = GENERIC_DIRSIZ(dp);
369
370         if (idp->uio->uio_resid < dp->d_reclen) {
371                 idp->eofflag = 0;
372                 return (-1);
373         }
374
375         if (idp->cookies) {
376                 if (idp->ncookies <= 0) {
377                         idp->eofflag = 0;
378                         return (-1);
379                 }
380
381                 *idp->cookies++ = off;
382                 --idp->ncookies;
383         }
384
385         if ((error = uiomove(dp, dp->d_reclen, idp->uio)) != 0)
386                 return (error);
387         idp->uio_off = off;
388         return (0);
389 }
390
391 static int
392 iso_shipdir(idp)
393         struct isoreaddir *idp;
394 {
395         struct dirent *dp;
396         int cl, sl, assoc;
397         int error;
398         char *cname, *sname;
399
400         cl = idp->current.d_namlen;
401         cname = idp->current.d_name;
402 assoc = (cl > 1) && (*cname == ASSOCCHAR);
403         if (assoc) {
404                 cl--;
405                 cname++;
406         }
407
408         dp = &idp->saveent;
409         sname = dp->d_name;
410         if (!(sl = dp->d_namlen)) {
411                 dp = &idp->assocent;
412                 sname = dp->d_name + 1;
413                 sl = dp->d_namlen - 1;
414         }
415         if (sl > 0) {
416                 if (sl != cl
417                     || bcmp(sname,cname,sl)) {
418                         if (idp->assocent.d_namlen) {
419                                 if ((error = iso_uiodir(idp,&idp->assocent,idp->assocoff)) != 0)
420                                         return (error);
421                                 idp->assocent.d_namlen = 0;
422                         }
423                         if (idp->saveent.d_namlen) {
424                                 if ((error = iso_uiodir(idp,&idp->saveent,idp->saveoff)) != 0)
425                                         return (error);
426                                 idp->saveent.d_namlen = 0;
427                         }
428                 }
429         }
430         idp->current.d_reclen = GENERIC_DIRSIZ(&idp->current);
431         if (assoc) {
432                 idp->assocoff = idp->curroff;
433                 bcopy(&idp->current,&idp->assocent,idp->current.d_reclen);
434         } else {
435                 idp->saveoff = idp->curroff;
436                 bcopy(&idp->current,&idp->saveent,idp->current.d_reclen);
437         }
438         return (0);
439 }
440
441 /*
442  * Vnode op for readdir
443  */
444 static int
445 cd9660_readdir(ap)
446         struct vop_readdir_args /* {
447                 struct vnode *a_vp;
448                 struct uio *a_uio;
449                 struct ucred *a_cred;
450                 int *a_eofflag;
451                 int *a_ncookies;
452                 u_long **a_cookies;
453         } */ *ap;
454 {
455         struct uio *uio = ap->a_uio;
456         struct isoreaddir *idp;
457         struct vnode *vdp = ap->a_vp;
458         struct iso_node *dp;
459         struct iso_mnt *imp;
460         struct buf *bp = NULL;
461         struct iso_directory_record *ep;
462         int entryoffsetinblock;
463         doff_t endsearch;
464         u_long bmask;
465         int error = 0;
466         int reclen;
467         u_short namelen;
468         int ncookies = 0;
469         u_long *cookies = NULL;
470
471         dp = VTOI(vdp);
472         imp = dp->i_mnt;
473         bmask = imp->im_bmask;
474
475         MALLOC(idp, struct isoreaddir *, sizeof(*idp), M_TEMP, M_WAITOK);
476         idp->saveent.d_namlen = idp->assocent.d_namlen = 0;
477         /*
478          * XXX
479          * Is it worth trying to figure out the type?
480          */
481         idp->saveent.d_type = idp->assocent.d_type = idp->current.d_type =
482             DT_UNKNOWN;
483         idp->uio = uio;
484         if (ap->a_ncookies == NULL) {
485                 idp->cookies = NULL;
486         } else {
487                 /*
488                  * Guess the number of cookies needed.
489                  */
490                 ncookies = uio->uio_resid / 16;
491                 MALLOC(cookies, u_long *, ncookies * sizeof(u_long),
492                     M_TEMP, M_WAITOK);
493                 idp->cookies = cookies;
494                 idp->ncookies = ncookies;
495         }
496         idp->eofflag = 1;
497         idp->curroff = uio->uio_offset;
498
499         if ((entryoffsetinblock = idp->curroff & bmask) &&
500             (error = cd9660_blkatoff(vdp, (off_t)idp->curroff, NULL, &bp))) {
501                 FREE(idp, M_TEMP);
502                 return (error);
503         }
504         endsearch = dp->i_size;
505
506         while (idp->curroff < endsearch) {
507                 /*
508                  * If offset is on a block boundary,
509                  * read the next directory block.
510                  * Release previous if it exists.
511                  */
512                 if ((idp->curroff & bmask) == 0) {
513                         if (bp != NULL)
514                                 brelse(bp);
515                         if ((error =
516                             cd9660_blkatoff(vdp, (off_t)idp->curroff, NULL, &bp)) != 0)
517                                 break;
518                         entryoffsetinblock = 0;
519                 }
520                 /*
521                  * Get pointer to next entry.
522                  */
523                 ep = (struct iso_directory_record *)
524                         ((char *)bp->b_data + entryoffsetinblock);
525
526                 reclen = isonum_711(ep->length);
527                 if (reclen == 0) {
528                         /* skip to next block, if any */
529                         idp->curroff =
530                             (idp->curroff & ~bmask) + imp->logical_block_size;
531                         continue;
532                 }
533
534                 if (reclen < ISO_DIRECTORY_RECORD_SIZE) {
535                         error = EINVAL;
536                         /* illegal entry, stop */
537                         break;
538                 }
539
540                 if (entryoffsetinblock + reclen > imp->logical_block_size) {
541                         error = EINVAL;
542                         /* illegal directory, so stop looking */
543                         break;
544                 }
545
546                 idp->current.d_namlen = isonum_711(ep->name_len);
547
548                 if (reclen < ISO_DIRECTORY_RECORD_SIZE + idp->current.d_namlen) {
549                         error = EINVAL;
550                         /* illegal entry, stop */
551                         break;
552                 }
553
554                 if (isonum_711(ep->flags)&2)
555                         idp->current.d_fileno = isodirino(ep, imp);
556                 else
557                         idp->current.d_fileno = dbtob(bp->b_blkno) +
558                                 entryoffsetinblock;
559
560                 idp->curroff += reclen;
561
562                 switch (imp->iso_ftype) {
563                 case ISO_FTYPE_RRIP:
564                         cd9660_rrip_getname(ep,idp->current.d_name, &namelen,
565                                            &idp->current.d_fileno,imp);
566                         idp->current.d_namlen = (u_char)namelen;
567                         if (idp->current.d_namlen)
568                                 error = iso_uiodir(idp,&idp->current,idp->curroff);
569                         break;
570                 default: /* ISO_FTYPE_DEFAULT || ISO_FTYPE_9660 || ISO_FTYPE_HIGH_SIERRA*/
571                         strcpy(idp->current.d_name,"..");
572                         if (idp->current.d_namlen == 1 && ep->name[0] == 0) {
573                                 idp->current.d_namlen = 1;
574                                 error = iso_uiodir(idp,&idp->current,idp->curroff);
575                         } else if (idp->current.d_namlen == 1 && ep->name[0] == 1) {
576                                 idp->current.d_namlen = 2;
577                                 error = iso_uiodir(idp,&idp->current,idp->curroff);
578                         } else {
579                                 isofntrans(ep->name,idp->current.d_namlen,
580                                            idp->current.d_name, &namelen,
581                                            imp->iso_ftype == ISO_FTYPE_9660,
582                                            isonum_711(ep->flags)&4,
583                                            imp->joliet_level,
584                                            imp->im_flags,
585                                            imp->im_d2l);
586                                 idp->current.d_namlen = (u_char)namelen;
587                                 if (imp->iso_ftype == ISO_FTYPE_DEFAULT)
588                                         error = iso_shipdir(idp);
589                                 else
590                                         error = iso_uiodir(idp,&idp->current,idp->curroff);
591                         }
592                 }
593                 if (error)
594                         break;
595
596                 entryoffsetinblock += reclen;
597         }
598
599         if (!error && imp->iso_ftype == ISO_FTYPE_DEFAULT) {
600                 idp->current.d_namlen = 0;
601                 error = iso_shipdir(idp);
602         }
603         if (error < 0)
604                 error = 0;
605
606         if (ap->a_ncookies != NULL) {
607                 if (error)
608                         free(cookies, M_TEMP);
609                 else {
610                         /*
611                          * Work out the number of cookies actually used.
612                          */
613                         *ap->a_ncookies = ncookies - idp->ncookies;
614                         *ap->a_cookies = cookies;
615                 }
616         }
617
618         if (bp)
619                 brelse (bp);
620
621         uio->uio_offset = idp->uio_off;
622         *ap->a_eofflag = idp->eofflag;
623
624         FREE(idp, M_TEMP);
625
626         return (error);
627 }
628
629 /*
630  * Return target name of a symbolic link
631  * Shouldn't we get the parent vnode and read the data from there?
632  * This could eventually result in deadlocks in cd9660_lookup.
633  * But otherwise the block read here is in the block buffer two times.
634  */
635 typedef struct iso_directory_record ISODIR;
636 typedef struct iso_node             ISONODE;
637 typedef struct iso_mnt              ISOMNT;
638 static int
639 cd9660_readlink(ap)
640         struct vop_readlink_args /* {
641                 struct vnode *a_vp;
642                 struct uio *a_uio;
643                 struct ucred *a_cred;
644         } */ *ap;
645 {
646         ISONODE *ip;
647         ISODIR  *dirp;
648         ISOMNT  *imp;
649         struct  buf *bp;
650         struct  uio *uio;
651         u_short symlen;
652         int     error;
653         char    *symname;
654
655         ip  = VTOI(ap->a_vp);
656         imp = ip->i_mnt;
657         uio = ap->a_uio;
658
659         if (imp->iso_ftype != ISO_FTYPE_RRIP)
660                 return (EINVAL);
661
662         /*
663          * Get parents directory record block that this inode included.
664          */
665         error = bread(imp->im_devvp,
666                       (ip->i_number >> imp->im_bshift) <<
667                       (imp->im_bshift - DEV_BSHIFT),
668                       imp->logical_block_size, NOCRED, &bp);
669         if (error) {
670                 brelse(bp);
671                 return (EINVAL);
672         }
673
674         /*
675          * Setup the directory pointer for this inode
676          */
677         dirp = (ISODIR *)(bp->b_data + (ip->i_number & imp->im_bmask));
678
679         /*
680          * Just make sure, we have a right one....
681          *   1: Check not cross boundary on block
682          */
683         if ((ip->i_number & imp->im_bmask) + isonum_711(dirp->length)
684             > (unsigned)imp->logical_block_size) {
685                 brelse(bp);
686                 return (EINVAL);
687         }
688
689         /*
690          * Now get a buffer
691          * Abuse a namei buffer for now.
692          */
693         if (uio->uio_segflg == UIO_SYSSPACE)
694                 symname = uio->uio_iov->iov_base;
695         else
696                 symname = uma_zalloc(namei_zone, M_WAITOK);
697
698         /*
699          * Ok, we just gathering a symbolic name in SL record.
700          */
701         if (cd9660_rrip_getsymname(dirp, symname, &symlen, imp) == 0) {
702                 if (uio->uio_segflg != UIO_SYSSPACE)
703                         uma_zfree(namei_zone, symname);
704                 brelse(bp);
705                 return (EINVAL);
706         }
707         /*
708          * Don't forget before you leave from home ;-)
709          */
710         brelse(bp);
711
712         /*
713          * return with the symbolic name to caller's.
714          */
715         if (uio->uio_segflg != UIO_SYSSPACE) {
716                 error = uiomove(symname, symlen, uio);
717                 uma_zfree(namei_zone, symname);
718                 return (error);
719         }
720         uio->uio_resid -= symlen;
721         uio->uio_iov->iov_base = (char *)uio->uio_iov->iov_base + symlen;
722         uio->uio_iov->iov_len -= symlen;
723         return (0);
724 }
725
726 /*
727  * Calculate the logical to physical mapping if not done already,
728  * then call the device strategy routine.
729  */
730 static int
731 cd9660_strategy(ap)
732         struct vop_strategy_args /* {
733                 struct buf *a_vp;
734                 struct buf *a_bp;
735         } */ *ap;
736 {
737         struct buf *bp = ap->a_bp;
738         struct vnode *vp = ap->a_vp;
739         struct iso_node *ip;
740         struct bufobj *bo;
741
742         ip = VTOI(vp);
743         if (vp->v_type == VBLK || vp->v_type == VCHR)
744                 panic("cd9660_strategy: spec");
745         if (bp->b_blkno == bp->b_lblkno) {
746                 bp->b_blkno = (ip->iso_start + bp->b_lblkno) <<
747                     (ip->i_mnt->im_bshift - DEV_BSHIFT);
748                 if ((long)bp->b_blkno == -1)    /* XXX: cut&paste junk ? */
749                         clrbuf(bp);
750         }
751         if ((long)bp->b_blkno == -1) {  /* XXX: cut&paste junk ? */
752                 bufdone(bp);
753                 return (0);
754         }
755         bp->b_iooffset = dbtob(bp->b_blkno);
756         bo = ip->i_mnt->im_bo;
757         BO_STRATEGY(bo, bp);
758         return (0);
759 }
760
761 /*
762  * Return POSIX pathconf information applicable to cd9660 filesystems.
763  */
764 static int
765 cd9660_pathconf(ap)
766         struct vop_pathconf_args /* {
767                 struct vnode *a_vp;
768                 int a_name;
769                 register_t *a_retval;
770         } */ *ap;
771 {
772
773         switch (ap->a_name) {
774         case _PC_LINK_MAX:
775                 *ap->a_retval = 1;
776                 return (0);
777         case _PC_NAME_MAX:
778                 if (VTOI(ap->a_vp)->i_mnt->iso_ftype == ISO_FTYPE_RRIP)
779                         *ap->a_retval = NAME_MAX;
780                 else
781                         *ap->a_retval = 37;
782                 return (0);
783         case _PC_PATH_MAX:
784                 *ap->a_retval = PATH_MAX;
785                 return (0);
786         case _PC_PIPE_BUF:
787                 *ap->a_retval = PIPE_BUF;
788                 return (0);
789         case _PC_CHOWN_RESTRICTED:
790                 *ap->a_retval = 1;
791                 return (0);
792         case _PC_NO_TRUNC:
793                 *ap->a_retval = 1;
794                 return (0);
795         default:
796                 return (EINVAL);
797         }
798         /* NOTREACHED */
799 }
800
801 /*
802  * Vnode pointer to File handle
803  */
804 static int
805 cd9660_vptofh(ap)
806         struct vop_vptofh_args /* {
807                 struct vnode *a_vp;
808                 struct fid *a_fhp;
809         } */ *ap;
810 {
811         struct iso_node *ip = VTOI(ap->a_vp);
812         struct ifid *ifhp;
813
814         ifhp = (struct ifid *)ap->a_fhp;
815         ifhp->ifid_len = sizeof(struct ifid);
816
817         ifhp->ifid_ino = ip->i_number;
818         ifhp->ifid_start = ip->iso_start;
819
820 #ifdef  ISOFS_DBG
821         printf("vptofh: ino %d, start %ld\n",
822                ifhp->ifid_ino,ifhp->ifid_start);
823 #endif
824         return 0;
825 }
826
827 /*
828  * Global vfs data structures for cd9660
829  */
830 struct vop_vector cd9660_vnodeops = {
831         .vop_default =          &default_vnodeops,
832         .vop_open =             cd9660_open,
833         .vop_access =           cd9660_access,
834         .vop_bmap =             cd9660_bmap,
835         .vop_cachedlookup =     cd9660_lookup,
836         .vop_getattr =          cd9660_getattr,
837         .vop_inactive =         cd9660_inactive,
838         .vop_ioctl =            cd9660_ioctl,
839         .vop_lookup =           vfs_cache_lookup,
840         .vop_pathconf =         cd9660_pathconf,
841         .vop_read =             cd9660_read,
842         .vop_readdir =          cd9660_readdir,
843         .vop_readlink =         cd9660_readlink,
844         .vop_reclaim =          cd9660_reclaim,
845         .vop_setattr =          cd9660_setattr,
846         .vop_strategy =         cd9660_strategy,
847         .vop_vptofh =           cd9660_vptofh,
848 };
849
850 /*
851  * Special device vnode ops
852  */
853
854 struct vop_vector cd9660_fifoops = {
855         .vop_default =          &fifo_specops,
856         .vop_access =           cd9660_access,
857         .vop_getattr =          cd9660_getattr,
858         .vop_inactive =         cd9660_inactive,
859         .vop_reclaim =          cd9660_reclaim,
860         .vop_setattr =          cd9660_setattr,
861         .vop_vptofh =           cd9660_vptofh,
862 };