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