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