dsynth.1: Ada is the name of a person, not an acronym.
[dragonfly.git] / sys / vfs / isofs / cd9660 / cd9660_rrip.c
1 /*-
2  * Copyright (c) 1993, 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. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  *
34  *      @(#)cd9660_rrip.c       8.6 (Berkeley) 12/5/94
35  * $FreeBSD: src/sys/isofs/cd9660/cd9660_rrip.c,v 1.17 1999/08/28 00:46:06 peter Exp $
36  */
37
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/buf.h>
41 #include <sys/vnode.h>
42 #include <sys/mount.h>
43 #include <sys/kernel.h>
44
45 #include "iso.h"
46 #include "cd9660_node.h"
47 #include "cd9660_rrip.h"
48 #include "iso_rrip.h"
49
50 #include <sys/buf2.h>
51
52 typedef int     rrt_func_t(void *, ISO_RRIP_ANALYZE *ana);
53
54 typedef struct {
55         char type[2];
56         rrt_func_t *func;
57         void (*func2)(struct iso_directory_record *isodir, ISO_RRIP_ANALYZE *ana);
58         int result;
59 } RRIP_TABLE;
60
61 static int      cd9660_rrip_altname(ISO_RRIP_ALTNAME *p, ISO_RRIP_ANALYZE *ana);
62 static int      cd9660_rrip_attr(ISO_RRIP_ATTR *p, ISO_RRIP_ANALYZE *ana);
63 static int      cd9660_rrip_cont(ISO_RRIP_CONT *p, ISO_RRIP_ANALYZE *ana);
64 static void     cd9660_rrip_defattr(struct iso_directory_record *isodir,
65                     ISO_RRIP_ANALYZE *ana);
66 static void     cd9660_rrip_defname(struct iso_directory_record *isodir,
67                     ISO_RRIP_ANALYZE *ana);
68 static void     cd9660_rrip_deftstamp(struct iso_directory_record *isodir,
69                     ISO_RRIP_ANALYZE *ana);
70 static int      cd9660_rrip_device(ISO_RRIP_DEVICE *p, ISO_RRIP_ANALYZE *ana);
71 static int      cd9660_rrip_extref(ISO_RRIP_EXTREF *p, ISO_RRIP_ANALYZE *ana);
72 static int      cd9660_rrip_idflag(ISO_RRIP_IDFLAG *p, ISO_RRIP_ANALYZE *ana);
73 static int      cd9660_rrip_loop(struct iso_directory_record *isodir,
74                     ISO_RRIP_ANALYZE *ana, RRIP_TABLE *table);
75 static int      cd9660_rrip_pclink(ISO_RRIP_CLINK *p, ISO_RRIP_ANALYZE *ana);
76 static int      cd9660_rrip_reldir(ISO_RRIP_RELDIR *p, ISO_RRIP_ANALYZE *ana);
77 static int      cd9660_rrip_slink(ISO_RRIP_SLINK *p, ISO_RRIP_ANALYZE *ana);
78 static int      cd9660_rrip_stop(ISO_SUSP_HEADER *p, ISO_RRIP_ANALYZE *ana);
79 static int      cd9660_rrip_tstamp(ISO_RRIP_TSTAMP *p, ISO_RRIP_ANALYZE *ana);
80
81 /*
82  * POSIX file attribute
83  */
84 static int
85 cd9660_rrip_attr(ISO_RRIP_ATTR *p, ISO_RRIP_ANALYZE *ana)
86 {
87         ana->inop->inode.iso_mode = isonum_733(p->mode);
88         ana->inop->inode.iso_uid = isonum_733(p->uid);
89         ana->inop->inode.iso_gid = isonum_733(p->gid);
90         ana->inop->inode.iso_links = isonum_733(p->links);
91         ana->fields &= ~ISO_SUSP_ATTR;
92         return ISO_SUSP_ATTR;
93 }
94
95 static void
96 cd9660_rrip_defattr(struct iso_directory_record *isodir, ISO_RRIP_ANALYZE *ana)
97 {
98         /* But this is a required field! */
99         kprintf("RRIP without PX field?\n");
100         cd9660_defattr(isodir,ana->inop,NULL,ISO_FTYPE_RRIP);
101 }
102
103 /*
104  * Symbolic Links
105  */
106 static int
107 cd9660_rrip_slink(ISO_RRIP_SLINK *p, ISO_RRIP_ANALYZE *ana)
108 {
109         ISO_RRIP_SLINK_COMPONENT *pcomp;
110         ISO_RRIP_SLINK_COMPONENT *pcompe;
111         int error, len, wlen, cont;
112         char *outbuf, *inbuf, *freebuf;
113
114         pcomp = (ISO_RRIP_SLINK_COMPONENT *)p->component;
115         pcompe = (ISO_RRIP_SLINK_COMPONENT *)((char *)p + isonum_711(p->h.length));
116         len = *ana->outlen;
117         outbuf = ana->outbuf;
118         cont = ana->cont;
119         freebuf = NULL;
120
121         /*
122          * Gathering a Symbolic name from each component with path
123          */
124         for (;
125              pcomp < pcompe;
126              pcomp = (ISO_RRIP_SLINK_COMPONENT *)((char *)pcomp + ISO_RRIP_SLSIZ
127                                                   + isonum_711(pcomp->clen))) {
128
129                 if (!cont) {
130                         if (len < ana->maxlen) {
131                                 len++;
132                                 *outbuf++ = '/';
133                         }
134                 }
135                 cont = 0;
136
137                 inbuf = "..";
138                 wlen = 0;
139
140                 switch (*pcomp->cflag) {
141
142                 case ISO_SUSP_CFLAG_CURRENT:
143                         /* Inserting Current */
144                         wlen = 1;
145                         break;
146
147                 case ISO_SUSP_CFLAG_PARENT:
148                         /* Inserting Parent */
149                         wlen = 2;
150                         break;
151
152                 case ISO_SUSP_CFLAG_ROOT:
153                         /* Inserting slash for ROOT */
154                         /* start over from beginning(?) */
155                         outbuf -= len;
156                         len = 0;
157                         break;
158
159                 case ISO_SUSP_CFLAG_VOLROOT:
160                         /* Inserting a mount point i.e. "/cdrom" */
161                         /* same as above */
162                         outbuf -= len;
163                         len = 0;
164                         error = cache_fullpath(NULL, &ana->imp->im_mountp->mnt_ncmountpt, NULL,
165                                                &inbuf, &freebuf, 0);
166                         if (error)
167                                 goto bad;
168                         wlen = strlen(inbuf);
169                         break;
170
171                 case ISO_SUSP_CFLAG_HOST:
172                         /* Inserting hostname i.e. "kurt.tools.de" */
173                         inbuf = hostname;
174                         wlen = strlen(hostname);
175                         break;
176
177                 case ISO_SUSP_CFLAG_CONTINUE:
178                         cont = 1;
179                         /* FALLTHROUGH */
180                 case 0:
181                         /* Inserting component */
182                         wlen = isonum_711(pcomp->clen);
183                         inbuf = pcomp->name;
184                         break;
185                 default:
186                         kprintf("RRIP with incorrect flags?");
187                         wlen = ana->maxlen + 1;
188                         break;
189                 }
190
191                 if (len + wlen > ana->maxlen)
192                         goto bad;
193
194                 bcopy(inbuf,outbuf,wlen);
195                 outbuf += wlen;
196                 len += wlen;
197
198                 if (freebuf != NULL) {
199                         kfree(freebuf, M_TEMP);
200                         freebuf = NULL;
201                 }
202         }
203         ana->outbuf = outbuf;
204         *ana->outlen = len;
205         ana->cont = cont;
206
207         if (!isonum_711(p->flags)) {
208                 ana->fields &= ~ISO_SUSP_SLINK;
209                 return ISO_SUSP_SLINK;
210         }
211         return 0;
212
213 bad:
214         if (freebuf != NULL)
215                 kfree(freebuf, M_TEMP);
216         ana->cont = 1;
217         ana->fields = 0;
218         ana->outbuf -= *ana->outlen;
219         *ana->outlen = 0;
220         return 0;
221 }
222
223 /*
224  * Alternate name
225  */
226 static int
227 cd9660_rrip_altname(ISO_RRIP_ALTNAME *p, ISO_RRIP_ANALYZE *ana)
228 {
229         char *inbuf;
230         int wlen;
231         int cont;
232
233         inbuf = "..";
234         wlen = 0;
235         cont = 0;
236
237         switch (*p->flags) {
238         case ISO_SUSP_CFLAG_CURRENT:
239                 /* Inserting Current */
240                 wlen = 1;
241                 break;
242
243         case ISO_SUSP_CFLAG_PARENT:
244                 /* Inserting Parent */
245                 wlen = 2;
246                 break;
247
248         case ISO_SUSP_CFLAG_HOST:
249                 /* Inserting hostname i.e. "kurt.tools.de" */
250                 inbuf = hostname;
251                 wlen = strlen(hostname);
252                 break;
253
254         case ISO_SUSP_CFLAG_CONTINUE:
255                 cont = 1;
256                 /* FALLTHROUGH */
257         case 0:
258                 /* Inserting component */
259                 wlen = isonum_711(p->h.length) - 5;
260                 inbuf = (char *)p + 5;
261                 break;
262
263         default:
264                 kprintf("RRIP with incorrect NM flags?\n");
265                 wlen = ana->maxlen + 1;
266                 break;
267         }
268
269         if ((*ana->outlen += wlen) > ana->maxlen) {
270                 /* treat as no name field */
271                 ana->fields &= ~ISO_SUSP_ALTNAME;
272                 ana->outbuf -= *ana->outlen - wlen;
273                 *ana->outlen = 0;
274                 return 0;
275         }
276
277         bcopy(inbuf,ana->outbuf,wlen);
278         ana->outbuf += wlen;
279
280         if (!cont) {
281                 ana->fields &= ~ISO_SUSP_ALTNAME;
282                 return ISO_SUSP_ALTNAME;
283         }
284         return 0;
285 }
286
287 static void
288 cd9660_rrip_defname(struct iso_directory_record *isodir, ISO_RRIP_ANALYZE *ana)
289 {
290         isofntrans(isodir->name,isonum_711(isodir->name_len),
291                    ana->outbuf,ana->outlen,
292                    1,isonum_711(isodir->flags)&4, ana->imp->joliet_level,
293                    ana->imp->im_flags, ana->imp->im_d2l);
294         switch (*ana->outbuf) {
295         default:
296                 break;
297         case 1:
298                 *ana->outlen = 2;
299                 /* FALLTHROUGH */
300         case 0:
301                 /* outlen is 1 already */
302                 strcpy(ana->outbuf,"..");
303                 break;
304         }
305 }
306
307 /*
308  * Parent or Child Link
309  */
310 static int
311 cd9660_rrip_pclink(ISO_RRIP_CLINK *p, ISO_RRIP_ANALYZE *ana)
312 {
313         *ana->inump = isonum_733(p->dir_loc) << ana->imp->im_bshift;
314         ana->fields &= ~(ISO_SUSP_CLINK|ISO_SUSP_PLINK);
315         return *p->h.type == 'C' ? ISO_SUSP_CLINK : ISO_SUSP_PLINK;
316 }
317
318 /*
319  * Relocated directory
320  */
321 static int
322 cd9660_rrip_reldir(ISO_RRIP_RELDIR *p, ISO_RRIP_ANALYZE *ana)
323 {
324         /* special hack to make caller aware of RE field */
325         *ana->outlen = 0;
326         ana->fields = 0;
327         return ISO_SUSP_RELDIR|ISO_SUSP_ALTNAME|ISO_SUSP_CLINK|ISO_SUSP_PLINK;
328 }
329
330 static int
331 cd9660_rrip_tstamp(ISO_RRIP_TSTAMP *p, ISO_RRIP_ANALYZE *ana)
332 {
333         u_char *ptime;
334
335         ptime = p->time;
336
337         /* Check a format of time stamp (7bytes/17bytes) */
338         if (!(*p->flags&ISO_SUSP_TSTAMP_FORM17)) {
339                 if (*p->flags&ISO_SUSP_TSTAMP_CREAT)
340                         ptime += 7;
341
342                 if (*p->flags&ISO_SUSP_TSTAMP_MODIFY) {
343                         cd9660_tstamp_conv7(ptime,&ana->inop->inode.iso_mtime,
344                                             ISO_FTYPE_RRIP);
345                         ptime += 7;
346                 } else
347                         bzero(&ana->inop->inode.iso_mtime,sizeof(struct timespec));
348
349                 if (*p->flags&ISO_SUSP_TSTAMP_ACCESS) {
350                         cd9660_tstamp_conv7(ptime,&ana->inop->inode.iso_atime,
351                                             ISO_FTYPE_RRIP);
352                         ptime += 7;
353                 } else
354                         ana->inop->inode.iso_atime = ana->inop->inode.iso_mtime;
355
356                 if (*p->flags&ISO_SUSP_TSTAMP_ATTR)
357                         cd9660_tstamp_conv7(ptime,&ana->inop->inode.iso_ctime,
358                                             ISO_FTYPE_RRIP);
359                 else
360                         ana->inop->inode.iso_ctime = ana->inop->inode.iso_mtime;
361
362         } else {
363                 if (*p->flags&ISO_SUSP_TSTAMP_CREAT)
364                         ptime += 17;
365
366                 if (*p->flags&ISO_SUSP_TSTAMP_MODIFY) {
367                         cd9660_tstamp_conv17(ptime,&ana->inop->inode.iso_mtime);
368                         ptime += 17;
369                 } else
370                         bzero(&ana->inop->inode.iso_mtime,sizeof(struct timespec));
371
372                 if (*p->flags&ISO_SUSP_TSTAMP_ACCESS) {
373                         cd9660_tstamp_conv17(ptime,&ana->inop->inode.iso_atime);
374                         ptime += 17;
375                 } else
376                         ana->inop->inode.iso_atime = ana->inop->inode.iso_mtime;
377
378                 if (*p->flags&ISO_SUSP_TSTAMP_ATTR)
379                         cd9660_tstamp_conv17(ptime,&ana->inop->inode.iso_ctime);
380                 else
381                         ana->inop->inode.iso_ctime = ana->inop->inode.iso_mtime;
382
383         }
384         ana->fields &= ~ISO_SUSP_TSTAMP;
385         return ISO_SUSP_TSTAMP;
386 }
387
388 static void
389 cd9660_rrip_deftstamp(struct iso_directory_record *isodir, ISO_RRIP_ANALYZE *ana)
390 {
391         cd9660_deftstamp(isodir,ana->inop,NULL,ISO_FTYPE_RRIP);
392 }
393
394 /*
395  * POSIX device modes
396  */
397 static int
398 cd9660_rrip_device(ISO_RRIP_DEVICE *p, ISO_RRIP_ANALYZE *ana)
399 {
400         u_int high, low;
401
402         high = isonum_733(p->dev_t_high);
403         low  = isonum_733(p->dev_t_low);
404
405         if (high == 0)
406                 ana->inop->inode.iso_rdev = makeudev(umajor(low), uminor(low));
407         else
408                 ana->inop->inode.iso_rdev = makeudev(high, uminor(low));
409         ana->fields &= ~ISO_SUSP_DEVICE;
410         return ISO_SUSP_DEVICE;
411 }
412
413 /*
414  * Flag indicating
415  */
416 static int
417 cd9660_rrip_idflag(ISO_RRIP_IDFLAG *p, ISO_RRIP_ANALYZE *ana)
418 {
419         ana->fields &= isonum_711(p->flags)|~0xff; /* don't touch high bits */
420         /* special handling of RE field */
421         if (ana->fields&ISO_SUSP_RELDIR)
422                 return cd9660_rrip_reldir(/* XXX */ (ISO_RRIP_RELDIR *)p,ana);
423
424         return ISO_SUSP_IDFLAG;
425 }
426
427 /*
428  * Continuation pointer
429  */
430 static int
431 cd9660_rrip_cont(ISO_RRIP_CONT *p, ISO_RRIP_ANALYZE *ana)
432 {
433         ana->iso_ce_blk = isonum_733(p->location);
434         ana->iso_ce_off = isonum_733(p->offset);
435         ana->iso_ce_len = isonum_733(p->length);
436         return ISO_SUSP_CONT;
437 }
438
439 /*
440  * System Use end
441  */
442 static int
443 cd9660_rrip_stop(ISO_SUSP_HEADER *p, ISO_RRIP_ANALYZE *ana)
444 {
445         return ISO_SUSP_STOP;
446 }
447
448 /*
449  * Extension reference
450  */
451 static int
452 cd9660_rrip_extref(ISO_RRIP_EXTREF *p, ISO_RRIP_ANALYZE *ana)
453 {
454         if (isonum_711(p->len_id) != 10
455             || bcmp((char *)p + 8,"RRIP_1991A",10)
456             || isonum_711(p->version) != 1)
457                 return 0;
458         ana->fields &= ~ISO_SUSP_EXTREF;
459         return ISO_SUSP_EXTREF;
460 }
461
462 static int
463 cd9660_rrip_loop(struct iso_directory_record *isodir, ISO_RRIP_ANALYZE *ana,
464                  RRIP_TABLE *table)
465 {
466         RRIP_TABLE *ptable;
467         ISO_SUSP_HEADER *phead;
468         ISO_SUSP_HEADER *pend;
469         struct buf *bp = NULL;
470         char *pwhead;
471         u_short c;
472         int result;
473
474         /*
475          * Note: If name length is odd,
476          *       it will be padding 1 byte after the name
477          */
478         pwhead = isodir->name + isonum_711(isodir->name_len);
479         if (!(isonum_711(isodir->name_len)&1))
480                 pwhead++;
481         isochar(isodir->name, pwhead, ana->imp->joliet_level, &c, NULL,
482                 ana->imp->im_flags, ana->imp->im_d2l);
483
484         /* If it's not the '.' entry of the root dir obey SP field */
485         if (c != 0 || isonum_733(isodir->extent) != ana->imp->root_extent)
486                 pwhead += ana->imp->rr_skip;
487         else
488                 pwhead += ana->imp->rr_skip0;
489
490         phead = (ISO_SUSP_HEADER *)pwhead;
491         pend = (ISO_SUSP_HEADER *)((char *)isodir + isonum_711(isodir->length));
492
493         result = 0;
494         while (1) {
495                 ana->iso_ce_len = 0;
496                 /*
497                  * Note: "pend" should be more than one SUSP header
498                  */
499                 while (pend >= phead + 1) {
500                         if (isonum_711(phead->version) == 1) {
501                                 for (ptable = table; ptable->func; ptable++) {
502                                         if (*phead->type == *ptable->type
503                                             && phead->type[1] == ptable->type[1]) {
504                                                 result |= ptable->func(phead,ana);
505                                                 break;
506                                         }
507                                 }
508                                 if (!ana->fields)
509                                         break;
510                         }
511                         if (result&ISO_SUSP_STOP) {
512                                 result &= ~ISO_SUSP_STOP;
513                                 break;
514                         }
515                         /* plausibility check */
516                         if (isonum_711(phead->length) < sizeof(*phead))
517                                 break;
518                         /*
519                          * move to next SUSP
520                          * Hopefully this works with newer versions, too
521                          */
522                         phead = (ISO_SUSP_HEADER *)((char *)phead + isonum_711(phead->length));
523                 }
524
525                 if (ana->fields && ana->iso_ce_len) {
526                         if (ana->iso_ce_blk >= ana->imp->volume_space_size
527                             || ana->iso_ce_off + ana->iso_ce_len > ana->imp->logical_block_size
528                             || bread(ana->imp->im_devvp,
529                                      lblktooff(ana->imp, ana->iso_ce_blk),
530                                      ana->imp->logical_block_size, &bp))
531                                 /* what to do now? */
532                                 break;
533                         phead = (ISO_SUSP_HEADER *)(bp->b_data + ana->iso_ce_off);
534                         pend = (ISO_SUSP_HEADER *) ((char *)phead + ana->iso_ce_len);
535                 } else
536                         break;
537         }
538         if (bp)
539                 brelse(bp);
540         /*
541          * If we don't find the Basic SUSP stuffs, just set default value
542          *   (attribute/time stamp)
543          */
544         for (ptable = table; ptable->func2; ptable++)
545                 if (!(ptable->result&result))
546                         ptable->func2(isodir,ana);
547
548         return result;
549 }
550
551 /*
552  * Get Attributes.
553  */
554 /*
555  * XXX the casts are bogus but will do for now.
556  */
557 #define BC      (rrt_func_t *)
558 static RRIP_TABLE rrip_table_analyze[] = {
559         { "PX", BC cd9660_rrip_attr,    cd9660_rrip_defattr,    ISO_SUSP_ATTR },
560         { "TF", BC cd9660_rrip_tstamp,  cd9660_rrip_deftstamp,  ISO_SUSP_TSTAMP },
561         { "PN", BC cd9660_rrip_device,  0,                      ISO_SUSP_DEVICE },
562         { "RR", BC cd9660_rrip_idflag,  0,                      ISO_SUSP_IDFLAG },
563         { "CE", BC cd9660_rrip_cont,    0,                      ISO_SUSP_CONT },
564         { "ST", BC cd9660_rrip_stop,    0,                      ISO_SUSP_STOP },
565         { "",   0,                      0,                      0 }
566 };
567
568 int
569 cd9660_rrip_analyze(struct iso_directory_record *isodir, struct iso_node *inop,
570                     struct iso_mnt *imp)
571 {
572         ISO_RRIP_ANALYZE analyze;
573
574         analyze.inop = inop;
575         analyze.imp = imp;
576         analyze.fields = ISO_SUSP_ATTR|ISO_SUSP_TSTAMP|ISO_SUSP_DEVICE;
577
578         return cd9660_rrip_loop(isodir,&analyze,rrip_table_analyze);
579 }
580
581 /*
582  * Get Alternate Name.
583  */
584 static RRIP_TABLE rrip_table_getname[] = {
585         { "NM", BC cd9660_rrip_altname, cd9660_rrip_defname,    ISO_SUSP_ALTNAME },
586         { "CL", BC cd9660_rrip_pclink,  0,                      ISO_SUSP_CLINK|ISO_SUSP_PLINK },
587         { "PL", BC cd9660_rrip_pclink,  0,                      ISO_SUSP_CLINK|ISO_SUSP_PLINK },
588         { "RE", BC cd9660_rrip_reldir,  0,                      ISO_SUSP_RELDIR },
589         { "RR", BC cd9660_rrip_idflag,  0,                      ISO_SUSP_IDFLAG },
590         { "CE", BC cd9660_rrip_cont,    0,                      ISO_SUSP_CONT },
591         { "ST", BC cd9660_rrip_stop,    0,                      ISO_SUSP_STOP },
592         { "",   0,                      0,                      0 }
593 };
594
595 int
596 cd9660_rrip_getname(struct iso_directory_record *isodir, char *outbuf,
597                     u_short *outlen, ino_t *inump, struct iso_mnt *imp)
598 {
599         ISO_RRIP_ANALYZE analyze;
600         RRIP_TABLE *tab;
601         u_short c;
602
603         analyze.outbuf = outbuf;
604         analyze.outlen = outlen;
605         analyze.maxlen = NAME_MAX;
606         analyze.inump = inump;
607         analyze.imp = imp;
608         analyze.fields = ISO_SUSP_ALTNAME|ISO_SUSP_RELDIR|ISO_SUSP_CLINK|ISO_SUSP_PLINK;
609         *outlen = 0;
610
611         isochar(isodir->name, isodir->name + isonum_711(isodir->name_len),
612                 imp->joliet_level, &c, NULL, imp->im_flags, imp->im_d2l);
613         tab = rrip_table_getname;
614         if (c == 0 || c == 1) {
615                 cd9660_rrip_defname(isodir,&analyze);
616
617                 analyze.fields &= ~ISO_SUSP_ALTNAME;
618                 tab++;
619         }
620
621         return cd9660_rrip_loop(isodir,&analyze,tab);
622 }
623
624 /*
625  * Get Symbolic Link.
626  */
627 static RRIP_TABLE rrip_table_getsymname[] = {
628         { "SL", BC cd9660_rrip_slink,   0,                      ISO_SUSP_SLINK },
629         { "RR", BC cd9660_rrip_idflag,  0,                      ISO_SUSP_IDFLAG },
630         { "CE", BC cd9660_rrip_cont,    0,                      ISO_SUSP_CONT },
631         { "ST", BC cd9660_rrip_stop,    0,                      ISO_SUSP_STOP },
632         { "",   0,                      0,                      0 }
633 };
634
635 int
636 cd9660_rrip_getsymname(struct iso_directory_record *isodir, char *outbuf,
637                        u_short *outlen, struct iso_mnt *imp)
638 {
639         ISO_RRIP_ANALYZE analyze;
640
641         analyze.outbuf = outbuf;
642         analyze.outlen = outlen;
643         *outlen = 0;
644         analyze.maxlen = MAXPATHLEN;
645         analyze.cont = 1;               /* don't start with a slash */
646         analyze.imp = imp;
647         analyze.fields = ISO_SUSP_SLINK;
648
649         return (cd9660_rrip_loop(isodir,&analyze,rrip_table_getsymname)&ISO_SUSP_SLINK);
650 }
651
652 static RRIP_TABLE rrip_table_extref[] = {
653         { "ER", BC cd9660_rrip_extref,  0,                      ISO_SUSP_EXTREF },
654         { "CE", BC cd9660_rrip_cont,    0,                      ISO_SUSP_CONT },
655         { "ST", BC cd9660_rrip_stop,    0,                      ISO_SUSP_STOP },
656         { "",   0,                      0,                      0 }
657 };
658
659 /*
660  * Check for Rock Ridge Extension and return offset of its fields.
661  * Note: We insist on the ER field.
662  */
663 int
664 cd9660_rrip_offset(struct iso_directory_record *isodir, struct iso_mnt *imp)
665 {
666         ISO_RRIP_OFFSET *p;
667         ISO_RRIP_ANALYZE analyze;
668
669         imp->rr_skip0 = 0;
670         p = (ISO_RRIP_OFFSET *)(isodir->name + 1);
671         if (bcmp(p,"SP\7\1\276\357",6)) {
672                 /* Maybe, it's a CDROM XA disc? */
673                 imp->rr_skip0 = 15;
674                 p = (ISO_RRIP_OFFSET *)((char *)p + 15);
675                 if (bcmp(p,"SP\7\1\276\357",6))
676                         return -1;
677         }
678
679         analyze.imp = imp;
680         analyze.fields = ISO_SUSP_EXTREF;
681         if (!(cd9660_rrip_loop(isodir,&analyze,rrip_table_extref)&ISO_SUSP_EXTREF))
682                 return -1;
683
684         return isonum_711(p->skip);
685 }