]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/fs/cd9660/cd9660_vnops.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.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 vnode *vp = ap->a_vp;
173         struct iso_node *ip = VTOI(vp);
174
175         if (vp->v_type == VCHR || vp->v_type == VBLK)
176                 return (EOPNOTSUPP);
177
178         vnode_create_vobject(vp, ip->i_size, ap->a_td);
179         return (0);
180 }
181
182
183 static int
184 cd9660_getattr(ap)
185         struct vop_getattr_args /* {
186                 struct vnode *a_vp;
187                 struct vattr *a_vap;
188                 struct ucred *a_cred;
189                 struct thread *a_td;
190         } */ *ap;
191
192 {
193         struct vnode *vp = ap->a_vp;
194         struct vattr *vap = ap->a_vap;
195         struct iso_node *ip = VTOI(vp);
196
197         vap->va_fsid    = dev2udev(ip->i_mnt->im_dev);
198         vap->va_fileid  = ip->i_number;
199
200         vap->va_mode    = ip->inode.iso_mode;
201         vap->va_nlink   = ip->inode.iso_links;
202         vap->va_uid     = ip->inode.iso_uid;
203         vap->va_gid     = ip->inode.iso_gid;
204         vap->va_atime   = ip->inode.iso_atime;
205         vap->va_mtime   = ip->inode.iso_mtime;
206         vap->va_ctime   = ip->inode.iso_ctime;
207         vap->va_rdev    = ip->inode.iso_rdev;
208
209         vap->va_size    = (u_quad_t) ip->i_size;
210         if (ip->i_size == 0 && (vap->va_mode & S_IFMT) == S_IFLNK) {
211                 struct vop_readlink_args rdlnk;
212                 struct iovec aiov;
213                 struct uio auio;
214                 char *cp;
215
216                 MALLOC(cp, char *, MAXPATHLEN, M_TEMP, M_WAITOK);
217                 aiov.iov_base = cp;
218                 aiov.iov_len = MAXPATHLEN;
219                 auio.uio_iov = &aiov;
220                 auio.uio_iovcnt = 1;
221                 auio.uio_offset = 0;
222                 auio.uio_rw = UIO_READ;
223                 auio.uio_segflg = UIO_SYSSPACE;
224                 auio.uio_td = ap->a_td;
225                 auio.uio_resid = MAXPATHLEN;
226                 rdlnk.a_uio = &auio;
227                 rdlnk.a_vp = ap->a_vp;
228                 rdlnk.a_cred = ap->a_cred;
229                 if (cd9660_readlink(&rdlnk) == 0)
230                         vap->va_size = MAXPATHLEN - auio.uio_resid;
231                 FREE(cp, M_TEMP);
232         }
233         vap->va_flags   = 0;
234         vap->va_gen = 1;
235         vap->va_blocksize = ip->i_mnt->logical_block_size;
236         vap->va_bytes   = (u_quad_t) ip->i_size;
237         vap->va_type    = vp->v_type;
238         vap->va_filerev = 0;
239         return (0);
240 }
241
242 /*
243  * Vnode op for ioctl.
244  */
245 static int
246 cd9660_ioctl(ap)
247         struct vop_ioctl_args /* {
248                 struct vnode *a_vp;
249                 u_long  a_command;
250                 caddr_t  a_data;
251                 int  a_fflag;
252                 struct ucred *a_cred;
253                 struct thread *a_td;
254         } */ *ap;
255 {
256         struct vnode *vp = ap->a_vp;
257         struct iso_node *ip = VTOI(vp);
258
259         if (vp->v_type == VCHR || vp->v_type == VBLK)
260                 return (EOPNOTSUPP);
261
262         switch (ap->a_command) {
263
264         case FIOGETLBA:
265                 *(int *)(ap->a_data) = ip->iso_start;
266                 return 0;
267         default:
268                 return (ENOTTY);
269         }
270 }
271
272 /*
273  * Vnode op for reading.
274  */
275 static int
276 cd9660_read(ap)
277         struct vop_read_args /* {
278                 struct vnode *a_vp;
279                 struct uio *a_uio;
280                 int a_ioflag;
281                 struct ucred *a_cred;
282         } */ *ap;
283 {
284         struct vnode *vp = ap->a_vp;
285         struct uio *uio = ap->a_uio;
286         struct iso_node *ip = VTOI(vp);
287         struct iso_mnt *imp;
288         struct buf *bp;
289         daddr_t lbn, rablock;
290         off_t diff;
291         int rasize, error = 0;
292         int seqcount;
293         long size, n, on;
294
295         if (vp->v_type == VCHR || vp->v_type == VBLK)
296                 return (EOPNOTSUPP);
297
298         seqcount = ap->a_ioflag >> IO_SEQSHIFT;
299
300         if (uio->uio_resid == 0)
301                 return (0);
302         if (uio->uio_offset < 0)
303                 return (EINVAL);
304         ip->i_flag |= IN_ACCESS;
305         imp = ip->i_mnt;
306         do {
307                 lbn = lblkno(imp, uio->uio_offset);
308                 on = blkoff(imp, uio->uio_offset);
309                 n = min((u_int)(imp->logical_block_size - on),
310                         uio->uio_resid);
311                 diff = (off_t)ip->i_size - uio->uio_offset;
312                 if (diff <= 0)
313                         return (0);
314                 if (diff < n)
315                         n = diff;
316                 size = blksize(imp, ip, lbn);
317                 rablock = lbn + 1;
318                 if ((vp->v_mount->mnt_flag & MNT_NOCLUSTERR) == 0) {
319                         if (lblktosize(imp, rablock) < ip->i_size)
320                                 error = cluster_read(vp, (off_t)ip->i_size,
321                                          lbn, size, NOCRED, uio->uio_resid,
322                                          (ap->a_ioflag >> 16), &bp);
323                         else
324                                 error = bread(vp, lbn, size, NOCRED, &bp);
325                 } else {
326                         if (seqcount > 1 &&
327                             lblktosize(imp, rablock) < ip->i_size) {
328                                 rasize = blksize(imp, ip, rablock);
329                                 error = breadn(vp, lbn, size, &rablock,
330                                                &rasize, 1, NOCRED, &bp);
331                         } else
332                                 error = bread(vp, lbn, size, NOCRED, &bp);
333                 }
334                 n = min(n, size - bp->b_resid);
335                 if (error) {
336                         brelse(bp);
337                         return (error);
338                 }
339
340                 error = uiomove(bp->b_data + on, (int)n, uio);
341                 brelse(bp);
342         } while (error == 0 && uio->uio_resid > 0 && n != 0);
343         return (error);
344 }
345
346 /*
347  * Structure for reading directories
348  */
349 struct isoreaddir {
350         struct dirent saveent;
351         struct dirent assocent;
352         struct dirent current;
353         off_t saveoff;
354         off_t assocoff;
355         off_t curroff;
356         struct uio *uio;
357         off_t uio_off;
358         int eofflag;
359         u_long *cookies;
360         int ncookies;
361 };
362
363 static int
364 iso_uiodir(idp,dp,off)
365         struct isoreaddir *idp;
366         struct dirent *dp;
367         off_t off;
368 {
369         int error;
370
371         dp->d_name[dp->d_namlen] = 0;
372         dp->d_reclen = GENERIC_DIRSIZ(dp);
373
374         if (idp->uio->uio_resid < dp->d_reclen) {
375                 idp->eofflag = 0;
376                 return (-1);
377         }
378
379         if (idp->cookies) {
380                 if (idp->ncookies <= 0) {
381                         idp->eofflag = 0;
382                         return (-1);
383                 }
384
385                 *idp->cookies++ = off;
386                 --idp->ncookies;
387         }
388
389         if ((error = uiomove(dp, dp->d_reclen, idp->uio)) != 0)
390                 return (error);
391         idp->uio_off = off;
392         return (0);
393 }
394
395 static int
396 iso_shipdir(idp)
397         struct isoreaddir *idp;
398 {
399         struct dirent *dp;
400         int cl, sl, assoc;
401         int error;
402         char *cname, *sname;
403
404         cl = idp->current.d_namlen;
405         cname = idp->current.d_name;
406 assoc = (cl > 1) && (*cname == ASSOCCHAR);
407         if (assoc) {
408                 cl--;
409                 cname++;
410         }
411
412         dp = &idp->saveent;
413         sname = dp->d_name;
414         if (!(sl = dp->d_namlen)) {
415                 dp = &idp->assocent;
416                 sname = dp->d_name + 1;
417                 sl = dp->d_namlen - 1;
418         }
419         if (sl > 0) {
420                 if (sl != cl
421                     || bcmp(sname,cname,sl)) {
422                         if (idp->assocent.d_namlen) {
423                                 if ((error = iso_uiodir(idp,&idp->assocent,idp->assocoff)) != 0)
424                                         return (error);
425                                 idp->assocent.d_namlen = 0;
426                         }
427                         if (idp->saveent.d_namlen) {
428                                 if ((error = iso_uiodir(idp,&idp->saveent,idp->saveoff)) != 0)
429                                         return (error);
430                                 idp->saveent.d_namlen = 0;
431                         }
432                 }
433         }
434         idp->current.d_reclen = GENERIC_DIRSIZ(&idp->current);
435         if (assoc) {
436                 idp->assocoff = idp->curroff;
437                 bcopy(&idp->current,&idp->assocent,idp->current.d_reclen);
438         } else {
439                 idp->saveoff = idp->curroff;
440                 bcopy(&idp->current,&idp->saveent,idp->current.d_reclen);
441         }
442         return (0);
443 }
444
445 /*
446  * Vnode op for readdir
447  */
448 static int
449 cd9660_readdir(ap)
450         struct vop_readdir_args /* {
451                 struct vnode *a_vp;
452                 struct uio *a_uio;
453                 struct ucred *a_cred;
454                 int *a_eofflag;
455                 int *a_ncookies;
456                 u_long **a_cookies;
457         } */ *ap;
458 {
459         struct uio *uio = ap->a_uio;
460         struct isoreaddir *idp;
461         struct vnode *vdp = ap->a_vp;
462         struct iso_node *dp;
463         struct iso_mnt *imp;
464         struct buf *bp = NULL;
465         struct iso_directory_record *ep;
466         int entryoffsetinblock;
467         doff_t endsearch;
468         u_long bmask;
469         int error = 0;
470         int reclen;
471         u_short namelen;
472         int ncookies = 0;
473         u_long *cookies = NULL;
474
475         dp = VTOI(vdp);
476         imp = dp->i_mnt;
477         bmask = imp->im_bmask;
478
479         MALLOC(idp, struct isoreaddir *, sizeof(*idp), M_TEMP, M_WAITOK);
480         idp->saveent.d_namlen = idp->assocent.d_namlen = 0;
481         /*
482          * XXX
483          * Is it worth trying to figure out the type?
484          */
485         idp->saveent.d_type = idp->assocent.d_type = idp->current.d_type =
486             DT_UNKNOWN;
487         idp->uio = uio;
488         if (ap->a_ncookies == NULL) {
489                 idp->cookies = NULL;
490         } else {
491                 /*
492                  * Guess the number of cookies needed.
493                  */
494                 ncookies = uio->uio_resid / 16;
495                 MALLOC(cookies, u_long *, ncookies * sizeof(u_long),
496                     M_TEMP, M_WAITOK);
497                 idp->cookies = cookies;
498                 idp->ncookies = ncookies;
499         }
500         idp->eofflag = 1;
501         idp->curroff = uio->uio_offset;
502         idp->uio_off = uio->uio_offset;
503
504         if ((entryoffsetinblock = idp->curroff & bmask) &&
505             (error = cd9660_blkatoff(vdp, (off_t)idp->curroff, NULL, &bp))) {
506                 FREE(idp, M_TEMP);
507                 return (error);
508         }
509         endsearch = dp->i_size;
510
511         while (idp->curroff < endsearch) {
512                 /*
513                  * If offset is on a block boundary,
514                  * read the next directory block.
515                  * Release previous if it exists.
516                  */
517                 if ((idp->curroff & bmask) == 0) {
518                         if (bp != NULL)
519                                 brelse(bp);
520                         if ((error =
521                             cd9660_blkatoff(vdp, (off_t)idp->curroff, NULL, &bp)) != 0)
522                                 break;
523                         entryoffsetinblock = 0;
524                 }
525                 /*
526                  * Get pointer to next entry.
527                  */
528                 ep = (struct iso_directory_record *)
529                         ((char *)bp->b_data + entryoffsetinblock);
530
531                 reclen = isonum_711(ep->length);
532                 if (reclen == 0) {
533                         /* skip to next block, if any */
534                         idp->curroff =
535                             (idp->curroff & ~bmask) + imp->logical_block_size;
536                         continue;
537                 }
538
539                 if (reclen < ISO_DIRECTORY_RECORD_SIZE) {
540                         error = EINVAL;
541                         /* illegal entry, stop */
542                         break;
543                 }
544
545                 if (entryoffsetinblock + reclen > imp->logical_block_size) {
546                         error = EINVAL;
547                         /* illegal directory, so stop looking */
548                         break;
549                 }
550
551                 idp->current.d_namlen = isonum_711(ep->name_len);
552
553                 if (reclen < ISO_DIRECTORY_RECORD_SIZE + idp->current.d_namlen) {
554                         error = EINVAL;
555                         /* illegal entry, stop */
556                         break;
557                 }
558
559                 if (isonum_711(ep->flags)&2)
560                         idp->current.d_fileno = isodirino(ep, imp);
561                 else
562                         idp->current.d_fileno = dbtob(bp->b_blkno) +
563                                 entryoffsetinblock;
564
565                 idp->curroff += reclen;
566
567                 switch (imp->iso_ftype) {
568                 case ISO_FTYPE_RRIP:
569                         cd9660_rrip_getname(ep,idp->current.d_name, &namelen,
570                                            &idp->current.d_fileno,imp);
571                         idp->current.d_namlen = (u_char)namelen;
572                         if (idp->current.d_namlen)
573                                 error = iso_uiodir(idp,&idp->current,idp->curroff);
574                         break;
575                 default: /* ISO_FTYPE_DEFAULT || ISO_FTYPE_9660 || ISO_FTYPE_HIGH_SIERRA*/
576                         strcpy(idp->current.d_name,"..");
577                         if (idp->current.d_namlen == 1 && ep->name[0] == 0) {
578                                 idp->current.d_namlen = 1;
579                                 error = iso_uiodir(idp,&idp->current,idp->curroff);
580                         } else if (idp->current.d_namlen == 1 && ep->name[0] == 1) {
581                                 idp->current.d_namlen = 2;
582                                 error = iso_uiodir(idp,&idp->current,idp->curroff);
583                         } else {
584                                 isofntrans(ep->name,idp->current.d_namlen,
585                                            idp->current.d_name, &namelen,
586                                            imp->iso_ftype == ISO_FTYPE_9660,
587                                            isonum_711(ep->flags)&4,
588                                            imp->joliet_level,
589                                            imp->im_flags,
590                                            imp->im_d2l);
591                                 idp->current.d_namlen = (u_char)namelen;
592                                 if (imp->iso_ftype == ISO_FTYPE_DEFAULT)
593                                         error = iso_shipdir(idp);
594                                 else
595                                         error = iso_uiodir(idp,&idp->current,idp->curroff);
596                         }
597                 }
598                 if (error)
599                         break;
600
601                 entryoffsetinblock += reclen;
602         }
603
604         if (!error && imp->iso_ftype == ISO_FTYPE_DEFAULT) {
605                 idp->current.d_namlen = 0;
606                 error = iso_shipdir(idp);
607         }
608         if (error < 0)
609                 error = 0;
610
611         if (ap->a_ncookies != NULL) {
612                 if (error)
613                         free(cookies, M_TEMP);
614                 else {
615                         /*
616                          * Work out the number of cookies actually used.
617                          */
618                         *ap->a_ncookies = ncookies - idp->ncookies;
619                         *ap->a_cookies = cookies;
620                 }
621         }
622
623         if (bp)
624                 brelse (bp);
625
626         uio->uio_offset = idp->uio_off;
627         *ap->a_eofflag = idp->eofflag;
628
629         FREE(idp, M_TEMP);
630
631         return (error);
632 }
633
634 /*
635  * Return target name of a symbolic link
636  * Shouldn't we get the parent vnode and read the data from there?
637  * This could eventually result in deadlocks in cd9660_lookup.
638  * But otherwise the block read here is in the block buffer two times.
639  */
640 typedef struct iso_directory_record ISODIR;
641 typedef struct iso_node             ISONODE;
642 typedef struct iso_mnt              ISOMNT;
643 static int
644 cd9660_readlink(ap)
645         struct vop_readlink_args /* {
646                 struct vnode *a_vp;
647                 struct uio *a_uio;
648                 struct ucred *a_cred;
649         } */ *ap;
650 {
651         ISONODE *ip;
652         ISODIR  *dirp;
653         ISOMNT  *imp;
654         struct  buf *bp;
655         struct  uio *uio;
656         u_short symlen;
657         int     error;
658         char    *symname;
659
660         ip  = VTOI(ap->a_vp);
661         imp = ip->i_mnt;
662         uio = ap->a_uio;
663
664         if (imp->iso_ftype != ISO_FTYPE_RRIP)
665                 return (EINVAL);
666
667         /*
668          * Get parents directory record block that this inode included.
669          */
670         error = bread(imp->im_devvp,
671                       (ip->i_number >> imp->im_bshift) <<
672                       (imp->im_bshift - DEV_BSHIFT),
673                       imp->logical_block_size, NOCRED, &bp);
674         if (error) {
675                 brelse(bp);
676                 return (EINVAL);
677         }
678
679         /*
680          * Setup the directory pointer for this inode
681          */
682         dirp = (ISODIR *)(bp->b_data + (ip->i_number & imp->im_bmask));
683
684         /*
685          * Just make sure, we have a right one....
686          *   1: Check not cross boundary on block
687          */
688         if ((ip->i_number & imp->im_bmask) + isonum_711(dirp->length)
689             > (unsigned)imp->logical_block_size) {
690                 brelse(bp);
691                 return (EINVAL);
692         }
693
694         /*
695          * Now get a buffer
696          * Abuse a namei buffer for now.
697          */
698         if (uio->uio_segflg == UIO_SYSSPACE)
699                 symname = uio->uio_iov->iov_base;
700         else
701                 symname = uma_zalloc(namei_zone, M_WAITOK);
702
703         /*
704          * Ok, we just gathering a symbolic name in SL record.
705          */
706         if (cd9660_rrip_getsymname(dirp, symname, &symlen, imp) == 0) {
707                 if (uio->uio_segflg != UIO_SYSSPACE)
708                         uma_zfree(namei_zone, symname);
709                 brelse(bp);
710                 return (EINVAL);
711         }
712         /*
713          * Don't forget before you leave from home ;-)
714          */
715         brelse(bp);
716
717         /*
718          * return with the symbolic name to caller's.
719          */
720         if (uio->uio_segflg != UIO_SYSSPACE) {
721                 error = uiomove(symname, symlen, uio);
722                 uma_zfree(namei_zone, symname);
723                 return (error);
724         }
725         uio->uio_resid -= symlen;
726         uio->uio_iov->iov_base = (char *)uio->uio_iov->iov_base + symlen;
727         uio->uio_iov->iov_len -= symlen;
728         return (0);
729 }
730
731 /*
732  * Calculate the logical to physical mapping if not done already,
733  * then call the device strategy routine.
734  */
735 static int
736 cd9660_strategy(ap)
737         struct vop_strategy_args /* {
738                 struct buf *a_vp;
739                 struct buf *a_bp;
740         } */ *ap;
741 {
742         struct buf *bp = ap->a_bp;
743         struct vnode *vp = ap->a_vp;
744         struct iso_node *ip;
745         struct bufobj *bo;
746
747         ip = VTOI(vp);
748         if (vp->v_type == VBLK || vp->v_type == VCHR)
749                 panic("cd9660_strategy: spec");
750         if (bp->b_blkno == bp->b_lblkno) {
751                 bp->b_blkno = (ip->iso_start + bp->b_lblkno) <<
752                     (ip->i_mnt->im_bshift - DEV_BSHIFT);
753                 if ((long)bp->b_blkno == -1)    /* XXX: cut&paste junk ? */
754                         clrbuf(bp);
755         }
756         if ((long)bp->b_blkno == -1) {  /* XXX: cut&paste junk ? */
757                 bufdone(bp);
758                 return (0);
759         }
760         bp->b_iooffset = dbtob(bp->b_blkno);
761         bo = ip->i_mnt->im_bo;
762         BO_STRATEGY(bo, bp);
763         return (0);
764 }
765
766 /*
767  * Return POSIX pathconf information applicable to cd9660 filesystems.
768  */
769 static int
770 cd9660_pathconf(ap)
771         struct vop_pathconf_args /* {
772                 struct vnode *a_vp;
773                 int a_name;
774                 register_t *a_retval;
775         } */ *ap;
776 {
777
778         switch (ap->a_name) {
779         case _PC_LINK_MAX:
780                 *ap->a_retval = 1;
781                 return (0);
782         case _PC_NAME_MAX:
783                 if (VTOI(ap->a_vp)->i_mnt->iso_ftype == ISO_FTYPE_RRIP)
784                         *ap->a_retval = NAME_MAX;
785                 else
786                         *ap->a_retval = 37;
787                 return (0);
788         case _PC_PATH_MAX:
789                 *ap->a_retval = PATH_MAX;
790                 return (0);
791         case _PC_PIPE_BUF:
792                 *ap->a_retval = PIPE_BUF;
793                 return (0);
794         case _PC_CHOWN_RESTRICTED:
795                 *ap->a_retval = 1;
796                 return (0);
797         case _PC_NO_TRUNC:
798                 *ap->a_retval = 1;
799                 return (0);
800         default:
801                 return (EINVAL);
802         }
803         /* NOTREACHED */
804 }
805
806 /*
807  * Vnode pointer to File handle
808  */
809 static int
810 cd9660_vptofh(ap)
811         struct vop_vptofh_args /* {
812                 struct vnode *a_vp;
813                 struct fid *a_fhp;
814         } */ *ap;
815 {
816         struct iso_node *ip = VTOI(ap->a_vp);
817         struct ifid *ifhp;
818
819         ifhp = (struct ifid *)ap->a_fhp;
820         ifhp->ifid_len = sizeof(struct ifid);
821
822         ifhp->ifid_ino = ip->i_number;
823         ifhp->ifid_start = ip->iso_start;
824
825 #ifdef  ISOFS_DBG
826         printf("vptofh: ino %d, start %ld\n",
827                ifhp->ifid_ino,ifhp->ifid_start);
828 #endif
829         return 0;
830 }
831
832 /*
833  * Global vfs data structures for cd9660
834  */
835 struct vop_vector cd9660_vnodeops = {
836         .vop_default =          &default_vnodeops,
837         .vop_open =             cd9660_open,
838         .vop_access =           cd9660_access,
839         .vop_bmap =             cd9660_bmap,
840         .vop_cachedlookup =     cd9660_lookup,
841         .vop_getattr =          cd9660_getattr,
842         .vop_inactive =         cd9660_inactive,
843         .vop_ioctl =            cd9660_ioctl,
844         .vop_lookup =           vfs_cache_lookup,
845         .vop_pathconf =         cd9660_pathconf,
846         .vop_read =             cd9660_read,
847         .vop_readdir =          cd9660_readdir,
848         .vop_readlink =         cd9660_readlink,
849         .vop_reclaim =          cd9660_reclaim,
850         .vop_setattr =          cd9660_setattr,
851         .vop_strategy =         cd9660_strategy,
852         .vop_vptofh =           cd9660_vptofh,
853 };
854
855 /*
856  * Special device vnode ops
857  */
858
859 struct vop_vector cd9660_fifoops = {
860         .vop_default =          &fifo_specops,
861         .vop_access =           cd9660_access,
862         .vop_getattr =          cd9660_getattr,
863         .vop_inactive =         cd9660_inactive,
864         .vop_reclaim =          cd9660_reclaim,
865         .vop_setattr =          cd9660_setattr,
866         .vop_vptofh =           cd9660_vptofh,
867 };