Line data Source code
1 : /* $OpenBSD: cd9660_vnops.c,v 1.76 2016/06/19 11:54:33 natano 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/conf.h>
49 : #include <sys/mount.h>
50 : #include <sys/vnode.h>
51 : #include <sys/lock.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/poll.h>
58 : #include <sys/specdev.h>
59 : #include <sys/unistd.h>
60 :
61 : #include <miscfs/fifofs/fifo.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 : int cd9660_kqfilter(void *v);
69 :
70 :
71 : /*
72 : * Structure for reading directories
73 : */
74 : struct isoreaddir {
75 : struct dirent saveent;
76 : struct dirent assocent;
77 : struct dirent current;
78 : off_t saveoff;
79 : off_t assocoff;
80 : off_t curroff;
81 : struct uio *uio;
82 : off_t uio_off;
83 : int eofflag;
84 : };
85 :
86 : int iso_uiodir(struct isoreaddir *, struct dirent *, off_t);
87 : int iso_shipdir(struct isoreaddir *);
88 :
89 : /*
90 : * Setattr call. Only allowed for block and character special devices.
91 : */
92 : int
93 0 : cd9660_setattr(void *v)
94 : {
95 0 : struct vop_setattr_args *ap = v;
96 0 : struct vnode *vp = ap->a_vp;
97 0 : struct vattr *vap = ap->a_vap;
98 :
99 0 : if (vap->va_flags != VNOVAL || vap->va_uid != (uid_t)VNOVAL ||
100 0 : vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_nsec != VNOVAL ||
101 0 : vap->va_mtime.tv_nsec != VNOVAL || vap->va_mode != (mode_t)VNOVAL ||
102 0 : (vap->va_vaflags & VA_UTIMES_CHANGE))
103 0 : return (EROFS);
104 0 : if (vap->va_size != VNOVAL) {
105 0 : switch (vp->v_type) {
106 : case VDIR:
107 0 : return (EISDIR);
108 : case VLNK:
109 : case VREG:
110 0 : return (EROFS);
111 : case VCHR:
112 : case VBLK:
113 : case VSOCK:
114 : case VFIFO:
115 0 : return (0);
116 : default:
117 0 : return (EINVAL);
118 : }
119 : }
120 :
121 0 : return (EINVAL);
122 0 : }
123 :
124 : /*
125 : * Open called.
126 : *
127 : * Nothing to do.
128 : */
129 : /* ARGSUSED */
130 : int
131 0 : cd9660_open(void *v)
132 : {
133 0 : return (0);
134 : }
135 :
136 : /*
137 : * Close called
138 : *
139 : * Update the times on the inode on writeable file systems.
140 : */
141 : /* ARGSUSED */
142 : int
143 0 : cd9660_close(void *v)
144 : {
145 0 : return (0);
146 : }
147 :
148 : /*
149 : * Check mode permission on inode pointer. Mode is READ, WRITE or EXEC.
150 : * The mode is shifted to select the owner/group/other fields. The
151 : * super user is granted all permissions.
152 : */
153 : int
154 0 : cd9660_access(void *v)
155 : {
156 0 : struct vop_access_args *ap = v;
157 0 : struct iso_node *ip = VTOI(ap->a_vp);
158 :
159 0 : return (vaccess(ap->a_vp->v_type, ip->inode.iso_mode & ALLPERMS,
160 0 : ip->inode.iso_uid, ip->inode.iso_gid, ap->a_mode, ap->a_cred));
161 : }
162 :
163 : int
164 0 : cd9660_getattr(void *v)
165 : {
166 0 : struct vop_getattr_args *ap = v;
167 0 : struct vnode *vp = ap->a_vp;
168 0 : register struct vattr *vap = ap->a_vap;
169 0 : register struct iso_node *ip = VTOI(vp);
170 :
171 0 : vap->va_fsid = ip->i_dev;
172 0 : vap->va_fileid = ip->i_number;
173 :
174 0 : vap->va_mode = ip->inode.iso_mode & ALLPERMS;
175 0 : vap->va_nlink = ip->inode.iso_links;
176 0 : vap->va_uid = ip->inode.iso_uid;
177 0 : vap->va_gid = ip->inode.iso_gid;
178 0 : vap->va_atime = ip->inode.iso_atime;
179 0 : vap->va_mtime = ip->inode.iso_mtime;
180 0 : vap->va_ctime = ip->inode.iso_ctime;
181 0 : vap->va_rdev = ip->inode.iso_rdev;
182 :
183 0 : vap->va_size = (u_quad_t) ip->i_size;
184 0 : if (ip->i_size == 0 && vp->v_type == VLNK) {
185 0 : struct vop_readlink_args rdlnk;
186 0 : struct iovec aiov;
187 0 : struct uio auio;
188 : char *cp;
189 :
190 0 : cp = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
191 0 : aiov.iov_base = cp;
192 0 : aiov.iov_len = MAXPATHLEN;
193 0 : auio.uio_iov = &aiov;
194 0 : auio.uio_iovcnt = 1;
195 0 : auio.uio_offset = 0;
196 0 : auio.uio_rw = UIO_READ;
197 0 : auio.uio_segflg = UIO_SYSSPACE;
198 0 : auio.uio_procp = ap->a_p;
199 0 : auio.uio_resid = MAXPATHLEN;
200 0 : rdlnk.a_uio = &auio;
201 0 : rdlnk.a_vp = ap->a_vp;
202 0 : rdlnk.a_cred = ap->a_cred;
203 0 : if (cd9660_readlink(&rdlnk) == 0)
204 0 : vap->va_size = MAXPATHLEN - auio.uio_resid;
205 0 : free(cp, M_TEMP, 0);
206 0 : }
207 0 : vap->va_flags = 0;
208 0 : vap->va_gen = 1;
209 0 : vap->va_blocksize = ip->i_mnt->logical_block_size;
210 0 : vap->va_bytes = (u_quad_t) ip->i_size;
211 0 : vap->va_type = vp->v_type;
212 0 : return (0);
213 : }
214 :
215 : /*
216 : * Vnode op for reading.
217 : */
218 : int
219 0 : cd9660_read(void *v)
220 : {
221 0 : struct vop_read_args *ap = v;
222 0 : struct vnode *vp = ap->a_vp;
223 0 : register struct uio *uio = ap->a_uio;
224 0 : register struct iso_node *ip = VTOI(vp);
225 : register struct iso_mnt *imp;
226 0 : struct buf *bp;
227 : daddr_t lbn, rablock;
228 : off_t diff;
229 : int error = 0;
230 : long size, on;
231 : size_t n;
232 :
233 0 : if (uio->uio_resid == 0)
234 0 : return (0);
235 0 : if (uio->uio_offset < 0)
236 0 : return (EINVAL);
237 0 : ip->i_flag |= IN_ACCESS;
238 0 : imp = ip->i_mnt;
239 0 : do {
240 0 : struct cluster_info *ci = &ip->i_ci;
241 :
242 0 : lbn = lblkno(imp, uio->uio_offset);
243 0 : on = blkoff(imp, uio->uio_offset);
244 0 : n = ulmin(imp->logical_block_size - on, uio->uio_resid);
245 0 : diff = (off_t)ip->i_size - uio->uio_offset;
246 0 : if (diff <= 0)
247 0 : return (0);
248 0 : if (diff < n)
249 0 : n = diff;
250 0 : size = blksize(imp, ip, lbn);
251 0 : rablock = lbn + 1;
252 : #define MAX_RA 32
253 0 : if (ci->ci_lastr + 1 == lbn) {
254 : struct ra {
255 : daddr_t blks[MAX_RA];
256 : int sizes[MAX_RA];
257 : } *ra;
258 : int i;
259 :
260 0 : ra = malloc(sizeof *ra, M_TEMP, M_WAITOK);
261 0 : for (i = 0; i < MAX_RA &&
262 0 : lblktosize(imp, (rablock + i)) < ip->i_size;
263 0 : i++) {
264 0 : ra->blks[i] = rablock + i;
265 0 : ra->sizes[i] = blksize(imp, ip, rablock + i);
266 : }
267 0 : error = breadn(vp, lbn, size, ra->blks,
268 0 : ra->sizes, i, &bp);
269 0 : free(ra, M_TEMP, 0);
270 0 : } else
271 0 : error = bread(vp, lbn, size, &bp);
272 0 : ci->ci_lastr = lbn;
273 0 : n = ulmin(n, size - bp->b_resid);
274 0 : if (error) {
275 0 : brelse(bp);
276 0 : return (error);
277 : }
278 :
279 0 : error = uiomove(bp->b_data + on, n, uio);
280 :
281 0 : brelse(bp);
282 0 : } while (error == 0 && uio->uio_resid > 0 && n != 0);
283 0 : return (error);
284 0 : }
285 :
286 : /* ARGSUSED */
287 : int
288 0 : cd9660_ioctl(void *v)
289 : {
290 0 : return (ENOTTY);
291 : }
292 :
293 : /* ARGSUSED */
294 : int
295 0 : cd9660_poll(void *v)
296 : {
297 0 : struct vop_poll_args *ap = v;
298 :
299 : /*
300 : * We should really check to see if I/O is possible.
301 : */
302 0 : return (ap->a_events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM));
303 : }
304 :
305 : /*
306 : * Mmap a file
307 : *
308 : * NB Currently unsupported.
309 : */
310 : /* ARGSUSED */
311 : int
312 0 : cd9660_mmap(void *v)
313 : {
314 :
315 0 : return (EINVAL);
316 : }
317 :
318 : /*
319 : * Seek on a file
320 : *
321 : * Nothing to do, so just return.
322 : */
323 : /* ARGSUSED */
324 : int
325 0 : cd9660_seek(void *v)
326 : {
327 0 : return (0);
328 : }
329 :
330 : int
331 0 : iso_uiodir(idp,dp,off)
332 : struct isoreaddir *idp;
333 : struct dirent *dp;
334 : off_t off;
335 : {
336 : int error;
337 :
338 0 : dp->d_name[dp->d_namlen] = 0;
339 0 : dp->d_reclen = DIRENT_SIZE(dp);
340 :
341 0 : if (idp->uio->uio_resid < dp->d_reclen) {
342 0 : idp->eofflag = 0;
343 0 : return (-1);
344 : }
345 :
346 0 : dp->d_off = off;
347 0 : if ((error = uiomove(dp, dp->d_reclen, idp->uio)) != 0)
348 0 : return (error);
349 0 : idp->uio_off = off;
350 0 : return (0);
351 0 : }
352 :
353 : int
354 0 : iso_shipdir(idp)
355 : struct isoreaddir *idp;
356 : {
357 : struct dirent *dp;
358 : int cl, sl, assoc;
359 : int error;
360 : char *cname, *sname;
361 :
362 0 : cl = idp->current.d_namlen;
363 0 : cname = idp->current.d_name;
364 :
365 0 : if ((assoc = cl > 1 && *cname == ASSOCCHAR)) {
366 0 : cl--;
367 0 : cname++;
368 0 : }
369 :
370 0 : dp = &idp->saveent;
371 0 : sname = dp->d_name;
372 0 : if (!(sl = dp->d_namlen)) {
373 0 : dp = &idp->assocent;
374 0 : sname = dp->d_name + 1;
375 0 : sl = dp->d_namlen - 1;
376 0 : }
377 0 : if (sl > 0) {
378 0 : if (sl != cl
379 0 : || bcmp(sname,cname,sl)) {
380 0 : if (idp->assocent.d_namlen) {
381 0 : error = iso_uiodir(idp, &idp->assocent,
382 0 : idp->assocoff);
383 0 : if (error)
384 0 : return (error);
385 0 : idp->assocent.d_namlen = 0;
386 0 : }
387 0 : if (idp->saveent.d_namlen) {
388 0 : error = iso_uiodir(idp, &idp->saveent,
389 0 : idp->saveoff);
390 0 : if (error)
391 0 : return (error);
392 0 : idp->saveent.d_namlen = 0;
393 0 : }
394 : }
395 : }
396 0 : idp->current.d_reclen = DIRENT_SIZE(&idp->current);
397 0 : if (assoc) {
398 0 : idp->assocoff = idp->curroff;
399 0 : bcopy(&idp->current,&idp->assocent,idp->current.d_reclen);
400 0 : } else {
401 0 : idp->saveoff = idp->curroff;
402 0 : bcopy(&idp->current,&idp->saveent,idp->current.d_reclen);
403 : }
404 0 : return (0);
405 0 : }
406 :
407 : /*
408 : * Vnode op for readdir
409 : */
410 : int
411 0 : cd9660_readdir(void *v)
412 : {
413 0 : struct vop_readdir_args *ap = v;
414 0 : register struct uio *uio = ap->a_uio;
415 : struct isoreaddir *idp;
416 0 : struct vnode *vdp = ap->a_vp;
417 : struct iso_node *dp;
418 : struct iso_mnt *imp;
419 0 : struct buf *bp = NULL;
420 : struct iso_directory_record *ep;
421 : int entryoffsetinblock;
422 : doff_t endsearch;
423 : u_long bmask;
424 : int error = 0;
425 : int reclen;
426 0 : u_short namelen;
427 0 : cdino_t ino;
428 :
429 0 : dp = VTOI(vdp);
430 0 : imp = dp->i_mnt;
431 0 : bmask = imp->im_bmask;
432 :
433 0 : idp = malloc(sizeof(*idp), M_TEMP, M_WAITOK);
434 :
435 : /*
436 : * These are passed to copyout(), so make sure there's no garbage
437 : * being leaked in padding or after short names.
438 : */
439 0 : memset(&idp->saveent, 0, sizeof(idp->saveent));
440 0 : memset(&idp->assocent, 0, sizeof(idp->assocent));
441 0 : memset(&idp->current, 0, sizeof(idp->current));
442 :
443 : /*
444 : * XXX
445 : * Is it worth trying to figure out the type?
446 : */
447 0 : idp->saveent.d_type = idp->assocent.d_type = idp->current.d_type =
448 : DT_UNKNOWN;
449 0 : idp->uio = uio;
450 0 : idp->eofflag = 1;
451 0 : idp->curroff = uio->uio_offset;
452 0 : idp->uio_off = uio->uio_offset;
453 :
454 0 : if ((entryoffsetinblock = idp->curroff & bmask) &&
455 0 : (error = cd9660_bufatoff(dp, (off_t)idp->curroff, NULL, &bp))) {
456 0 : free(idp, M_TEMP, 0);
457 0 : return (error);
458 : }
459 0 : endsearch = dp->i_size;
460 :
461 0 : while (idp->curroff < endsearch) {
462 : /*
463 : * If offset is on a block boundary,
464 : * read the next directory block.
465 : * Release previous if it exists.
466 : */
467 0 : if ((idp->curroff & bmask) == 0) {
468 0 : if (bp != NULL)
469 0 : brelse(bp);
470 0 : error = cd9660_bufatoff(dp, (off_t)idp->curroff,
471 : NULL, &bp);
472 0 : if (error)
473 : break;
474 : entryoffsetinblock = 0;
475 0 : }
476 : /*
477 : * Get pointer to next entry.
478 : */
479 0 : ep = (struct iso_directory_record *)
480 0 : ((char *)bp->b_data + entryoffsetinblock);
481 :
482 0 : reclen = isonum_711(ep->length);
483 0 : if (reclen == 0) {
484 : /* skip to next block, if any */
485 0 : idp->curroff =
486 0 : (idp->curroff & ~bmask) + imp->logical_block_size;
487 0 : continue;
488 : }
489 :
490 0 : if (reclen < ISO_DIRECTORY_RECORD_SIZE) {
491 : error = EINVAL;
492 : /* illegal entry, stop */
493 0 : break;
494 : }
495 :
496 0 : if (entryoffsetinblock + reclen > imp->logical_block_size) {
497 : error = EINVAL;
498 : /* illegal directory, so stop looking */
499 0 : break;
500 : }
501 :
502 0 : idp->current.d_namlen = isonum_711(ep->name_len);
503 :
504 0 : if (reclen < ISO_DIRECTORY_RECORD_SIZE + idp->current.d_namlen) {
505 : error = EINVAL;
506 : /* illegal entry, stop */
507 0 : break;
508 : }
509 :
510 0 : if (isonum_711(ep->flags)&2)
511 0 : ino = isodirino(ep, imp);
512 : else
513 0 : ino = dbtob(bp->b_blkno) + entryoffsetinblock;
514 :
515 0 : idp->curroff += reclen;
516 :
517 0 : switch (imp->iso_ftype) {
518 : case ISO_FTYPE_RRIP:
519 0 : cd9660_rrip_getname(ep,idp->current.d_name, &namelen,
520 : &ino, imp);
521 0 : idp->current.d_fileno = ino;
522 0 : idp->current.d_namlen = (u_char)namelen;
523 0 : if (idp->current.d_namlen)
524 0 : error = iso_uiodir(idp,&idp->current,idp->curroff);
525 : break;
526 : default: /* ISO_FTYPE_DEFAULT || ISO_FTYPE_9660 */
527 0 : idp->current.d_fileno = ino;
528 0 : strlcpy(idp->current.d_name,"..",
529 : sizeof idp->current.d_name);
530 0 : if (idp->current.d_namlen == 1 && ep->name[0] == 0) {
531 0 : idp->current.d_namlen = 1;
532 0 : error = iso_uiodir(idp,&idp->current,idp->curroff);
533 0 : } else if (idp->current.d_namlen == 1 &&
534 0 : ep->name[0] == 1) {
535 0 : idp->current.d_namlen = 2;
536 0 : error = iso_uiodir(idp,&idp->current,idp->curroff);
537 0 : } else {
538 0 : isofntrans(ep->name,idp->current.d_namlen,
539 : idp->current.d_name, &namelen,
540 0 : imp->iso_ftype == ISO_FTYPE_9660,
541 0 : isonum_711(ep->flags) & 4,
542 0 : imp->joliet_level);
543 0 : idp->current.d_namlen = (u_char)namelen;
544 0 : if (imp->iso_ftype == ISO_FTYPE_DEFAULT)
545 0 : error = iso_shipdir(idp);
546 : else
547 0 : error = iso_uiodir(idp,&idp->current,idp->curroff);
548 : }
549 : }
550 0 : if (error)
551 : break;
552 :
553 : entryoffsetinblock += reclen;
554 : }
555 :
556 0 : if (!error && imp->iso_ftype == ISO_FTYPE_DEFAULT) {
557 0 : idp->current.d_namlen = 0;
558 0 : error = iso_shipdir(idp);
559 0 : }
560 0 : if (error < 0)
561 0 : error = 0;
562 :
563 0 : if (bp)
564 0 : brelse (bp);
565 :
566 0 : uio->uio_offset = idp->uio_off;
567 0 : *ap->a_eofflag = idp->eofflag;
568 :
569 0 : free(idp, M_TEMP, 0);
570 :
571 0 : return (error);
572 0 : }
573 :
574 : /*
575 : * Return target name of a symbolic link
576 : * Shouldn't we get the parent vnode and read the data from there?
577 : * This could eventually result in deadlocks in cd9660_lookup.
578 : * But otherwise the block read here is in the block buffer two times.
579 : */
580 : typedef struct iso_directory_record ISODIR;
581 : typedef struct iso_node ISONODE;
582 : typedef struct iso_mnt ISOMNT;
583 : int
584 0 : cd9660_readlink(void *v)
585 : {
586 0 : struct vop_readlink_args *ap = v;
587 : ISONODE *ip;
588 : ISODIR *dirp;
589 : ISOMNT *imp;
590 0 : struct buf *bp;
591 : struct uio *uio;
592 0 : u_short symlen;
593 : int error;
594 : char *symname;
595 :
596 0 : ip = VTOI(ap->a_vp);
597 0 : imp = ip->i_mnt;
598 0 : uio = ap->a_uio;
599 :
600 0 : if (imp->iso_ftype != ISO_FTYPE_RRIP)
601 0 : return (EINVAL);
602 :
603 : /*
604 : * Get parents directory record block that this inode included.
605 : */
606 0 : error = bread(imp->im_devvp,
607 0 : (ip->i_number >> imp->im_bshift) <<
608 0 : (imp->im_bshift - DEV_BSHIFT),
609 0 : imp->logical_block_size, &bp);
610 0 : if (error) {
611 0 : brelse(bp);
612 0 : return (EINVAL);
613 : }
614 :
615 : /*
616 : * Setup the directory pointer for this inode
617 : */
618 0 : dirp = (ISODIR *)(bp->b_data + (ip->i_number & imp->im_bmask));
619 :
620 : /*
621 : * Just make sure, we have a right one....
622 : * 1: Check not cross boundary on block
623 : */
624 0 : if ((ip->i_number & imp->im_bmask) + isonum_711(dirp->length)
625 0 : > imp->logical_block_size) {
626 0 : brelse(bp);
627 0 : return (EINVAL);
628 : }
629 :
630 : /*
631 : * Now get a buffer
632 : * Abuse a namei buffer for now.
633 : */
634 0 : if (uio->uio_segflg == UIO_SYSSPACE &&
635 0 : uio->uio_iov->iov_len >= MAXPATHLEN)
636 0 : symname = uio->uio_iov->iov_base;
637 : else
638 0 : symname = pool_get(&namei_pool, PR_WAITOK);
639 :
640 : /*
641 : * Ok, we just gathering a symbolic name in SL record.
642 : */
643 0 : if (cd9660_rrip_getsymname(dirp, symname, &symlen, imp) == 0) {
644 0 : if (uio->uio_segflg != UIO_SYSSPACE ||
645 0 : uio->uio_iov->iov_len < MAXPATHLEN)
646 0 : pool_put(&namei_pool, symname);
647 0 : brelse(bp);
648 0 : return (EINVAL);
649 : }
650 : /*
651 : * Don't forget before you leave from home ;-)
652 : */
653 0 : brelse(bp);
654 :
655 : /*
656 : * return with the symbolic name to caller's.
657 : */
658 0 : if (uio->uio_segflg != UIO_SYSSPACE ||
659 0 : uio->uio_iov->iov_len < MAXPATHLEN) {
660 0 : error = uiomove(symname, symlen, uio);
661 0 : pool_put(&namei_pool, symname);
662 0 : return (error);
663 : }
664 0 : uio->uio_resid -= symlen;
665 0 : uio->uio_iov->iov_base = (char *)uio->uio_iov->iov_base + symlen;
666 0 : uio->uio_iov->iov_len -= symlen;
667 0 : return (0);
668 0 : }
669 :
670 : int
671 0 : cd9660_link(void *v)
672 : {
673 0 : struct vop_link_args *ap = v;
674 :
675 0 : VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
676 0 : vput(ap->a_dvp);
677 0 : return (EROFS);
678 : }
679 :
680 : int
681 0 : cd9660_symlink(void *v)
682 : {
683 0 : struct vop_symlink_args *ap = v;
684 :
685 0 : VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
686 0 : vput(ap->a_dvp);
687 0 : return (EROFS);
688 : }
689 :
690 : /*
691 : * Lock an inode.
692 : */
693 : int
694 0 : cd9660_lock(void *v)
695 : {
696 0 : struct vop_lock_args *ap = v;
697 0 : struct vnode *vp = ap->a_vp;
698 :
699 0 : return rrw_enter(&VTOI(vp)->i_lock, ap->a_flags & LK_RWFLAGS);
700 : }
701 :
702 : /*
703 : * Unlock an inode.
704 : */
705 : int
706 0 : cd9660_unlock(void *v)
707 : {
708 0 : struct vop_unlock_args *ap = v;
709 0 : struct vnode *vp = ap->a_vp;
710 :
711 0 : rrw_exit(&VTOI(vp)->i_lock);
712 0 : return 0;
713 : }
714 :
715 : /*
716 : * Calculate the logical to physical mapping if not done already,
717 : * then call the device strategy routine.
718 : */
719 : int
720 0 : cd9660_strategy(void *v)
721 : {
722 0 : struct vop_strategy_args *ap = v;
723 0 : struct buf *bp = ap->a_bp;
724 0 : struct vnode *vp = bp->b_vp;
725 : struct iso_node *ip;
726 : int error;
727 : int s;
728 :
729 0 : ip = VTOI(vp);
730 0 : if (vp->v_type == VBLK || vp->v_type == VCHR)
731 0 : panic("cd9660_strategy: spec");
732 0 : if (bp->b_blkno == bp->b_lblkno) {
733 0 : error = VOP_BMAP(vp, bp->b_lblkno, NULL, &bp->b_blkno, NULL);
734 0 : if (error) {
735 0 : bp->b_error = error;
736 0 : bp->b_flags |= B_ERROR;
737 0 : s = splbio();
738 0 : biodone(bp);
739 0 : splx(s);
740 0 : return (error);
741 : }
742 0 : if ((long)bp->b_blkno == -1)
743 0 : clrbuf(bp);
744 : }
745 0 : if ((long)bp->b_blkno == -1) {
746 0 : s = splbio();
747 0 : biodone(bp);
748 0 : splx(s);
749 0 : return (0);
750 : }
751 0 : vp = ip->i_devvp;
752 0 : bp->b_dev = vp->v_rdev;
753 0 : (vp->v_op->vop_strategy)(ap);
754 0 : return (0);
755 0 : }
756 :
757 : /*
758 : * Print out the contents of an inode.
759 : */
760 : /*ARGSUSED*/
761 : int
762 0 : cd9660_print(void *v)
763 : {
764 0 : printf("tag VT_ISOFS, isofs vnode\n");
765 0 : return (0);
766 : }
767 :
768 : /*
769 : * Check for a locked inode.
770 : */
771 : int
772 0 : cd9660_islocked(void *v)
773 : {
774 0 : struct vop_islocked_args *ap = v;
775 :
776 0 : return rrw_status(&VTOI(ap->a_vp)->i_lock);
777 : }
778 :
779 : /*
780 : * Return POSIX pathconf information applicable to cd9660 filesystems.
781 : */
782 : int
783 0 : cd9660_pathconf(void *v)
784 : {
785 0 : struct vop_pathconf_args *ap = v;
786 : int error = 0;
787 :
788 0 : switch (ap->a_name) {
789 : case _PC_LINK_MAX:
790 0 : *ap->a_retval = 1;
791 0 : break;
792 : case _PC_NAME_MAX:
793 0 : if (VTOI(ap->a_vp)->i_mnt->iso_ftype == ISO_FTYPE_RRIP)
794 0 : *ap->a_retval = NAME_MAX;
795 : else
796 0 : *ap->a_retval = 37;
797 : break;
798 : case _PC_CHOWN_RESTRICTED:
799 0 : *ap->a_retval = 1;
800 0 : break;
801 : case _PC_NO_TRUNC:
802 0 : *ap->a_retval = 1;
803 0 : break;
804 : case _PC_TIMESTAMP_RESOLUTION:
805 0 : *ap->a_retval = 1000000000; /* one billion nanoseconds */
806 0 : break;
807 : default:
808 : error = EINVAL;
809 0 : break;
810 : }
811 :
812 0 : return (error);
813 : }
814 :
815 : /*
816 : * Global vfs data structures for isofs
817 : */
818 : #define cd9660_create eopnotsupp
819 : #define cd9660_mknod eopnotsupp
820 : #define cd9660_write eopnotsupp
821 : #define cd9660_fsync nullop
822 : #define cd9660_remove eopnotsupp
823 : #define cd9660_rename eopnotsupp
824 : #define cd9660_mkdir eopnotsupp
825 : #define cd9660_rmdir eopnotsupp
826 : #define cd9660_advlock eopnotsupp
827 : #define cd9660_valloc eopnotsupp
828 : #define cd9660_vfree eopnotsupp
829 : #define cd9660_truncate eopnotsupp
830 : #define cd9660_update eopnotsupp
831 : #define cd9660_bwrite eopnotsupp
832 : #define cd9660_revoke vop_generic_revoke
833 :
834 : /* Global vfs data structures for cd9660. */
835 : struct vops cd9660_vops = {
836 : .vop_lookup = cd9660_lookup,
837 : .vop_create = cd9660_create,
838 : .vop_mknod = cd9660_mknod,
839 : .vop_open = cd9660_open,
840 : .vop_close = cd9660_close,
841 : .vop_access = cd9660_access,
842 : .vop_getattr = cd9660_getattr,
843 : .vop_setattr = cd9660_setattr,
844 : .vop_read = cd9660_read,
845 : .vop_write = cd9660_write,
846 : .vop_ioctl = cd9660_ioctl,
847 : .vop_poll = cd9660_poll,
848 : .vop_kqfilter = cd9660_kqfilter,
849 : .vop_revoke = cd9660_revoke,
850 : .vop_fsync = cd9660_fsync,
851 : .vop_remove = cd9660_remove,
852 : .vop_link = cd9660_link,
853 : .vop_rename = cd9660_rename,
854 : .vop_mkdir = cd9660_mkdir,
855 : .vop_rmdir = cd9660_rmdir,
856 : .vop_symlink = cd9660_symlink,
857 : .vop_readdir = cd9660_readdir,
858 : .vop_readlink = cd9660_readlink,
859 : .vop_abortop = vop_generic_abortop,
860 : .vop_inactive = cd9660_inactive,
861 : .vop_reclaim = cd9660_reclaim,
862 : .vop_lock = cd9660_lock,
863 : .vop_unlock = cd9660_unlock,
864 : .vop_bmap = cd9660_bmap,
865 : .vop_strategy = cd9660_strategy,
866 : .vop_print = cd9660_print,
867 : .vop_islocked = cd9660_islocked,
868 : .vop_pathconf = cd9660_pathconf,
869 : .vop_advlock = cd9660_advlock,
870 : .vop_bwrite = vop_generic_bwrite
871 : };
872 :
873 : /* Special device vnode ops */
874 : struct vops cd9660_specvops = {
875 : .vop_access = cd9660_access,
876 : .vop_getattr = cd9660_getattr,
877 : .vop_setattr = cd9660_setattr,
878 : .vop_inactive = cd9660_inactive,
879 : .vop_reclaim = cd9660_reclaim,
880 : .vop_lock = cd9660_lock,
881 : .vop_unlock = cd9660_unlock,
882 : .vop_print = cd9660_print,
883 : .vop_islocked = cd9660_islocked,
884 :
885 : /* XXX: Keep in sync with spec_vops. */
886 : .vop_lookup = vop_generic_lookup,
887 : .vop_create = spec_badop,
888 : .vop_mknod = spec_badop,
889 : .vop_open = spec_open,
890 : .vop_close = spec_close,
891 : .vop_read = spec_read,
892 : .vop_write = spec_write,
893 : .vop_ioctl = spec_ioctl,
894 : .vop_poll = spec_poll,
895 : .vop_kqfilter = spec_kqfilter,
896 : .vop_revoke = vop_generic_revoke,
897 : .vop_fsync = spec_fsync,
898 : .vop_remove = spec_badop,
899 : .vop_link = spec_badop,
900 : .vop_rename = spec_badop,
901 : .vop_mkdir = spec_badop,
902 : .vop_rmdir = spec_badop,
903 : .vop_symlink = spec_badop,
904 : .vop_readdir = spec_badop,
905 : .vop_readlink = spec_badop,
906 : .vop_abortop = spec_badop,
907 : .vop_bmap = vop_generic_bmap,
908 : .vop_strategy = spec_strategy,
909 : .vop_pathconf = spec_pathconf,
910 : .vop_advlock = spec_advlock,
911 : .vop_bwrite = vop_generic_bwrite,
912 : };
913 :
914 : #ifdef FIFO
915 : struct vops cd9660_fifovops = {
916 : .vop_access = cd9660_access,
917 : .vop_getattr = cd9660_getattr,
918 : .vop_setattr = cd9660_setattr,
919 : .vop_inactive = cd9660_inactive,
920 : .vop_reclaim = cd9660_reclaim,
921 : .vop_lock = cd9660_lock,
922 : .vop_unlock = cd9660_unlock,
923 : .vop_print = cd9660_print,
924 : .vop_islocked = cd9660_islocked,
925 : .vop_bwrite = vop_generic_bwrite,
926 :
927 : /* XXX: Keep in sync with fifo_vops. */
928 : .vop_lookup = vop_generic_lookup,
929 : .vop_create = fifo_badop,
930 : .vop_mknod = fifo_badop,
931 : .vop_open = fifo_open,
932 : .vop_close = fifo_close,
933 : .vop_read = fifo_read,
934 : .vop_write = fifo_write,
935 : .vop_ioctl = fifo_ioctl,
936 : .vop_poll = fifo_poll,
937 : .vop_kqfilter = fifo_kqfilter,
938 : .vop_revoke = vop_generic_revoke,
939 : .vop_fsync = nullop,
940 : .vop_remove = fifo_badop,
941 : .vop_link = fifo_badop,
942 : .vop_rename = fifo_badop,
943 : .vop_mkdir = fifo_badop,
944 : .vop_rmdir = fifo_badop,
945 : .vop_symlink = fifo_badop,
946 : .vop_readdir = fifo_badop,
947 : .vop_readlink = fifo_badop,
948 : .vop_abortop = fifo_badop,
949 : .vop_bmap = vop_generic_bmap,
950 : .vop_strategy = fifo_badop,
951 : .vop_pathconf = fifo_pathconf,
952 : .vop_advlock = fifo_advlock,
953 : };
954 : #endif /* FIFO */
955 :
956 : void filt_cd9660detach(struct knote *kn);
957 : int filt_cd9660read(struct knote *kn, long hint);
958 : int filt_cd9660write(struct knote *kn, long hint);
959 : int filt_cd9660vnode(struct knote *kn, long hint);
960 :
961 : struct filterops cd9660read_filtops =
962 : { 1, NULL, filt_cd9660detach, filt_cd9660read };
963 : struct filterops cd9660write_filtops =
964 : { 1, NULL, filt_cd9660detach, filt_cd9660write };
965 : struct filterops cd9660vnode_filtops =
966 : { 1, NULL, filt_cd9660detach, filt_cd9660vnode };
967 :
968 : int
969 0 : cd9660_kqfilter(void *v)
970 : {
971 0 : struct vop_kqfilter_args *ap = v;
972 0 : struct vnode *vp = ap->a_vp;
973 0 : struct knote *kn = ap->a_kn;
974 :
975 0 : switch (kn->kn_filter) {
976 : case EVFILT_READ:
977 0 : kn->kn_fop = &cd9660read_filtops;
978 0 : break;
979 : case EVFILT_WRITE:
980 0 : kn->kn_fop = &cd9660write_filtops;
981 0 : break;
982 : case EVFILT_VNODE:
983 0 : kn->kn_fop = &cd9660vnode_filtops;
984 0 : break;
985 : default:
986 0 : return (EINVAL);
987 : }
988 :
989 0 : kn->kn_hook = (caddr_t)vp;
990 :
991 0 : SLIST_INSERT_HEAD(&vp->v_selectinfo.si_note, kn, kn_selnext);
992 :
993 0 : return (0);
994 0 : }
995 :
996 : void
997 0 : filt_cd9660detach(struct knote *kn)
998 : {
999 0 : struct vnode *vp = (struct vnode *)kn->kn_hook;
1000 :
1001 0 : SLIST_REMOVE(&vp->v_selectinfo.si_note, kn, knote, kn_selnext);
1002 0 : }
1003 :
1004 : int
1005 0 : filt_cd9660read(struct knote *kn, long hint)
1006 : {
1007 0 : struct vnode *vp = (struct vnode *)kn->kn_hook;
1008 0 : struct iso_node *node = VTOI(vp);
1009 :
1010 : /*
1011 : * filesystem is gone, so set the EOF flag and schedule
1012 : * the knote for deletion.
1013 : */
1014 0 : if (hint == NOTE_REVOKE) {
1015 0 : kn->kn_flags |= (EV_EOF | EV_ONESHOT);
1016 0 : return (1);
1017 : }
1018 :
1019 0 : kn->kn_data = node->i_size - kn->kn_fp->f_offset;
1020 0 : if (kn->kn_data == 0 && kn->kn_sfflags & NOTE_EOF) {
1021 0 : kn->kn_fflags |= NOTE_EOF;
1022 0 : return (1);
1023 : }
1024 :
1025 0 : return (kn->kn_data != 0);
1026 0 : }
1027 :
1028 : int
1029 0 : filt_cd9660write(struct knote *kn, long hint)
1030 : {
1031 : /*
1032 : * filesystem is gone, so set the EOF flag and schedule
1033 : * the knote for deletion.
1034 : */
1035 0 : if (hint == NOTE_REVOKE) {
1036 0 : kn->kn_flags |= (EV_EOF | EV_ONESHOT);
1037 0 : return (1);
1038 : }
1039 :
1040 0 : kn->kn_data = 0;
1041 0 : return (1);
1042 0 : }
1043 :
1044 : int
1045 0 : filt_cd9660vnode(struct knote *kn, long hint)
1046 : {
1047 0 : if (kn->kn_sfflags & hint)
1048 0 : kn->kn_fflags |= hint;
1049 0 : if (hint == NOTE_REVOKE) {
1050 0 : kn->kn_flags |= EV_EOF;
1051 0 : return (1);
1052 : }
1053 0 : return (kn->kn_fflags != 0);
1054 0 : }
|