Annotation of src/sys/fs/cd9660/cd9660_node.c, Revision 1.23
1.23 ! matt 1: /* $NetBSD: cd9660_node.c,v 1.22 2008/01/30 09:50:19 ad Exp $ */
1.1 jdolecek 2:
3: /*-
4: * Copyright (c) 1982, 1986, 1989, 1994
5: * The Regents of the University of California. All rights reserved.
6: *
7: * This code is derived from software contributed to Berkeley
8: * by Pace Willisson (pace@blitz.com). The Rock Ridge Extension
9: * Support code is derived from software contributed to Berkeley
10: * by Atsushi Murai (amurai@spec.co.jp).
11: *
12: * Redistribution and use in source and binary forms, with or without
13: * modification, are permitted provided that the following conditions
14: * are met:
15: * 1. Redistributions of source code must retain the above copyright
16: * notice, this list of conditions and the following disclaimer.
17: * 2. Redistributions in binary form must reproduce the above copyright
18: * notice, this list of conditions and the following disclaimer in the
19: * documentation and/or other materials provided with the distribution.
1.5 agc 20: * 3. Neither the name of the University nor the names of its contributors
1.1 jdolecek 21: * may be used to endorse or promote products derived from this software
22: * without specific prior written permission.
23: *
24: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34: * SUCH DAMAGE.
35: *
36: * @(#)cd9660_node.c 8.8 (Berkeley) 5/22/95
37: */
38:
39: #include <sys/cdefs.h>
1.23 ! matt 40: __KERNEL_RCSID(0, "$NetBSD: cd9660_node.c,v 1.22 2008/01/30 09:50:19 ad Exp $");
1.1 jdolecek 41:
42: #include <sys/param.h>
43: #include <sys/systm.h>
44: #include <sys/mount.h>
45: #include <sys/proc.h>
46: #include <sys/file.h>
47: #include <sys/buf.h>
48: #include <sys/vnode.h>
49: #include <sys/namei.h>
50: #include <sys/kernel.h>
51: #include <sys/malloc.h>
52: #include <sys/pool.h>
53: #include <sys/stat.h>
54:
55: #include <fs/cd9660/iso.h>
56: #include <fs/cd9660/cd9660_extern.h>
57: #include <fs/cd9660/cd9660_node.h>
58: #include <fs/cd9660/cd9660_mount.h>
59: #include <fs/cd9660/iso_rrip.h>
60:
61: /*
62: * Structures associated with iso_node caching.
63: */
64: LIST_HEAD(ihashhead, iso_node) *isohashtbl;
65: u_long isohash;
66: #define INOHASH(device, inum) (((device) + ((inum)>>12)) & isohash)
1.19 ad 67: kmutex_t cd9660_ihash_lock;
68: kmutex_t cd9660_hashlock;
1.1 jdolecek 69:
70: extern int prtactive; /* 1 => print out reclaim of active vnodes */
71:
1.16 pooka 72: struct pool cd9660_node_pool;
1.1 jdolecek 73:
1.23 ! matt 74: static u_int cd9660_chars2ui(const u_char *, int);
1.1 jdolecek 75:
76: /*
77: * Initialize hash links for inodes and dnodes.
78: */
79: void
1.23 ! matt 80: cd9660_init(void)
1.1 jdolecek 81: {
1.16 pooka 82:
1.6 atatat 83: malloc_type_attach(M_ISOFSMNT);
1.8 atatat 84: pool_init(&cd9660_node_pool, sizeof(struct iso_node), 0, 0, 0,
1.15 ad 85: "cd9660nopl", &pool_allocator_nointr, IPL_NONE);
1.1 jdolecek 86: isohashtbl = hashinit(desiredvnodes, HASH_LIST, M_ISOFSMNT, M_WAITOK,
87: &isohash);
1.19 ad 88: mutex_init(&cd9660_ihash_lock, MUTEX_DEFAULT, IPL_NONE);
89: mutex_init(&cd9660_hashlock, MUTEX_DEFAULT, IPL_NONE);
1.1 jdolecek 90: }
91:
92: /*
93: * Reinitialize inode hash table.
94: */
95:
96: void
1.23 ! matt 97: cd9660_reinit(void)
1.1 jdolecek 98: {
99: struct iso_node *ip;
100: struct ihashhead *oldhash1, *hash1;
101: u_long oldmask1, mask1, val;
102: u_int i;
103:
104: hash1 = hashinit(desiredvnodes, HASH_LIST, M_ISOFSMNT, M_WAITOK,
105: &mask1);
106:
1.19 ad 107: mutex_enter(&cd9660_ihash_lock);
1.1 jdolecek 108: oldhash1 = isohashtbl;
109: oldmask1 = isohash;
110: isohashtbl = hash1;
111: isohash = mask1;
112: for (i = 0; i <= oldmask1; i++) {
113: while ((ip = LIST_FIRST(&oldhash1[i])) != NULL) {
114: LIST_REMOVE(ip, i_hash);
115: val = INOHASH(ip->i_dev, ip->i_number);
116: LIST_INSERT_HEAD(&hash1[val], ip, i_hash);
117: }
118: }
1.19 ad 119: mutex_exit(&cd9660_ihash_lock);
1.1 jdolecek 120: hashdone(oldhash1, M_ISOFSMNT);
121: }
122:
123: /*
124: * Destroy node pool and hash table.
125: */
126: void
1.23 ! matt 127: cd9660_done(void)
1.1 jdolecek 128: {
129: hashdone(isohashtbl, M_ISOFSMNT);
130: pool_destroy(&cd9660_node_pool);
1.19 ad 131: mutex_destroy(&cd9660_ihash_lock);
132: mutex_destroy(&cd9660_hashlock);
1.6 atatat 133: malloc_type_detach(M_ISOFSMNT);
1.1 jdolecek 134: }
135:
136: /*
137: * Use the device/inum pair to find the incore inode, and return a pointer
138: * to it. If it is in core, but locked, wait for it.
139: */
140: struct vnode *
1.23 ! matt 141: cd9660_ihashget(dev_t dev, ino_t inum, int flags)
1.1 jdolecek 142: {
143: struct iso_node *ip;
144: struct vnode *vp;
145:
146: loop:
1.19 ad 147: mutex_enter(&cd9660_ihash_lock);
1.1 jdolecek 148: LIST_FOREACH(ip, &isohashtbl[INOHASH(dev, inum)], i_hash) {
149: if (inum == ip->i_number && dev == ip->i_dev) {
150: vp = ITOV(ip);
1.19 ad 151: if (flags == 0) {
152: mutex_exit(&cd9660_ihash_lock);
153: } else {
1.20 ad 154: mutex_enter(&vp->v_interlock);
1.19 ad 155: mutex_exit(&cd9660_ihash_lock);
156: if (vget(vp, flags | LK_INTERLOCK))
157: goto loop;
158: }
1.1 jdolecek 159: return (vp);
160: }
161: }
1.19 ad 162: mutex_exit(&cd9660_ihash_lock);
1.1 jdolecek 163: return (NULL);
164: }
165:
166: /*
167: * Insert the inode into the hash table, and return it locked.
168: *
169: * ip->i_vnode must be initialized first.
170: */
171: void
1.23 ! matt 172: cd9660_ihashins(struct iso_node *ip)
1.1 jdolecek 173: {
174: struct ihashhead *ipp;
175:
1.19 ad 176: KASSERT(mutex_owned(&cd9660_hashlock));
177:
178: mutex_enter(&cd9660_ihash_lock);
1.1 jdolecek 179: ipp = &isohashtbl[INOHASH(ip->i_dev, ip->i_number)];
180: LIST_INSERT_HEAD(ipp, ip, i_hash);
1.19 ad 181: mutex_exit(&cd9660_ihash_lock);
1.1 jdolecek 182:
1.22 ad 183: vlockmgr(&ip->i_vnode->v_lock, LK_EXCLUSIVE);
1.1 jdolecek 184: }
185:
186: /*
187: * Remove the inode from the hash table.
188: */
189: void
1.23 ! matt 190: cd9660_ihashrem(struct iso_node *ip)
1.1 jdolecek 191: {
1.19 ad 192: mutex_enter(&cd9660_ihash_lock);
1.1 jdolecek 193: LIST_REMOVE(ip, i_hash);
1.19 ad 194: mutex_exit(&cd9660_ihash_lock);
1.1 jdolecek 195: }
196:
197: /*
198: * Last reference to an inode, write the inode out and if necessary,
199: * truncate and deallocate the file.
200: */
201: int
1.23 ! matt 202: cd9660_inactive(void *v)
1.1 jdolecek 203: {
204: struct vop_inactive_args /* {
205: struct vnode *a_vp;
1.20 ad 206: bool *a_recycle;
1.1 jdolecek 207: } */ *ap = v;
208: struct vnode *vp = ap->a_vp;
209: struct iso_node *ip = VTOI(vp);
210: int error = 0;
1.9 perry 211:
1.1 jdolecek 212: /*
213: * If we are done with the inode, reclaim it
214: * so that it can be reused immediately.
215: */
1.20 ad 216: ip->i_flag = 0;
217: *ap->a_recycle = (ip->inode.iso_mode == 0);
218: VOP_UNLOCK(vp, 0);
1.1 jdolecek 219: return error;
220: }
221:
222: /*
223: * Reclaim an inode so that it can be used for other purposes.
224: */
225: int
1.23 ! matt 226: cd9660_reclaim(void *v)
1.1 jdolecek 227: {
228: struct vop_reclaim_args /* {
229: struct vnode *a_vp;
1.13 christos 230: struct lwp *a_l;
1.1 jdolecek 231: } */ *ap = v;
232: struct vnode *vp = ap->a_vp;
233: struct iso_node *ip = VTOI(vp);
1.9 perry 234:
1.21 ad 235: if (prtactive && vp->v_usecount > 1)
1.1 jdolecek 236: vprint("cd9660_reclaim: pushing active", vp);
237: /*
238: * Remove the inode from its hash chain.
239: */
240: cd9660_ihashrem(ip);
241: /*
242: * Purge old data structures associated with the inode.
243: */
244: cache_purge(vp);
245: if (ip->i_devvp) {
246: vrele(ip->i_devvp);
247: ip->i_devvp = 0;
248: }
1.14 ad 249: genfs_node_destroy(vp);
1.1 jdolecek 250: pool_put(&cd9660_node_pool, vp->v_data);
251: vp->v_data = NULL;
252: return (0);
253: }
254:
255: /*
256: * File attributes
257: */
258: void
1.23 ! matt 259: cd9660_defattr(struct iso_directory_record *isodir, struct iso_node *inop,
! 260: struct buf *bp)
1.1 jdolecek 261: {
262: struct buf *bp2 = NULL;
263: struct iso_mnt *imp;
264: struct iso_extended_attributes *ap = NULL;
265: int off;
1.9 perry 266:
1.1 jdolecek 267: if (isonum_711(isodir->flags)&2) {
268: inop->inode.iso_mode = S_IFDIR;
269: /*
270: * If we return 2, fts() will assume there are no subdirectories
271: * (just links for the path and .), so instead we return 1.
272: */
273: inop->inode.iso_links = 1;
274: } else {
275: inop->inode.iso_mode = S_IFREG;
276: inop->inode.iso_links = 1;
277: }
278: if (!bp
279: && ((imp = inop->i_mnt)->im_flags & ISOFSMNT_EXTATT)
280: && (off = isonum_711(isodir->ext_attr_length))) {
1.12 yamt 281: cd9660_blkatoff(ITOV(inop), (off_t)-(off << imp->im_bshift),
282: NULL, &bp2);
1.1 jdolecek 283: bp = bp2;
284: }
285: if (bp) {
286: ap = (struct iso_extended_attributes *)bp->b_data;
1.9 perry 287:
1.1 jdolecek 288: if (isonum_711(ap->version) == 1) {
289: if (!(ap->perm[1]&0x10))
290: inop->inode.iso_mode |= S_IRUSR;
291: if (!(ap->perm[1]&0x40))
292: inop->inode.iso_mode |= S_IXUSR;
293: if (!(ap->perm[0]&0x01))
294: inop->inode.iso_mode |= S_IRGRP;
295: if (!(ap->perm[0]&0x04))
296: inop->inode.iso_mode |= S_IXGRP;
297: if (!(ap->perm[0]&0x10))
298: inop->inode.iso_mode |= S_IROTH;
299: if (!(ap->perm[0]&0x40))
300: inop->inode.iso_mode |= S_IXOTH;
301: inop->inode.iso_uid = isonum_723(ap->owner); /* what about 0? */
302: inop->inode.iso_gid = isonum_723(ap->group); /* what about 0? */
303: } else
304: ap = NULL;
305: }
306: if (!ap) {
307: inop->inode.iso_mode |=
308: S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
309: inop->inode.iso_uid = (uid_t)0;
310: inop->inode.iso_gid = (gid_t)0;
311: }
312: if (bp2)
1.17 ad 313: brelse(bp2, 0);
1.1 jdolecek 314: }
315:
316: /*
317: * Time stamps
318: */
319: void
1.23 ! matt 320: cd9660_deftstamp(struct iso_directory_record *isodir, struct iso_node *inop,
! 321: struct buf *bp)
1.1 jdolecek 322: {
323: struct buf *bp2 = NULL;
324: struct iso_mnt *imp;
325: struct iso_extended_attributes *ap = NULL;
326: int off;
1.9 perry 327:
1.1 jdolecek 328: if (!bp
329: && ((imp = inop->i_mnt)->im_flags & ISOFSMNT_EXTATT)
330: && (off = isonum_711(isodir->ext_attr_length))) {
1.12 yamt 331: cd9660_blkatoff(ITOV(inop), (off_t)-(off << imp->im_bshift),
332: NULL, &bp2);
1.1 jdolecek 333: bp = bp2;
334: }
335: if (bp) {
336: ap = (struct iso_extended_attributes *)bp->b_data;
1.9 perry 337:
1.1 jdolecek 338: if (isonum_711(ap->version) == 1) {
339: if (!cd9660_tstamp_conv17(ap->ftime,&inop->inode.iso_atime))
340: cd9660_tstamp_conv17(ap->ctime,&inop->inode.iso_atime);
341: if (!cd9660_tstamp_conv17(ap->ctime,&inop->inode.iso_ctime))
342: inop->inode.iso_ctime = inop->inode.iso_atime;
343: if (!cd9660_tstamp_conv17(ap->mtime,&inop->inode.iso_mtime))
344: inop->inode.iso_mtime = inop->inode.iso_ctime;
345: } else
346: ap = NULL;
347: }
348: if (!ap) {
349: cd9660_tstamp_conv7(isodir->date,&inop->inode.iso_ctime);
350: inop->inode.iso_atime = inop->inode.iso_ctime;
351: inop->inode.iso_mtime = inop->inode.iso_ctime;
352: }
353: if (bp2)
1.17 ad 354: brelse(bp2, 0);
1.1 jdolecek 355: }
356:
357: int
1.23 ! matt 358: cd9660_tstamp_conv7(const u_char *pi, struct timespec *pu)
1.1 jdolecek 359: {
360: int crtime, days;
361: int y, m, d, hour, minute, second, tz;
1.9 perry 362:
1.1 jdolecek 363: y = pi[0] + 1900;
364: m = pi[1];
365: d = pi[2];
366: hour = pi[3];
367: minute = pi[4];
368: second = pi[5];
369: tz = pi[6];
1.9 perry 370:
1.1 jdolecek 371: if (y < 1970) {
372: pu->tv_sec = 0;
373: pu->tv_nsec = 0;
374: return 0;
375: } else {
376: #ifdef ORIGINAL
377: /* computes day number relative to Sept. 19th,1989 */
378: /* don't even *THINK* about changing formula. It works! */
379: days = 367*(y-1980)-7*(y+(m+9)/12)/4-3*((y+(m-9)/7)/100+1)/4+275*m/9+d-100;
380: #else
381: /*
382: * Changed :-) to make it relative to Jan. 1st, 1970
383: * and to disambiguate negative division
384: */
385: days = 367*(y-1960)-7*(y+(m+9)/12)/4-3*((y+(m+9)/12-1)/100+1)/4+275*m/9+d-239;
386: #endif
387: crtime = ((((days * 24) + hour) * 60 + minute) * 60) + second;
1.9 perry 388:
1.1 jdolecek 389: /* timezone offset is unreliable on some disks */
390: if (-48 <= tz && tz <= 52)
391: crtime -= tz * 15 * 60;
392: }
393: pu->tv_sec = crtime;
394: pu->tv_nsec = 0;
395: return 1;
396: }
397:
398: static u_int
1.23 ! matt 399: cd9660_chars2ui(const u_char *begin, int len)
1.1 jdolecek 400: {
401: u_int rc;
1.9 perry 402:
1.1 jdolecek 403: for (rc = 0; --len >= 0;) {
404: rc *= 10;
405: rc += *begin++ - '0';
406: }
407: return rc;
408: }
409:
410: int
1.23 ! matt 411: cd9660_tstamp_conv17(const u_char *pi, struct timespec *pu)
1.1 jdolecek 412: {
1.10 christos 413: u_char tbuf[7];
1.9 perry 414:
1.1 jdolecek 415: /* year:"0001"-"9999" -> -1900 */
1.10 christos 416: tbuf[0] = cd9660_chars2ui(pi,4) - 1900;
1.9 perry 417:
1.1 jdolecek 418: /* month: " 1"-"12" -> 1 - 12 */
1.10 christos 419: tbuf[1] = cd9660_chars2ui(pi + 4,2);
1.9 perry 420:
1.1 jdolecek 421: /* day: " 1"-"31" -> 1 - 31 */
1.10 christos 422: tbuf[2] = cd9660_chars2ui(pi + 6,2);
1.9 perry 423:
1.1 jdolecek 424: /* hour: " 0"-"23" -> 0 - 23 */
1.10 christos 425: tbuf[3] = cd9660_chars2ui(pi + 8,2);
1.9 perry 426:
1.1 jdolecek 427: /* minute:" 0"-"59" -> 0 - 59 */
1.10 christos 428: tbuf[4] = cd9660_chars2ui(pi + 10,2);
1.9 perry 429:
1.1 jdolecek 430: /* second:" 0"-"59" -> 0 - 59 */
1.10 christos 431: tbuf[5] = cd9660_chars2ui(pi + 12,2);
1.9 perry 432:
1.1 jdolecek 433: /* difference of GMT */
1.10 christos 434: tbuf[6] = pi[16];
1.9 perry 435:
1.10 christos 436: return cd9660_tstamp_conv7(tbuf,pu);
1.1 jdolecek 437: }
438:
439: ino_t
1.23 ! matt 440: isodirino(struct iso_directory_record *isodir, struct iso_mnt *imp)
1.1 jdolecek 441: {
442: ino_t ino;
443:
444: ino = (isonum_733(isodir->extent) + isonum_711(isodir->ext_attr_length))
445: << imp->im_bshift;
446: return (ino);
447: }
CVSweb <webmaster@jp.NetBSD.org>