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