Deleted Added
full compact
cd9660_node.c (6603) cd9660_node.c (7090)
1/*-
2 * Copyright (c) 1982, 1986, 1989, 1994
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley
6 * by Pace Willisson (pace@blitz.com). The Rock Ridge Extension
7 * Support code is derived from software contributed to Berkeley
8 * by Atsushi Murai (amurai@spec.co.jp).
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 *
38 * @(#)cd9660_node.c 8.2 (Berkeley) 1/23/94
1/*-
2 * Copyright (c) 1982, 1986, 1989, 1994
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley
6 * by Pace Willisson (pace@blitz.com). The Rock Ridge Extension
7 * Support code is derived from software contributed to Berkeley
8 * by Atsushi Murai (amurai@spec.co.jp).
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 *
38 * @(#)cd9660_node.c 8.2 (Berkeley) 1/23/94
39 * $Id: cd9660_node.c,v 1.8 1995/01/16 17:03:24 joerg Exp $
39 * $Id: cd9660_node.c,v 1.9 1995/02/21 18:41:30 bde Exp $
40 */
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/kernel.h>
50#include <sys/malloc.h>
51#include <sys/stat.h>
52
53#include <isofs/cd9660/iso.h>
54#include <isofs/cd9660/cd9660_node.h>
55#include <isofs/cd9660/iso_rrip.h>
56
57#define INOHSZ 512
58#if ((INOHSZ&(INOHSZ-1)) == 0)
59#define INOHASH(dev,ino) (((dev)+((ino)>>12))&(INOHSZ-1))
60#else
61#define INOHASH(dev,ino) (((unsigned)((dev)+((ino)>>12)))%INOHSZ)
62#endif
63
64union iso_ihead {
65 union iso_ihead *ih_head[2];
66 struct iso_node *ih_chain[2];
67} iso_ihead[INOHSZ];
68
69#ifdef ISODEVMAP
70#define DNOHSZ 64
71#if ((DNOHSZ&(DNOHSZ-1)) == 0)
72#define DNOHASH(dev,ino) (((dev)+((ino)>>12))&(DNOHSZ-1))
73#else
74#define DNOHASH(dev,ino) (((unsigned)((dev)+((ino)>>12)))%DNOHSZ)
75#endif
76
77union iso_dhead {
78 union iso_dhead *dh_head[2];
79 struct iso_dnode *dh_chain[2];
80} iso_dhead[DNOHSZ];
81#endif
82
40 */
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/kernel.h>
50#include <sys/malloc.h>
51#include <sys/stat.h>
52
53#include <isofs/cd9660/iso.h>
54#include <isofs/cd9660/cd9660_node.h>
55#include <isofs/cd9660/iso_rrip.h>
56
57#define INOHSZ 512
58#if ((INOHSZ&(INOHSZ-1)) == 0)
59#define INOHASH(dev,ino) (((dev)+((ino)>>12))&(INOHSZ-1))
60#else
61#define INOHASH(dev,ino) (((unsigned)((dev)+((ino)>>12)))%INOHSZ)
62#endif
63
64union iso_ihead {
65 union iso_ihead *ih_head[2];
66 struct iso_node *ih_chain[2];
67} iso_ihead[INOHSZ];
68
69#ifdef ISODEVMAP
70#define DNOHSZ 64
71#if ((DNOHSZ&(DNOHSZ-1)) == 0)
72#define DNOHASH(dev,ino) (((dev)+((ino)>>12))&(DNOHSZ-1))
73#else
74#define DNOHASH(dev,ino) (((unsigned)((dev)+((ino)>>12)))%DNOHSZ)
75#endif
76
77union iso_dhead {
78 union iso_dhead *dh_head[2];
79 struct iso_dnode *dh_chain[2];
80} iso_dhead[DNOHSZ];
81#endif
82
83int prtactive; /* 1 => print out reclaim of active vnodes */
84
85/*
86 * Initialize hash links for inodes and dnodes.
87 */
88int
89cd9660_init()
90{
91 register int i;
92 register union iso_ihead *ih = iso_ihead;
93#ifdef ISODEVMAP
94 register union iso_dhead *dh = iso_dhead;
95#endif
96
97 for (i = INOHSZ; --i >= 0; ih++) {
98 ih->ih_head[0] = ih;
99 ih->ih_head[1] = ih;
100 }
101#ifdef ISODEVMAP
102 for (i = DNOHSZ; --i >= 0; dh++) {
103 dh->dh_head[0] = dh;
104 dh->dh_head[1] = dh;
105 }
106#endif
107 return (0);
108}
109
110#ifdef ISODEVMAP
111/*
112 * Enter a new node into the device hash list
113 */
114struct iso_dnode *
115iso_dmap(dev,ino,create)
116 dev_t dev;
117 ino_t ino;
118 int create;
119{
120 struct iso_dnode *dp;
121 union iso_dhead *dh;
122
123 dh = &iso_dhead[DNOHASH(dev, ino)];
124 for (dp = dh->dh_chain[0];
125 dp != (struct iso_dnode *)dh;
126 dp = dp->d_forw)
127 if (ino == dp->i_number && dev == dp->i_dev)
128 return dp;
129
130 if (!create)
131 return (struct iso_dnode *)0;
132
133 MALLOC(dp,struct iso_dnode *,sizeof(struct iso_dnode),M_CACHE,M_WAITOK);
134 dp->i_dev = dev;
135 dp->i_number = ino;
136 insque(dp,dh);
137
138 return dp;
139}
140
141void
142iso_dunmap(dev)
143 dev_t dev;
144{
145 struct iso_dnode *dp, *dq;
146 union iso_dhead *dh;
147
148 for (dh = iso_dhead; dh < iso_dhead + DNOHSZ; dh++) {
149 for (dp = dh->dh_chain[0];
150 dp != (struct iso_dnode *)dh;
151 dp = dq) {
152 dq = dp->d_forw;
153 if (dev == dp->i_dev) {
154 remque(dp);
155 FREE(dp,M_CACHE);
156 }
157 }
158 }
159}
160#endif
161
162/*
163 * Look up a ISOFS dinode number to find its incore vnode.
164 * If it is not in core, read it in from the specified device.
165 * If it is in core, wait for the lock bit to clear, then
166 * return the inode locked. Detection and handling of mount
167 * points must be done by the calling routine.
168 */
169int
170iso_iget(xp, ino, relocated, ipp, isodir)
171 struct iso_node *xp;
172 ino_t ino;
173 int relocated;
174 struct iso_node **ipp;
175 struct iso_directory_record *isodir;
176{
177 dev_t dev = xp->i_dev;
178 struct mount *mntp = ITOV(xp)->v_mount;
179 register struct iso_node *ip, *iq;
180 register struct vnode *vp;
181#ifdef ISODEVMAP
182 register struct iso_dnode *dp;
183#endif
184 struct vnode *nvp;
185 struct buf *bp = NULL, *bp2 = NULL;
186 union iso_ihead *ih;
187 int error, result;
188 struct iso_mnt *imp;
189
190 ih = &iso_ihead[INOHASH(dev, ino)];
191loop:
192 for (ip = ih->ih_chain[0];
193 ip != (struct iso_node *)ih;
194 ip = ip->i_forw) {
195 if (ino != ip->i_number || dev != ip->i_dev)
196 continue;
197 if ((ip->i_flag&ILOCKED) != 0) {
198 ip->i_flag |= IWANT;
199 (void) tsleep((caddr_t)ip, PINOD, "isoigt", 0);
200 goto loop;
201 }
202 if (vget(ITOV(ip), 1))
203 goto loop;
204 *ipp = ip;
205 return 0;
206 }
207 /*
208 * Allocate a new vnode/iso_node.
209 */
210 if ((error = getnewvnode(VT_ISOFS, mntp, cd9660_vnodeop_p, &nvp))) {
211 *ipp = 0;
212 return error;
213 }
214 MALLOC(ip, struct iso_node *, sizeof(struct iso_node),
215 M_ISOFSNODE, M_WAITOK);
216 bzero((caddr_t)ip, sizeof(struct iso_node));
217 nvp->v_data = ip;
218 ip->i_vnode = nvp;
219 ip->i_flag = 0;
220 ip->i_devvp = 0;
221 ip->i_diroff = 0;
222 ip->i_lockf = 0;
223
224 /*
225 * Put it onto its hash chain and lock it so that other requests for
226 * this inode will block if they arrive while we are sleeping waiting
227 * for old data structures to be purged or for the contents of the
228 * disk portion of this inode to be read.
229 */
230 ip->i_dev = dev;
231 ip->i_number = ino;
232 insque(ip, ih);
233 ISO_ILOCK(ip);
234
235 imp = VFSTOISOFS (mntp);
236 ip->i_mnt = imp;
237 ip->i_devvp = imp->im_devvp;
238 VREF(ip->i_devvp);
239
240 if (relocated) {
241 /*
242 * On relocated directories we must
243 * read the `.' entry out of a dir.
244 */
245 ip->iso_start = ino >> imp->im_bshift;
246 if ((error = iso_blkatoff(ip,0,&bp))) {
247 vrele(ip->i_devvp);
248 remque(ip);
249 ip->i_forw = ip;
250 ip->i_back = ip;
251 iso_iput(ip);
252 *ipp = 0;
253 return error;
254 }
255 isodir = (struct iso_directory_record *)bp->b_un.b_addr;
256 }
257
258 ip->iso_extent = isonum_733(isodir->extent);
259 ip->i_size = isonum_733(isodir->size);
260 ip->iso_start = isonum_711(isodir->ext_attr_length) + ip->iso_extent;
261
262 vp = ITOV(ip);
263
264 /*
265 * Setup time stamp, attribute
266 */
267 vp->v_type = VNON;
268 switch (imp->iso_ftype) {
269 default: /* ISO_FTYPE_9660 || ISO_FTYPE_HIGH_SIERRA */
270 if ((imp->im_flags&ISOFSMNT_EXTATT)
271 && isonum_711(isodir->ext_attr_length))
272 iso_blkatoff(ip,-isonum_711(isodir->ext_attr_length),
273 &bp2);
274 cd9660_defattr(isodir,ip,bp2,imp->iso_ftype );
275 cd9660_deftstamp(isodir,ip,bp2,imp->iso_ftype );
276 break;
277 case ISO_FTYPE_RRIP:
278 result = cd9660_rrip_analyze(isodir,ip,imp);
279 break;
280 }
281 if (bp2)
282 brelse(bp2);
283 if (bp)
284 brelse(bp);
285
286 /*
287 * Initialize the associated vnode
288 */
289 vp->v_type = IFTOVT(ip->inode.iso_mode);
290
291 if ( vp->v_type == VFIFO ) {
83/*
84 * Initialize hash links for inodes and dnodes.
85 */
86int
87cd9660_init()
88{
89 register int i;
90 register union iso_ihead *ih = iso_ihead;
91#ifdef ISODEVMAP
92 register union iso_dhead *dh = iso_dhead;
93#endif
94
95 for (i = INOHSZ; --i >= 0; ih++) {
96 ih->ih_head[0] = ih;
97 ih->ih_head[1] = ih;
98 }
99#ifdef ISODEVMAP
100 for (i = DNOHSZ; --i >= 0; dh++) {
101 dh->dh_head[0] = dh;
102 dh->dh_head[1] = dh;
103 }
104#endif
105 return (0);
106}
107
108#ifdef ISODEVMAP
109/*
110 * Enter a new node into the device hash list
111 */
112struct iso_dnode *
113iso_dmap(dev,ino,create)
114 dev_t dev;
115 ino_t ino;
116 int create;
117{
118 struct iso_dnode *dp;
119 union iso_dhead *dh;
120
121 dh = &iso_dhead[DNOHASH(dev, ino)];
122 for (dp = dh->dh_chain[0];
123 dp != (struct iso_dnode *)dh;
124 dp = dp->d_forw)
125 if (ino == dp->i_number && dev == dp->i_dev)
126 return dp;
127
128 if (!create)
129 return (struct iso_dnode *)0;
130
131 MALLOC(dp,struct iso_dnode *,sizeof(struct iso_dnode),M_CACHE,M_WAITOK);
132 dp->i_dev = dev;
133 dp->i_number = ino;
134 insque(dp,dh);
135
136 return dp;
137}
138
139void
140iso_dunmap(dev)
141 dev_t dev;
142{
143 struct iso_dnode *dp, *dq;
144 union iso_dhead *dh;
145
146 for (dh = iso_dhead; dh < iso_dhead + DNOHSZ; dh++) {
147 for (dp = dh->dh_chain[0];
148 dp != (struct iso_dnode *)dh;
149 dp = dq) {
150 dq = dp->d_forw;
151 if (dev == dp->i_dev) {
152 remque(dp);
153 FREE(dp,M_CACHE);
154 }
155 }
156 }
157}
158#endif
159
160/*
161 * Look up a ISOFS dinode number to find its incore vnode.
162 * If it is not in core, read it in from the specified device.
163 * If it is in core, wait for the lock bit to clear, then
164 * return the inode locked. Detection and handling of mount
165 * points must be done by the calling routine.
166 */
167int
168iso_iget(xp, ino, relocated, ipp, isodir)
169 struct iso_node *xp;
170 ino_t ino;
171 int relocated;
172 struct iso_node **ipp;
173 struct iso_directory_record *isodir;
174{
175 dev_t dev = xp->i_dev;
176 struct mount *mntp = ITOV(xp)->v_mount;
177 register struct iso_node *ip, *iq;
178 register struct vnode *vp;
179#ifdef ISODEVMAP
180 register struct iso_dnode *dp;
181#endif
182 struct vnode *nvp;
183 struct buf *bp = NULL, *bp2 = NULL;
184 union iso_ihead *ih;
185 int error, result;
186 struct iso_mnt *imp;
187
188 ih = &iso_ihead[INOHASH(dev, ino)];
189loop:
190 for (ip = ih->ih_chain[0];
191 ip != (struct iso_node *)ih;
192 ip = ip->i_forw) {
193 if (ino != ip->i_number || dev != ip->i_dev)
194 continue;
195 if ((ip->i_flag&ILOCKED) != 0) {
196 ip->i_flag |= IWANT;
197 (void) tsleep((caddr_t)ip, PINOD, "isoigt", 0);
198 goto loop;
199 }
200 if (vget(ITOV(ip), 1))
201 goto loop;
202 *ipp = ip;
203 return 0;
204 }
205 /*
206 * Allocate a new vnode/iso_node.
207 */
208 if ((error = getnewvnode(VT_ISOFS, mntp, cd9660_vnodeop_p, &nvp))) {
209 *ipp = 0;
210 return error;
211 }
212 MALLOC(ip, struct iso_node *, sizeof(struct iso_node),
213 M_ISOFSNODE, M_WAITOK);
214 bzero((caddr_t)ip, sizeof(struct iso_node));
215 nvp->v_data = ip;
216 ip->i_vnode = nvp;
217 ip->i_flag = 0;
218 ip->i_devvp = 0;
219 ip->i_diroff = 0;
220 ip->i_lockf = 0;
221
222 /*
223 * Put it onto its hash chain and lock it so that other requests for
224 * this inode will block if they arrive while we are sleeping waiting
225 * for old data structures to be purged or for the contents of the
226 * disk portion of this inode to be read.
227 */
228 ip->i_dev = dev;
229 ip->i_number = ino;
230 insque(ip, ih);
231 ISO_ILOCK(ip);
232
233 imp = VFSTOISOFS (mntp);
234 ip->i_mnt = imp;
235 ip->i_devvp = imp->im_devvp;
236 VREF(ip->i_devvp);
237
238 if (relocated) {
239 /*
240 * On relocated directories we must
241 * read the `.' entry out of a dir.
242 */
243 ip->iso_start = ino >> imp->im_bshift;
244 if ((error = iso_blkatoff(ip,0,&bp))) {
245 vrele(ip->i_devvp);
246 remque(ip);
247 ip->i_forw = ip;
248 ip->i_back = ip;
249 iso_iput(ip);
250 *ipp = 0;
251 return error;
252 }
253 isodir = (struct iso_directory_record *)bp->b_un.b_addr;
254 }
255
256 ip->iso_extent = isonum_733(isodir->extent);
257 ip->i_size = isonum_733(isodir->size);
258 ip->iso_start = isonum_711(isodir->ext_attr_length) + ip->iso_extent;
259
260 vp = ITOV(ip);
261
262 /*
263 * Setup time stamp, attribute
264 */
265 vp->v_type = VNON;
266 switch (imp->iso_ftype) {
267 default: /* ISO_FTYPE_9660 || ISO_FTYPE_HIGH_SIERRA */
268 if ((imp->im_flags&ISOFSMNT_EXTATT)
269 && isonum_711(isodir->ext_attr_length))
270 iso_blkatoff(ip,-isonum_711(isodir->ext_attr_length),
271 &bp2);
272 cd9660_defattr(isodir,ip,bp2,imp->iso_ftype );
273 cd9660_deftstamp(isodir,ip,bp2,imp->iso_ftype );
274 break;
275 case ISO_FTYPE_RRIP:
276 result = cd9660_rrip_analyze(isodir,ip,imp);
277 break;
278 }
279 if (bp2)
280 brelse(bp2);
281 if (bp)
282 brelse(bp);
283
284 /*
285 * Initialize the associated vnode
286 */
287 vp->v_type = IFTOVT(ip->inode.iso_mode);
288
289 if ( vp->v_type == VFIFO ) {
292 extern int (**cd9660_fifoop_p)();
293 vp->v_op = cd9660_fifoop_p;
294 } else if ( vp->v_type == VCHR || vp->v_type == VBLK ) {
290 vp->v_op = cd9660_fifoop_p;
291 } else if ( vp->v_type == VCHR || vp->v_type == VBLK ) {
295 extern int (**cd9660_specop_p)();
296
297 /*
298 * if device, look at device number table for translation
299 */
300#ifdef ISODEVMAP
301 if (dp = iso_dmap(dev,ino,0))
302 ip->inode.iso_rdev = dp->d_dev;
303#endif
304 vp->v_op = cd9660_specop_p;
305 if ((nvp = checkalias(vp, ip->inode.iso_rdev, mntp))) {
306 /*
307 * Reinitialize aliased inode.
308 */
309 vp = nvp;
310 iq = VTOI(vp);
311 iq->i_vnode = vp;
312 iq->i_flag = 0;
313 ISO_ILOCK(iq);
314 iq->i_dev = dev;
315 iq->i_number = ino;
316 iq->i_mnt = ip->i_mnt;
317 bcopy(&ip->iso_extent,&iq->iso_extent,
318 (char *)(ip + 1) - (char *)&ip->iso_extent);
319 insque(iq, ih);
320 /*
321 * Discard unneeded vnode
322 * (This introduces the need of INACTIVE modification)
323 */
324 ip->inode.iso_mode = 0;
325 iso_iput(ip);
326 ip = iq;
327 }
328 }
329
330 if (ip->iso_extent == imp->root_extent)
331 vp->v_flag |= VROOT;
332
333 *ipp = ip;
334 return 0;
335}
336
337/*
338 * Unlock and decrement the reference count of an inode structure.
339 */
340int
341iso_iput(ip)
342 register struct iso_node *ip;
343{
344
345 if ((ip->i_flag & ILOCKED) == 0)
346 panic("iso_iput");
347 ISO_IUNLOCK(ip);
348 vrele(ITOV(ip));
349 return (0);
350}
351
352/*
353 * Last reference to an inode, write the inode out and if necessary,
354 * truncate and deallocate the file.
355 */
356int
357cd9660_inactive(ap)
358 struct vop_inactive_args /* {
359 struct vnode *a_vp;
360 } */ *ap;
361{
362 struct vnode *vp = ap->a_vp;
363 register struct iso_node *ip = VTOI(vp);
364 int error = 0;
365
366 if (prtactive && vp->v_usecount != 0)
367 vprint("cd9660_inactive: pushing active", vp);
368
369 ip->i_flag = 0;
370 /*
371 * If we are done with the inode, reclaim it
372 * so that it can be reused immediately.
373 */
374 if (vp->v_usecount == 0 && ip->inode.iso_mode == 0)
375 vgone(vp);
376 return error;
377}
378
379/*
380 * Reclaim an inode so that it can be used for other purposes.
381 */
382int
383cd9660_reclaim(ap)
384 struct vop_reclaim_args /* {
385 struct vnode *a_vp;
386 } */ *ap;
387{
388 register struct vnode *vp = ap->a_vp;
389 register struct iso_node *ip = VTOI(vp);
390
391 if (prtactive && vp->v_usecount != 0)
392 vprint("cd9660_reclaim: pushing active", vp);
393 /*
394 * Remove the inode from its hash chain.
395 */
396 remque(ip);
397 ip->i_forw = ip;
398 ip->i_back = ip;
399 /*
400 * Purge old data structures associated with the inode.
401 */
402 cache_purge(vp);
403 if (ip->i_devvp) {
404 vrele(ip->i_devvp);
405 ip->i_devvp = 0;
406 }
407 FREE(vp->v_data, M_ISOFSNODE);
408 vp->v_data = NULL;
409 return 0;
410}
411
412/*
413 * Lock an inode. If its already locked, set the WANT bit and sleep.
414 */
415int
416iso_ilock(ip)
417 register struct iso_node *ip;
418{
419
420 while (ip->i_flag & ILOCKED) {
421 ip->i_flag |= IWANT;
422 if (ip->i_spare0 == curproc->p_pid)
423 panic("locking against myself");
424 ip->i_spare1 = curproc->p_pid;
425 (void) tsleep((caddr_t)ip, PINOD, "isoilk", 0);
426 }
427 ip->i_spare1 = 0;
428 ip->i_spare0 = curproc->p_pid;
429 ip->i_flag |= ILOCKED;
430 return (0);
431}
432
433/*
434 * Unlock an inode. If WANT bit is on, wakeup.
435 */
436int
437iso_iunlock(ip)
438 register struct iso_node *ip;
439{
440
441 if ((ip->i_flag & ILOCKED) == 0)
442 vprint("iso_iunlock: unlocked inode", ITOV(ip));
443 ip->i_spare0 = 0;
444 ip->i_flag &= ~ILOCKED;
445 if (ip->i_flag&IWANT) {
446 ip->i_flag &= ~IWANT;
447 wakeup((caddr_t)ip);
448 }
449 return (0);
450}
451
452/*
453 * File attributes
454 */
455void
456cd9660_defattr(isodir,inop,bp,ftype)
457 struct iso_directory_record *isodir;
458 struct iso_node *inop;
459 struct buf *bp;
460 enum ISO_FTYPE ftype;
461{
462 struct buf *bp2 = NULL;
463 struct iso_mnt *imp;
464 struct iso_extended_attributes *ap = NULL;
465 int off;
466
467 /* high sierra does not have timezone data, flag is one byte ahead */
468 if (isonum_711(ftype == ISO_FTYPE_HIGH_SIERRA?
469 &isodir->date[6]: isodir->flags)&2) {
470 inop->inode.iso_mode = S_IFDIR;
471 /*
472 * If we return 2, fts() will assume there are no subdirectories
473 * (just links for the path and .), so instead we return 1.
474 */
475 inop->inode.iso_links = 1;
476 } else {
477 inop->inode.iso_mode = S_IFREG;
478 inop->inode.iso_links = 1;
479 }
480 if (!bp
481 && ((imp = inop->i_mnt)->im_flags&ISOFSMNT_EXTATT)
482 && (off = isonum_711(isodir->ext_attr_length))) {
483 iso_blkatoff(inop,-off * imp->logical_block_size,&bp2);
484 bp = bp2;
485 }
486 if (bp) {
487 ap = (struct iso_extended_attributes *)bp->b_un.b_addr;
488
489 if (isonum_711(ap->version) == 1) {
490 if (!(ap->perm[0]&0x40))
491 inop->inode.iso_mode |= VEXEC >> 6;
492 if (!(ap->perm[0]&0x10))
493 inop->inode.iso_mode |= VREAD >> 6;
494 if (!(ap->perm[0]&4))
495 inop->inode.iso_mode |= VEXEC >> 3;
496 if (!(ap->perm[0]&1))
497 inop->inode.iso_mode |= VREAD >> 3;
498 if (!(ap->perm[1]&0x40))
499 inop->inode.iso_mode |= VEXEC;
500 if (!(ap->perm[1]&0x10))
501 inop->inode.iso_mode |= VREAD;
502 inop->inode.iso_uid = isonum_723(ap->owner); /* what about 0? */
503 inop->inode.iso_gid = isonum_723(ap->group); /* what about 0? */
504 } else
505 ap = NULL;
506 }
507 if (!ap) {
508 inop->inode.iso_mode |= VREAD|VEXEC|(VREAD|VEXEC)>>3|(VREAD|VEXEC)>>6;
509 inop->inode.iso_uid = (uid_t)0;
510 inop->inode.iso_gid = (gid_t)0;
511 }
512 if (bp2)
513 brelse(bp2);
514}
515
516/*
517 * Time stamps
518 */
519void
520cd9660_deftstamp(isodir,inop,bp,ftype)
521 struct iso_directory_record *isodir;
522 struct iso_node *inop;
523 struct buf *bp;
524 enum ISO_FTYPE ftype;
525{
526 struct buf *bp2 = NULL;
527 struct iso_mnt *imp;
528 struct iso_extended_attributes *ap = NULL;
529 int off;
530
531 if (!bp
532 && ((imp = inop->i_mnt)->im_flags&ISOFSMNT_EXTATT)
533 && (off = isonum_711(isodir->ext_attr_length))) {
534 iso_blkatoff(inop,-off * imp->logical_block_size,&bp2);
535 bp = bp2;
536 }
537 if (bp) {
538 ap = (struct iso_extended_attributes *)bp->b_un.b_addr;
539
540 if (ftype != ISO_FTYPE_HIGH_SIERRA
541 && isonum_711(ap->version) == 1) {
542 if (!cd9660_tstamp_conv17(ap->ftime,&inop->inode.iso_atime))
543 cd9660_tstamp_conv17(ap->ctime,&inop->inode.iso_atime);
544 if (!cd9660_tstamp_conv17(ap->ctime,&inop->inode.iso_ctime))
545 inop->inode.iso_ctime = inop->inode.iso_atime;
546 if (!cd9660_tstamp_conv17(ap->mtime,&inop->inode.iso_mtime))
547 inop->inode.iso_mtime = inop->inode.iso_ctime;
548 } else
549 ap = NULL;
550 }
551 if (!ap) {
552 cd9660_tstamp_conv7(isodir->date,&inop->inode.iso_ctime,ftype);
553 inop->inode.iso_atime = inop->inode.iso_ctime;
554 inop->inode.iso_mtime = inop->inode.iso_ctime;
555 }
556 if (bp2)
557 brelse(bp2);
558}
559
560int
561cd9660_tstamp_conv7(pi,pu,ftype)
562char *pi;
563struct timespec *pu;
564enum ISO_FTYPE ftype;
565{
566 int crtime, days;
567 int y, m, d, hour, minute, second, tz;
568
569 y = pi[0] + 1900;
570 m = pi[1];
571 d = pi[2];
572 hour = pi[3];
573 minute = pi[4];
574 second = pi[5];
575 if(ftype != ISO_FTYPE_HIGH_SIERRA)
576 tz = pi[6];
577 else
578 /* original high sierra misses timezone data */
579 tz = 0;
580
581 if (y < 1970) {
582 pu->ts_sec = 0;
583 pu->ts_nsec = 0;
584 return 0;
585 } else {
586#ifdef ORIGINAL
587 /* computes day number relative to Sept. 19th,1989 */
588 /* don't even *THINK* about changing formula. It works! */
589 days = 367*(y-1980)-7*(y+(m+9)/12)/4-3*((y+(m-9)/7)/100+1)/4+275*m/9+d-100;
590#else
591 /*
592 * Changed :-) to make it relative to Jan. 1st, 1970
593 * and to disambiguate negative division
594 */
595 days = 367*(y-1960)-7*(y+(m+9)/12)/4-3*((y+(m+9)/12-1)/100+1)/4+275*m/9+d-239;
596#endif
597 crtime = ((((days * 24) + hour) * 60 + minute) * 60) + second;
598
599 /* timezone offset is unreliable on some disks */
600 if (-48 <= tz && tz <= 52)
601 crtime -= tz * 15 * 60;
602 }
603 pu->ts_sec = crtime;
604 pu->ts_nsec = 0;
605 return 1;
606}
607
608static unsigned
609cd9660_chars2ui(begin,len)
610 unsigned char *begin;
611 int len;
612{
613 unsigned rc;
614
615 for (rc = 0; --len >= 0;) {
616 rc *= 10;
617 rc += *begin++ - '0';
618 }
619 return rc;
620}
621
622int
623cd9660_tstamp_conv17(pi,pu)
624 unsigned char *pi;
625 struct timespec *pu;
626{
627 unsigned char buf[7];
628
629 /* year:"0001"-"9999" -> -1900 */
630 buf[0] = cd9660_chars2ui(pi,4) - 1900;
631
632 /* month: " 1"-"12" -> 1 - 12 */
633 buf[1] = cd9660_chars2ui(pi + 4,2);
634
635 /* day: " 1"-"31" -> 1 - 31 */
636 buf[2] = cd9660_chars2ui(pi + 6,2);
637
638 /* hour: " 0"-"23" -> 0 - 23 */
639 buf[3] = cd9660_chars2ui(pi + 8,2);
640
641 /* minute:" 0"-"59" -> 0 - 59 */
642 buf[4] = cd9660_chars2ui(pi + 10,2);
643
644 /* second:" 0"-"59" -> 0 - 59 */
645 buf[5] = cd9660_chars2ui(pi + 12,2);
646
647 /* difference of GMT */
648 buf[6] = pi[16];
649
650 return cd9660_tstamp_conv7(buf, pu, ISO_FTYPE_DEFAULT);
651}
652
653void
654isodirino(inump,isodir,imp)
655 ino_t *inump;
656 struct iso_directory_record *isodir;
657 struct iso_mnt *imp;
658{
659 *inump = (isonum_733(isodir->extent) + isonum_711(isodir->ext_attr_length))
660 * imp->logical_block_size;
661}
292 /*
293 * if device, look at device number table for translation
294 */
295#ifdef ISODEVMAP
296 if (dp = iso_dmap(dev,ino,0))
297 ip->inode.iso_rdev = dp->d_dev;
298#endif
299 vp->v_op = cd9660_specop_p;
300 if ((nvp = checkalias(vp, ip->inode.iso_rdev, mntp))) {
301 /*
302 * Reinitialize aliased inode.
303 */
304 vp = nvp;
305 iq = VTOI(vp);
306 iq->i_vnode = vp;
307 iq->i_flag = 0;
308 ISO_ILOCK(iq);
309 iq->i_dev = dev;
310 iq->i_number = ino;
311 iq->i_mnt = ip->i_mnt;
312 bcopy(&ip->iso_extent,&iq->iso_extent,
313 (char *)(ip + 1) - (char *)&ip->iso_extent);
314 insque(iq, ih);
315 /*
316 * Discard unneeded vnode
317 * (This introduces the need of INACTIVE modification)
318 */
319 ip->inode.iso_mode = 0;
320 iso_iput(ip);
321 ip = iq;
322 }
323 }
324
325 if (ip->iso_extent == imp->root_extent)
326 vp->v_flag |= VROOT;
327
328 *ipp = ip;
329 return 0;
330}
331
332/*
333 * Unlock and decrement the reference count of an inode structure.
334 */
335int
336iso_iput(ip)
337 register struct iso_node *ip;
338{
339
340 if ((ip->i_flag & ILOCKED) == 0)
341 panic("iso_iput");
342 ISO_IUNLOCK(ip);
343 vrele(ITOV(ip));
344 return (0);
345}
346
347/*
348 * Last reference to an inode, write the inode out and if necessary,
349 * truncate and deallocate the file.
350 */
351int
352cd9660_inactive(ap)
353 struct vop_inactive_args /* {
354 struct vnode *a_vp;
355 } */ *ap;
356{
357 struct vnode *vp = ap->a_vp;
358 register struct iso_node *ip = VTOI(vp);
359 int error = 0;
360
361 if (prtactive && vp->v_usecount != 0)
362 vprint("cd9660_inactive: pushing active", vp);
363
364 ip->i_flag = 0;
365 /*
366 * If we are done with the inode, reclaim it
367 * so that it can be reused immediately.
368 */
369 if (vp->v_usecount == 0 && ip->inode.iso_mode == 0)
370 vgone(vp);
371 return error;
372}
373
374/*
375 * Reclaim an inode so that it can be used for other purposes.
376 */
377int
378cd9660_reclaim(ap)
379 struct vop_reclaim_args /* {
380 struct vnode *a_vp;
381 } */ *ap;
382{
383 register struct vnode *vp = ap->a_vp;
384 register struct iso_node *ip = VTOI(vp);
385
386 if (prtactive && vp->v_usecount != 0)
387 vprint("cd9660_reclaim: pushing active", vp);
388 /*
389 * Remove the inode from its hash chain.
390 */
391 remque(ip);
392 ip->i_forw = ip;
393 ip->i_back = ip;
394 /*
395 * Purge old data structures associated with the inode.
396 */
397 cache_purge(vp);
398 if (ip->i_devvp) {
399 vrele(ip->i_devvp);
400 ip->i_devvp = 0;
401 }
402 FREE(vp->v_data, M_ISOFSNODE);
403 vp->v_data = NULL;
404 return 0;
405}
406
407/*
408 * Lock an inode. If its already locked, set the WANT bit and sleep.
409 */
410int
411iso_ilock(ip)
412 register struct iso_node *ip;
413{
414
415 while (ip->i_flag & ILOCKED) {
416 ip->i_flag |= IWANT;
417 if (ip->i_spare0 == curproc->p_pid)
418 panic("locking against myself");
419 ip->i_spare1 = curproc->p_pid;
420 (void) tsleep((caddr_t)ip, PINOD, "isoilk", 0);
421 }
422 ip->i_spare1 = 0;
423 ip->i_spare0 = curproc->p_pid;
424 ip->i_flag |= ILOCKED;
425 return (0);
426}
427
428/*
429 * Unlock an inode. If WANT bit is on, wakeup.
430 */
431int
432iso_iunlock(ip)
433 register struct iso_node *ip;
434{
435
436 if ((ip->i_flag & ILOCKED) == 0)
437 vprint("iso_iunlock: unlocked inode", ITOV(ip));
438 ip->i_spare0 = 0;
439 ip->i_flag &= ~ILOCKED;
440 if (ip->i_flag&IWANT) {
441 ip->i_flag &= ~IWANT;
442 wakeup((caddr_t)ip);
443 }
444 return (0);
445}
446
447/*
448 * File attributes
449 */
450void
451cd9660_defattr(isodir,inop,bp,ftype)
452 struct iso_directory_record *isodir;
453 struct iso_node *inop;
454 struct buf *bp;
455 enum ISO_FTYPE ftype;
456{
457 struct buf *bp2 = NULL;
458 struct iso_mnt *imp;
459 struct iso_extended_attributes *ap = NULL;
460 int off;
461
462 /* high sierra does not have timezone data, flag is one byte ahead */
463 if (isonum_711(ftype == ISO_FTYPE_HIGH_SIERRA?
464 &isodir->date[6]: isodir->flags)&2) {
465 inop->inode.iso_mode = S_IFDIR;
466 /*
467 * If we return 2, fts() will assume there are no subdirectories
468 * (just links for the path and .), so instead we return 1.
469 */
470 inop->inode.iso_links = 1;
471 } else {
472 inop->inode.iso_mode = S_IFREG;
473 inop->inode.iso_links = 1;
474 }
475 if (!bp
476 && ((imp = inop->i_mnt)->im_flags&ISOFSMNT_EXTATT)
477 && (off = isonum_711(isodir->ext_attr_length))) {
478 iso_blkatoff(inop,-off * imp->logical_block_size,&bp2);
479 bp = bp2;
480 }
481 if (bp) {
482 ap = (struct iso_extended_attributes *)bp->b_un.b_addr;
483
484 if (isonum_711(ap->version) == 1) {
485 if (!(ap->perm[0]&0x40))
486 inop->inode.iso_mode |= VEXEC >> 6;
487 if (!(ap->perm[0]&0x10))
488 inop->inode.iso_mode |= VREAD >> 6;
489 if (!(ap->perm[0]&4))
490 inop->inode.iso_mode |= VEXEC >> 3;
491 if (!(ap->perm[0]&1))
492 inop->inode.iso_mode |= VREAD >> 3;
493 if (!(ap->perm[1]&0x40))
494 inop->inode.iso_mode |= VEXEC;
495 if (!(ap->perm[1]&0x10))
496 inop->inode.iso_mode |= VREAD;
497 inop->inode.iso_uid = isonum_723(ap->owner); /* what about 0? */
498 inop->inode.iso_gid = isonum_723(ap->group); /* what about 0? */
499 } else
500 ap = NULL;
501 }
502 if (!ap) {
503 inop->inode.iso_mode |= VREAD|VEXEC|(VREAD|VEXEC)>>3|(VREAD|VEXEC)>>6;
504 inop->inode.iso_uid = (uid_t)0;
505 inop->inode.iso_gid = (gid_t)0;
506 }
507 if (bp2)
508 brelse(bp2);
509}
510
511/*
512 * Time stamps
513 */
514void
515cd9660_deftstamp(isodir,inop,bp,ftype)
516 struct iso_directory_record *isodir;
517 struct iso_node *inop;
518 struct buf *bp;
519 enum ISO_FTYPE ftype;
520{
521 struct buf *bp2 = NULL;
522 struct iso_mnt *imp;
523 struct iso_extended_attributes *ap = NULL;
524 int off;
525
526 if (!bp
527 && ((imp = inop->i_mnt)->im_flags&ISOFSMNT_EXTATT)
528 && (off = isonum_711(isodir->ext_attr_length))) {
529 iso_blkatoff(inop,-off * imp->logical_block_size,&bp2);
530 bp = bp2;
531 }
532 if (bp) {
533 ap = (struct iso_extended_attributes *)bp->b_un.b_addr;
534
535 if (ftype != ISO_FTYPE_HIGH_SIERRA
536 && isonum_711(ap->version) == 1) {
537 if (!cd9660_tstamp_conv17(ap->ftime,&inop->inode.iso_atime))
538 cd9660_tstamp_conv17(ap->ctime,&inop->inode.iso_atime);
539 if (!cd9660_tstamp_conv17(ap->ctime,&inop->inode.iso_ctime))
540 inop->inode.iso_ctime = inop->inode.iso_atime;
541 if (!cd9660_tstamp_conv17(ap->mtime,&inop->inode.iso_mtime))
542 inop->inode.iso_mtime = inop->inode.iso_ctime;
543 } else
544 ap = NULL;
545 }
546 if (!ap) {
547 cd9660_tstamp_conv7(isodir->date,&inop->inode.iso_ctime,ftype);
548 inop->inode.iso_atime = inop->inode.iso_ctime;
549 inop->inode.iso_mtime = inop->inode.iso_ctime;
550 }
551 if (bp2)
552 brelse(bp2);
553}
554
555int
556cd9660_tstamp_conv7(pi,pu,ftype)
557char *pi;
558struct timespec *pu;
559enum ISO_FTYPE ftype;
560{
561 int crtime, days;
562 int y, m, d, hour, minute, second, tz;
563
564 y = pi[0] + 1900;
565 m = pi[1];
566 d = pi[2];
567 hour = pi[3];
568 minute = pi[4];
569 second = pi[5];
570 if(ftype != ISO_FTYPE_HIGH_SIERRA)
571 tz = pi[6];
572 else
573 /* original high sierra misses timezone data */
574 tz = 0;
575
576 if (y < 1970) {
577 pu->ts_sec = 0;
578 pu->ts_nsec = 0;
579 return 0;
580 } else {
581#ifdef ORIGINAL
582 /* computes day number relative to Sept. 19th,1989 */
583 /* don't even *THINK* about changing formula. It works! */
584 days = 367*(y-1980)-7*(y+(m+9)/12)/4-3*((y+(m-9)/7)/100+1)/4+275*m/9+d-100;
585#else
586 /*
587 * Changed :-) to make it relative to Jan. 1st, 1970
588 * and to disambiguate negative division
589 */
590 days = 367*(y-1960)-7*(y+(m+9)/12)/4-3*((y+(m+9)/12-1)/100+1)/4+275*m/9+d-239;
591#endif
592 crtime = ((((days * 24) + hour) * 60 + minute) * 60) + second;
593
594 /* timezone offset is unreliable on some disks */
595 if (-48 <= tz && tz <= 52)
596 crtime -= tz * 15 * 60;
597 }
598 pu->ts_sec = crtime;
599 pu->ts_nsec = 0;
600 return 1;
601}
602
603static unsigned
604cd9660_chars2ui(begin,len)
605 unsigned char *begin;
606 int len;
607{
608 unsigned rc;
609
610 for (rc = 0; --len >= 0;) {
611 rc *= 10;
612 rc += *begin++ - '0';
613 }
614 return rc;
615}
616
617int
618cd9660_tstamp_conv17(pi,pu)
619 unsigned char *pi;
620 struct timespec *pu;
621{
622 unsigned char buf[7];
623
624 /* year:"0001"-"9999" -> -1900 */
625 buf[0] = cd9660_chars2ui(pi,4) - 1900;
626
627 /* month: " 1"-"12" -> 1 - 12 */
628 buf[1] = cd9660_chars2ui(pi + 4,2);
629
630 /* day: " 1"-"31" -> 1 - 31 */
631 buf[2] = cd9660_chars2ui(pi + 6,2);
632
633 /* hour: " 0"-"23" -> 0 - 23 */
634 buf[3] = cd9660_chars2ui(pi + 8,2);
635
636 /* minute:" 0"-"59" -> 0 - 59 */
637 buf[4] = cd9660_chars2ui(pi + 10,2);
638
639 /* second:" 0"-"59" -> 0 - 59 */
640 buf[5] = cd9660_chars2ui(pi + 12,2);
641
642 /* difference of GMT */
643 buf[6] = pi[16];
644
645 return cd9660_tstamp_conv7(buf, pu, ISO_FTYPE_DEFAULT);
646}
647
648void
649isodirino(inump,isodir,imp)
650 ino_t *inump;
651 struct iso_directory_record *isodir;
652 struct iso_mnt *imp;
653{
654 *inump = (isonum_733(isodir->extent) + isonum_711(isodir->ext_attr_length))
655 * imp->logical_block_size;
656}