Annotation of sys/isofs/cd9660/cd9660_node.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: cd9660_node.c,v 1.19 2007/06/01 23:47:55 deraadt Exp $ */
! 2: /* $NetBSD: cd9660_node.c,v 1.17 1997/05/05 07:13:57 mycroft Exp $ */
! 3:
! 4: /*-
! 5: * Copyright (c) 1982, 1986, 1989, 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_node.c 8.5 (Berkeley) 12/5/94
! 38: */
! 39:
! 40: #include <sys/param.h>
! 41: #include <sys/systm.h>
! 42: #include <sys/mount.h>
! 43: #include <sys/proc.h>
! 44: #include <sys/file.h>
! 45: #include <sys/buf.h>
! 46: #include <sys/vnode.h>
! 47: #include <sys/namei.h>
! 48: #include <sys/kernel.h>
! 49: #include <sys/malloc.h>
! 50: #include <sys/stat.h>
! 51:
! 52: #include <isofs/cd9660/iso.h>
! 53: #include <isofs/cd9660/cd9660_extern.h>
! 54: #include <isofs/cd9660/cd9660_node.h>
! 55: #include <isofs/cd9660/iso_rrip.h>
! 56:
! 57: /*
! 58: * Structures associated with iso_node caching.
! 59: */
! 60: struct iso_node **isohashtbl;
! 61: u_long isohash;
! 62: #define INOHASH(device, inum) (((device) + ((inum)>>12)) & isohash)
! 63: struct simplelock cd9660_ihash_slock;
! 64:
! 65: #ifdef ISODEVMAP
! 66: struct iso_node **idvhashtbl;
! 67: u_long idvhash;
! 68: #define DNOHASH(device, inum) (((device) + ((inum)>>12)) & idvhash)
! 69: #endif
! 70:
! 71: extern int prtactive; /* 1 => print out reclaim of active vnodes */
! 72:
! 73: static u_int cd9660_chars2ui(u_char *, int);
! 74:
! 75: /*
! 76: * Initialize hash links for inodes and dnodes.
! 77: */
! 78: int
! 79: cd9660_init(vfsp)
! 80: struct vfsconf *vfsp;
! 81: {
! 82:
! 83: isohashtbl = hashinit(desiredvnodes, M_ISOFSMNT, M_WAITOK, &isohash);
! 84: simple_lock_init(&cd9660_ihash_slock);
! 85: #ifdef ISODEVMAP
! 86: idvhashtbl = hashinit(desiredvnodes / 8, M_ISOFSMNT, M_WAITOK, &idvhash);
! 87: #endif
! 88: return (0);
! 89: }
! 90:
! 91: #ifdef ISODEVMAP
! 92: /*
! 93: * Enter a new node into the device hash list
! 94: */
! 95: struct iso_dnode *
! 96: iso_dmap(device, inum, create)
! 97: dev_t device;
! 98: ino_t inum;
! 99: int create;
! 100: {
! 101: register struct iso_dnode **dpp, *dp, *dq;
! 102:
! 103: dpp = &idvhashtbl[DNOHASH(device, inum)];
! 104: for (dp = *dpp;; dp = dp->d_next) {
! 105: if (dp == NULL)
! 106: return (NULL);
! 107: if (inum == dp->i_number && device == dp->i_dev)
! 108: return (dp);
! 109: }
! 110:
! 111: if (!create)
! 112: return (NULL);
! 113:
! 114: MALLOC(dp, struct iso_dnode *, sizeof(struct iso_dnode), M_CACHE,
! 115: M_WAITOK);
! 116: dp->i_dev = dev;
! 117: dp->i_number = ino;
! 118:
! 119: if (dq = *dpp)
! 120: dq->d_prev = dp->d_next;
! 121: dp->d_next = dq;
! 122: dp->d_prev = dpp;
! 123: *dpp = dp;
! 124:
! 125: return (dp);
! 126: }
! 127:
! 128: void
! 129: iso_dunmap(device)
! 130: dev_t device;
! 131: {
! 132: struct iso_dnode **dpp, *dp, *dq;
! 133:
! 134: for (dpp = idvhashtbl; dpp <= idvhashtbl + idvhash; dpp++) {
! 135: for (dp = *dpp; dp != NULL; dp = dq) {
! 136: dq = dp->d_next;
! 137: if (device == dp->i_dev) {
! 138: if (dq)
! 139: dq->d_prev = dp->d_prev;
! 140: *dp->d_prev = dq;
! 141: FREE(dp, M_CACHE);
! 142: }
! 143: }
! 144: }
! 145: }
! 146: #endif
! 147:
! 148: /*
! 149: * Use the device/inum pair to find the incore inode, and return a pointer
! 150: * to it. If it is in core, but locked, wait for it.
! 151: */
! 152: struct vnode *
! 153: cd9660_ihashget(dev, inum)
! 154: dev_t dev;
! 155: ino_t inum;
! 156: {
! 157: struct proc *p = curproc; /* XXX */
! 158: struct iso_node *ip;
! 159: struct vnode *vp;
! 160:
! 161: loop:
! 162: simple_lock(&cd9660_ihash_slock);
! 163: for (ip = isohashtbl[INOHASH(dev, inum)]; ip; ip = ip->i_next) {
! 164: if (inum == ip->i_number && dev == ip->i_dev) {
! 165: vp = ITOV(ip);
! 166: simple_unlock(&cd9660_ihash_slock);
! 167: if (vget(vp, LK_EXCLUSIVE, p))
! 168: goto loop;
! 169: return (vp);
! 170: }
! 171: }
! 172: simple_unlock(&cd9660_ihash_slock);
! 173: return (NULL);
! 174: }
! 175:
! 176: /*
! 177: * Insert the inode into the hash table, and return it locked.
! 178: */
! 179: int
! 180: cd9660_ihashins(ip)
! 181: struct iso_node *ip;
! 182: {
! 183: struct iso_node **ipp, *iq;
! 184:
! 185: simple_lock(&cd9660_ihash_slock);
! 186: ipp = &isohashtbl[INOHASH(ip->i_dev, ip->i_number)];
! 187:
! 188: for (iq = *ipp; iq; iq = iq->i_next) {
! 189: if (iq->i_dev == ip->i_dev &&
! 190: iq->i_number == ip->i_number)
! 191: return (EEXIST);
! 192: }
! 193:
! 194: if ((iq = *ipp) != NULL)
! 195: iq->i_prev = &ip->i_next;
! 196: ip->i_next = iq;
! 197: ip->i_prev = ipp;
! 198: *ipp = ip;
! 199: simple_unlock(&cd9660_ihash_slock);
! 200:
! 201: lockmgr(&ip->i_lock, LK_EXCLUSIVE, NULL);
! 202:
! 203: return (0);
! 204: }
! 205:
! 206: /*
! 207: * Remove the inode from the hash table.
! 208: */
! 209: void
! 210: cd9660_ihashrem(ip)
! 211: register struct iso_node *ip;
! 212: {
! 213: register struct iso_node *iq;
! 214:
! 215: if (ip->i_prev == NULL)
! 216: return;
! 217:
! 218: simple_lock(&cd9660_ihash_slock);
! 219: if ((iq = ip->i_next) != NULL)
! 220: iq->i_prev = ip->i_prev;
! 221: *ip->i_prev = iq;
! 222: #ifdef DIAGNOSTIC
! 223: ip->i_next = NULL;
! 224: ip->i_prev = NULL;
! 225: #endif
! 226: simple_unlock(&cd9660_ihash_slock);
! 227: }
! 228:
! 229: /*
! 230: * Last reference to an inode, write the inode out and if necessary,
! 231: * truncate and deallocate the file.
! 232: */
! 233: int
! 234: cd9660_inactive(v)
! 235: void *v;
! 236: {
! 237: struct vop_inactive_args *ap = v;
! 238: struct vnode *vp = ap->a_vp;
! 239: struct proc *p = ap->a_p;
! 240: register struct iso_node *ip = VTOI(vp);
! 241: int error = 0;
! 242:
! 243: #ifdef DIAGNOSTIC
! 244: if (prtactive && vp->v_usecount != 0)
! 245: vprint("cd9660_inactive: pushing active", vp);
! 246: #endif
! 247:
! 248: ip->i_flag = 0;
! 249: VOP_UNLOCK(vp, 0, p);
! 250: /*
! 251: * If we are done with the inode, reclaim it
! 252: * so that it can be reused immediately.
! 253: */
! 254: if (ip->inode.iso_mode == 0)
! 255: vrecycle(vp, p);
! 256:
! 257: return (error);
! 258: }
! 259:
! 260: /*
! 261: * Reclaim an inode so that it can be used for other purposes.
! 262: */
! 263: int
! 264: cd9660_reclaim(v)
! 265: void *v;
! 266: {
! 267: struct vop_reclaim_args *ap = v;
! 268: register struct vnode *vp = ap->a_vp;
! 269: register struct iso_node *ip = VTOI(vp);
! 270:
! 271: #ifdef DIAGNOSTIC
! 272: if (prtactive && vp->v_usecount != 0)
! 273: vprint("cd9660_reclaim: pushing active", vp);
! 274: #endif
! 275:
! 276: /*
! 277: * Remove the inode from its hash chain.
! 278: */
! 279: cd9660_ihashrem(ip);
! 280: /*
! 281: * Purge old data structures associated with the inode.
! 282: */
! 283: cache_purge(vp);
! 284: if (ip->i_devvp) {
! 285: vrele(ip->i_devvp);
! 286: ip->i_devvp = 0;
! 287: }
! 288: FREE(vp->v_data, M_ISOFSNODE);
! 289: vp->v_data = NULL;
! 290: return (0);
! 291: }
! 292:
! 293: /*
! 294: * File attributes
! 295: */
! 296: void
! 297: cd9660_defattr(isodir, inop, bp)
! 298: struct iso_directory_record *isodir;
! 299: struct iso_node *inop;
! 300: struct buf *bp;
! 301: {
! 302: struct buf *bp2 = NULL;
! 303: struct iso_mnt *imp;
! 304: struct iso_extended_attributes *ap = NULL;
! 305: int off;
! 306:
! 307: if (isonum_711(isodir->flags)&2) {
! 308: inop->inode.iso_mode = S_IFDIR;
! 309: /*
! 310: * If we return 2, fts() will assume there are no subdirectories
! 311: * (just links for the path and .), so instead we return 1.
! 312: */
! 313: inop->inode.iso_links = 1;
! 314: } else {
! 315: inop->inode.iso_mode = S_IFREG;
! 316: inop->inode.iso_links = 1;
! 317: }
! 318: if (!bp
! 319: && ((imp = inop->i_mnt)->im_flags & ISOFSMNT_EXTATT)
! 320: && (off = isonum_711(isodir->ext_attr_length))) {
! 321: cd9660_bufatoff(inop, (off_t)-(off << imp->im_bshift), NULL,
! 322: &bp2);
! 323: bp = bp2;
! 324: }
! 325: if (bp) {
! 326: ap = (struct iso_extended_attributes *)bp->b_data;
! 327:
! 328: if (isonum_711(ap->version) == 1) {
! 329: if (!(ap->perm[1]&0x10))
! 330: inop->inode.iso_mode |= S_IRUSR;
! 331: if (!(ap->perm[1]&0x40))
! 332: inop->inode.iso_mode |= S_IXUSR;
! 333: if (!(ap->perm[0]&0x01))
! 334: inop->inode.iso_mode |= S_IRGRP;
! 335: if (!(ap->perm[0]&0x04))
! 336: inop->inode.iso_mode |= S_IXGRP;
! 337: if (!(ap->perm[0]&0x10))
! 338: inop->inode.iso_mode |= S_IROTH;
! 339: if (!(ap->perm[0]&0x40))
! 340: inop->inode.iso_mode |= S_IXOTH;
! 341: inop->inode.iso_uid = isonum_723(ap->owner); /* what about 0? */
! 342: inop->inode.iso_gid = isonum_723(ap->group); /* what about 0? */
! 343: } else
! 344: ap = NULL;
! 345: }
! 346: if (!ap) {
! 347: inop->inode.iso_mode |=
! 348: S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
! 349: inop->inode.iso_uid = (uid_t)0;
! 350: inop->inode.iso_gid = (gid_t)0;
! 351: }
! 352: if (bp2)
! 353: brelse(bp2);
! 354: }
! 355:
! 356: /*
! 357: * Time stamps
! 358: */
! 359: void
! 360: cd9660_deftstamp(isodir,inop,bp)
! 361: struct iso_directory_record *isodir;
! 362: struct iso_node *inop;
! 363: struct buf *bp;
! 364: {
! 365: struct buf *bp2 = NULL;
! 366: struct iso_mnt *imp;
! 367: struct iso_extended_attributes *ap = NULL;
! 368: int off;
! 369:
! 370: if (!bp
! 371: && ((imp = inop->i_mnt)->im_flags & ISOFSMNT_EXTATT)
! 372: && (off = isonum_711(isodir->ext_attr_length))) {
! 373: cd9660_bufatoff(inop, (off_t)-(off << imp->im_bshift), NULL,
! 374: &bp2);
! 375: bp = bp2;
! 376: }
! 377: if (bp) {
! 378: ap = (struct iso_extended_attributes *)bp->b_data;
! 379:
! 380: if (isonum_711(ap->version) == 1) {
! 381: if (!cd9660_tstamp_conv17(ap->ftime,&inop->inode.iso_atime))
! 382: cd9660_tstamp_conv17(ap->ctime,&inop->inode.iso_atime);
! 383: if (!cd9660_tstamp_conv17(ap->ctime,&inop->inode.iso_ctime))
! 384: inop->inode.iso_ctime = inop->inode.iso_atime;
! 385: if (!cd9660_tstamp_conv17(ap->mtime,&inop->inode.iso_mtime))
! 386: inop->inode.iso_mtime = inop->inode.iso_ctime;
! 387: } else
! 388: ap = NULL;
! 389: }
! 390: if (!ap) {
! 391: cd9660_tstamp_conv7(isodir->date,&inop->inode.iso_ctime);
! 392: inop->inode.iso_atime = inop->inode.iso_ctime;
! 393: inop->inode.iso_mtime = inop->inode.iso_ctime;
! 394: }
! 395: if (bp2)
! 396: brelse(bp2);
! 397: }
! 398:
! 399: int
! 400: cd9660_tstamp_conv7(pi,pu)
! 401: u_char *pi;
! 402: struct timespec *pu;
! 403: {
! 404: int crtime, days;
! 405: int y, m, d, hour, minute, second;
! 406: signed char tz;
! 407:
! 408: y = pi[0] + 1900;
! 409: m = pi[1];
! 410: d = pi[2];
! 411: hour = pi[3];
! 412: minute = pi[4];
! 413: second = pi[5];
! 414: tz = (signed char) pi[6];
! 415:
! 416: if (y < 1970) {
! 417: pu->tv_sec = 0;
! 418: pu->tv_nsec = 0;
! 419: return (0);
! 420: } else {
! 421: #ifdef ORIGINAL
! 422: /* computes day number relative to Sept. 19th,1989 */
! 423: /* don't even *THINK* about changing formula. It works! */
! 424: days = 367*(y-1980)-7*(y+(m+9)/12)/4-3*((y+(m-9)/7)/100+1)/4+275*m/9+d-100;
! 425: #else
! 426: /*
! 427: * Changed :-) to make it relative to Jan. 1st, 1970
! 428: * and to disambiguate negative division
! 429: */
! 430: days = 367*(y-1960)-7*(y+(m+9)/12)/4-3*((y+(m+9)/12-1)/100+1)/4+275*m/9+d-239;
! 431: #endif
! 432: crtime = ((((days * 24) + hour) * 60 + minute) * 60) + second;
! 433:
! 434: /* timezone offset is unreliable on some disks */
! 435: if (-48 <= tz && tz <= 52)
! 436: crtime -= tz * 15 * 60;
! 437: }
! 438: pu->tv_sec = crtime;
! 439: pu->tv_nsec = 0;
! 440: return (1);
! 441: }
! 442:
! 443: static u_int
! 444: cd9660_chars2ui(begin,len)
! 445: u_char *begin;
! 446: int len;
! 447: {
! 448: u_int rc;
! 449:
! 450: for (rc = 0; --len >= 0;) {
! 451: rc *= 10;
! 452: rc += *begin++ - '0';
! 453: }
! 454: return (rc);
! 455: }
! 456:
! 457: int
! 458: cd9660_tstamp_conv17(pi,pu)
! 459: u_char *pi;
! 460: struct timespec *pu;
! 461: {
! 462: u_char buf[7];
! 463:
! 464: /* year:"0001"-"9999" -> -1900 */
! 465: buf[0] = cd9660_chars2ui(pi,4) - 1900;
! 466:
! 467: /* month: " 1"-"12" -> 1 - 12 */
! 468: buf[1] = cd9660_chars2ui(pi + 4,2);
! 469:
! 470: /* day: " 1"-"31" -> 1 - 31 */
! 471: buf[2] = cd9660_chars2ui(pi + 6,2);
! 472:
! 473: /* hour: " 0"-"23" -> 0 - 23 */
! 474: buf[3] = cd9660_chars2ui(pi + 8,2);
! 475:
! 476: /* minute:" 0"-"59" -> 0 - 59 */
! 477: buf[4] = cd9660_chars2ui(pi + 10,2);
! 478:
! 479: /* second:" 0"-"59" -> 0 - 59 */
! 480: buf[5] = cd9660_chars2ui(pi + 12,2);
! 481:
! 482: /* difference of GMT */
! 483: buf[6] = pi[16];
! 484:
! 485: return (cd9660_tstamp_conv7(buf,pu));
! 486: }
! 487:
! 488: ino_t
! 489: isodirino(isodir, imp)
! 490: struct iso_directory_record *isodir;
! 491: struct iso_mnt *imp;
! 492: {
! 493: ino_t ino;
! 494:
! 495: ino = (isonum_733(isodir->extent) +
! 496: isonum_711(isodir->ext_attr_length)) << imp->im_bshift;
! 497: return (ino);
! 498: }
CVSweb