165789Smckusick /*- 2*69426Smckusick * Copyright (c) 1982, 1986, 1989, 1994, 1995 365789Smckusick * The Regents of the University of California. All rights reserved. 465789Smckusick * 565789Smckusick * This code is derived from software contributed to Berkeley 665789Smckusick * by Pace Willisson (pace@blitz.com). The Rock Ridge Extension 765789Smckusick * Support code is derived from software contributed to Berkeley 865789Smckusick * by Atsushi Murai (amurai@spec.co.jp). 965789Smckusick * 1065789Smckusick * %sccs.include.redist.c% 1165789Smckusick * 12*69426Smckusick * @(#)cd9660_node.c 8.7 (Berkeley) 05/14/95 1365789Smckusick */ 1465789Smckusick 1565789Smckusick #include <sys/param.h> 1665789Smckusick #include <sys/systm.h> 1765789Smckusick #include <sys/mount.h> 1865789Smckusick #include <sys/proc.h> 1965789Smckusick #include <sys/file.h> 2065789Smckusick #include <sys/buf.h> 2165789Smckusick #include <sys/vnode.h> 2265789Smckusick #include <sys/kernel.h> 2365789Smckusick #include <sys/malloc.h> 2465789Smckusick #include <sys/stat.h> 2565789Smckusick 2665789Smckusick #include <isofs/cd9660/iso.h> 2765855Smckusick #include <isofs/cd9660/cd9660_node.h> 2868680Smckusick #include <isofs/cd9660/cd9660_mount.h> 2965789Smckusick #include <isofs/cd9660/iso_rrip.h> 3065789Smckusick 3167523Smckusick /* 3267523Smckusick * Structures associated with iso_node caching. 3367523Smckusick */ 3467523Smckusick struct iso_node **isohashtbl; 3567523Smckusick u_long isohash; 3667523Smckusick #define INOHASH(device, inum) (((device) + ((inum)>>12)) & isohash) 37*69426Smckusick struct simplelock cd9660_ihash_slock; 3865789Smckusick 3967523Smckusick #ifdef ISODEVMAP 4067523Smckusick struct iso_node **idvhashtbl; 4167523Smckusick u_long idvhash; 4267523Smckusick #define DNOHASH(device, inum) (((device) + ((inum)>>12)) & idvhash) 4365789Smckusick #endif 4465789Smckusick 4565789Smckusick int prtactive; /* 1 => print out reclaim of active vnodes */ 4665789Smckusick 4765789Smckusick /* 4865789Smckusick * Initialize hash links for inodes and dnodes. 4965789Smckusick */ 5068680Smckusick cd9660_init(vfsp) 5168680Smckusick struct vfsconf *vfsp; 5265789Smckusick { 5365789Smckusick 5467523Smckusick isohashtbl = hashinit(desiredvnodes, M_ISOFSMNT, &isohash); 55*69426Smckusick simple_lock_init(&cd9660_ihash_slock); 5667523Smckusick #ifdef ISODEVMAP 5767523Smckusick idvhashtbl = hashinit(desiredvnodes / 8, M_ISOFSMNT, &idvhash); 5865789Smckusick #endif 5965789Smckusick } 6065789Smckusick 6167523Smckusick #ifdef ISODEVMAP 6265789Smckusick /* 6365789Smckusick * Enter a new node into the device hash list 6465789Smckusick */ 6565789Smckusick struct iso_dnode * 6667523Smckusick iso_dmap(device, inum, create) 6767523Smckusick dev_t device; 6867523Smckusick ino_t inum; 6965789Smckusick int create; 7065789Smckusick { 7167523Smckusick register struct iso_dnode **dpp, *dp, *dq; 7265789Smckusick 7367523Smckusick dpp = &idvhashtbl[DNOHASH(device, inum)]; 7467523Smckusick for (dp = *dpp;; dp = dp->d_next) { 7567523Smckusick if (dp == NULL) 7667523Smckusick return (NULL); 7767523Smckusick if (inum == dp->i_number && device == dp->i_dev) 7867523Smckusick return (dp); 7967523Smckusick 8065789Smckusick if (!create) 8167523Smckusick return (NULL); 8265789Smckusick 8367523Smckusick MALLOC(dp, struct iso_dnode *, sizeof(struct iso_dnode), M_CACHE, 8467523Smckusick M_WAITOK); 8565789Smckusick dp->i_dev = dev; 8665789Smckusick dp->i_number = ino; 8767523Smckusick 8867523Smckusick if (dq = *dpp) 8967523Smckusick dq->d_prev = dp->d_next; 9067523Smckusick dp->d_next = dq; 9167523Smckusick dp->d_prev = dpp; 9267523Smckusick *dpp = dp; 9367523Smckusick 9467523Smckusick return (dp); 9565789Smckusick } 9665789Smckusick 9765789Smckusick void 9867523Smckusick iso_dunmap(device) 9967523Smckusick dev_t device; 10065789Smckusick { 10167523Smckusick struct iso_dnode **dpp, *dp, *dq; 10265789Smckusick 10367523Smckusick for (dpp = idvhashtbl; dpp <= idvhashtbl + idvhash; dpp++) { 10467523Smckusick for (dp = *dpp; dp != NULL; dp = dq) 10567523Smckusick dq = dp->d_next; 10667523Smckusick if (device == dp->i_dev) { 10767523Smckusick if (dq) 10867523Smckusick dq->d_prev = dp->d_prev; 10967523Smckusick *dp->d_prev = dq; 11067523Smckusick FREE(dp, M_CACHE); 11165789Smckusick } 11265789Smckusick } 11365789Smckusick } 11465789Smckusick } 11565789Smckusick #endif 11665789Smckusick 11765789Smckusick /* 11867523Smckusick * Use the device/inum pair to find the incore inode, and return a pointer 11967523Smckusick * to it. If it is in core, but locked, wait for it. 12065789Smckusick */ 12167523Smckusick struct vnode * 122*69426Smckusick cd9660_ihashget(dev, inum) 123*69426Smckusick dev_t dev; 12467523Smckusick ino_t inum; 12565789Smckusick { 126*69426Smckusick struct proc *p = curproc; /* XXX */ 127*69426Smckusick struct iso_node *ip; 12867523Smckusick struct vnode *vp; 12965789Smckusick 130*69426Smckusick loop: 131*69426Smckusick simple_lock(&cd9660_ihash_slock); 132*69426Smckusick for (ip = isohashtbl[INOHASH(dev, inum)]; ip; ip = ip->i_next) { 133*69426Smckusick if (inum == ip->i_number && dev == ip->i_dev) { 134*69426Smckusick vp = ITOV(ip); 135*69426Smckusick simple_lock(&vp->v_interlock); 136*69426Smckusick simple_unlock(&cd9660_ihash_slock); 137*69426Smckusick if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, p)) 138*69426Smckusick goto loop; 139*69426Smckusick return (vp); 14065789Smckusick } 141*69426Smckusick } 142*69426Smckusick simple_unlock(&cd9660_ihash_slock); 143*69426Smckusick return (NULL); 14467523Smckusick } 14565789Smckusick 14667523Smckusick /* 14767523Smckusick * Insert the inode into the hash table, and return it locked. 14867523Smckusick */ 14967523Smckusick void 15067523Smckusick cd9660_ihashins(ip) 15167523Smckusick struct iso_node *ip; 15267523Smckusick { 153*69426Smckusick struct proc *p = curproc; /* XXX */ 15467523Smckusick struct iso_node **ipp, *iq; 15567523Smckusick 156*69426Smckusick simple_lock(&cd9660_ihash_slock); 15767523Smckusick ipp = &isohashtbl[INOHASH(ip->i_dev, ip->i_number)]; 15867523Smckusick if (iq = *ipp) 15967523Smckusick iq->i_prev = &ip->i_next; 16067523Smckusick ip->i_next = iq; 16167523Smckusick ip->i_prev = ipp; 16265789Smckusick *ipp = ip; 163*69426Smckusick simple_unlock(&cd9660_ihash_slock); 164*69426Smckusick 165*69426Smckusick lockmgr(&ip->i_lock, LK_EXCLUSIVE, (struct simplelock *)0, p); 16665789Smckusick } 16765789Smckusick 16865789Smckusick /* 16967523Smckusick * Remove the inode from the hash table. 17065789Smckusick */ 17167523Smckusick void 17267523Smckusick cd9660_ihashrem(ip) 17365789Smckusick register struct iso_node *ip; 17465789Smckusick { 17567523Smckusick register struct iso_node *iq; 17667523Smckusick 177*69426Smckusick simple_lock(&cd9660_ihash_slock); 17867523Smckusick if (iq = ip->i_next) 17967523Smckusick iq->i_prev = ip->i_prev; 18067523Smckusick *ip->i_prev = iq; 18167523Smckusick #ifdef DIAGNOSTIC 18267523Smckusick ip->i_next = NULL; 18367523Smckusick ip->i_prev = NULL; 18467523Smckusick #endif 185*69426Smckusick simple_unlock(&cd9660_ihash_slock); 18665789Smckusick } 18765789Smckusick 18865789Smckusick /* 18965789Smckusick * Last reference to an inode, write the inode out and if necessary, 19065789Smckusick * truncate and deallocate the file. 19165789Smckusick */ 19265789Smckusick int 19365855Smckusick cd9660_inactive(ap) 19465789Smckusick struct vop_inactive_args /* { 19565789Smckusick struct vnode *a_vp; 196*69426Smckusick struct proc *a_p; 19765789Smckusick } */ *ap; 19865789Smckusick { 19965789Smckusick struct vnode *vp = ap->a_vp; 20065789Smckusick register struct iso_node *ip = VTOI(vp); 20165789Smckusick int mode, error = 0; 20265789Smckusick 20365789Smckusick if (prtactive && vp->v_usecount != 0) 20465855Smckusick vprint("cd9660_inactive: pushing active", vp); 20565789Smckusick 20665789Smckusick ip->i_flag = 0; 20765789Smckusick /* 20865789Smckusick * If we are done with the inode, reclaim it 20965789Smckusick * so that it can be reused immediately. 21065789Smckusick */ 21165789Smckusick if (vp->v_usecount == 0 && ip->inode.iso_mode == 0) 21265789Smckusick vgone(vp); 21365789Smckusick return error; 21465789Smckusick } 21565789Smckusick 21665789Smckusick /* 21765789Smckusick * Reclaim an inode so that it can be used for other purposes. 21865789Smckusick */ 21965789Smckusick int 22065855Smckusick cd9660_reclaim(ap) 22165789Smckusick struct vop_reclaim_args /* { 22265789Smckusick struct vnode *a_vp; 223*69426Smckusick struct proc *a_p; 22465789Smckusick } */ *ap; 22565789Smckusick { 22665789Smckusick register struct vnode *vp = ap->a_vp; 22765789Smckusick register struct iso_node *ip = VTOI(vp); 22865789Smckusick int i; 22965789Smckusick 23065789Smckusick if (prtactive && vp->v_usecount != 0) 23165855Smckusick vprint("cd9660_reclaim: pushing active", vp); 23265789Smckusick /* 23365789Smckusick * Remove the inode from its hash chain. 23465789Smckusick */ 23567523Smckusick cd9660_ihashrem(ip); 23665789Smckusick /* 23765789Smckusick * Purge old data structures associated with the inode. 23865789Smckusick */ 23965789Smckusick cache_purge(vp); 24065789Smckusick if (ip->i_devvp) { 24165789Smckusick vrele(ip->i_devvp); 24265789Smckusick ip->i_devvp = 0; 24365789Smckusick } 24465789Smckusick FREE(vp->v_data, M_ISOFSNODE); 24565789Smckusick vp->v_data = NULL; 24667523Smckusick return (0); 24765789Smckusick } 24865789Smckusick 24965789Smckusick /* 25065789Smckusick * File attributes 25165789Smckusick */ 25265789Smckusick void 25368048Smckusick cd9660_defattr(isodir, inop, bp) 25465789Smckusick struct iso_directory_record *isodir; 25565789Smckusick struct iso_node *inop; 25665789Smckusick struct buf *bp; 25765789Smckusick { 25865789Smckusick struct buf *bp2 = NULL; 25965789Smckusick struct iso_mnt *imp; 26065789Smckusick struct iso_extended_attributes *ap = NULL; 26165789Smckusick int off; 26265789Smckusick 26365789Smckusick if (isonum_711(isodir->flags)&2) { 26465789Smckusick inop->inode.iso_mode = S_IFDIR; 26565789Smckusick /* 26665789Smckusick * If we return 2, fts() will assume there are no subdirectories 26765789Smckusick * (just links for the path and .), so instead we return 1. 26865789Smckusick */ 26965789Smckusick inop->inode.iso_links = 1; 27065789Smckusick } else { 27165789Smckusick inop->inode.iso_mode = S_IFREG; 27265789Smckusick inop->inode.iso_links = 1; 27365789Smckusick } 27465789Smckusick if (!bp 27568048Smckusick && ((imp = inop->i_mnt)->im_flags & ISOFSMNT_EXTATT) 27665789Smckusick && (off = isonum_711(isodir->ext_attr_length))) { 27768048Smckusick VOP_BLKATOFF(ITOV(inop), (off_t)-(off << imp->im_bshift), NULL, 27868048Smckusick &bp2); 27965789Smckusick bp = bp2; 28065789Smckusick } 28165789Smckusick if (bp) { 28268048Smckusick ap = (struct iso_extended_attributes *)bp->b_data; 28365789Smckusick 28465789Smckusick if (isonum_711(ap->version) == 1) { 28565789Smckusick if (!(ap->perm[0]&0x40)) 28665789Smckusick inop->inode.iso_mode |= VEXEC >> 6; 28765789Smckusick if (!(ap->perm[0]&0x10)) 28865789Smckusick inop->inode.iso_mode |= VREAD >> 6; 28965789Smckusick if (!(ap->perm[0]&4)) 29065789Smckusick inop->inode.iso_mode |= VEXEC >> 3; 29165789Smckusick if (!(ap->perm[0]&1)) 29265789Smckusick inop->inode.iso_mode |= VREAD >> 3; 29365789Smckusick if (!(ap->perm[1]&0x40)) 29465789Smckusick inop->inode.iso_mode |= VEXEC; 29565789Smckusick if (!(ap->perm[1]&0x10)) 29665789Smckusick inop->inode.iso_mode |= VREAD; 29765789Smckusick inop->inode.iso_uid = isonum_723(ap->owner); /* what about 0? */ 29865789Smckusick inop->inode.iso_gid = isonum_723(ap->group); /* what about 0? */ 29965789Smckusick } else 30065789Smckusick ap = NULL; 30165789Smckusick } 30265789Smckusick if (!ap) { 30365789Smckusick inop->inode.iso_mode |= VREAD|VEXEC|(VREAD|VEXEC)>>3|(VREAD|VEXEC)>>6; 30465789Smckusick inop->inode.iso_uid = (uid_t)0; 30565789Smckusick inop->inode.iso_gid = (gid_t)0; 30665789Smckusick } 30765789Smckusick if (bp2) 30865789Smckusick brelse(bp2); 30965789Smckusick } 31065789Smckusick 31165789Smckusick /* 31265789Smckusick * Time stamps 31365789Smckusick */ 31465789Smckusick void 31565855Smckusick cd9660_deftstamp(isodir,inop,bp) 31665789Smckusick struct iso_directory_record *isodir; 31765789Smckusick struct iso_node *inop; 31865789Smckusick struct buf *bp; 31965789Smckusick { 32065789Smckusick struct buf *bp2 = NULL; 32165789Smckusick struct iso_mnt *imp; 32265789Smckusick struct iso_extended_attributes *ap = NULL; 32365789Smckusick int off; 32465789Smckusick 32565789Smckusick if (!bp 32668048Smckusick && ((imp = inop->i_mnt)->im_flags & ISOFSMNT_EXTATT) 32765789Smckusick && (off = isonum_711(isodir->ext_attr_length))) { 32868048Smckusick VOP_BLKATOFF(ITOV(inop), (off_t)-(off << imp->im_bshift), NULL, 32968048Smckusick &bp2); 33065789Smckusick bp = bp2; 33165789Smckusick } 33265789Smckusick if (bp) { 33368048Smckusick ap = (struct iso_extended_attributes *)bp->b_data; 33465789Smckusick 33565789Smckusick if (isonum_711(ap->version) == 1) { 33665855Smckusick if (!cd9660_tstamp_conv17(ap->ftime,&inop->inode.iso_atime)) 33765855Smckusick cd9660_tstamp_conv17(ap->ctime,&inop->inode.iso_atime); 33865855Smckusick if (!cd9660_tstamp_conv17(ap->ctime,&inop->inode.iso_ctime)) 33965789Smckusick inop->inode.iso_ctime = inop->inode.iso_atime; 34065855Smckusick if (!cd9660_tstamp_conv17(ap->mtime,&inop->inode.iso_mtime)) 34165789Smckusick inop->inode.iso_mtime = inop->inode.iso_ctime; 34265789Smckusick } else 34365789Smckusick ap = NULL; 34465789Smckusick } 34565789Smckusick if (!ap) { 34665855Smckusick cd9660_tstamp_conv7(isodir->date,&inop->inode.iso_ctime); 34765789Smckusick inop->inode.iso_atime = inop->inode.iso_ctime; 34865789Smckusick inop->inode.iso_mtime = inop->inode.iso_ctime; 34965789Smckusick } 35065789Smckusick if (bp2) 35165789Smckusick brelse(bp2); 35265789Smckusick } 35365789Smckusick 35465789Smckusick int 35565855Smckusick cd9660_tstamp_conv7(pi,pu) 35668048Smckusick u_char *pi; 35768048Smckusick struct timespec *pu; 35865789Smckusick { 35965789Smckusick int i; 36065789Smckusick int crtime, days; 36165789Smckusick int y, m, d, hour, minute, second, tz; 36265789Smckusick 36365789Smckusick y = pi[0] + 1900; 36465789Smckusick m = pi[1]; 36565789Smckusick d = pi[2]; 36665789Smckusick hour = pi[3]; 36765789Smckusick minute = pi[4]; 36865789Smckusick second = pi[5]; 36965789Smckusick tz = pi[6]; 37065789Smckusick 37165789Smckusick if (y < 1970) { 37268048Smckusick pu->ts_sec = 0; 37368048Smckusick pu->ts_nsec = 0; 37465789Smckusick return 0; 37565789Smckusick } else { 37665789Smckusick #ifdef ORIGINAL 37765789Smckusick /* computes day number relative to Sept. 19th,1989 */ 37865789Smckusick /* don't even *THINK* about changing formula. It works! */ 37965789Smckusick days = 367*(y-1980)-7*(y+(m+9)/12)/4-3*((y+(m-9)/7)/100+1)/4+275*m/9+d-100; 38065789Smckusick #else 38165789Smckusick /* 38265789Smckusick * Changed :-) to make it relative to Jan. 1st, 1970 38365789Smckusick * and to disambiguate negative division 38465789Smckusick */ 38565789Smckusick days = 367*(y-1960)-7*(y+(m+9)/12)/4-3*((y+(m+9)/12-1)/100+1)/4+275*m/9+d-239; 38665789Smckusick #endif 38765789Smckusick crtime = ((((days * 24) + hour) * 60 + minute) * 60) + second; 38865789Smckusick 38965789Smckusick /* timezone offset is unreliable on some disks */ 39065789Smckusick if (-48 <= tz && tz <= 52) 39167376Smkm crtime -= tz * 15 * 60; 39265789Smckusick } 39368048Smckusick pu->ts_sec = crtime; 39468048Smckusick pu->ts_nsec = 0; 39565789Smckusick return 1; 39665789Smckusick } 39765789Smckusick 39868048Smckusick static u_int 39965855Smckusick cd9660_chars2ui(begin,len) 40068048Smckusick u_char *begin; 40165789Smckusick int len; 40265789Smckusick { 40368048Smckusick u_int rc; 40465789Smckusick 40565789Smckusick for (rc = 0; --len >= 0;) { 40665789Smckusick rc *= 10; 40765789Smckusick rc += *begin++ - '0'; 40865789Smckusick } 40965789Smckusick return rc; 41065789Smckusick } 41165789Smckusick 41265789Smckusick int 41365855Smckusick cd9660_tstamp_conv17(pi,pu) 41468048Smckusick u_char *pi; 41568048Smckusick struct timespec *pu; 41665789Smckusick { 41768048Smckusick u_char buf[7]; 41865789Smckusick 41965789Smckusick /* year:"0001"-"9999" -> -1900 */ 42065855Smckusick buf[0] = cd9660_chars2ui(pi,4) - 1900; 42165789Smckusick 42265789Smckusick /* month: " 1"-"12" -> 1 - 12 */ 42365855Smckusick buf[1] = cd9660_chars2ui(pi + 4,2); 42465789Smckusick 42565789Smckusick /* day: " 1"-"31" -> 1 - 31 */ 42665855Smckusick buf[2] = cd9660_chars2ui(pi + 6,2); 42765789Smckusick 42865789Smckusick /* hour: " 0"-"23" -> 0 - 23 */ 42965855Smckusick buf[3] = cd9660_chars2ui(pi + 8,2); 43065789Smckusick 43165789Smckusick /* minute:" 0"-"59" -> 0 - 59 */ 43265855Smckusick buf[4] = cd9660_chars2ui(pi + 10,2); 43365789Smckusick 43465789Smckusick /* second:" 0"-"59" -> 0 - 59 */ 43565855Smckusick buf[5] = cd9660_chars2ui(pi + 12,2); 43665789Smckusick 43765789Smckusick /* difference of GMT */ 43865789Smckusick buf[6] = pi[16]; 43965789Smckusick 44065855Smckusick return cd9660_tstamp_conv7(buf,pu); 44165789Smckusick } 44265789Smckusick 44368048Smckusick ino_t 44468048Smckusick isodirino(isodir, imp) 44565789Smckusick struct iso_directory_record *isodir; 44665789Smckusick struct iso_mnt *imp; 44765789Smckusick { 44868048Smckusick ino_t ino; 44968048Smckusick 45068048Smckusick ino = (isonum_733(isodir->extent) + isonum_711(isodir->ext_attr_length)) 45168048Smckusick << imp->im_bshift; 45268048Smckusick return (ino); 45365789Smckusick } 454