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