xref: /freebsd/sys/fs/cd9660/cd9660_rrip.c (revision 3d945604ef8e1aaa49e153d82821fb4c6c1e67f2)
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 1993, 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.
20  * 3. Neither the name of the University nor the names of its contributors
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 
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/bio.h>
40 #include <sys/buf.h>
41 #include <sys/jail.h>
42 #include <sys/vnode.h>
43 #include <sys/mount.h>
44 #include <sys/kernel.h>
45 
46 #include <fs/cd9660/iso.h>
47 #include <fs/cd9660/cd9660_node.h>
48 #include <fs/cd9660/cd9660_rrip.h>
49 #include <fs/cd9660/iso_rrip.h>
50 
51 typedef int	rrt_func_t(void *, size_t, ISO_RRIP_ANALYZE *ana);
52 
53 typedef struct {
54 	char type[2];
55 	rrt_func_t *func;
56 	void (*func2)(struct iso_directory_record *isodir, ISO_RRIP_ANALYZE *ana);
57 	int result;
58 } RRIP_TABLE;
59 
60 static int	cd9660_rrip_altname(ISO_RRIP_ALTNAME *p, size_t len,
61 		    ISO_RRIP_ANALYZE *ana);
62 static int	cd9660_rrip_attr(ISO_RRIP_ATTR *p, size_t len,
63 		    ISO_RRIP_ANALYZE *ana);
64 static int	cd9660_rrip_cont(ISO_RRIP_CONT *p, size_t len,
65 		    ISO_RRIP_ANALYZE *ana);
66 static void	cd9660_rrip_defattr(struct iso_directory_record *isodir,
67 		    ISO_RRIP_ANALYZE *ana);
68 static void	cd9660_rrip_defname(struct iso_directory_record *isodir,
69 		    ISO_RRIP_ANALYZE *ana);
70 static void	cd9660_rrip_deftstamp(struct iso_directory_record *isodir,
71 		    ISO_RRIP_ANALYZE *ana);
72 static int	cd9660_rrip_device(ISO_RRIP_DEVICE *p, size_t len,
73 		    ISO_RRIP_ANALYZE *ana);
74 static int	cd9660_rrip_extref(ISO_RRIP_EXTREF *p, size_t len,
75 		    ISO_RRIP_ANALYZE *ana);
76 static int	cd9660_rrip_idflag(ISO_RRIP_IDFLAG *p, size_t len,
77 		    ISO_RRIP_ANALYZE *ana);
78 static int	cd9660_rrip_loop(struct iso_directory_record *isodir,
79 		    ISO_RRIP_ANALYZE *ana, RRIP_TABLE *table);
80 static int	cd9660_rrip_pclink(ISO_RRIP_CLINK *p, size_t len,
81 		    ISO_RRIP_ANALYZE *ana);
82 static int	cd9660_rrip_reldir(ISO_RRIP_RELDIR *p, size_t len,
83 		    ISO_RRIP_ANALYZE *ana);
84 static int	cd9660_rrip_slink(ISO_RRIP_SLINK *p, size_t len,
85 		    ISO_RRIP_ANALYZE *ana);
86 static int	cd9660_rrip_stop(ISO_SUSP_HEADER *p, size_t len,
87 		    ISO_RRIP_ANALYZE *ana);
88 static int	cd9660_rrip_tstamp(ISO_RRIP_TSTAMP *p, size_t len,
89 		    ISO_RRIP_ANALYZE *ana);
90 
91 /*
92  * POSIX file attribute
93  */
94 static int
cd9660_rrip_attr(ISO_RRIP_ATTR * p,size_t len,ISO_RRIP_ANALYZE * ana)95 cd9660_rrip_attr(ISO_RRIP_ATTR *p, size_t len, ISO_RRIP_ANALYZE *ana)
96 {
97 	if (len < sizeof(*p)) {
98 		ana->error = true;
99 		return (0);
100 	}
101 
102 	ana->inop->inode.iso_mode = isonum_733(p->mode);
103 	ana->inop->inode.iso_uid = isonum_733(p->uid);
104 	ana->inop->inode.iso_gid = isonum_733(p->gid);
105 	ana->inop->inode.iso_links = isonum_733(p->links);
106 	ana->fields &= ~ISO_SUSP_ATTR;
107 	return (ISO_SUSP_ATTR);
108 }
109 
110 static void
cd9660_rrip_defattr(struct iso_directory_record * isodir,ISO_RRIP_ANALYZE * ana)111 cd9660_rrip_defattr(struct iso_directory_record *isodir, ISO_RRIP_ANALYZE *ana)
112 {
113 	/* But this is a required field! */
114 	printf("RRIP without PX field?\n");
115 	cd9660_defattr(isodir, ana->inop, NULL, ISO_FTYPE_RRIP);
116 }
117 
118 /*
119  * Symbolic Links
120  */
121 static int
cd9660_rrip_slink(ISO_RRIP_SLINK * p,size_t plen,ISO_RRIP_ANALYZE * ana)122 cd9660_rrip_slink(ISO_RRIP_SLINK *p, size_t plen, ISO_RRIP_ANALYZE *ana)
123 {
124 	ISO_RRIP_SLINK_COMPONENT *pcomp;
125 	ISO_RRIP_SLINK_COMPONENT *pcompe;
126 	ISO_RRIP_SLINK_COMPONENT *pcompn;
127 	int len, wlen, cont;
128 	char *outbuf, *inbuf;
129 	char hostbuf[MAXHOSTNAMELEN];
130 
131 	/* This requires at least one byte of a component. */
132 	if (plen < sizeof(*p)) {
133 		ana->error = true;
134 		return (0);
135 	}
136 
137 	pcomp = (ISO_RRIP_SLINK_COMPONENT *)p->component;
138 	pcompe = (ISO_RRIP_SLINK_COMPONENT *)((char *)p + plen);
139 	len = *ana->outlen;
140 	outbuf = ana->outbuf;
141 	cont = ana->cont;
142 
143 	/*
144 	 * Gathering a Symbolic name from each component with path
145 	 */
146 	for (; pcomp < pcompe; pcomp = pcompn) {
147 		pcompn = (ISO_RRIP_SLINK_COMPONENT *)((char *)pcomp +
148 		    ISO_RRIP_SLSIZ + isonum_711(pcomp->clen));
149 
150 		/* If this component overflows the buffer, abort parsing. */
151 		if (pcompn > pcompe) {
152 			ana->error = true;
153 			return (0);
154 		}
155 
156 		if (!cont) {
157 			if (len < ana->maxlen) {
158 				len++;
159 				*outbuf++ = '/';
160 			}
161 		}
162 		cont = 0;
163 
164 		inbuf = "..";
165 		wlen = 0;
166 
167 		switch (*pcomp->cflag) {
168 		case ISO_SUSP_CFLAG_CURRENT:
169 			/* Inserting Current */
170 			wlen = 1;
171 			break;
172 
173 		case ISO_SUSP_CFLAG_PARENT:
174 			/* Inserting Parent */
175 			wlen = 2;
176 			break;
177 
178 		case ISO_SUSP_CFLAG_ROOT:
179 			/* Inserting slash for ROOT */
180 			/* Double slash, nothing really to do here. */
181 			break;
182 
183 		case ISO_SUSP_CFLAG_VOLROOT:
184 			/* Inserting a mount point i.e. "/cdrom" */
185 			/* same as above */
186 			outbuf -= len;
187 			len = 0;
188 			inbuf = ana->imp->im_mountp->mnt_stat.f_mntonname;
189 			wlen = strlen(inbuf);
190 			break;
191 
192 		case ISO_SUSP_CFLAG_HOST:
193 			/* Inserting hostname i.e. "kurt.tools.de" */
194 			getcredhostname(curthread->td_ucred, hostbuf,
195 			    sizeof(hostbuf));
196 			inbuf = hostbuf;
197 			wlen = strlen(inbuf);
198 			break;
199 
200 		case ISO_SUSP_CFLAG_CONTINUE:
201 			cont = 1;
202 			/* FALLTHROUGH */
203 		case 0:
204 			/* Inserting component */
205 			wlen = isonum_711(pcomp->clen);
206 			inbuf = pcomp->name;
207 			break;
208 		default:
209 			printf("RRIP with incorrect flags?");
210 			ana->error = true;
211 			return (0);
212 		}
213 
214 		if (len + wlen > ana->maxlen) {
215 			ana->error = true;
216 			return (0);
217 		}
218 
219 		memcpy(outbuf, inbuf, wlen);
220 		outbuf += wlen;
221 		len += wlen;
222 	}
223 	ana->outbuf = outbuf;
224 	*ana->outlen = len;
225 	ana->cont = cont;
226 
227 	if (!isonum_711(p->flags)) {
228 		ana->fields &= ~ISO_SUSP_SLINK;
229 		return (ISO_SUSP_SLINK);
230 	}
231 	return (0);
232 }
233 
234 /*
235  * Alternate name
236  */
237 static int
cd9660_rrip_altname(ISO_RRIP_ALTNAME * p,size_t len,ISO_RRIP_ANALYZE * ana)238 cd9660_rrip_altname(ISO_RRIP_ALTNAME *p, size_t len, ISO_RRIP_ANALYZE *ana)
239 {
240 	char *inbuf;
241 	int wlen;
242 	int cont;
243 	char hostbuf[MAXHOSTNAMELEN];
244 
245 	if (len < sizeof(*p)) {
246 		ana->error = true;
247 		return (0);
248 	}
249 
250 	inbuf = "..";
251 	wlen = 0;
252 	cont = 0;
253 
254 	switch (*p->flags) {
255 	case ISO_SUSP_CFLAG_CURRENT:
256 		/* Inserting Current */
257 		wlen = 1;
258 		break;
259 
260 	case ISO_SUSP_CFLAG_PARENT:
261 		/* Inserting Parent */
262 		wlen = 2;
263 		break;
264 
265 	case ISO_SUSP_CFLAG_HOST:
266 		/* Inserting hostname i.e. "kurt.tools.de" */
267 		getcredhostname(curthread->td_ucred, hostbuf, sizeof(hostbuf));
268 		inbuf = hostbuf;
269 		wlen = strlen(inbuf);
270 		break;
271 
272 	case ISO_SUSP_CFLAG_CONTINUE:
273 		cont = 1;
274 		/* FALLTHROUGH */
275 	case 0:
276 		/* Inserting component */
277 		wlen = len - sizeof(*p);
278 		inbuf = (char *)(p + 1);
279 		break;
280 
281 	default:
282 		printf("RRIP with incorrect NM flags?\n");
283 		ana->error = true;
284 		return (0);
285 	}
286 
287 	if ((*ana->outlen += wlen) > ana->maxlen) {
288 		ana->error = true;
289 		return (0);
290 	}
291 
292 	memcpy(ana->outbuf, inbuf, wlen);
293 	ana->outbuf += wlen;
294 
295 	if (!cont) {
296 		ana->fields &= ~ISO_SUSP_ALTNAME;
297 		return (ISO_SUSP_ALTNAME);
298 	}
299 	return (0);
300 }
301 
302 static void
cd9660_rrip_defname(struct iso_directory_record * isodir,ISO_RRIP_ANALYZE * ana)303 cd9660_rrip_defname(struct iso_directory_record *isodir, ISO_RRIP_ANALYZE *ana)
304 {
305 	isofntrans(isodir->name, isonum_711(isodir->name_len),
306 	    ana->outbuf, ana->outlen, 1, isonum_711(isodir->flags)&4,
307 	    ana->imp->joliet_level, ana->imp->im_flags, ana->imp->im_d2l);
308 	switch (*ana->outbuf) {
309 	default:
310 		break;
311 	case 1:
312 		*ana->outlen = 2;
313 		/* FALLTHROUGH */
314 	case 0:
315 		/* outlen is 1 already */
316 		strcpy(ana->outbuf, "..");
317 		break;
318 	}
319 }
320 
321 /*
322  * Parent or Child Link
323  */
324 static int
cd9660_rrip_pclink(ISO_RRIP_CLINK * p,size_t len,ISO_RRIP_ANALYZE * ana)325 cd9660_rrip_pclink(ISO_RRIP_CLINK *p, size_t len, ISO_RRIP_ANALYZE *ana)
326 {
327 	if (len < sizeof(*p)) {
328 		ana->error = true;
329 		return (0);
330 	}
331 
332 	*ana->inump = isonum_733(p->dir_loc) << ana->imp->im_bshift;
333 	ana->fields &= ~(ISO_SUSP_CLINK | ISO_SUSP_PLINK);
334 	return (*p->h.type == 'C' ? ISO_SUSP_CLINK : ISO_SUSP_PLINK);
335 }
336 
337 /*
338  * Relocated directory
339  */
340 static int
cd9660_rrip_reldir(ISO_RRIP_RELDIR * p,size_t len,ISO_RRIP_ANALYZE * ana)341 cd9660_rrip_reldir(ISO_RRIP_RELDIR *p, size_t len, ISO_RRIP_ANALYZE *ana)
342 {
343 	/* special hack to make caller aware of RE field */
344 	*ana->outlen = 0;
345 	ana->fields = 0;
346 	return (ISO_SUSP_RELDIR | ISO_SUSP_ALTNAME | ISO_SUSP_CLINK | ISO_SUSP_PLINK);
347 }
348 
349 static int
cd9660_rrip_tstamp(ISO_RRIP_TSTAMP * p,size_t len,ISO_RRIP_ANALYZE * ana)350 cd9660_rrip_tstamp(ISO_RRIP_TSTAMP *p, size_t len, ISO_RRIP_ANALYZE *ana)
351 {
352 	u_char *ptime;
353 	u_int count;
354 
355 	if (len < sizeof(*p))
356 		goto bad;
357 
358 	count = 0;
359 	if (*p->flags & ISO_SUSP_TSTAMP_CREAT)
360 		count++;
361 	if (*p->flags & ISO_SUSP_TSTAMP_MODIFY)
362 		count++;
363 	if (*p->flags & ISO_SUSP_TSTAMP_ACCESS)
364 		count++;
365 	if (*p->flags & ISO_SUSP_TSTAMP_ATTR)
366 		count++;
367 	if (*p->flags & ISO_SUSP_TSTAMP_FORM17)
368 		count *= 17;
369 	else
370 		count *= 7;
371 	if (offsetof(ISO_RRIP_TSTAMP, time) + count > len)
372 		goto bad;
373 
374 	ptime = p->time;
375 
376 	/* Check a format of time stamp (7bytes/17bytes) */
377 	if (!(*p->flags & ISO_SUSP_TSTAMP_FORM17)) {
378 		if (*p->flags & ISO_SUSP_TSTAMP_CREAT) {
379 			cd9660_tstamp_conv7(ptime,
380 			    &ana->inop->inode.iso_birthtime, ISO_FTYPE_RRIP);
381 			ptime += 7;
382 		} else {
383 			memset(&ana->inop->inode.iso_birthtime, 0,
384 			    sizeof(struct timespec));
385 		}
386 		if (*p->flags & ISO_SUSP_TSTAMP_MODIFY) {
387 			cd9660_tstamp_conv7(ptime, &ana->inop->inode.iso_mtime,
388 			    ISO_FTYPE_RRIP);
389 			ptime += 7;
390 		} else {
391 			ana->inop->inode.iso_mtime =
392 			    ana->inop->inode.iso_birthtime;
393 		}
394 		if (*p->flags & ISO_SUSP_TSTAMP_ACCESS) {
395 			cd9660_tstamp_conv7(ptime, &ana->inop->inode.iso_atime,
396 			    ISO_FTYPE_RRIP);
397 			ptime += 7;
398 		} else {
399 			ana->inop->inode.iso_atime = ana->inop->inode.iso_mtime;
400 		}
401 		if (*p->flags & ISO_SUSP_TSTAMP_ATTR) {
402 			cd9660_tstamp_conv7(ptime, &ana->inop->inode.iso_ctime,
403 			    ISO_FTYPE_RRIP);
404 		} else {
405 			ana->inop->inode.iso_ctime = ana->inop->inode.iso_mtime;
406 		}
407 	} else {
408 		if (*p->flags & ISO_SUSP_TSTAMP_CREAT) {
409 			cd9660_tstamp_conv17(ptime,
410 			    &ana->inop->inode.iso_birthtime);
411 			ptime += 17;
412 		} else {
413 			memset(&ana->inop->inode.iso_birthtime, 0,
414 			    sizeof(struct timespec));
415 		}
416 		if (*p->flags & ISO_SUSP_TSTAMP_MODIFY) {
417 			cd9660_tstamp_conv17(ptime, &ana->inop->inode.iso_mtime);
418 			ptime += 17;
419 		} else {
420 			ana->inop->inode.iso_mtime =
421 			    ana->inop->inode.iso_birthtime;
422 		}
423 		if (*p->flags & ISO_SUSP_TSTAMP_ACCESS) {
424 			cd9660_tstamp_conv17(ptime, &ana->inop->inode.iso_atime);
425 			ptime += 17;
426 		} else {
427 			ana->inop->inode.iso_atime = ana->inop->inode.iso_mtime;
428 		}
429 		if (*p->flags & ISO_SUSP_TSTAMP_ATTR) {
430 			cd9660_tstamp_conv17(ptime, &ana->inop->inode.iso_ctime);
431 		} else {
432 			ana->inop->inode.iso_ctime = ana->inop->inode.iso_mtime;
433 		}
434 	}
435 	ana->fields &= ~ISO_SUSP_TSTAMP;
436 	return (ISO_SUSP_TSTAMP);
437 
438 bad:
439 	ana->error = true;
440 	return (0);
441 }
442 
443 static void
cd9660_rrip_deftstamp(struct iso_directory_record * isodir,ISO_RRIP_ANALYZE * ana)444 cd9660_rrip_deftstamp(struct iso_directory_record *isodir,
445     ISO_RRIP_ANALYZE *ana)
446 {
447 	cd9660_deftstamp(isodir, ana->inop, NULL, ISO_FTYPE_RRIP);
448 }
449 
450 /*
451  * POSIX device modes
452  */
453 static int
cd9660_rrip_device(ISO_RRIP_DEVICE * p,size_t len,ISO_RRIP_ANALYZE * ana)454 cd9660_rrip_device(ISO_RRIP_DEVICE *p, size_t len, ISO_RRIP_ANALYZE *ana)
455 {
456 	u_int high, low;
457 
458 	if (len < sizeof(*p)) {
459 		ana->error = true;
460 		return (0);
461 	}
462 
463 	high = isonum_733(p->dev_t_high);
464 	low  = isonum_733(p->dev_t_low);
465 
466 	if (high == 0)
467 		ana->inop->inode.iso_rdev = makedev(major(low), minor(low));
468 	else
469 		ana->inop->inode.iso_rdev = makedev(high, minor(low));
470 	ana->fields &= ~ISO_SUSP_DEVICE;
471 	return (ISO_SUSP_DEVICE);
472 }
473 
474 /*
475  * Flag indicating
476  */
477 static int
cd9660_rrip_idflag(ISO_RRIP_IDFLAG * p,size_t len,ISO_RRIP_ANALYZE * ana)478 cd9660_rrip_idflag(ISO_RRIP_IDFLAG *p, size_t len, ISO_RRIP_ANALYZE *ana)
479 {
480 	if (len < sizeof(*p)) {
481 		ana->error = true;
482 		return (0);
483 	}
484 
485 	ana->fields &= isonum_711(p->flags) | ~0xff; /* don't touch high bits */
486 	/* special handling of RE field */
487 	if (ana->fields & ISO_SUSP_RELDIR)
488 		return (cd9660_rrip_reldir(/* XXX */ (ISO_RRIP_RELDIR *)p, len, ana));
489 
490 	return (ISO_SUSP_IDFLAG);
491 }
492 
493 /*
494  * Continuation pointer
495  */
496 static int
cd9660_rrip_cont(ISO_RRIP_CONT * p,size_t len,ISO_RRIP_ANALYZE * ana)497 cd9660_rrip_cont(ISO_RRIP_CONT *p, size_t len, ISO_RRIP_ANALYZE *ana)
498 {
499 	if (len < sizeof(*p)) {
500 		ana->error = true;
501 		return (0);
502 	}
503 
504 	ana->iso_ce_blk = isonum_733(p->location);
505 	ana->iso_ce_off = isonum_733(p->offset);
506 	ana->iso_ce_len = isonum_733(p->length);
507 	return (ISO_SUSP_CONT);
508 }
509 
510 /*
511  * System Use end
512  */
513 static int
cd9660_rrip_stop(ISO_SUSP_HEADER * p,size_t len,ISO_RRIP_ANALYZE * ana)514 cd9660_rrip_stop(ISO_SUSP_HEADER *p, size_t len, ISO_RRIP_ANALYZE *ana)
515 {
516 	return (ISO_SUSP_STOP);
517 }
518 
519 /*
520  * Extension reference
521  */
522 static int
cd9660_rrip_extref(ISO_RRIP_EXTREF * p,size_t plen,ISO_RRIP_ANALYZE * ana)523 cd9660_rrip_extref(ISO_RRIP_EXTREF *p, size_t plen, ISO_RRIP_ANALYZE *ana)
524 {
525 	size_t len;
526 	char *data;
527 
528 	if (plen < sizeof(*p)) {
529 		ana->error = true;
530 		return (0);
531 	}
532 
533 	len = isonum_711(p->len_id);
534 	data = (char *)(p + 1);
535 	if ((len == 10 && memcmp(data, "RRIP_1991A", len) == 0) ||
536 	    (len == 10 && memcmp(data, "IEEE_P1282", len) == 0) ||
537 	    (len ==  9 && memcmp(data, "IEEE_1282", len) == 0)) {
538 		if (isonum_711(p->version) == 1) {
539 			ana->fields &= ~ISO_SUSP_EXTREF;
540 			return (ISO_SUSP_EXTREF);
541 		}
542 	}
543 	return (0);
544 }
545 
546 static int
cd9660_rrip_loop(struct iso_directory_record * isodir,ISO_RRIP_ANALYZE * ana,RRIP_TABLE * table)547 cd9660_rrip_loop(struct iso_directory_record *isodir, ISO_RRIP_ANALYZE *ana,
548     RRIP_TABLE *table)
549 {
550 	RRIP_TABLE *ptable;
551 	ISO_SUSP_HEADER *phead;
552 	ISO_SUSP_HEADER *pend;
553 	ISO_SUSP_HEADER *pnext;
554 	struct buf *bp = NULL;
555 	char *pwhead;
556 	u_short c;
557 	int result;
558 
559 	/*
560 	 * Note: If name length is odd,
561 	 *	 it will be padding 1 byte after the name
562 	 */
563 	pwhead = isodir->name + isonum_711(isodir->name_len);
564 	if (!(isonum_711(isodir->name_len)&1))
565 		pwhead++;
566 	isochar(isodir->name, pwhead, ana->imp->joliet_level, &c, NULL,
567 	    ana->imp->im_flags, ana->imp->im_d2l);
568 
569 	/* If it's not the '.' entry of the root dir obey SP field */
570 	if (c != 0 || isonum_733(isodir->extent) != ana->imp->root_extent)
571 		pwhead += ana->imp->rr_skip;
572 	else
573 		pwhead += ana->imp->rr_skip0;
574 
575 	phead = (ISO_SUSP_HEADER *)pwhead;
576 	pend = (ISO_SUSP_HEADER *)((char *)isodir + isonum_711(isodir->length));
577 
578 	result = 0;
579 	ana->error = false;
580 	while (1) {
581 		ana->iso_ce_len = 0;
582 		/*
583 		 * Note: "pend" should be more than one SUSP header
584 		 */
585 		while (pend >= phead + 1) {
586 			/* Validate length. */
587 			if (isonum_711(phead->length) < sizeof(*phead))
588 				break;
589 
590 			/*
591 			 * Next SUSP
592 			 * Hopefully this works with newer versions, too
593 			 */
594 			pnext = (ISO_SUSP_HEADER *)((char *)phead +
595 			    isonum_711(phead->length));
596 
597 			/* If the record doesn't fit, break out of the loop. */
598 			if (pnext > pend)
599 				break;
600 
601 			if (isonum_711(phead->version) == 1) {
602 				for (ptable = table; ptable->func; ptable++) {
603 					if (phead->type[0] == ptable->type[0] &&
604 					    phead->type[1] == ptable->type[1]) {
605 						result |= ptable->func(phead,
606 						    isonum_711(phead->length),
607 						    ana);
608 						break;
609 					}
610 				}
611 				if (ana->error) {
612 					*ana->outlen = 0;
613 					result = 0;
614 					goto error;
615 				}
616 
617 				if (!ana->fields)
618 					break;
619 			}
620 			if (result & ISO_SUSP_STOP) {
621 				result &= ~ISO_SUSP_STOP;
622 				break;
623 			}
624 
625 			phead = pnext;
626 		}
627 
628 		if (ana->fields && ana->iso_ce_len) {
629 			if (ana->iso_ce_blk >= ana->imp->volume_space_size ||
630 			    ana->iso_ce_off + ana->iso_ce_len >
631 			    ana->imp->logical_block_size)
632 				break;
633 			if (bp != NULL) {
634 				brelse(bp);
635 				bp = NULL;
636 			}
637 			if (bread(ana->imp->im_devvp,
638 			    ana->iso_ce_blk <<
639 			    (ana->imp->im_bshift - DEV_BSHIFT),
640 			    ana->imp->logical_block_size, NOCRED, &bp) != 0)
641 				/* what to do now? */
642 				break;
643 			phead = (ISO_SUSP_HEADER *)(bp->b_data + ana->iso_ce_off);
644 			pend = (ISO_SUSP_HEADER *)((char *)phead + ana->iso_ce_len);
645 		} else
646 			break;
647 	}
648 error:
649 	if (bp)
650 		brelse(bp);
651 	/*
652 	 * If we don't find the Basic SUSP stuffs, just set default value
653 	 *   (attribute/time stamp)
654 	 */
655 	for (ptable = table; ptable->func2; ptable++)
656 		if (!(ptable->result & result))
657 			ptable->func2(isodir, ana);
658 
659 	return (result);
660 }
661 
662 /*
663  * Get Attributes.
664  */
665 /*
666  * XXX the casts are bogus but will do for now.
667  */
668 #define	BC	(rrt_func_t *)
669 static RRIP_TABLE rrip_table_analyze[] = {
670 	{ "PX", BC cd9660_rrip_attr,	cd9660_rrip_defattr,	ISO_SUSP_ATTR },
671 	{ "TF", BC cd9660_rrip_tstamp,	cd9660_rrip_deftstamp,	ISO_SUSP_TSTAMP },
672 	{ "PN", BC cd9660_rrip_device,	0,			ISO_SUSP_DEVICE },
673 	{ "RR", BC cd9660_rrip_idflag,	0,			ISO_SUSP_IDFLAG },
674 	{ "CE", BC cd9660_rrip_cont,	0,			ISO_SUSP_CONT },
675 	{ "ST", BC cd9660_rrip_stop,	0,			ISO_SUSP_STOP },
676 	{ "",	0,			0,			0 }
677 };
678 
679 int
cd9660_rrip_analyze(struct iso_directory_record * isodir,struct iso_node * inop,struct iso_mnt * imp)680 cd9660_rrip_analyze(struct iso_directory_record *isodir, struct iso_node *inop,
681     struct iso_mnt *imp)
682 {
683 	ISO_RRIP_ANALYZE analyze;
684 
685 	analyze.inop = inop;
686 	analyze.imp = imp;
687 	analyze.fields = ISO_SUSP_ATTR | ISO_SUSP_TSTAMP | ISO_SUSP_DEVICE;
688 
689 	return (cd9660_rrip_loop(isodir, &analyze, rrip_table_analyze));
690 }
691 
692 /*
693  * Get Alternate Name.
694  */
695 static RRIP_TABLE rrip_table_getname[] = {
696 	{ "NM", BC cd9660_rrip_altname,	cd9660_rrip_defname,	ISO_SUSP_ALTNAME },
697 	{ "CL", BC cd9660_rrip_pclink,	0,			ISO_SUSP_CLINK | ISO_SUSP_PLINK },
698 	{ "PL", BC cd9660_rrip_pclink,	0,			ISO_SUSP_CLINK | ISO_SUSP_PLINK },
699 	{ "RE", BC cd9660_rrip_reldir,	0,			ISO_SUSP_RELDIR },
700 	{ "RR", BC cd9660_rrip_idflag,	0,			ISO_SUSP_IDFLAG },
701 	{ "CE", BC cd9660_rrip_cont,	0,			ISO_SUSP_CONT },
702 	{ "ST", BC cd9660_rrip_stop,	0,			ISO_SUSP_STOP },
703 	{ "",	0,			0,			0 }
704 };
705 
706 int
cd9660_rrip_getname(struct iso_directory_record * isodir,char * outbuf,u_short * outlen,ino_t * inump,struct iso_mnt * imp)707 cd9660_rrip_getname(struct iso_directory_record *isodir, char *outbuf,
708     u_short *outlen, ino_t *inump, struct iso_mnt *imp)
709 {
710 	ISO_RRIP_ANALYZE analyze;
711 	RRIP_TABLE *tab;
712 	u_short c;
713 
714 	analyze.outbuf = outbuf;
715 	analyze.outlen = outlen;
716 	analyze.maxlen = NAME_MAX;
717 	analyze.inump = inump;
718 	analyze.imp = imp;
719 	analyze.fields = ISO_SUSP_ALTNAME | ISO_SUSP_RELDIR | ISO_SUSP_CLINK | ISO_SUSP_PLINK;
720 	*outlen = 0;
721 
722 	isochar(isodir->name, isodir->name + isonum_711(isodir->name_len),
723 	    imp->joliet_level, &c, NULL, imp->im_flags, imp->im_d2l);
724 	tab = rrip_table_getname;
725 	if (c == 0 || c == 1) {
726 		cd9660_rrip_defname(isodir, &analyze);
727 
728 		analyze.fields &= ~ISO_SUSP_ALTNAME;
729 		tab++;
730 	}
731 
732 	return (cd9660_rrip_loop(isodir, &analyze, tab));
733 }
734 
735 /*
736  * Get Symbolic Link.
737  */
738 static RRIP_TABLE rrip_table_getsymname[] = {
739 	{ "SL", BC cd9660_rrip_slink,	0,			ISO_SUSP_SLINK },
740 	{ "RR", BC cd9660_rrip_idflag,	0,			ISO_SUSP_IDFLAG },
741 	{ "CE", BC cd9660_rrip_cont,	0,			ISO_SUSP_CONT },
742 	{ "ST", BC cd9660_rrip_stop,	0,			ISO_SUSP_STOP },
743 	{ "",	0,			0,			0 }
744 };
745 
746 int
cd9660_rrip_getsymname(struct iso_directory_record * isodir,char * outbuf,u_short * outlen,struct iso_mnt * imp)747 cd9660_rrip_getsymname(struct iso_directory_record *isodir, char *outbuf,
748     u_short *outlen, struct iso_mnt *imp)
749 {
750 	ISO_RRIP_ANALYZE analyze;
751 	int ret;
752 
753 	analyze.outbuf = outbuf;
754 	analyze.outlen = outlen;
755 	*outlen = 0;
756 	analyze.maxlen = MAXPATHLEN;
757 	analyze.cont = 1;		/* don't start with a slash */
758 	analyze.imp = imp;
759 	analyze.fields = ISO_SUSP_SLINK;
760 
761 	ret = cd9660_rrip_loop(isodir, &analyze, rrip_table_getsymname);
762 	return (ret & ISO_SUSP_SLINK);
763 }
764 
765 static RRIP_TABLE rrip_table_extref[] = {
766 	{ "ER", BC cd9660_rrip_extref,	0,			ISO_SUSP_EXTREF },
767 	{ "CE", BC cd9660_rrip_cont,	0,			ISO_SUSP_CONT },
768 	{ "ST", BC cd9660_rrip_stop,	0,			ISO_SUSP_STOP },
769 	{ "",	0,			0,			0 }
770 };
771 
772 /*
773  * Check for Rock Ridge Extension and return offset of its fields.
774  * Note: We insist on the ER field.
775  */
776 int
cd9660_rrip_offset(struct iso_directory_record * isodir,struct iso_mnt * imp)777 cd9660_rrip_offset(struct iso_directory_record *isodir, struct iso_mnt *imp)
778 {
779 	ISO_RRIP_OFFSET *p;
780 	ISO_RRIP_ANALYZE analyze;
781 	int ret;
782 
783 	imp->rr_skip0 = 0;
784 	p = (ISO_RRIP_OFFSET *)(isodir->name + 1);
785 	if (memcmp(p, "SP\7\1\276\357", 6) != 0) {
786 		/* Maybe, it's a CDROM XA disc? */
787 		imp->rr_skip0 = 15;
788 		p = (ISO_RRIP_OFFSET *)((char *)p + 15);
789 		if (memcmp(p, "SP\7\1\276\357", 6) != 0)
790 			return (-1);
791 	}
792 
793 	analyze.imp = imp;
794 	analyze.fields = ISO_SUSP_EXTREF;
795 	ret = cd9660_rrip_loop(isodir, &analyze, rrip_table_extref);
796 	if ((ret & ISO_SUSP_EXTREF) == 0)
797 		return (-1);
798 
799 	return (isonum_711(p->skip));
800 }
801