11541Srgrimes/*-
222521Sdyson * Copyright (c) 1982, 1986, 1989, 1994, 1995
31541Srgrimes *	The Regents of the University of California.  All rights reserved.
41541Srgrimes *
51541Srgrimes * This code is derived from software contributed to Berkeley
61541Srgrimes * by Pace Willisson (pace@blitz.com).  The Rock Ridge Extension
71541Srgrimes * Support code is derived from software contributed to Berkeley
81541Srgrimes * by Atsushi Murai (amurai@spec.co.jp).
91541Srgrimes *
101541Srgrimes * Redistribution and use in source and binary forms, with or without
111541Srgrimes * modification, are permitted provided that the following conditions
121541Srgrimes * are met:
131541Srgrimes * 1. Redistributions of source code must retain the above copyright
141541Srgrimes *    notice, this list of conditions and the following disclaimer.
151541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
161541Srgrimes *    notice, this list of conditions and the following disclaimer in the
171541Srgrimes *    documentation and/or other materials provided with the distribution.
181541Srgrimes * 4. Neither the name of the University nor the names of its contributors
191541Srgrimes *    may be used to endorse or promote products derived from this software
201541Srgrimes *    without specific prior written permission.
211541Srgrimes *
221541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
231541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
241541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
251541Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
261541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
271541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
281541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
291541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
301541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
311541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
321541Srgrimes * SUCH DAMAGE.
331541Srgrimes *
341541Srgrimes *	@(#)cd9660_node.c	8.2 (Berkeley) 1/23/94
351541Srgrimes */
361541Srgrimes
37116181Sobrien#include <sys/cdefs.h>
38116181Sobrien__FBSDID("$FreeBSD$");
39116181Sobrien
401541Srgrimes#include <sys/param.h>
411541Srgrimes#include <sys/systm.h>
421541Srgrimes#include <sys/mount.h>
4360041Sphk#include <sys/bio.h>
441541Srgrimes#include <sys/buf.h>
451541Srgrimes#include <sys/vnode.h>
461541Srgrimes#include <sys/malloc.h>
471541Srgrimes#include <sys/stat.h>
4871576Sjasone#include <sys/mutex.h>
491541Srgrimes
50166639Srodrigc#include <fs/cd9660/iso.h>
51166639Srodrigc#include <fs/cd9660/cd9660_node.h>
52166639Srodrigc#include <fs/cd9660/cd9660_mount.h>
531541Srgrimes
5492765Salfredstatic unsigned	cd9660_chars2ui(unsigned char *begin, int len);
5512597Sbde
561541Srgrimes/*
571541Srgrimes * Last reference to an inode, write the inode out and if necessary,
581541Srgrimes * truncate and deallocate the file.
591541Srgrimes */
601541Srgrimesint
611541Srgrimescd9660_inactive(ap)
621541Srgrimes	struct vop_inactive_args /* {
631541Srgrimes		struct vnode *a_vp;
6483366Sjulian		struct thread *a_td;
651541Srgrimes	} */ *ap;
661541Srgrimes{
671541Srgrimes	struct vnode *vp = ap->a_vp;
68131526Sphk	struct iso_node *ip = VTOI(vp);
693106Sgpalmer	int error = 0;
708876Srgrimes
711541Srgrimes	/*
721541Srgrimes	 * If we are done with the inode, reclaim it
731541Srgrimes	 * so that it can be reused immediately.
741541Srgrimes	 */
7522521Sdyson	if (ip->inode.iso_mode == 0)
76234607Strasz		vrecycle(vp);
771541Srgrimes	return error;
781541Srgrimes}
791541Srgrimes
801541Srgrimes/*
811541Srgrimes * Reclaim an inode so that it can be used for other purposes.
821541Srgrimes */
831541Srgrimesint
841541Srgrimescd9660_reclaim(ap)
851541Srgrimes	struct vop_reclaim_args /* {
861541Srgrimes		struct vnode *a_vp;
8783366Sjulian		struct thread *a_td;
881541Srgrimes	} */ *ap;
891541Srgrimes{
90131526Sphk	struct vnode *vp = ap->a_vp;
918876Srgrimes
921541Srgrimes	/*
93154487Salfred	 * Destroy the vm object and flush associated pages.
94154487Salfred	 */
95154487Salfred	vnode_destroy_vobject(vp);
96154487Salfred	/*
971541Srgrimes	 * Remove the inode from its hash chain.
981541Srgrimes	 */
99143577Sphk	vfs_hash_remove(vp);
100143577Sphk
1011541Srgrimes	/*
1021541Srgrimes	 * Purge old data structures associated with the inode.
1031541Srgrimes	 */
104184205Sdes	free(vp->v_data, M_ISOFSNODE);
1051541Srgrimes	vp->v_data = NULL;
1061549Srgrimes	return (0);
1071541Srgrimes}
1081541Srgrimes
1091541Srgrimes/*
1101541Srgrimes * File attributes
1111541Srgrimes */
1121541Srgrimesvoid
11322521Sdysoncd9660_defattr(isodir, inop, bp, ftype)
1141541Srgrimes	struct iso_directory_record *isodir;
1151541Srgrimes	struct iso_node *inop;
1161541Srgrimes	struct buf *bp;
1175651Sjoerg	enum ISO_FTYPE ftype;
1181541Srgrimes{
1191541Srgrimes	struct buf *bp2 = NULL;
1201541Srgrimes	struct iso_mnt *imp;
1211541Srgrimes	struct iso_extended_attributes *ap = NULL;
1221541Srgrimes	int off;
1238876Srgrimes
1245651Sjoerg	/* high sierra does not have timezone data, flag is one byte ahead */
1255651Sjoerg	if (isonum_711(ftype == ISO_FTYPE_HIGH_SIERRA?
1265651Sjoerg		       &isodir->date[6]: isodir->flags)&2) {
1271541Srgrimes		inop->inode.iso_mode = S_IFDIR;
1281541Srgrimes		/*
1291541Srgrimes		 * If we return 2, fts() will assume there are no subdirectories
1301541Srgrimes		 * (just links for the path and .), so instead we return 1.
1311541Srgrimes		 */
1321541Srgrimes		inop->inode.iso_links = 1;
1331541Srgrimes	} else {
1341541Srgrimes		inop->inode.iso_mode = S_IFREG;
1351541Srgrimes		inop->inode.iso_links = 1;
1361541Srgrimes	}
1371541Srgrimes	if (!bp
13822521Sdyson	    && ((imp = inop->i_mnt)->im_flags & ISOFSMNT_EXTATT)
1391541Srgrimes	    && (off = isonum_711(isodir->ext_attr_length))) {
14030474Sphk		cd9660_blkatoff(ITOV(inop), (off_t)-(off << imp->im_bshift), NULL,
14122521Sdyson			     &bp2);
1421541Srgrimes		bp = bp2;
1431541Srgrimes	}
1441541Srgrimes	if (bp) {
14522521Sdyson		ap = (struct iso_extended_attributes *)bp->b_data;
146131526Sphk
1471541Srgrimes		if (isonum_711(ap->version) == 1) {
1481541Srgrimes			if (!(ap->perm[0]&0x40))
149183577Strasz				inop->inode.iso_mode |= S_IXOTH;
1501541Srgrimes			if (!(ap->perm[0]&0x10))
151183577Strasz				inop->inode.iso_mode |= S_IROTH;
1521541Srgrimes			if (!(ap->perm[0]&4))
153183577Strasz				inop->inode.iso_mode |= S_IXGRP;
1541541Srgrimes			if (!(ap->perm[0]&1))
155183577Strasz				inop->inode.iso_mode |= S_IRGRP;
1561541Srgrimes			if (!(ap->perm[1]&0x40))
157183577Strasz				inop->inode.iso_mode |= S_IXUSR;
1581541Srgrimes			if (!(ap->perm[1]&0x10))
159183577Strasz				inop->inode.iso_mode |= S_IRUSR;
1601541Srgrimes			inop->inode.iso_uid = isonum_723(ap->owner); /* what about 0? */
1611541Srgrimes			inop->inode.iso_gid = isonum_723(ap->group); /* what about 0? */
1621541Srgrimes		} else
1631541Srgrimes			ap = NULL;
1641541Srgrimes	}
1651541Srgrimes	if (!ap) {
166183577Strasz		inop->inode.iso_mode |= S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
1671541Srgrimes		inop->inode.iso_uid = (uid_t)0;
1681541Srgrimes		inop->inode.iso_gid = (gid_t)0;
1691541Srgrimes	}
1701541Srgrimes	if (bp2)
1711541Srgrimes		brelse(bp2);
1721541Srgrimes}
1731541Srgrimes
1741541Srgrimes/*
1751541Srgrimes * Time stamps
1761541Srgrimes */
1771541Srgrimesvoid
1785651Sjoergcd9660_deftstamp(isodir,inop,bp,ftype)
1791541Srgrimes	struct iso_directory_record *isodir;
1801541Srgrimes	struct iso_node *inop;
1811541Srgrimes	struct buf *bp;
1825651Sjoerg	enum ISO_FTYPE ftype;
1831541Srgrimes{
1841541Srgrimes	struct buf *bp2 = NULL;
1851541Srgrimes	struct iso_mnt *imp;
1861541Srgrimes	struct iso_extended_attributes *ap = NULL;
1871541Srgrimes	int off;
1888876Srgrimes
1891541Srgrimes	if (!bp
19022521Sdyson	    && ((imp = inop->i_mnt)->im_flags & ISOFSMNT_EXTATT)
1911541Srgrimes	    && (off = isonum_711(isodir->ext_attr_length))) {
19230474Sphk		cd9660_blkatoff(ITOV(inop), (off_t)-(off << imp->im_bshift), NULL,
19322521Sdyson			     &bp2);
1941541Srgrimes		bp = bp2;
1951541Srgrimes	}
1961541Srgrimes	if (bp) {
19722521Sdyson		ap = (struct iso_extended_attributes *)bp->b_data;
198131526Sphk
19922567Sbde		if (ftype != ISO_FTYPE_HIGH_SIERRA
20022567Sbde		    && isonum_711(ap->version) == 1) {
2011541Srgrimes			if (!cd9660_tstamp_conv17(ap->ftime,&inop->inode.iso_atime))
2021541Srgrimes				cd9660_tstamp_conv17(ap->ctime,&inop->inode.iso_atime);
2031541Srgrimes			if (!cd9660_tstamp_conv17(ap->ctime,&inop->inode.iso_ctime))
2041541Srgrimes				inop->inode.iso_ctime = inop->inode.iso_atime;
2051541Srgrimes			if (!cd9660_tstamp_conv17(ap->mtime,&inop->inode.iso_mtime))
2061541Srgrimes				inop->inode.iso_mtime = inop->inode.iso_ctime;
2071541Srgrimes		} else
2081541Srgrimes			ap = NULL;
2091541Srgrimes	}
2101541Srgrimes	if (!ap) {
2115651Sjoerg		cd9660_tstamp_conv7(isodir->date,&inop->inode.iso_ctime,ftype);
2121541Srgrimes		inop->inode.iso_atime = inop->inode.iso_ctime;
2131541Srgrimes		inop->inode.iso_mtime = inop->inode.iso_ctime;
2141541Srgrimes	}
2151541Srgrimes	if (bp2)
2161541Srgrimes		brelse(bp2);
2171541Srgrimes}
2181541Srgrimes
2191541Srgrimesint
2205651Sjoergcd9660_tstamp_conv7(pi,pu,ftype)
22122521Sdyson	u_char *pi;
22222521Sdyson	struct timespec *pu;
22322521Sdyson	enum ISO_FTYPE ftype;
2241541Srgrimes{
2251541Srgrimes	int crtime, days;
2261541Srgrimes	int y, m, d, hour, minute, second, tz;
2278876Srgrimes
2281541Srgrimes	y = pi[0] + 1900;
2291541Srgrimes	m = pi[1];
2301541Srgrimes	d = pi[2];
2311541Srgrimes	hour = pi[3];
2321541Srgrimes	minute = pi[4];
2331541Srgrimes	second = pi[5];
2345651Sjoerg	if(ftype != ISO_FTYPE_HIGH_SIERRA)
235185361Skientzle		tz = ((signed char *)pi)[6]; /* Timezone value is signed. */
2365651Sjoerg	else
2375651Sjoerg		/* original high sierra misses timezone data */
2385651Sjoerg		tz = 0;
2398876Srgrimes
2401541Srgrimes	if (y < 1970) {
24118412Snate		pu->tv_sec  = 0;
24218412Snate		pu->tv_nsec = 0;
2431541Srgrimes		return 0;
2441541Srgrimes	} else {
2451541Srgrimes#ifdef	ORIGINAL
2461541Srgrimes		/* computes day number relative to Sept. 19th,1989 */
2471541Srgrimes		/* don't even *THINK* about changing formula. It works! */
2481541Srgrimes		days = 367*(y-1980)-7*(y+(m+9)/12)/4-3*((y+(m-9)/7)/100+1)/4+275*m/9+d-100;
2491541Srgrimes#else
2501541Srgrimes		/*
2511541Srgrimes		 * Changed :-) to make it relative to Jan. 1st, 1970
2521541Srgrimes		 * and to disambiguate negative division
2531541Srgrimes		 */
2541541Srgrimes		days = 367*(y-1960)-7*(y+(m+9)/12)/4-3*((y+(m+9)/12-1)/100+1)/4+275*m/9+d-239;
2551541Srgrimes#endif
2561541Srgrimes		crtime = ((((days * 24) + hour) * 60 + minute) * 60) + second;
2578876Srgrimes
2581541Srgrimes		/* timezone offset is unreliable on some disks */
2591541Srgrimes		if (-48 <= tz && tz <= 52)
2606603Sbde			crtime -= tz * 15 * 60;
2611541Srgrimes	}
26218412Snate	pu->tv_sec  = crtime;
26318412Snate	pu->tv_nsec = 0;
2641541Srgrimes	return 1;
2651541Srgrimes}
2661541Srgrimes
26722521Sdysonstatic u_int
2681541Srgrimescd9660_chars2ui(begin,len)
26922521Sdyson	u_char *begin;
2701541Srgrimes	int len;
2711541Srgrimes{
27222521Sdyson	u_int rc;
273131526Sphk
2741541Srgrimes	for (rc = 0; --len >= 0;) {
2751541Srgrimes		rc *= 10;
2761541Srgrimes		rc += *begin++ - '0';
2771541Srgrimes	}
2781541Srgrimes	return rc;
2791541Srgrimes}
2801541Srgrimes
2811541Srgrimesint
2821541Srgrimescd9660_tstamp_conv17(pi,pu)
28322521Sdyson	u_char *pi;
2842806Sbde	struct timespec *pu;
2851541Srgrimes{
28622521Sdyson	u_char buf[7];
287131526Sphk
28822521Sdyson	/* year:"0001"-"9999" -> -1900  */
2891541Srgrimes	buf[0] = cd9660_chars2ui(pi,4) - 1900;
2908876Srgrimes
2915651Sjoerg	/* month: " 1"-"12"   -> 1 - 12 */
2921541Srgrimes	buf[1] = cd9660_chars2ui(pi + 4,2);
2938876Srgrimes
2945651Sjoerg	/* day:	  " 1"-"31"   -> 1 - 31 */
2951541Srgrimes	buf[2] = cd9660_chars2ui(pi + 6,2);
2968876Srgrimes
2975651Sjoerg	/* hour:  " 0"-"23"   -> 0 - 23 */
2981541Srgrimes	buf[3] = cd9660_chars2ui(pi + 8,2);
2998876Srgrimes
3005651Sjoerg	/* minute:" 0"-"59"   -> 0 - 59 */
3011541Srgrimes	buf[4] = cd9660_chars2ui(pi + 10,2);
3028876Srgrimes
3035651Sjoerg	/* second:" 0"-"59"   -> 0 - 59 */
3041541Srgrimes	buf[5] = cd9660_chars2ui(pi + 12,2);
3058876Srgrimes
3061541Srgrimes	/* difference of GMT */
3071541Srgrimes	buf[6] = pi[16];
3088876Srgrimes
3095651Sjoerg	return cd9660_tstamp_conv7(buf, pu, ISO_FTYPE_DEFAULT);
3101541Srgrimes}
3111541Srgrimes
31222521Sdysonino_t
31322521Sdysonisodirino(isodir, imp)
3141541Srgrimes	struct iso_directory_record *isodir;
3151541Srgrimes	struct iso_mnt *imp;
3161541Srgrimes{
31722521Sdyson	ino_t ino;
31822521Sdyson
31922521Sdyson	ino = (isonum_733(isodir->extent) + isonum_711(isodir->ext_attr_length))
32022521Sdyson	      << imp->im_bshift;
32122521Sdyson	return (ino);
3221541Srgrimes}
323