1 /* $OpenBSD: cd9660_vnops.c,v 1.32 2004/11/29 17:05:05 grange Exp $ */
2 /* $NetBSD: cd9660_vnops.c,v 1.42 1997/10/16 23:56:57 christos Exp $ */
3
4 /*-
5 * Copyright (c) 1994
6 * The Regents of the University of California. All rights reserved.
7 *
8 * This code is derived from software contributed to Berkeley
9 * by Pace Willisson (pace@blitz.com). The Rock Ridge Extension
10 * Support code is derived from software contributed to Berkeley
11 * by Atsushi Murai (amurai@spec.co.jp).
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. Neither the name of the University nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 *
37 * @(#)cd9660_vnops.c 8.15 (Berkeley) 12/5/94
38 */
39
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/namei.h>
43 #include <sys/resourcevar.h>
44 #include <sys/kernel.h>
45 #include <sys/file.h>
46 #include <sys/stat.h>
47 #include <sys/buf.h>
48 #include <sys/proc.h>
49 #include <sys/conf.h>
50 #include <sys/mount.h>
51 #include <sys/vnode.h>
52 #include <sys/malloc.h>
53 #include <sys/pool.h>
54 #include <sys/dirent.h>
55 #include <sys/ioctl.h>
56 #include <sys/ioccom.h>
57 #include <sys/cdio.h>
58 #include <sys/poll.h>
59
60 #include <miscfs/fifofs/fifo.h>
61 #include <miscfs/specfs/specdev.h>
62
63 #include <isofs/cd9660/iso.h>
64 #include <isofs/cd9660/cd9660_extern.h>
65 #include <isofs/cd9660/cd9660_node.h>
66 #include <isofs/cd9660/iso_rrip.h>
67
68 /*
69 * Structure for reading directories
70 */
71 struct isoreaddir {
72 struct dirent saveent;
73 struct dirent assocent;
74 struct dirent current;
75 off_t saveoff;
76 off_t assocoff;
77 off_t curroff;
78 struct uio *uio;
79 off_t uio_off;
80 int eofflag;
81 u_long *cookies;
82 int ncookies;
83 };
84
85 int iso_uiodir(struct isoreaddir *, struct dirent *, off_t);
86 int iso_shipdir(struct isoreaddir *);
87
88 #if 0
89 /*
90 * Mknod vnode call
91 * Actually remap the device number
92 */
93 int
94 cd9660_mknod(ndp, vap, cred, p)
95 struct nameidata *ndp;
96 struct ucred *cred;
97 struct vattr *vap;
98 struct proc *p;
99 {
100 #ifndef ISODEVMAP
101 pool_put(&namei_pool, ndp->ni_pnbuf);
102 vput(ndp->ni_dvp);
103 vput(ndp->ni_vp);
104 return (EINVAL);
105 #else
106 register struct vnode *vp;
107 struct iso_node *ip;
108 struct iso_dnode *dp;
109 int error;
110
111 vp = ndp->ni_vp;
112 ip = VTOI(vp);
113
114 if (ip->i_mnt->iso_ftype != ISO_FTYPE_RRIP
115 || vap->va_type != vp->v_type
116 || (vap->va_type != VCHR && vap->va_type != VBLK)) {
117 pool_put(&namei_pool, ndp->ni_pnbuf);
118 vput(ndp->ni_dvp);
119 vput(ndp->ni_vp);
120 return (EINVAL);
121 }
122
123 dp = iso_dmap(ip->i_dev,ip->i_number,1);
124 if (ip->inode.iso_rdev == vap->va_rdev || vap->va_rdev == VNOVAL) {
125 /* same as the unmapped one, delete the mapping */
126 remque(dp);
127 FREE(dp, M_CACHE);
128 } else
129 /* enter new mapping */
130 dp->d_dev = vap->va_rdev;
131
132 /*
133 * Remove inode so that it will be reloaded by iget and
134 * checked to see if it is an alias of an existing entry
135 * in the inode cache.
136 */
137 vput(vp);
138 vp->v_type = VNON;
139 vgone(vp);
140 return (0);
141 #endif
142 }
143 #endif
144
145 /*
146 * Setattr call. Only allowed for block and character special devices.
147 */
148 int
cd9660_setattr(v)149 cd9660_setattr(v)
150 void *v;
151 {
152 struct vop_setattr_args /* {
153 struct vnodeop_desc *a_desc;
154 struct vnode *a_vp;
155 struct vattr *a_vap;
156 struct ucred *a_cred;
157 struct proc *a_p;
158 } */ *ap = v;
159 struct vnode *vp = ap->a_vp;
160 struct vattr *vap = ap->a_vap;
161
162 if (vap->va_flags != VNOVAL || vap->va_uid != (uid_t)VNOVAL ||
163 vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL ||
164 vap->va_mtime.tv_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL)
165 return (EROFS);
166 if (vap->va_size != VNOVAL) {
167 switch (vp->v_type) {
168 case VDIR:
169 return (EISDIR);
170 case VLNK:
171 case VREG:
172 return (EROFS);
173 case VCHR:
174 case VBLK:
175 case VSOCK:
176 case VFIFO:
177 return (0);
178 default:
179 return (EINVAL);
180 }
181 }
182
183 return (EINVAL);
184 }
185
186 /*
187 * Open called.
188 *
189 * Nothing to do.
190 */
191 /* ARGSUSED */
192 int
cd9660_open(v)193 cd9660_open(v)
194 void *v;
195 {
196 return (0);
197 }
198
199 /*
200 * Close called
201 *
202 * Update the times on the inode on writeable file systems.
203 */
204 /* ARGSUSED */
205 int
cd9660_close(v)206 cd9660_close(v)
207 void *v;
208 {
209 return (0);
210 }
211
212 /*
213 * Check mode permission on inode pointer. Mode is READ, WRITE or EXEC.
214 * The mode is shifted to select the owner/group/other fields. The
215 * super user is granted all permissions.
216 */
217 int
cd9660_access(v)218 cd9660_access(v)
219 void *v;
220 {
221 struct vop_access_args /* {
222 struct vnode *a_vp;
223 int a_mode;
224 struct ucred *a_cred;
225 struct proc *a_p;
226 } */ *ap = v;
227 struct iso_node *ip = VTOI(ap->a_vp);
228
229 return (vaccess(ip->inode.iso_mode & ALLPERMS, ip->inode.iso_uid,
230 ip->inode.iso_gid, ap->a_mode, ap->a_cred));
231 }
232
233 int
cd9660_getattr(v)234 cd9660_getattr(v)
235 void *v;
236 {
237 struct vop_getattr_args /* {
238 struct vnode *a_vp;
239 struct vattr *a_vap;
240 struct ucred *a_cred;
241 struct proc *a_p;
242 } */ *ap = v;
243 struct vnode *vp = ap->a_vp;
244 register struct vattr *vap = ap->a_vap;
245 register struct iso_node *ip = VTOI(vp);
246
247 vap->va_fsid = ip->i_dev;
248 vap->va_fileid = ip->i_number;
249
250 vap->va_mode = ip->inode.iso_mode & ALLPERMS;
251 vap->va_nlink = ip->inode.iso_links;
252 vap->va_uid = ip->inode.iso_uid;
253 vap->va_gid = ip->inode.iso_gid;
254 vap->va_atime = ip->inode.iso_atime;
255 vap->va_mtime = ip->inode.iso_mtime;
256 vap->va_ctime = ip->inode.iso_ctime;
257 vap->va_rdev = ip->inode.iso_rdev;
258
259 vap->va_size = (u_quad_t) ip->i_size;
260 if (ip->i_size == 0 && vp->v_type == VLNK) {
261 struct vop_readlink_args rdlnk;
262 struct iovec aiov;
263 struct uio auio;
264 char *cp;
265
266 MALLOC(cp, char *, MAXPATHLEN, M_TEMP, M_WAITOK);
267 aiov.iov_base = cp;
268 aiov.iov_len = MAXPATHLEN;
269 auio.uio_iov = &aiov;
270 auio.uio_iovcnt = 1;
271 auio.uio_offset = 0;
272 auio.uio_rw = UIO_READ;
273 auio.uio_segflg = UIO_SYSSPACE;
274 auio.uio_procp = ap->a_p;
275 auio.uio_resid = MAXPATHLEN;
276 rdlnk.a_uio = &auio;
277 rdlnk.a_vp = ap->a_vp;
278 rdlnk.a_cred = ap->a_cred;
279 if (cd9660_readlink(&rdlnk) == 0)
280 vap->va_size = MAXPATHLEN - auio.uio_resid;
281 FREE(cp, M_TEMP);
282 }
283 vap->va_flags = 0;
284 vap->va_gen = 1;
285 vap->va_blocksize = ip->i_mnt->logical_block_size;
286 vap->va_bytes = (u_quad_t) ip->i_size;
287 vap->va_type = vp->v_type;
288 return (0);
289 }
290
291 #ifdef DEBUG
292 extern int doclusterread;
293 #else
294 #define doclusterread 1
295 #endif
296
297 /* XXX until cluster routines can handle block sizes less than one page */
298 #define cd9660_doclusterread \
299 (doclusterread && (ISO_DEFAULT_BLOCK_SIZE >= NBPG))
300
301 /*
302 * Vnode op for reading.
303 */
304 int
cd9660_read(v)305 cd9660_read(v)
306 void *v;
307 {
308 struct vop_read_args /* {
309 struct vnode *a_vp;
310 struct uio *a_uio;
311 int a_ioflag;
312 struct ucred *a_cred;
313 } */ *ap = v;
314 struct vnode *vp = ap->a_vp;
315 register struct uio *uio = ap->a_uio;
316 register struct iso_node *ip = VTOI(vp);
317 register struct iso_mnt *imp;
318 struct buf *bp;
319 daddr_t lbn, rablock;
320 off_t diff;
321 int error = 0;
322 long size, n, on;
323
324 if (uio->uio_resid == 0)
325 return (0);
326 if (uio->uio_offset < 0)
327 return (EINVAL);
328 ip->i_flag |= IN_ACCESS;
329 imp = ip->i_mnt;
330 do {
331 struct cluster_info *ci = &ip->i_ci;
332
333 lbn = lblkno(imp, uio->uio_offset);
334 on = blkoff(imp, uio->uio_offset);
335 n = min((u_int)(imp->logical_block_size - on),
336 uio->uio_resid);
337 diff = (off_t)ip->i_size - uio->uio_offset;
338 if (diff <= 0)
339 return (0);
340 if (diff < n)
341 n = diff;
342 size = blksize(imp, ip, lbn);
343 rablock = lbn + 1;
344 if (cd9660_doclusterread) {
345 if (lblktosize(imp, rablock) <= ip->i_size)
346 error = cluster_read(vp, &ip->i_ci,
347 (off_t)ip->i_size, lbn, size, NOCRED, &bp);
348 else
349 error = bread(vp, lbn, size, NOCRED, &bp);
350 } else {
351 #define MAX_RA 32
352 if (ci->ci_lastr + 1 == lbn) {
353 daddr_t rablks[MAX_RA];
354 int rasizes[MAX_RA];
355 int i;
356
357 for (i = 0; i < MAX_RA &&
358 lblktosize(imp, (rablock + i)) < ip->i_size;
359 i++) {
360 rablks[i] = rablock + i;
361 rasizes[i] = blksize(imp, ip, rablock + i);
362 }
363 error = breadn(vp, lbn, size, rablks,
364 rasizes, i, NOCRED, &bp);
365 } else
366 error = bread(vp, lbn, size, NOCRED, &bp);
367 }
368 ci->ci_lastr = lbn;
369 n = min(n, size - bp->b_resid);
370 if (error) {
371 brelse(bp);
372 return (error);
373 }
374
375 error = uiomove(bp->b_data + on, (int)n, uio);
376
377 if (n + on == imp->logical_block_size ||
378 uio->uio_offset == (off_t)ip->i_size)
379 bp->b_flags |= B_AGE;
380 brelse(bp);
381 } while (error == 0 && uio->uio_resid > 0 && n != 0);
382 return (error);
383 }
384
385 /* ARGSUSED */
386 int
cd9660_ioctl(v)387 cd9660_ioctl(v)
388 void *v;
389 {
390 struct vop_ioctl_args /* {
391 struct vnode *a_vp;
392 u_long a_command;
393 caddr_t a_data;
394 int a_fflag;
395 struct ucred *a_cred;
396 struct proc *a_p;
397 } */ *ap = v;
398 daddr_t *block;
399
400 switch (ap->a_command) {
401 case FIBMAP:
402 block = (daddr_t *)ap->a_data;
403
404 return (VOP_BMAP(ap->a_vp, *block, NULL, block, 0));
405 default:
406 return (ENOTTY);
407 }
408 }
409
410 /* ARGSUSED */
411 int
cd9660_poll(v)412 cd9660_poll(v)
413 void *v;
414 {
415 struct vop_poll_args /* {
416 struct vnode *a_vp;
417 int a_events;
418 struct proc *a_p;
419 } */ *ap = v;
420
421 /*
422 * We should really check to see if I/O is possible.
423 */
424 return (ap->a_events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM));
425 }
426
427 /*
428 * Mmap a file
429 *
430 * NB Currently unsupported.
431 */
432 /* ARGSUSED */
433 int
cd9660_mmap(v)434 cd9660_mmap(v)
435 void *v;
436 {
437
438 return (EINVAL);
439 }
440
441 /*
442 * Seek on a file
443 *
444 * Nothing to do, so just return.
445 */
446 /* ARGSUSED */
447 int
cd9660_seek(v)448 cd9660_seek(v)
449 void *v;
450 {
451 return (0);
452 }
453
454 int
iso_uiodir(idp,dp,off)455 iso_uiodir(idp,dp,off)
456 struct isoreaddir *idp;
457 struct dirent *dp;
458 off_t off;
459 {
460 int error;
461
462 dp->d_name[dp->d_namlen] = 0;
463 dp->d_reclen = DIRENT_SIZE(dp);
464
465 if (idp->uio->uio_resid < dp->d_reclen) {
466 idp->eofflag = 0;
467 return (-1);
468 }
469
470 if (idp->cookies) {
471 if (idp->ncookies <= 0) {
472 idp->eofflag = 0;
473 return (-1);
474 }
475
476 *idp->cookies++ = off;
477 --idp->ncookies;
478 }
479
480 if ((error = uiomove((caddr_t)dp, dp->d_reclen, idp->uio)) != 0)
481 return (error);
482 idp->uio_off = off;
483 return (0);
484 }
485
486 int
iso_shipdir(idp)487 iso_shipdir(idp)
488 struct isoreaddir *idp;
489 {
490 struct dirent *dp;
491 int cl, sl, assoc;
492 int error;
493 char *cname, *sname;
494
495 cl = idp->current.d_namlen;
496 cname = idp->current.d_name;
497
498 if ((assoc = cl > 1 && *cname == ASSOCCHAR)) {
499 cl--;
500 cname++;
501 }
502
503 dp = &idp->saveent;
504 sname = dp->d_name;
505 if (!(sl = dp->d_namlen)) {
506 dp = &idp->assocent;
507 sname = dp->d_name + 1;
508 sl = dp->d_namlen - 1;
509 }
510 if (sl > 0) {
511 if (sl != cl
512 || bcmp(sname,cname,sl)) {
513 if (idp->assocent.d_namlen) {
514 error = iso_uiodir(idp, &idp->assocent,
515 idp->assocoff);
516 if (error)
517 return (error);
518 idp->assocent.d_namlen = 0;
519 }
520 if (idp->saveent.d_namlen) {
521 error = iso_uiodir(idp, &idp->saveent,
522 idp->saveoff);
523 if (error)
524 return (error);
525 idp->saveent.d_namlen = 0;
526 }
527 }
528 }
529 idp->current.d_reclen = DIRENT_SIZE(&idp->current);
530 if (assoc) {
531 idp->assocoff = idp->curroff;
532 bcopy(&idp->current,&idp->assocent,idp->current.d_reclen);
533 } else {
534 idp->saveoff = idp->curroff;
535 bcopy(&idp->current,&idp->saveent,idp->current.d_reclen);
536 }
537 return (0);
538 }
539
540 /*
541 * Vnode op for readdir
542 */
543 int
cd9660_readdir(v)544 cd9660_readdir(v)
545 void *v;
546 {
547 struct vop_readdir_args /* {
548 struct vnode *a_vp;
549 struct uio *a_uio;
550 struct ucred *a_cred;
551 int *a_eofflag;
552 u_long *a_cookies;
553 int a_ncookies;
554 } */ *ap = v;
555 register struct uio *uio = ap->a_uio;
556 struct isoreaddir *idp;
557 struct vnode *vdp = ap->a_vp;
558 struct iso_node *dp;
559 struct iso_mnt *imp;
560 struct buf *bp = NULL;
561 struct iso_directory_record *ep;
562 int entryoffsetinblock;
563 doff_t endsearch;
564 u_long bmask;
565 int error = 0;
566 int reclen;
567 u_short namelen;
568 int ncookies = 0;
569 u_long *cookies = NULL;
570
571 dp = VTOI(vdp);
572 imp = dp->i_mnt;
573 bmask = imp->im_bmask;
574
575 MALLOC(idp, struct isoreaddir *, sizeof(*idp), M_TEMP, M_WAITOK);
576 idp->saveent.d_namlen = idp->assocent.d_namlen = 0;
577 /*
578 * XXX
579 * Is it worth trying to figure out the type?
580 */
581 idp->saveent.d_type = idp->assocent.d_type = idp->current.d_type =
582 DT_UNKNOWN;
583 idp->uio = uio;
584 if (ap->a_ncookies == NULL) {
585 idp->cookies = NULL;
586 } else {
587 /*
588 * Guess the number of cookies needed.
589 */
590 ncookies = uio->uio_resid / 16;
591 MALLOC(cookies, u_long *, ncookies * sizeof(u_long), M_TEMP,
592 M_WAITOK);
593 idp->cookies = cookies;
594 idp->ncookies = ncookies;
595 }
596 idp->eofflag = 1;
597 idp->curroff = uio->uio_offset;
598 idp->uio_off = uio->uio_offset;
599
600 if ((entryoffsetinblock = idp->curroff & bmask) &&
601 (error = cd9660_bufatoff(dp, (off_t)idp->curroff, NULL, &bp))) {
602 FREE(idp, M_TEMP);
603 return (error);
604 }
605 endsearch = dp->i_size;
606
607 while (idp->curroff < endsearch) {
608 /*
609 * If offset is on a block boundary,
610 * read the next directory block.
611 * Release previous if it exists.
612 */
613 if ((idp->curroff & bmask) == 0) {
614 if (bp != NULL)
615 brelse(bp);
616 error = cd9660_bufatoff(dp, (off_t)idp->curroff,
617 NULL, &bp);
618 if (error)
619 break;
620 entryoffsetinblock = 0;
621 }
622 /*
623 * Get pointer to next entry.
624 */
625 ep = (struct iso_directory_record *)
626 ((char *)bp->b_data + entryoffsetinblock);
627
628 reclen = isonum_711(ep->length);
629 if (reclen == 0) {
630 /* skip to next block, if any */
631 idp->curroff =
632 (idp->curroff & ~bmask) + imp->logical_block_size;
633 continue;
634 }
635
636 if (reclen < ISO_DIRECTORY_RECORD_SIZE) {
637 error = EINVAL;
638 /* illegal entry, stop */
639 break;
640 }
641
642 if (entryoffsetinblock + reclen > imp->logical_block_size) {
643 error = EINVAL;
644 /* illegal directory, so stop looking */
645 break;
646 }
647
648 idp->current.d_namlen = isonum_711(ep->name_len);
649
650 if (reclen < ISO_DIRECTORY_RECORD_SIZE + idp->current.d_namlen) {
651 error = EINVAL;
652 /* illegal entry, stop */
653 break;
654 }
655
656 if (isonum_711(ep->flags)&2)
657 idp->current.d_fileno = isodirino(ep, imp);
658 else
659 idp->current.d_fileno = dbtob(bp->b_blkno) +
660 entryoffsetinblock;
661
662 idp->curroff += reclen;
663
664 switch (imp->iso_ftype) {
665 case ISO_FTYPE_RRIP:
666 cd9660_rrip_getname(ep,idp->current.d_name, &namelen,
667 &idp->current.d_fileno,imp);
668 idp->current.d_namlen = (u_char)namelen;
669 if (idp->current.d_namlen)
670 error = iso_uiodir(idp,&idp->current,idp->curroff);
671 break;
672 default: /* ISO_FTYPE_DEFAULT || ISO_FTYPE_9660 */
673 strlcpy(idp->current.d_name,"..",
674 sizeof idp->current.d_name);
675 if (idp->current.d_namlen == 1 && ep->name[0] == 0) {
676 idp->current.d_namlen = 1;
677 error = iso_uiodir(idp,&idp->current,idp->curroff);
678 } else if (idp->current.d_namlen == 1 &&
679 ep->name[0] == 1) {
680 idp->current.d_namlen = 2;
681 error = iso_uiodir(idp,&idp->current,idp->curroff);
682 } else {
683 isofntrans(ep->name,idp->current.d_namlen,
684 idp->current.d_name, &namelen,
685 imp->iso_ftype == ISO_FTYPE_9660,
686 isonum_711(ep->flags) & 4,
687 imp->joliet_level);
688 idp->current.d_namlen = (u_char)namelen;
689 if (imp->iso_ftype == ISO_FTYPE_DEFAULT)
690 error = iso_shipdir(idp);
691 else
692 error = iso_uiodir(idp,&idp->current,idp->curroff);
693 }
694 }
695 if (error)
696 break;
697
698 entryoffsetinblock += reclen;
699 }
700
701 if (!error && imp->iso_ftype == ISO_FTYPE_DEFAULT) {
702 idp->current.d_namlen = 0;
703 error = iso_shipdir(idp);
704 }
705 if (error < 0)
706 error = 0;
707
708 if (ap->a_ncookies != NULL) {
709 if (error)
710 free(cookies, M_TEMP);
711 else {
712 /*
713 * Work out the number of cookies actually used.
714 */
715 *ap->a_ncookies = ncookies - idp->ncookies;
716 *ap->a_cookies = cookies;
717 }
718 }
719
720 if (bp)
721 brelse (bp);
722
723 uio->uio_offset = idp->uio_off;
724 *ap->a_eofflag = idp->eofflag;
725
726 FREE(idp, M_TEMP);
727
728 return (error);
729 }
730
731 /*
732 * Return target name of a symbolic link
733 * Shouldn't we get the parent vnode and read the data from there?
734 * This could eventually result in deadlocks in cd9660_lookup.
735 * But otherwise the block read here is in the block buffer two times.
736 */
737 typedef struct iso_directory_record ISODIR;
738 typedef struct iso_node ISONODE;
739 typedef struct iso_mnt ISOMNT;
740 int
cd9660_readlink(v)741 cd9660_readlink(v)
742 void *v;
743 {
744 struct vop_readlink_args /* {
745 struct vnode *a_vp;
746 struct uio *a_uio;
747 struct ucred *a_cred;
748 } */ *ap = v;
749 ISONODE *ip;
750 ISODIR *dirp;
751 ISOMNT *imp;
752 struct buf *bp;
753 struct uio *uio;
754 u_short symlen;
755 int error;
756 char *symname;
757
758 ip = VTOI(ap->a_vp);
759 imp = ip->i_mnt;
760 uio = ap->a_uio;
761
762 if (imp->iso_ftype != ISO_FTYPE_RRIP)
763 return (EINVAL);
764
765 /*
766 * Get parents directory record block that this inode included.
767 */
768 error = bread(imp->im_devvp,
769 (ip->i_number >> imp->im_bshift) <<
770 (imp->im_bshift - DEV_BSHIFT),
771 imp->logical_block_size, NOCRED, &bp);
772 if (error) {
773 brelse(bp);
774 return (EINVAL);
775 }
776
777 /*
778 * Setup the directory pointer for this inode
779 */
780 dirp = (ISODIR *)(bp->b_data + (ip->i_number & imp->im_bmask));
781
782 /*
783 * Just make sure, we have a right one....
784 * 1: Check not cross boundary on block
785 */
786 if ((ip->i_number & imp->im_bmask) + isonum_711(dirp->length)
787 > imp->logical_block_size) {
788 brelse(bp);
789 return (EINVAL);
790 }
791
792 /*
793 * Now get a buffer
794 * Abuse a namei buffer for now.
795 */
796 if (uio->uio_segflg == UIO_SYSSPACE &&
797 uio->uio_iov->iov_len >= MAXPATHLEN)
798 symname = uio->uio_iov->iov_base;
799 else
800 symname = pool_get(&namei_pool, PR_WAITOK);
801
802 /*
803 * Ok, we just gathering a symbolic name in SL record.
804 */
805 if (cd9660_rrip_getsymname(dirp, symname, &symlen, imp) == 0) {
806 if (uio->uio_segflg != UIO_SYSSPACE ||
807 uio->uio_iov->iov_len < MAXPATHLEN)
808 pool_put(&namei_pool, symname);
809 brelse(bp);
810 return (EINVAL);
811 }
812 /*
813 * Don't forget before you leave from home ;-)
814 */
815 brelse(bp);
816
817 /*
818 * return with the symbolic name to caller's.
819 */
820 if (uio->uio_segflg != UIO_SYSSPACE ||
821 uio->uio_iov->iov_len < MAXPATHLEN) {
822 error = uiomove(symname, symlen, uio);
823 pool_put(&namei_pool, symname);
824 return (error);
825 }
826 uio->uio_resid -= symlen;
827 uio->uio_iov->iov_base += symlen;
828 uio->uio_iov->iov_len -= symlen;
829 return (0);
830 }
831
832 int
cd9660_link(v)833 cd9660_link(v)
834 void *v;
835 {
836 struct vop_link_args /* {
837 struct vnode *a_dvp;
838 struct vnode *a_vp;
839 struct componentname *a_cnp;
840 } */ *ap = v;
841
842 VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
843 vput(ap->a_dvp);
844 return (EROFS);
845 }
846
847 int
cd9660_symlink(v)848 cd9660_symlink(v)
849 void *v;
850 {
851 struct vop_symlink_args /* {
852 struct vnode *a_dvp;
853 struct vnode **a_vpp;
854 struct componentname *a_cnp;
855 struct vattr *a_vap;
856 char *a_target;
857 } */ *ap = v;
858
859 VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
860 vput(ap->a_dvp);
861 return (EROFS);
862 }
863
864 /*
865 * Lock an inode.
866 */
867 int
cd9660_lock(v)868 cd9660_lock(v)
869 void *v;
870 {
871 struct vop_lock_args /* {
872 struct vnode *a_vp;
873 } */ *ap = v;
874 struct vnode *vp = ap->a_vp;
875
876 return (lockmgr(&VTOI(vp)->i_lock, ap->a_flags, &vp->v_interlock,
877 ap->a_p));
878 }
879
880 /*
881 * Unlock an inode.
882 */
883 int
cd9660_unlock(v)884 cd9660_unlock(v)
885 void *v;
886 {
887 struct vop_unlock_args /* {
888 struct vnode *a_vp;
889 } */ *ap = v;
890 struct vnode *vp = ap->a_vp;
891
892 return (lockmgr(&VTOI(vp)->i_lock, ap->a_flags | LK_RELEASE,
893 &vp->v_interlock, ap->a_p));
894 }
895
896 /*
897 * Calculate the logical to physical mapping if not done already,
898 * then call the device strategy routine.
899 */
900 int
cd9660_strategy(v)901 cd9660_strategy(v)
902 void *v;
903 {
904 struct vop_strategy_args /* {
905 struct buf *a_bp;
906 } */ *ap = v;
907 struct buf *bp = ap->a_bp;
908 struct vnode *vp = bp->b_vp;
909 struct iso_node *ip;
910 int error;
911 int s;
912
913 ip = VTOI(vp);
914 if (vp->v_type == VBLK || vp->v_type == VCHR)
915 panic("cd9660_strategy: spec");
916 if (bp->b_blkno == bp->b_lblkno) {
917 error = VOP_BMAP(vp, bp->b_lblkno, NULL, &bp->b_blkno, NULL);
918 if (error) {
919 bp->b_error = error;
920 bp->b_flags |= B_ERROR;
921 s = splbio();
922 biodone(bp);
923 splx(s);
924 return (error);
925 }
926 if ((long)bp->b_blkno == -1)
927 clrbuf(bp);
928 }
929 if ((long)bp->b_blkno == -1) {
930 s = splbio();
931 biodone(bp);
932 splx(s);
933 return (0);
934 }
935 vp = ip->i_devvp;
936 bp->b_dev = vp->v_rdev;
937 VOCALL (vp->v_op, VOFFSET(vop_strategy), ap);
938 return (0);
939 }
940
941 /*
942 * Print out the contents of an inode.
943 */
944 /*ARGSUSED*/
945 int
cd9660_print(v)946 cd9660_print(v)
947 void *v;
948 {
949 printf("tag VT_ISOFS, isofs vnode\n");
950 return (0);
951 }
952
953 /*
954 * Check for a locked inode.
955 */
956 int
cd9660_islocked(v)957 cd9660_islocked(v)
958 void *v;
959 {
960 struct vop_islocked_args /* {
961 struct vnode *a_vp;
962 } */ *ap = v;
963
964 return (lockstatus(&VTOI(ap->a_vp)->i_lock));
965 }
966
967 /*
968 * Return POSIX pathconf information applicable to cd9660 filesystems.
969 */
970 int
cd9660_pathconf(v)971 cd9660_pathconf(v)
972 void *v;
973 {
974 struct vop_pathconf_args /* {
975 struct vnode *a_vp;
976 int a_name;
977 register_t *a_retval;
978 } */ *ap = v;
979 switch (ap->a_name) {
980 case _PC_LINK_MAX:
981 *ap->a_retval = 1;
982 return (0);
983 case _PC_NAME_MAX:
984 if (VTOI(ap->a_vp)->i_mnt->iso_ftype == ISO_FTYPE_RRIP)
985 *ap->a_retval = NAME_MAX;
986 else
987 *ap->a_retval = 37;
988 return (0);
989 case _PC_PATH_MAX:
990 *ap->a_retval = PATH_MAX;
991 return (0);
992 case _PC_PIPE_BUF:
993 *ap->a_retval = PIPE_BUF;
994 return (0);
995 case _PC_CHOWN_RESTRICTED:
996 *ap->a_retval = 1;
997 return (0);
998 case _PC_NO_TRUNC:
999 *ap->a_retval = 1;
1000 return (0);
1001 default:
1002 return (EINVAL);
1003 }
1004 /* NOTREACHED */
1005 }
1006
1007 /*
1008 * Global vfs data structures for isofs
1009 */
1010 #define cd9660_create eopnotsupp
1011 #define cd9660_mknod eopnotsupp
1012 #define cd9660_write eopnotsupp
1013 #ifdef NFSSERVER
1014 int lease_check(void *);
1015 #define cd9660_lease_check lease_check
1016 #else
1017 #define cd9660_lease_check nullop
1018 #endif
1019 #define cd9660_fsync nullop
1020 #define cd9660_remove eopnotsupp
1021 #define cd9660_rename eopnotsupp
1022 #define cd9660_mkdir eopnotsupp
1023 #define cd9660_rmdir eopnotsupp
1024 #define cd9660_advlock eopnotsupp
1025 #define cd9660_valloc eopnotsupp
1026 #define cd9660_vfree eopnotsupp
1027 #define cd9660_truncate eopnotsupp
1028 #define cd9660_update eopnotsupp
1029 #define cd9660_bwrite eopnotsupp
1030 #define cd9660_revoke vop_generic_revoke
1031
1032 /*
1033 * Global vfs data structures for cd9660
1034 */
1035 int (**cd9660_vnodeop_p)(void *);
1036 struct vnodeopv_entry_desc cd9660_vnodeop_entries[] = {
1037 { &vop_default_desc, vn_default_error },
1038 { &vop_lookup_desc, cd9660_lookup }, /* lookup */
1039 { &vop_create_desc, cd9660_create }, /* create */
1040 { &vop_mknod_desc, cd9660_mknod }, /* mknod */
1041 { &vop_open_desc, cd9660_open }, /* open */
1042 { &vop_close_desc, cd9660_close }, /* close */
1043 { &vop_access_desc, cd9660_access }, /* access */
1044 { &vop_getattr_desc, cd9660_getattr }, /* getattr */
1045 { &vop_setattr_desc, cd9660_setattr }, /* setattr */
1046 { &vop_read_desc, cd9660_read }, /* read */
1047 { &vop_write_desc, cd9660_write }, /* write */
1048 { &vop_lease_desc, cd9660_lease_check },/* lease */
1049 { &vop_ioctl_desc, cd9660_ioctl }, /* ioctl */
1050 { &vop_poll_desc, cd9660_poll }, /* poll */
1051 { &vop_revoke_desc, cd9660_revoke }, /* revoke */
1052 { &vop_fsync_desc, cd9660_fsync }, /* fsync */
1053 { &vop_remove_desc, cd9660_remove }, /* remove */
1054 { &vop_link_desc, cd9660_link }, /* link */
1055 { &vop_rename_desc, cd9660_rename }, /* rename */
1056 { &vop_mkdir_desc, cd9660_mkdir }, /* mkdir */
1057 { &vop_rmdir_desc, cd9660_rmdir }, /* rmdir */
1058 { &vop_symlink_desc, cd9660_symlink }, /* symlink */
1059 { &vop_readdir_desc, cd9660_readdir }, /* readdir */
1060 { &vop_readlink_desc, cd9660_readlink },/* readlink */
1061 { &vop_abortop_desc, vop_generic_abortop }, /* abortop */
1062 { &vop_inactive_desc, cd9660_inactive },/* inactive */
1063 { &vop_reclaim_desc, cd9660_reclaim }, /* reclaim */
1064 { &vop_lock_desc, cd9660_lock }, /* lock */
1065 { &vop_unlock_desc, cd9660_unlock }, /* unlock */
1066 { &vop_bmap_desc, cd9660_bmap }, /* bmap */
1067 { &vop_strategy_desc, cd9660_strategy },/* strategy */
1068 { &vop_print_desc, cd9660_print }, /* print */
1069 { &vop_islocked_desc, cd9660_islocked },/* islocked */
1070 { &vop_pathconf_desc, cd9660_pathconf },/* pathconf */
1071 { &vop_advlock_desc, cd9660_advlock }, /* advlock */
1072 { &vop_bwrite_desc, vop_generic_bwrite },
1073 { NULL, NULL }
1074 };
1075 struct vnodeopv_desc cd9660_vnodeop_opv_desc =
1076 { &cd9660_vnodeop_p, cd9660_vnodeop_entries };
1077
1078 /*
1079 * Special device vnode ops
1080 */
1081 int (**cd9660_specop_p)(void *);
1082 struct vnodeopv_entry_desc cd9660_specop_entries[] = {
1083 { &vop_default_desc, spec_vnoperate },
1084 { &vop_access_desc, cd9660_access }, /* access */
1085 { &vop_getattr_desc, cd9660_getattr }, /* getattr */
1086 { &vop_setattr_desc, cd9660_setattr }, /* setattr */
1087 { &vop_inactive_desc, cd9660_inactive },/* inactive */
1088 { &vop_reclaim_desc, cd9660_reclaim }, /* reclaim */
1089 { &vop_lock_desc, cd9660_lock }, /* lock */
1090 { &vop_unlock_desc, cd9660_unlock }, /* unlock */
1091 { &vop_print_desc, cd9660_print }, /* print */
1092 { &vop_islocked_desc, cd9660_islocked },/* islocked */
1093 { NULL, NULL }
1094 };
1095 struct vnodeopv_desc cd9660_specop_opv_desc =
1096 { &cd9660_specop_p, cd9660_specop_entries };
1097
1098 #ifdef FIFO
1099 int (**cd9660_fifoop_p)(void *);
1100 struct vnodeopv_entry_desc cd9660_fifoop_entries[] = {
1101 { &vop_default_desc, fifo_vnoperate },
1102 { &vop_access_desc, cd9660_access }, /* access */
1103 { &vop_getattr_desc, cd9660_getattr }, /* getattr */
1104 { &vop_setattr_desc, cd9660_setattr }, /* setattr */
1105 { &vop_inactive_desc, cd9660_inactive },/* inactive */
1106 { &vop_reclaim_desc, cd9660_reclaim }, /* reclaim */
1107 { &vop_lock_desc, cd9660_lock }, /* lock */
1108 { &vop_unlock_desc, cd9660_unlock }, /* unlock */
1109 { &vop_print_desc, cd9660_print }, /* print */
1110 { &vop_islocked_desc, cd9660_islocked },/* islocked */
1111 { &vop_bwrite_desc, vop_generic_bwrite },
1112 { NULL, NULL }
1113 };
1114 struct vnodeopv_desc cd9660_fifoop_opv_desc =
1115 { &cd9660_fifoop_p, cd9660_fifoop_entries };
1116 #endif /* FIFO */
1117