165789Smckusick /*- 265789Smckusick * Copyright (c) 1982, 1986, 1989, 1994 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*68048Smckusick * @(#)cd9660_node.c 8.5 (Berkeley) 12/05/94 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> 2865789Smckusick #include <isofs/cd9660/iso_rrip.h> 2965789Smckusick 3067523Smckusick /* 3167523Smckusick * Structures associated with iso_node caching. 3267523Smckusick */ 3367523Smckusick struct iso_node **isohashtbl; 3467523Smckusick u_long isohash; 3567523Smckusick #define INOHASH(device, inum) (((device) + ((inum)>>12)) & isohash) 3665789Smckusick 3767523Smckusick #ifdef ISODEVMAP 3867523Smckusick struct iso_node **idvhashtbl; 3967523Smckusick u_long idvhash; 4067523Smckusick #define DNOHASH(device, inum) (((device) + ((inum)>>12)) & idvhash) 4165789Smckusick #endif 4265789Smckusick 4365789Smckusick int prtactive; /* 1 => print out reclaim of active vnodes */ 4465789Smckusick 4565789Smckusick /* 4665789Smckusick * Initialize hash links for inodes and dnodes. 4765789Smckusick */ 4865855Smckusick cd9660_init() 4965789Smckusick { 5065789Smckusick 5167523Smckusick isohashtbl = hashinit(desiredvnodes, M_ISOFSMNT, &isohash); 5267523Smckusick #ifdef ISODEVMAP 5367523Smckusick idvhashtbl = hashinit(desiredvnodes / 8, M_ISOFSMNT, &idvhash); 5465789Smckusick #endif 5565789Smckusick } 5665789Smckusick 5767523Smckusick #ifdef ISODEVMAP 5865789Smckusick /* 5965789Smckusick * Enter a new node into the device hash list 6065789Smckusick */ 6165789Smckusick struct iso_dnode * 6267523Smckusick iso_dmap(device, inum, create) 6367523Smckusick dev_t device; 6467523Smckusick ino_t inum; 6565789Smckusick int create; 6665789Smckusick { 6767523Smckusick register struct iso_dnode **dpp, *dp, *dq; 6865789Smckusick 6967523Smckusick dpp = &idvhashtbl[DNOHASH(device, inum)]; 7067523Smckusick for (dp = *dpp;; dp = dp->d_next) { 7167523Smckusick if (dp == NULL) 7267523Smckusick return (NULL); 7367523Smckusick if (inum == dp->i_number && device == dp->i_dev) 7467523Smckusick return (dp); 7567523Smckusick 7665789Smckusick if (!create) 7767523Smckusick return (NULL); 7865789Smckusick 7967523Smckusick MALLOC(dp, struct iso_dnode *, sizeof(struct iso_dnode), M_CACHE, 8067523Smckusick M_WAITOK); 8165789Smckusick dp->i_dev = dev; 8265789Smckusick dp->i_number = ino; 8367523Smckusick 8467523Smckusick if (dq = *dpp) 8567523Smckusick dq->d_prev = dp->d_next; 8667523Smckusick dp->d_next = dq; 8767523Smckusick dp->d_prev = dpp; 8867523Smckusick *dpp = dp; 8967523Smckusick 9067523Smckusick return (dp); 9165789Smckusick } 9265789Smckusick 9365789Smckusick void 9467523Smckusick iso_dunmap(device) 9567523Smckusick dev_t device; 9665789Smckusick { 9767523Smckusick struct iso_dnode **dpp, *dp, *dq; 9865789Smckusick 9967523Smckusick for (dpp = idvhashtbl; dpp <= idvhashtbl + idvhash; dpp++) { 10067523Smckusick for (dp = *dpp; dp != NULL; dp = dq) 10167523Smckusick dq = dp->d_next; 10267523Smckusick if (device == dp->i_dev) { 10367523Smckusick if (dq) 10467523Smckusick dq->d_prev = dp->d_prev; 10567523Smckusick *dp->d_prev = dq; 10667523Smckusick FREE(dp, M_CACHE); 10765789Smckusick } 10865789Smckusick } 10965789Smckusick } 11065789Smckusick } 11165789Smckusick #endif 11265789Smckusick 11365789Smckusick /* 11467523Smckusick * Use the device/inum pair to find the incore inode, and return a pointer 11567523Smckusick * to it. If it is in core, but locked, wait for it. 11665789Smckusick */ 11767523Smckusick struct vnode * 11867523Smckusick cd9660_ihashget(device, inum) 11967523Smckusick dev_t device; 12067523Smckusick ino_t inum; 12165789Smckusick { 12267523Smckusick register struct iso_node *ip; 12367523Smckusick struct vnode *vp; 12465789Smckusick 12567523Smckusick for (;;) 12667523Smckusick for (ip = isohashtbl[INOHASH(device, inum)];; ip = ip->i_next) { 12767523Smckusick if (ip == NULL) 12867523Smckusick return (NULL); 12967523Smckusick if (inum == ip->i_number && device == ip->i_dev) { 13067523Smckusick if (ip->i_flag & IN_LOCKED) { 13167523Smckusick ip->i_flag |= IN_WANTED; 13267523Smckusick sleep(ip, PINOD); 13367523Smckusick break; 13467523Smckusick } 13567523Smckusick vp = ITOV(ip); 13667523Smckusick if (!vget(vp, 1)) 13767523Smckusick return (vp); 13867523Smckusick break; 13967523Smckusick } 14065789Smckusick } 14167523Smckusick /* NOTREACHED */ 14267523Smckusick } 14365789Smckusick 14467523Smckusick /* 14567523Smckusick * Insert the inode into the hash table, and return it locked. 14667523Smckusick */ 14767523Smckusick void 14867523Smckusick cd9660_ihashins(ip) 14967523Smckusick struct iso_node *ip; 15067523Smckusick { 15167523Smckusick struct iso_node **ipp, *iq; 15267523Smckusick 15367523Smckusick ipp = &isohashtbl[INOHASH(ip->i_dev, ip->i_number)]; 15467523Smckusick if (iq = *ipp) 15567523Smckusick iq->i_prev = &ip->i_next; 15667523Smckusick ip->i_next = iq; 15767523Smckusick ip->i_prev = ipp; 15865789Smckusick *ipp = ip; 15967523Smckusick if (ip->i_flag & IN_LOCKED) 16067523Smckusick panic("cd9660_ihashins: already locked"); 16167523Smckusick if (curproc) 16267523Smckusick ip->i_lockholder = curproc->p_pid; 16367523Smckusick else 16467523Smckusick ip->i_lockholder = -1; 16567523Smckusick ip->i_flag |= IN_LOCKED; 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 17767523Smckusick if (iq = ip->i_next) 17867523Smckusick iq->i_prev = ip->i_prev; 17967523Smckusick *ip->i_prev = iq; 18067523Smckusick #ifdef DIAGNOSTIC 18167523Smckusick ip->i_next = NULL; 18267523Smckusick ip->i_prev = NULL; 18367523Smckusick #endif 18465789Smckusick } 18565789Smckusick 18665789Smckusick /* 18765789Smckusick * Last reference to an inode, write the inode out and if necessary, 18865789Smckusick * truncate and deallocate the file. 18965789Smckusick */ 19065789Smckusick int 19165855Smckusick cd9660_inactive(ap) 19265789Smckusick struct vop_inactive_args /* { 19365789Smckusick struct vnode *a_vp; 19465789Smckusick } */ *ap; 19565789Smckusick { 19665789Smckusick struct vnode *vp = ap->a_vp; 19765789Smckusick register struct iso_node *ip = VTOI(vp); 19865789Smckusick int mode, error = 0; 19965789Smckusick 20065789Smckusick if (prtactive && vp->v_usecount != 0) 20165855Smckusick vprint("cd9660_inactive: pushing active", vp); 20265789Smckusick 20365789Smckusick ip->i_flag = 0; 20465789Smckusick /* 20565789Smckusick * If we are done with the inode, reclaim it 20665789Smckusick * so that it can be reused immediately. 20765789Smckusick */ 20865789Smckusick if (vp->v_usecount == 0 && ip->inode.iso_mode == 0) 20965789Smckusick vgone(vp); 21065789Smckusick return error; 21165789Smckusick } 21265789Smckusick 21365789Smckusick /* 21465789Smckusick * Reclaim an inode so that it can be used for other purposes. 21565789Smckusick */ 21665789Smckusick int 21765855Smckusick cd9660_reclaim(ap) 21865789Smckusick struct vop_reclaim_args /* { 21965789Smckusick struct vnode *a_vp; 22065789Smckusick } */ *ap; 22165789Smckusick { 22265789Smckusick register struct vnode *vp = ap->a_vp; 22365789Smckusick register struct iso_node *ip = VTOI(vp); 22465789Smckusick int i; 22565789Smckusick 22665789Smckusick if (prtactive && vp->v_usecount != 0) 22765855Smckusick vprint("cd9660_reclaim: pushing active", vp); 22865789Smckusick /* 22965789Smckusick * Remove the inode from its hash chain. 23065789Smckusick */ 23167523Smckusick cd9660_ihashrem(ip); 23265789Smckusick /* 23365789Smckusick * Purge old data structures associated with the inode. 23465789Smckusick */ 23565789Smckusick cache_purge(vp); 23665789Smckusick if (ip->i_devvp) { 23765789Smckusick vrele(ip->i_devvp); 23865789Smckusick ip->i_devvp = 0; 23965789Smckusick } 24065789Smckusick FREE(vp->v_data, M_ISOFSNODE); 24165789Smckusick vp->v_data = NULL; 24267523Smckusick return (0); 24365789Smckusick } 24465789Smckusick 24565789Smckusick /* 24665789Smckusick * File attributes 24765789Smckusick */ 24865789Smckusick void 249*68048Smckusick cd9660_defattr(isodir, inop, bp) 25065789Smckusick struct iso_directory_record *isodir; 25165789Smckusick struct iso_node *inop; 25265789Smckusick struct buf *bp; 25365789Smckusick { 25465789Smckusick struct buf *bp2 = NULL; 25565789Smckusick struct iso_mnt *imp; 25665789Smckusick struct iso_extended_attributes *ap = NULL; 25765789Smckusick int off; 25865789Smckusick 25965789Smckusick if (isonum_711(isodir->flags)&2) { 26065789Smckusick inop->inode.iso_mode = S_IFDIR; 26165789Smckusick /* 26265789Smckusick * If we return 2, fts() will assume there are no subdirectories 26365789Smckusick * (just links for the path and .), so instead we return 1. 26465789Smckusick */ 26565789Smckusick inop->inode.iso_links = 1; 26665789Smckusick } else { 26765789Smckusick inop->inode.iso_mode = S_IFREG; 26865789Smckusick inop->inode.iso_links = 1; 26965789Smckusick } 27065789Smckusick if (!bp 271*68048Smckusick && ((imp = inop->i_mnt)->im_flags & ISOFSMNT_EXTATT) 27265789Smckusick && (off = isonum_711(isodir->ext_attr_length))) { 273*68048Smckusick VOP_BLKATOFF(ITOV(inop), (off_t)-(off << imp->im_bshift), NULL, 274*68048Smckusick &bp2); 27565789Smckusick bp = bp2; 27665789Smckusick } 27765789Smckusick if (bp) { 278*68048Smckusick ap = (struct iso_extended_attributes *)bp->b_data; 27965789Smckusick 28065789Smckusick if (isonum_711(ap->version) == 1) { 28165789Smckusick if (!(ap->perm[0]&0x40)) 28265789Smckusick inop->inode.iso_mode |= VEXEC >> 6; 28365789Smckusick if (!(ap->perm[0]&0x10)) 28465789Smckusick inop->inode.iso_mode |= VREAD >> 6; 28565789Smckusick if (!(ap->perm[0]&4)) 28665789Smckusick inop->inode.iso_mode |= VEXEC >> 3; 28765789Smckusick if (!(ap->perm[0]&1)) 28865789Smckusick inop->inode.iso_mode |= VREAD >> 3; 28965789Smckusick if (!(ap->perm[1]&0x40)) 29065789Smckusick inop->inode.iso_mode |= VEXEC; 29165789Smckusick if (!(ap->perm[1]&0x10)) 29265789Smckusick inop->inode.iso_mode |= VREAD; 29365789Smckusick inop->inode.iso_uid = isonum_723(ap->owner); /* what about 0? */ 29465789Smckusick inop->inode.iso_gid = isonum_723(ap->group); /* what about 0? */ 29565789Smckusick } else 29665789Smckusick ap = NULL; 29765789Smckusick } 29865789Smckusick if (!ap) { 29965789Smckusick inop->inode.iso_mode |= VREAD|VEXEC|(VREAD|VEXEC)>>3|(VREAD|VEXEC)>>6; 30065789Smckusick inop->inode.iso_uid = (uid_t)0; 30165789Smckusick inop->inode.iso_gid = (gid_t)0; 30265789Smckusick } 30365789Smckusick if (bp2) 30465789Smckusick brelse(bp2); 30565789Smckusick } 30665789Smckusick 30765789Smckusick /* 30865789Smckusick * Time stamps 30965789Smckusick */ 31065789Smckusick void 31165855Smckusick cd9660_deftstamp(isodir,inop,bp) 31265789Smckusick struct iso_directory_record *isodir; 31365789Smckusick struct iso_node *inop; 31465789Smckusick struct buf *bp; 31565789Smckusick { 31665789Smckusick struct buf *bp2 = NULL; 31765789Smckusick struct iso_mnt *imp; 31865789Smckusick struct iso_extended_attributes *ap = NULL; 31965789Smckusick int off; 32065789Smckusick 32165789Smckusick if (!bp 322*68048Smckusick && ((imp = inop->i_mnt)->im_flags & ISOFSMNT_EXTATT) 32365789Smckusick && (off = isonum_711(isodir->ext_attr_length))) { 324*68048Smckusick VOP_BLKATOFF(ITOV(inop), (off_t)-(off << imp->im_bshift), NULL, 325*68048Smckusick &bp2); 32665789Smckusick bp = bp2; 32765789Smckusick } 32865789Smckusick if (bp) { 329*68048Smckusick ap = (struct iso_extended_attributes *)bp->b_data; 33065789Smckusick 33165789Smckusick if (isonum_711(ap->version) == 1) { 33265855Smckusick if (!cd9660_tstamp_conv17(ap->ftime,&inop->inode.iso_atime)) 33365855Smckusick cd9660_tstamp_conv17(ap->ctime,&inop->inode.iso_atime); 33465855Smckusick if (!cd9660_tstamp_conv17(ap->ctime,&inop->inode.iso_ctime)) 33565789Smckusick inop->inode.iso_ctime = inop->inode.iso_atime; 33665855Smckusick if (!cd9660_tstamp_conv17(ap->mtime,&inop->inode.iso_mtime)) 33765789Smckusick inop->inode.iso_mtime = inop->inode.iso_ctime; 33865789Smckusick } else 33965789Smckusick ap = NULL; 34065789Smckusick } 34165789Smckusick if (!ap) { 34265855Smckusick cd9660_tstamp_conv7(isodir->date,&inop->inode.iso_ctime); 34365789Smckusick inop->inode.iso_atime = inop->inode.iso_ctime; 34465789Smckusick inop->inode.iso_mtime = inop->inode.iso_ctime; 34565789Smckusick } 34665789Smckusick if (bp2) 34765789Smckusick brelse(bp2); 34865789Smckusick } 34965789Smckusick 35065789Smckusick int 35165855Smckusick cd9660_tstamp_conv7(pi,pu) 352*68048Smckusick u_char *pi; 353*68048Smckusick struct timespec *pu; 35465789Smckusick { 35565789Smckusick int i; 35665789Smckusick int crtime, days; 35765789Smckusick int y, m, d, hour, minute, second, tz; 35865789Smckusick 35965789Smckusick y = pi[0] + 1900; 36065789Smckusick m = pi[1]; 36165789Smckusick d = pi[2]; 36265789Smckusick hour = pi[3]; 36365789Smckusick minute = pi[4]; 36465789Smckusick second = pi[5]; 36565789Smckusick tz = pi[6]; 36665789Smckusick 36765789Smckusick if (y < 1970) { 368*68048Smckusick pu->ts_sec = 0; 369*68048Smckusick pu->ts_nsec = 0; 37065789Smckusick return 0; 37165789Smckusick } else { 37265789Smckusick #ifdef ORIGINAL 37365789Smckusick /* computes day number relative to Sept. 19th,1989 */ 37465789Smckusick /* don't even *THINK* about changing formula. It works! */ 37565789Smckusick days = 367*(y-1980)-7*(y+(m+9)/12)/4-3*((y+(m-9)/7)/100+1)/4+275*m/9+d-100; 37665789Smckusick #else 37765789Smckusick /* 37865789Smckusick * Changed :-) to make it relative to Jan. 1st, 1970 37965789Smckusick * and to disambiguate negative division 38065789Smckusick */ 38165789Smckusick days = 367*(y-1960)-7*(y+(m+9)/12)/4-3*((y+(m+9)/12-1)/100+1)/4+275*m/9+d-239; 38265789Smckusick #endif 38365789Smckusick crtime = ((((days * 24) + hour) * 60 + minute) * 60) + second; 38465789Smckusick 38565789Smckusick /* timezone offset is unreliable on some disks */ 38665789Smckusick if (-48 <= tz && tz <= 52) 38767376Smkm crtime -= tz * 15 * 60; 38865789Smckusick } 389*68048Smckusick pu->ts_sec = crtime; 390*68048Smckusick pu->ts_nsec = 0; 39165789Smckusick return 1; 39265789Smckusick } 39365789Smckusick 394*68048Smckusick static u_int 39565855Smckusick cd9660_chars2ui(begin,len) 396*68048Smckusick u_char *begin; 39765789Smckusick int len; 39865789Smckusick { 399*68048Smckusick u_int rc; 40065789Smckusick 40165789Smckusick for (rc = 0; --len >= 0;) { 40265789Smckusick rc *= 10; 40365789Smckusick rc += *begin++ - '0'; 40465789Smckusick } 40565789Smckusick return rc; 40665789Smckusick } 40765789Smckusick 40865789Smckusick int 40965855Smckusick cd9660_tstamp_conv17(pi,pu) 410*68048Smckusick u_char *pi; 411*68048Smckusick struct timespec *pu; 41265789Smckusick { 413*68048Smckusick u_char buf[7]; 41465789Smckusick 41565789Smckusick /* year:"0001"-"9999" -> -1900 */ 41665855Smckusick buf[0] = cd9660_chars2ui(pi,4) - 1900; 41765789Smckusick 41865789Smckusick /* month: " 1"-"12" -> 1 - 12 */ 41965855Smckusick buf[1] = cd9660_chars2ui(pi + 4,2); 42065789Smckusick 42165789Smckusick /* day: " 1"-"31" -> 1 - 31 */ 42265855Smckusick buf[2] = cd9660_chars2ui(pi + 6,2); 42365789Smckusick 42465789Smckusick /* hour: " 0"-"23" -> 0 - 23 */ 42565855Smckusick buf[3] = cd9660_chars2ui(pi + 8,2); 42665789Smckusick 42765789Smckusick /* minute:" 0"-"59" -> 0 - 59 */ 42865855Smckusick buf[4] = cd9660_chars2ui(pi + 10,2); 42965789Smckusick 43065789Smckusick /* second:" 0"-"59" -> 0 - 59 */ 43165855Smckusick buf[5] = cd9660_chars2ui(pi + 12,2); 43265789Smckusick 43365789Smckusick /* difference of GMT */ 43465789Smckusick buf[6] = pi[16]; 43565789Smckusick 43665855Smckusick return cd9660_tstamp_conv7(buf,pu); 43765789Smckusick } 43865789Smckusick 439*68048Smckusick ino_t 440*68048Smckusick isodirino(isodir, imp) 44165789Smckusick struct iso_directory_record *isodir; 44265789Smckusick struct iso_mnt *imp; 44365789Smckusick { 444*68048Smckusick ino_t ino; 445*68048Smckusick 446*68048Smckusick ino = (isonum_733(isodir->extent) + isonum_711(isodir->ext_attr_length)) 447*68048Smckusick << imp->im_bshift; 448*68048Smckusick return (ino); 44965789Smckusick } 450