xref: /csrg-svn/sys/isofs/cd9660/cd9660_node.c (revision 67376)
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*67376Smkm  *	@(#)cd9660_node.c	8.3 (Berkeley) 06/14/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 
3065789Smckusick #define	INOHSZ	512
3165789Smckusick #if	((INOHSZ&(INOHSZ-1)) == 0)
3265789Smckusick #define	INOHASH(dev,ino)	(((dev)+((ino)>>12))&(INOHSZ-1))
3365789Smckusick #else
3465789Smckusick #define	INOHASH(dev,ino)	(((unsigned)((dev)+((ino)>>12)))%INOHSZ)
3565789Smckusick #endif
3665789Smckusick 
3765789Smckusick union iso_ihead {
3865789Smckusick 	union  iso_ihead *ih_head[2];
3965789Smckusick 	struct iso_node *ih_chain[2];
4065789Smckusick } iso_ihead[INOHSZ];
4165789Smckusick 
4265789Smckusick #ifdef	ISODEVMAP
4365789Smckusick #define	DNOHSZ	64
4465789Smckusick #if	((DNOHSZ&(DNOHSZ-1)) == 0)
4565789Smckusick #define	DNOHASH(dev,ino)	(((dev)+((ino)>>12))&(DNOHSZ-1))
4665789Smckusick #else
4765789Smckusick #define	DNOHASH(dev,ino)	(((unsigned)((dev)+((ino)>>12)))%DNOHSZ)
4865789Smckusick #endif
4965789Smckusick 
5065789Smckusick union iso_dhead {
5165789Smckusick 	union  iso_dhead  *dh_head[2];
5265789Smckusick 	struct iso_dnode *dh_chain[2];
5365789Smckusick } iso_dhead[DNOHSZ];
5465789Smckusick #endif
5565789Smckusick 
5665789Smckusick int prtactive;	/* 1 => print out reclaim of active vnodes */
5765789Smckusick 
5865789Smckusick /*
5965789Smckusick  * Initialize hash links for inodes and dnodes.
6065789Smckusick  */
6165855Smckusick cd9660_init()
6265789Smckusick {
6365789Smckusick 	register int i;
6465789Smckusick 	register union iso_ihead *ih = iso_ihead;
6565789Smckusick #ifdef	ISODEVMAP
6665789Smckusick 	register union iso_dhead *dh = iso_dhead;
6765789Smckusick #endif
6865789Smckusick 
6965789Smckusick 	for (i = INOHSZ; --i >= 0; ih++) {
7065789Smckusick 		ih->ih_head[0] = ih;
7165789Smckusick 		ih->ih_head[1] = ih;
7265789Smckusick 	}
7365789Smckusick #ifdef	ISODEVMAP
7465789Smckusick 	for (i = DNOHSZ; --i >= 0; dh++) {
7565789Smckusick 		dh->dh_head[0] = dh;
7665789Smckusick 		dh->dh_head[1] = dh;
7765789Smckusick 	}
7865789Smckusick #endif
7965789Smckusick }
8065789Smckusick 
8165789Smckusick #ifdef	ISODEVMAP
8265789Smckusick /*
8365789Smckusick  * Enter a new node into the device hash list
8465789Smckusick  */
8565789Smckusick struct iso_dnode *
8665789Smckusick iso_dmap(dev,ino,create)
8765789Smckusick 	dev_t	dev;
8865789Smckusick 	ino_t	ino;
8965789Smckusick 	int	create;
9065789Smckusick {
9165789Smckusick 	struct iso_dnode *dp;
9265789Smckusick 	union iso_dhead *dh;
9365789Smckusick 
9465789Smckusick 	dh = &iso_dhead[DNOHASH(dev, ino)];
9565789Smckusick 	for (dp = dh->dh_chain[0];
9665789Smckusick 	     dp != (struct iso_dnode *)dh;
9765789Smckusick 	     dp = dp->d_forw)
9865789Smckusick 		if (ino == dp->i_number && dev == dp->i_dev)
9965789Smckusick 			return dp;
10065789Smckusick 
10165789Smckusick 	if (!create)
10265789Smckusick 		return (struct iso_dnode *)0;
10365789Smckusick 
10465789Smckusick 	MALLOC(dp,struct iso_dnode *,sizeof(struct iso_dnode),M_CACHE,M_WAITOK);
10565789Smckusick 	dp->i_dev = dev;
10665789Smckusick 	dp->i_number = ino;
10765789Smckusick 	insque(dp,dh);
10865789Smckusick 
10965789Smckusick 	return dp;
11065789Smckusick }
11165789Smckusick 
11265789Smckusick void
11365789Smckusick iso_dunmap(dev)
11465789Smckusick 	dev_t	dev;
11565789Smckusick {
11665789Smckusick 	struct iso_dnode *dp, *dq;
11765789Smckusick 	union iso_dhead *dh;
11865789Smckusick 
11965789Smckusick 	for (dh = iso_dhead; dh < iso_dhead + DNOHSZ; dh++) {
12065789Smckusick 		for (dp = dh->dh_chain[0];
12165789Smckusick 		     dp != (struct iso_dnode *)dh;
12265789Smckusick 		     dp = dq) {
12365789Smckusick 			dq = dp->d_forw;
12465789Smckusick 			if (dev == dp->i_dev) {
12565789Smckusick 				remque(dp);
12665789Smckusick 				FREE(dp,M_CACHE);
12765789Smckusick 			}
12865789Smckusick 		}
12965789Smckusick 	}
13065789Smckusick }
13165789Smckusick #endif
13265789Smckusick 
13365789Smckusick /*
13465789Smckusick  * Look up a ISOFS dinode number to find its incore vnode.
13565789Smckusick  * If it is not in core, read it in from the specified device.
13665789Smckusick  * If it is in core, wait for the lock bit to clear, then
13765789Smckusick  * return the inode locked. Detection and handling of mount
13865789Smckusick  * points must be done by the calling routine.
13965789Smckusick  */
14065789Smckusick iso_iget(xp, ino, relocated, ipp, isodir)
14165789Smckusick 	struct iso_node *xp;
14265789Smckusick 	ino_t ino;
14365789Smckusick 	struct iso_node **ipp;
14465789Smckusick 	struct iso_directory_record *isodir;
14565789Smckusick {
14665789Smckusick 	dev_t dev = xp->i_dev;
14765789Smckusick 	struct mount *mntp = ITOV(xp)->v_mount;
14865789Smckusick 	register struct iso_node *ip, *iq;
14965789Smckusick 	register struct vnode *vp;
15065789Smckusick 	register struct iso_dnode *dp;
15165789Smckusick 	struct vnode *nvp;
15265789Smckusick 	struct buf *bp = NULL, *bp2 = NULL;
15365789Smckusick 	union iso_ihead *ih;
15465789Smckusick 	union iso_dhead *dh;
15565789Smckusick 	int i, error, result;
15665789Smckusick 	struct iso_mnt *imp;
15765789Smckusick 	ino_t defino;
15865789Smckusick 
15965789Smckusick 	ih = &iso_ihead[INOHASH(dev, ino)];
16065789Smckusick loop:
16165789Smckusick 	for (ip = ih->ih_chain[0];
16265789Smckusick 	     ip != (struct iso_node *)ih;
16365789Smckusick 	     ip = ip->i_forw) {
16465789Smckusick 		if (ino != ip->i_number || dev != ip->i_dev)
16565789Smckusick 			continue;
16665789Smckusick 		if ((ip->i_flag&ILOCKED) != 0) {
16765789Smckusick 			ip->i_flag |= IWANT;
16865789Smckusick 			sleep((caddr_t)ip, PINOD);
16965789Smckusick 			goto loop;
17065789Smckusick 		}
17165789Smckusick 		if (vget(ITOV(ip), 1))
17265789Smckusick 			goto loop;
17365789Smckusick 		*ipp = ip;
17465789Smckusick 		return 0;
17565789Smckusick 	}
17665789Smckusick 	/*
17765789Smckusick 	 * Allocate a new vnode/iso_node.
17865789Smckusick 	 */
17965855Smckusick 	if (error = getnewvnode(VT_ISOFS, mntp, cd9660_vnodeop_p, &nvp)) {
18065789Smckusick 		*ipp = 0;
18165789Smckusick 		return error;
18265789Smckusick 	}
18365789Smckusick 	MALLOC(ip, struct iso_node *, sizeof(struct iso_node),
18465789Smckusick 	       M_ISOFSNODE, M_WAITOK);
18565789Smckusick 	bzero((caddr_t)ip, sizeof(struct iso_node));
18665789Smckusick 	nvp->v_data = ip;
18765789Smckusick 	ip->i_vnode = nvp;
18865789Smckusick 	ip->i_flag = 0;
18965789Smckusick 	ip->i_devvp = 0;
19065789Smckusick 	ip->i_diroff = 0;
19165789Smckusick 	ip->i_lockf = 0;
19265789Smckusick 
19365789Smckusick 	/*
19465789Smckusick 	 * Put it onto its hash chain and lock it so that other requests for
19565789Smckusick 	 * this inode will block if they arrive while we are sleeping waiting
19665789Smckusick 	 * for old data structures to be purged or for the contents of the
19765789Smckusick 	 * disk portion of this inode to be read.
19865789Smckusick 	 */
19965789Smckusick 	ip->i_dev = dev;
20065789Smckusick 	ip->i_number = ino;
20165789Smckusick 	insque(ip, ih);
20265789Smckusick 	ISO_ILOCK(ip);
20365789Smckusick 
20465789Smckusick 	imp = VFSTOISOFS (mntp);
20565789Smckusick 	ip->i_mnt = imp;
20665789Smckusick 	ip->i_devvp = imp->im_devvp;
20765789Smckusick 	VREF(ip->i_devvp);
20865789Smckusick 
20965789Smckusick 	if (relocated) {
21065789Smckusick 		/*
21165789Smckusick 		 * On relocated directories we must
21265789Smckusick 		 * read the `.' entry out of a dir.
21365789Smckusick 		 */
21465789Smckusick 		ip->iso_start = ino >> imp->im_bshift;
21565789Smckusick 		if (error = iso_blkatoff(ip,0,&bp)) {
21665789Smckusick 			vrele(ip->i_devvp);
21765789Smckusick 			remque(ip);
21865789Smckusick 			ip->i_forw = ip;
21965789Smckusick 			ip->i_back = ip;
22065789Smckusick 			iso_iput(ip);
22165789Smckusick 			*ipp = 0;
22265789Smckusick 			return error;
22365789Smckusick 		}
22465789Smckusick 		isodir = (struct iso_directory_record *)bp->b_un.b_addr;
22565789Smckusick 	}
22665789Smckusick 
22765789Smckusick 	ip->iso_extent = isonum_733(isodir->extent);
22865789Smckusick 	ip->i_size = isonum_733(isodir->size);
22965789Smckusick 	ip->iso_start = isonum_711(isodir->ext_attr_length) + ip->iso_extent;
23065789Smckusick 
23165789Smckusick 	vp = ITOV(ip);
23265789Smckusick 
23365789Smckusick 	/*
23465789Smckusick 	 * Setup time stamp, attribute
23565789Smckusick 	 */
23665789Smckusick 	vp->v_type = VNON;
23765789Smckusick 	switch (imp->iso_ftype) {
23865789Smckusick 	default:	/* ISO_FTYPE_9660 */
23965789Smckusick 		if ((imp->im_flags&ISOFSMNT_EXTATT)
24065789Smckusick 		    && isonum_711(isodir->ext_attr_length))
24165789Smckusick 			iso_blkatoff(ip,-isonum_711(isodir->ext_attr_length),
24265789Smckusick 				     &bp2);
24365855Smckusick 		cd9660_defattr(isodir,ip,bp2 );
24465855Smckusick 		cd9660_deftstamp(isodir,ip,bp2 );
24565789Smckusick 		break;
24665789Smckusick 	case ISO_FTYPE_RRIP:
24765855Smckusick 		result = cd9660_rrip_analyze(isodir,ip,imp);
24865789Smckusick 		break;
24965789Smckusick 	}
25065789Smckusick 	if (bp2)
25165789Smckusick 		brelse(bp2);
25265789Smckusick 	if (bp)
25365789Smckusick 		brelse(bp);
25465789Smckusick 
25565789Smckusick 	/*
25665789Smckusick 	 * Initialize the associated vnode
25765789Smckusick 	 */
25865789Smckusick 	vp->v_type = IFTOVT(ip->inode.iso_mode);
25965789Smckusick 
26065789Smckusick 	if ( vp->v_type == VFIFO ) {
26165789Smckusick #ifdef	FIFO
26265855Smckusick 		extern int (**cd9660_fifoop_p)();
26365855Smckusick 		vp->v_op = cd9660_fifoop_p;
26465789Smckusick #else
26565789Smckusick 		iso_iput(ip);
26665789Smckusick 		*ipp = 0;
26765789Smckusick 		return EOPNOTSUPP;
26865789Smckusick #endif	/* FIFO */
26965789Smckusick 	} else if ( vp->v_type == VCHR || vp->v_type == VBLK ) {
27065855Smckusick 		extern int (**cd9660_specop_p)();
27165789Smckusick 
27265789Smckusick 		/*
27365789Smckusick 		 * if device, look at device number table for translation
27465789Smckusick 		 */
27565789Smckusick #ifdef	ISODEVMAP
27665789Smckusick 		if (dp = iso_dmap(dev,ino,0))
27765789Smckusick 			ip->inode.iso_rdev = dp->d_dev;
27865789Smckusick #endif
27965855Smckusick 		vp->v_op = cd9660_specop_p;
28065789Smckusick 		if (nvp = checkalias(vp, ip->inode.iso_rdev, mntp)) {
28165789Smckusick 			/*
28265789Smckusick 			 * Reinitialize aliased inode.
28365789Smckusick 			 */
28465789Smckusick 			vp = nvp;
28565789Smckusick 			iq = VTOI(vp);
28665789Smckusick 			iq->i_vnode = vp;
28765789Smckusick 			iq->i_flag = 0;
28865789Smckusick 			ISO_ILOCK(iq);
28965789Smckusick 			iq->i_dev = dev;
29065789Smckusick 			iq->i_number = ino;
29165789Smckusick 			iq->i_mnt = ip->i_mnt;
29265789Smckusick 			bcopy(&ip->iso_extent,&iq->iso_extent,
29365789Smckusick 			      (char *)(ip + 1) - (char *)&ip->iso_extent);
29465789Smckusick 			insque(iq, ih);
29565789Smckusick 			/*
29665789Smckusick 			 * Discard unneeded vnode
29765789Smckusick 			 * (This introduces the need of INACTIVE modification)
29865789Smckusick 			 */
29965789Smckusick 			ip->inode.iso_mode = 0;
30065789Smckusick 			iso_iput(ip);
30165789Smckusick 			ip = iq;
30265789Smckusick 		}
30365789Smckusick 	}
30465789Smckusick 
30565789Smckusick 	if (ip->iso_extent == imp->root_extent)
30665789Smckusick 		vp->v_flag |= VROOT;
30765789Smckusick 
30865789Smckusick 	*ipp = ip;
30965789Smckusick 	return 0;
31065789Smckusick }
31165789Smckusick 
31265789Smckusick /*
31365789Smckusick  * Unlock and decrement the reference count of an inode structure.
31465789Smckusick  */
31565789Smckusick iso_iput(ip)
31665789Smckusick 	register struct iso_node *ip;
31765789Smckusick {
31865789Smckusick 
31965789Smckusick 	if ((ip->i_flag & ILOCKED) == 0)
32065789Smckusick 		panic("iso_iput");
32165789Smckusick 	ISO_IUNLOCK(ip);
32265789Smckusick 	vrele(ITOV(ip));
32365789Smckusick }
32465789Smckusick 
32565789Smckusick /*
32665789Smckusick  * Last reference to an inode, write the inode out and if necessary,
32765789Smckusick  * truncate and deallocate the file.
32865789Smckusick  */
32965789Smckusick int
33065855Smckusick cd9660_inactive(ap)
33165789Smckusick 	struct vop_inactive_args /* {
33265789Smckusick 		struct vnode *a_vp;
33365789Smckusick 	} */ *ap;
33465789Smckusick {
33565789Smckusick 	struct vnode *vp = ap->a_vp;
33665789Smckusick 	register struct iso_node *ip = VTOI(vp);
33765789Smckusick 	int mode, error = 0;
33865789Smckusick 
33965789Smckusick 	if (prtactive && vp->v_usecount != 0)
34065855Smckusick 		vprint("cd9660_inactive: pushing active", vp);
34165789Smckusick 
34265789Smckusick 	ip->i_flag = 0;
34365789Smckusick 	/*
34465789Smckusick 	 * If we are done with the inode, reclaim it
34565789Smckusick 	 * so that it can be reused immediately.
34665789Smckusick 	 */
34765789Smckusick 	if (vp->v_usecount == 0 && ip->inode.iso_mode == 0)
34865789Smckusick 		vgone(vp);
34965789Smckusick 	return error;
35065789Smckusick }
35165789Smckusick 
35265789Smckusick /*
35365789Smckusick  * Reclaim an inode so that it can be used for other purposes.
35465789Smckusick  */
35565789Smckusick int
35665855Smckusick cd9660_reclaim(ap)
35765789Smckusick 	struct vop_reclaim_args /* {
35865789Smckusick 		struct vnode *a_vp;
35965789Smckusick 	} */ *ap;
36065789Smckusick {
36165789Smckusick 	register struct vnode *vp = ap->a_vp;
36265789Smckusick 	register struct iso_node *ip = VTOI(vp);
36365789Smckusick 	int i;
36465789Smckusick 
36565789Smckusick 	if (prtactive && vp->v_usecount != 0)
36665855Smckusick 		vprint("cd9660_reclaim: pushing active", vp);
36765789Smckusick 	/*
36865789Smckusick 	 * Remove the inode from its hash chain.
36965789Smckusick 	 */
37065789Smckusick 	remque(ip);
37165789Smckusick 	ip->i_forw = ip;
37265789Smckusick 	ip->i_back = ip;
37365789Smckusick 	/*
37465789Smckusick 	 * Purge old data structures associated with the inode.
37565789Smckusick 	 */
37665789Smckusick 	cache_purge(vp);
37765789Smckusick 	if (ip->i_devvp) {
37865789Smckusick 		vrele(ip->i_devvp);
37965789Smckusick 		ip->i_devvp = 0;
38065789Smckusick 	}
38165789Smckusick 	FREE(vp->v_data, M_ISOFSNODE);
38265789Smckusick 	vp->v_data = NULL;
38365789Smckusick 	return 0;
38465789Smckusick }
38565789Smckusick 
38665789Smckusick /*
38765789Smckusick  * Lock an inode. If its already locked, set the WANT bit and sleep.
38865789Smckusick  */
38965789Smckusick iso_ilock(ip)
39065789Smckusick 	register struct iso_node *ip;
39165789Smckusick {
39265789Smckusick 
39365789Smckusick 	while (ip->i_flag & ILOCKED) {
39465789Smckusick 		ip->i_flag |= IWANT;
39565789Smckusick 		if (ip->i_spare0 == curproc->p_pid)
39665789Smckusick 			panic("locking against myself");
39765789Smckusick 		ip->i_spare1 = curproc->p_pid;
39865789Smckusick 		(void) sleep((caddr_t)ip, PINOD);
39965789Smckusick 	}
40065789Smckusick 	ip->i_spare1 = 0;
40165789Smckusick 	ip->i_spare0 = curproc->p_pid;
40265789Smckusick 	ip->i_flag |= ILOCKED;
40365789Smckusick }
40465789Smckusick 
40565789Smckusick /*
40665789Smckusick  * Unlock an inode.  If WANT bit is on, wakeup.
40765789Smckusick  */
40865789Smckusick iso_iunlock(ip)
40965789Smckusick 	register struct iso_node *ip;
41065789Smckusick {
41165789Smckusick 
41265789Smckusick 	if ((ip->i_flag & ILOCKED) == 0)
41365789Smckusick 		vprint("iso_iunlock: unlocked inode", ITOV(ip));
41465789Smckusick 	ip->i_spare0 = 0;
41565789Smckusick 	ip->i_flag &= ~ILOCKED;
41665789Smckusick 	if (ip->i_flag&IWANT) {
41765789Smckusick 		ip->i_flag &= ~IWANT;
41865789Smckusick 		wakeup((caddr_t)ip);
41965789Smckusick 	}
42065789Smckusick }
42165789Smckusick 
42265789Smckusick /*
42365789Smckusick  * File attributes
42465789Smckusick  */
42565789Smckusick void
42665855Smckusick cd9660_defattr(isodir,inop,bp)
42765789Smckusick 	struct iso_directory_record *isodir;
42865789Smckusick 	struct iso_node *inop;
42965789Smckusick 	struct buf *bp;
43065789Smckusick {
43165789Smckusick 	struct buf *bp2 = NULL;
43265789Smckusick 	struct iso_mnt *imp;
43365789Smckusick 	struct iso_extended_attributes *ap = NULL;
43465789Smckusick 	int off;
43565789Smckusick 
43665789Smckusick 	if (isonum_711(isodir->flags)&2) {
43765789Smckusick 		inop->inode.iso_mode = S_IFDIR;
43865789Smckusick 		/*
43965789Smckusick 		 * If we return 2, fts() will assume there are no subdirectories
44065789Smckusick 		 * (just links for the path and .), so instead we return 1.
44165789Smckusick 		 */
44265789Smckusick 		inop->inode.iso_links = 1;
44365789Smckusick 	} else {
44465789Smckusick 		inop->inode.iso_mode = S_IFREG;
44565789Smckusick 		inop->inode.iso_links = 1;
44665789Smckusick 	}
44765789Smckusick 	if (!bp
44865789Smckusick 	    && ((imp = inop->i_mnt)->im_flags&ISOFSMNT_EXTATT)
44965789Smckusick 	    && (off = isonum_711(isodir->ext_attr_length))) {
45065789Smckusick 		iso_blkatoff(inop,-off * imp->logical_block_size,&bp2);
45165789Smckusick 		bp = bp2;
45265789Smckusick 	}
45365789Smckusick 	if (bp) {
45465789Smckusick 		ap = (struct iso_extended_attributes *)bp->b_un.b_addr;
45565789Smckusick 
45665789Smckusick 		if (isonum_711(ap->version) == 1) {
45765789Smckusick 			if (!(ap->perm[0]&0x40))
45865789Smckusick 				inop->inode.iso_mode |= VEXEC >> 6;
45965789Smckusick 			if (!(ap->perm[0]&0x10))
46065789Smckusick 				inop->inode.iso_mode |= VREAD >> 6;
46165789Smckusick 			if (!(ap->perm[0]&4))
46265789Smckusick 				inop->inode.iso_mode |= VEXEC >> 3;
46365789Smckusick 			if (!(ap->perm[0]&1))
46465789Smckusick 				inop->inode.iso_mode |= VREAD >> 3;
46565789Smckusick 			if (!(ap->perm[1]&0x40))
46665789Smckusick 				inop->inode.iso_mode |= VEXEC;
46765789Smckusick 			if (!(ap->perm[1]&0x10))
46865789Smckusick 				inop->inode.iso_mode |= VREAD;
46965789Smckusick 			inop->inode.iso_uid = isonum_723(ap->owner); /* what about 0? */
47065789Smckusick 			inop->inode.iso_gid = isonum_723(ap->group); /* what about 0? */
47165789Smckusick 		} else
47265789Smckusick 			ap = NULL;
47365789Smckusick 	}
47465789Smckusick 	if (!ap) {
47565789Smckusick 		inop->inode.iso_mode |= VREAD|VEXEC|(VREAD|VEXEC)>>3|(VREAD|VEXEC)>>6;
47665789Smckusick 		inop->inode.iso_uid = (uid_t)0;
47765789Smckusick 		inop->inode.iso_gid = (gid_t)0;
47865789Smckusick 	}
47965789Smckusick 	if (bp2)
48065789Smckusick 		brelse(bp2);
48165789Smckusick }
48265789Smckusick 
48365789Smckusick /*
48465789Smckusick  * Time stamps
48565789Smckusick  */
48665789Smckusick void
48765855Smckusick cd9660_deftstamp(isodir,inop,bp)
48865789Smckusick 	struct iso_directory_record *isodir;
48965789Smckusick 	struct iso_node *inop;
49065789Smckusick 	struct buf *bp;
49165789Smckusick {
49265789Smckusick 	struct buf *bp2 = NULL;
49365789Smckusick 	struct iso_mnt *imp;
49465789Smckusick 	struct iso_extended_attributes *ap = NULL;
49565789Smckusick 	int off;
49665789Smckusick 
49765789Smckusick 	if (!bp
49865789Smckusick 	    && ((imp = inop->i_mnt)->im_flags&ISOFSMNT_EXTATT)
49965789Smckusick 	    && (off = isonum_711(isodir->ext_attr_length))) {
50065789Smckusick 		iso_blkatoff(inop,-off * imp->logical_block_size,&bp2);
50165789Smckusick 		bp = bp2;
50265789Smckusick 	}
50365789Smckusick 	if (bp) {
50465789Smckusick 		ap = (struct iso_extended_attributes *)bp->b_un.b_addr;
50565789Smckusick 
50665789Smckusick 		if (isonum_711(ap->version) == 1) {
50765855Smckusick 			if (!cd9660_tstamp_conv17(ap->ftime,&inop->inode.iso_atime))
50865855Smckusick 				cd9660_tstamp_conv17(ap->ctime,&inop->inode.iso_atime);
50965855Smckusick 			if (!cd9660_tstamp_conv17(ap->ctime,&inop->inode.iso_ctime))
51065789Smckusick 				inop->inode.iso_ctime = inop->inode.iso_atime;
51165855Smckusick 			if (!cd9660_tstamp_conv17(ap->mtime,&inop->inode.iso_mtime))
51265789Smckusick 				inop->inode.iso_mtime = inop->inode.iso_ctime;
51365789Smckusick 		} else
51465789Smckusick 			ap = NULL;
51565789Smckusick 	}
51665789Smckusick 	if (!ap) {
51765855Smckusick 		cd9660_tstamp_conv7(isodir->date,&inop->inode.iso_ctime);
51865789Smckusick 		inop->inode.iso_atime = inop->inode.iso_ctime;
51965789Smckusick 		inop->inode.iso_mtime = inop->inode.iso_ctime;
52065789Smckusick 	}
52165789Smckusick 	if (bp2)
52265789Smckusick 		brelse(bp2);
52365789Smckusick }
52465789Smckusick 
52565789Smckusick int
52665855Smckusick cd9660_tstamp_conv7(pi,pu)
52765789Smckusick char *pi;
52865789Smckusick struct timeval *pu;
52965789Smckusick {
53065789Smckusick 	int i;
53165789Smckusick 	int crtime, days;
53265789Smckusick 	int y, m, d, hour, minute, second, tz;
53365789Smckusick 
53465789Smckusick 	y = pi[0] + 1900;
53565789Smckusick 	m = pi[1];
53665789Smckusick 	d = pi[2];
53765789Smckusick 	hour = pi[3];
53865789Smckusick 	minute = pi[4];
53965789Smckusick 	second = pi[5];
54065789Smckusick 	tz = pi[6];
54165789Smckusick 
54265789Smckusick 	if (y < 1970) {
54365789Smckusick 		pu->tv_sec  = 0;
54465789Smckusick 		pu->tv_usec = 0;
54565789Smckusick 		return 0;
54665789Smckusick 	} else {
54765789Smckusick #ifdef	ORIGINAL
54865789Smckusick 		/* computes day number relative to Sept. 19th,1989 */
54965789Smckusick 		/* don't even *THINK* about changing formula. It works! */
55065789Smckusick 		days = 367*(y-1980)-7*(y+(m+9)/12)/4-3*((y+(m-9)/7)/100+1)/4+275*m/9+d-100;
55165789Smckusick #else
55265789Smckusick 		/*
55365789Smckusick 		 * Changed :-) to make it relative to Jan. 1st, 1970
55465789Smckusick 		 * and to disambiguate negative division
55565789Smckusick 		 */
55665789Smckusick 		days = 367*(y-1960)-7*(y+(m+9)/12)/4-3*((y+(m+9)/12-1)/100+1)/4+275*m/9+d-239;
55765789Smckusick #endif
55865789Smckusick 		crtime = ((((days * 24) + hour) * 60 + minute) * 60) + second;
55965789Smckusick 
56065789Smckusick 		/* timezone offset is unreliable on some disks */
56165789Smckusick 		if (-48 <= tz && tz <= 52)
562*67376Smkm 			crtime -= tz * 15 * 60;
56365789Smckusick 	}
56465789Smckusick 	pu->tv_sec  = crtime;
56565789Smckusick 	pu->tv_usec = 0;
56665789Smckusick 	return 1;
56765789Smckusick }
56865789Smckusick 
56965789Smckusick static unsigned
57065855Smckusick cd9660_chars2ui(begin,len)
57165789Smckusick 	unsigned char *begin;
57265789Smckusick 	int len;
57365789Smckusick {
57465789Smckusick 	unsigned rc;
57565789Smckusick 
57665789Smckusick 	for (rc = 0; --len >= 0;) {
57765789Smckusick 		rc *= 10;
57865789Smckusick 		rc += *begin++ - '0';
57965789Smckusick 	}
58065789Smckusick 	return rc;
58165789Smckusick }
58265789Smckusick 
58365789Smckusick int
58465855Smckusick cd9660_tstamp_conv17(pi,pu)
58565789Smckusick 	unsigned char *pi;
58665789Smckusick 	struct timeval *pu;
58765789Smckusick {
58865789Smckusick 	unsigned char buf[7];
58965789Smckusick 
59065789Smckusick 	/* year:"0001"-"9999" -> -1900  */
59165855Smckusick 	buf[0] = cd9660_chars2ui(pi,4) - 1900;
59265789Smckusick 
59365789Smckusick 	/* month: " 1"-"12"      -> 1 - 12 */
59465855Smckusick 	buf[1] = cd9660_chars2ui(pi + 4,2);
59565789Smckusick 
59665789Smckusick 	/* day:   " 1"-"31"      -> 1 - 31 */
59765855Smckusick 	buf[2] = cd9660_chars2ui(pi + 6,2);
59865789Smckusick 
59965789Smckusick 	/* hour:  " 0"-"23"      -> 0 - 23 */
60065855Smckusick 	buf[3] = cd9660_chars2ui(pi + 8,2);
60165789Smckusick 
60265789Smckusick 	/* minute:" 0"-"59"      -> 0 - 59 */
60365855Smckusick 	buf[4] = cd9660_chars2ui(pi + 10,2);
60465789Smckusick 
60565789Smckusick 	/* second:" 0"-"59"      -> 0 - 59 */
60665855Smckusick 	buf[5] = cd9660_chars2ui(pi + 12,2);
60765789Smckusick 
60865789Smckusick 	/* difference of GMT */
60965789Smckusick 	buf[6] = pi[16];
61065789Smckusick 
61165855Smckusick 	return cd9660_tstamp_conv7(buf,pu);
61265789Smckusick }
61365789Smckusick 
61465789Smckusick void
61565789Smckusick isodirino(inump,isodir,imp)
61665789Smckusick 	ino_t *inump;
61765789Smckusick 	struct iso_directory_record *isodir;
61865789Smckusick 	struct iso_mnt *imp;
61965789Smckusick {
62065789Smckusick 	*inump = (isonum_733(isodir->extent) + isonum_711(isodir->ext_attr_length))
62165789Smckusick 		 * imp->logical_block_size;
62265789Smckusick }
623