1 /*
2   Copyright (C) 2003-2008, 2011-2015, 2017 Rocky Bernstein <rocky@gnu.org>
3   Copyright (C) 2001 Herbert Valerio Riedel <hvr@gnu.org>
4 
5   This program is free software: you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published by
7   the Free Software Foundation, either version 3 of the License, or
8   (at your option) any later version.
9 
10   This program is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU General Public License for more details.
14 
15   You should have received a copy of the GNU General Public License
16   along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18 /* iso9660 filesystem-based routines */
19 
20 /* FIXME: _cdio_list_free for iso9660 statbuf is insufficient because it doesn't
21    free bits that are allocated inside the data. */
22 
23 
24 #if defined(HAVE_CONFIG_H) && !defined(__CDIO_CONFIG_H__)
25 #include "config.h"
26 #define __CDIO_CONFIG_H__ 1
27 #endif
28 
29 #ifdef HAVE_STDBOOL_H
30 # include <stdbool.h>
31 #endif
32 
33 #ifdef HAVE_STDIO_H
34 #include <stdio.h>
35 #endif
36 
37 #ifdef HAVE_STRING_H
38 #include <string.h>
39 #endif
40 
41 #ifdef HAVE_ERRNO_H
42 #include <errno.h>
43 #endif
44 
45 #ifdef HAVE_LANGINFO_CODESET
46 #include <langinfo.h>
47 #endif
48 
49 #include <cdio/cdio.h>
50 #include <cdio/bytesex.h>
51 #include <cdio/iso9660.h>
52 #include <cdio/util.h>
53 #include <cdio/utf8.h>
54 
55 /* Private headers */
56 #include "cdio_assert.h"
57 #include "_cdio_stdio.h"
58 #include "cdio_private.h"
59 
60 /** Implementation of iso9660_t type */
61 struct _iso9660_s {
62   CdioDataSource_t *stream; /**< Stream pointer */
63   bool_3way_t b_xa;         /**< true if has XA attributes. */
64   bool_3way_t b_mode2;      /**< true if has mode 2, false for mode 1. */
65   uint8_t  u_joliet_level;  /**< 0 = no Joliet extensions.
66 			         1-3: Joliet level. */
67   iso9660_pvd_t pvd;
68   iso9660_svd_t svd;
69   iso_extension_mask_t iso_extension_mask; /**< What extensions we
70 					        tolerate. */
71   uint32_t i_datastart;     /**< Usually 0 when i_framesize is ISO_BLOCKSIZE.
72 			         This is the normal condition. But in a fuzzy
73 			         read we may be reading a CD-image
74 			         and not a true ISO 9660 image this might be
75 			         CDIO_CD_SYNC_SIZE
76                             */
77   uint32_t i_framesize;     /**< Usually ISO_BLOCKSIZE (2048), but in a
78 			        fuzzy read, we may be reading a CD-image
79 			        and not a true ISO 9660 image this might
80 			        be CDIO_CD_FRAMESIZE_RAW (2352) or
81 			        M2RAW_SECTOR_SIZE (2336).
82                             */
83   int i_fuzzy_offset;       /**< Adjustment in bytes to make ISO_STANDARD_ID
84 			         ("CD001") come out as ISO_PVD_SECTOR
85 			         (frame 16).  Normally this should be 0
86 			         for an ISO 9660 image, but if one is
87 			         say reading a BIN/CUE or cdrdao BIN/TOC
88 			         without having the CUE or TOC and
89 			         trying to extract an ISO-9660
90 			         filesystem inside that it may be
91 			         different.
92 			     */
93     bool b_have_superblock; /**< Superblock has been read in? */
94 
95 };
96 
97 static long int iso9660_seek_read_framesize (const iso9660_t *p_iso,
98 					     void *ptr, lsn_t start,
99 					     long int size,
100 					     uint16_t i_framesize);
101 
102 /* Adjust the p_iso's i_datastart, i_byte_offset and i_framesize
103    based on whether we find a frame header or not.
104 */
105 static void
adjust_fuzzy_pvd(iso9660_t * p_iso)106 adjust_fuzzy_pvd( iso9660_t *p_iso )
107 {
108   long int i_byte_offset;
109 
110   if (!p_iso) return;
111 
112   i_byte_offset = (ISO_PVD_SECTOR * p_iso->i_framesize)
113     + p_iso->i_fuzzy_offset + p_iso->i_datastart;
114 
115   /* If we have a raw 2352-byte frame then we should expect to see a sync
116      frame and a header.
117    */
118   if (CDIO_CD_FRAMESIZE_RAW == p_iso->i_framesize) {
119     char buf[CDIO_CD_SYNC_SIZE + CDIO_CD_HEADER_SIZE + CDIO_CD_SUBHEADER_SIZE];
120 
121     i_byte_offset -= CDIO_CD_SYNC_SIZE + CDIO_CD_HEADER_SIZE + CDIO_CD_SUBHEADER_SIZE;
122 
123     if ( DRIVER_OP_SUCCESS != cdio_stream_seek (p_iso->stream, i_byte_offset,
124 						SEEK_SET) )
125       return;
126     if (sizeof(buf) == cdio_stream_read (p_iso->stream, buf, sizeof(buf), 1)) {
127       /* Does the sector frame header suggest Mode 1 format? */
128       if (!memcmp(CDIO_SECTOR_SYNC_HEADER, buf+CDIO_CD_SUBHEADER_SIZE,
129 		  CDIO_CD_SYNC_SIZE)) {
130 	if (buf[14+CDIO_CD_SUBHEADER_SIZE] != 0x16) {
131 	  cdio_warn ("Expecting the PVD sector header MSF to be 0x16, is: %x",
132 		     buf[14]);
133 	}
134 	if (buf[15+CDIO_CD_SUBHEADER_SIZE] != 0x1) {
135 	  cdio_warn ("Expecting the PVD sector mode to be Mode 1 is: %x",
136 		     buf[15]);
137 	}
138 	p_iso->b_mode2 = nope;
139 	p_iso->b_xa = nope;
140       } else if (!memcmp(CDIO_SECTOR_SYNC_HEADER, buf, CDIO_CD_SYNC_SIZE)) {
141 	/* Frame header indicates Mode 2 Form 1*/
142 	if (buf[14] != 0x16) {
143 	  cdio_warn ("Expecting the PVD sector header MSF to be 0x16, is: %x",
144 		     buf[14]);
145 	}
146 	if (buf[15] != 0x2) {
147 	  cdio_warn ("Expecting the PVD sector mode to be Mode 2 is: %x",
148 		     buf[15]);
149 	}
150 	p_iso->b_mode2 = yep;
151 	/* Do do: check Mode 2 Form 2? */
152       } else {
153 	  /* Has no frame header */
154 	  p_iso->i_framesize = M2RAW_SECTOR_SIZE;
155 	  p_iso->i_fuzzy_offset = (CDIO_CD_FRAMESIZE_RAW - M2RAW_SECTOR_SIZE)
156 	    * ISO_PVD_SECTOR + p_iso->i_fuzzy_offset + p_iso->i_datastart;
157 	  p_iso->i_datastart = 0;
158 	}
159     }
160   }
161 
162 
163 }
164 
165 /*!
166   Open an ISO 9660 image for reading in either fuzzy mode or not.
167 */
168 static iso9660_t *
iso9660_open_ext_private(const char * psz_path,iso_extension_mask_t iso_extension_mask,uint16_t i_fuzz,bool b_fuzzy)169 iso9660_open_ext_private (const char *psz_path,
170 			  iso_extension_mask_t iso_extension_mask,
171 			  uint16_t i_fuzz, bool b_fuzzy)
172 {
173   iso9660_t *p_iso = (iso9660_t *) calloc(1, sizeof(iso9660_t)) ;
174 
175   if (!p_iso) return NULL;
176 
177   p_iso->stream = cdio_stdio_new( psz_path );
178   if (NULL == p_iso->stream)
179     goto error;
180 
181   p_iso->i_framesize = ISO_BLOCKSIZE;
182 
183   p_iso->b_have_superblock = (b_fuzzy)
184     ? iso9660_ifs_fuzzy_read_superblock(p_iso, iso_extension_mask, i_fuzz)
185     : iso9660_ifs_read_superblock(p_iso, iso_extension_mask) ;
186 
187   if ( ! p_iso->b_have_superblock ) goto error;
188 
189   /* Determine if image has XA attributes. */
190 
191   p_iso->b_xa = strncmp ((char *) &(p_iso->pvd) + ISO_XA_MARKER_OFFSET,
192 			 ISO_XA_MARKER_STRING,
193 			 sizeof (ISO_XA_MARKER_STRING))
194     ? nope : yep;
195 
196   p_iso->iso_extension_mask = iso_extension_mask;
197   return p_iso;
198 
199  error:
200   if (p_iso && p_iso->stream) cdio_stdio_destroy(p_iso->stream);
201   free(p_iso);
202 
203   return NULL;
204 }
205 
206 /*!
207   Open an ISO 9660 image for reading. Maybe in the future we will have
208   a mode. NULL is returned on error.
209 
210   @param psz_path full path of ISO9660 file.
211 
212   @return a IS9660 structure  is unconditionally returned. The caller
213   should call iso9660_close() when done.
214 */
215 iso9660_t *
iso9660_open(const char * psz_path)216 iso9660_open (const char *psz_path /*, mode*/)
217 {
218   return iso9660_open_ext(psz_path, ISO_EXTENSION_NONE);
219 }
220 
221 /*!
222   Open an ISO 9660 image for reading allowing various ISO 9660
223   extensions.  Maybe in the future we will have a mode. NULL is
224   returned on error.
225 
226   @see iso9660_open_fuzzy
227 */
228 iso9660_t *
iso9660_open_ext(const char * psz_path,iso_extension_mask_t iso_extension_mask)229 iso9660_open_ext (const char *psz_path,
230 		  iso_extension_mask_t iso_extension_mask)
231 {
232   return iso9660_open_ext_private(psz_path, iso_extension_mask, 0, false);
233 }
234 
235 
236 /*! Open an ISO 9660 image for "fuzzy" reading. This means that we
237   will try to guess various internal offset based on internal
238   checks. This may be useful when trying to read an ISO 9660 image
239   contained in a file format that libiso9660 doesn't know natively
240   (or knows imperfectly.)
241 
242   Some tolerence allowed for positioning the ISO 9660 image. We scan
243   for STANDARD_ID and use that to set the eventual offset to adjust
244   by (as long as that is <= i_fuzz).
245 
246   Maybe in the future we will have a mode. NULL is returned on error.
247 
248   @see iso9660_open, @see iso9660_fuzzy_ext
249 */
250 iso9660_t *
iso9660_open_fuzzy(const char * psz_path,uint16_t i_fuzz)251 iso9660_open_fuzzy (const char *psz_path, uint16_t i_fuzz /*, mode*/)
252 {
253   return iso9660_open_fuzzy_ext(psz_path, ISO_EXTENSION_NONE, i_fuzz);
254 }
255 
256 /*!
257   Open an ISO 9660 image for reading with some tolerence for positioning
258   of the ISO9660 image. We scan for ISO_STANDARD_ID and use that to set
259   the eventual offset to adjust by (as long as that is <= i_fuzz).
260 
261   Maybe in the future we will have a mode. NULL is returned on error.
262 
263   @see iso9660_open_ext @see iso9660_open_fuzzy
264 */
265 iso9660_t *
iso9660_open_fuzzy_ext(const char * psz_path,iso_extension_mask_t iso_extension_mask,uint16_t i_fuzz)266 iso9660_open_fuzzy_ext (const char *psz_path,
267 			iso_extension_mask_t iso_extension_mask,
268 			uint16_t i_fuzz)
269 {
270   return iso9660_open_ext_private(psz_path, iso_extension_mask, i_fuzz,
271 				  true);
272 }
273 
274 /*! Close previously opened ISO 9660 image and free resources
275     associated with the image. Call this when done using using an ISO
276     9660 image.
277 
278     @return true is unconditionally returned. If there was an error
279     false would be returned.
280 */
281 bool
iso9660_close(iso9660_t * p_iso)282 iso9660_close (iso9660_t *p_iso)
283 {
284   if (NULL != p_iso) {
285     cdio_stdio_destroy(p_iso->stream);
286     p_iso->stream = NULL;
287     free(p_iso);
288   }
289   return true;
290 }
291 
292 static bool
check_pvd(const iso9660_pvd_t * p_pvd,cdio_log_level_t log_level)293 check_pvd (const iso9660_pvd_t *p_pvd, cdio_log_level_t log_level)
294 {
295   if ( ISO_VD_PRIMARY != from_711(p_pvd->type) ) {
296     cdio_log (log_level, "unexpected PVD type %d", p_pvd->type);
297     return false;
298   }
299 
300   if (strncmp (p_pvd->id, ISO_STANDARD_ID, strlen (ISO_STANDARD_ID)))
301     {
302       cdio_log (log_level, "unexpected ID encountered (expected `"
303 		ISO_STANDARD_ID "', got `%.5s')", p_pvd->id);
304       return false;
305     }
306   return true;
307 }
308 
309 
310 /*!
311   Core procedure for the iso9660_ifs_get_###_id() calls.
312   pvd_member/svd_member is a pointer to an achar_t or dchar_t
313   ID string which we can superset as char.
314   If the Joliet converted string is the same as the achar_t/dchar_t
315   one, we fall back to using the latter, as it may be longer.
316 */
317 static inline bool
get_member_id(iso9660_t * p_iso,cdio_utf8_t ** p_psz_member_id,char * pvd_member,char * svd_member,size_t max_size)318 get_member_id(iso9660_t *p_iso, cdio_utf8_t **p_psz_member_id,
319               char* pvd_member, char* svd_member, size_t max_size)
320 {
321   int j;
322   bool strip;
323 
324   if (!p_iso) {
325     *p_psz_member_id = NULL;
326     return false;
327   }
328 #ifdef HAVE_JOLIET
329   if (p_iso->u_joliet_level) {
330     /* Translate USC-2 string from Secondary Volume Descriptor */
331     if (cdio_charset_to_utf8(svd_member, max_size,
332                             p_psz_member_id, "UCS-2BE")) {
333       /* NB: *p_psz_member_id is never NULL on success. */
334       if (strncmp(*p_psz_member_id, pvd_member,
335                   strlen(*p_psz_member_id)) != 0) {
336         /* Strip trailing spaces */
337         for (j = strlen(*p_psz_member_id)-1; j >= 0; j--) {
338           if ((*p_psz_member_id)[j] != ' ')
339             break;
340           (*p_psz_member_id)[j] = '\0';
341         }
342         if ((*p_psz_member_id)[0] != 0) {
343           /* Joliet string is not empty and differs from
344              non Joliet one => use it */
345           return true;
346         }
347       }
348       /* Joliet string was either empty or same */
349       free(*p_psz_member_id);
350     }
351   }
352 #endif /*HAVE_JOLIET*/
353   *p_psz_member_id = calloc(max_size+1, sizeof(cdio_utf8_t));
354   if (!*p_psz_member_id) {
355     cdio_warn("Memory allocation error");
356     return false;
357   }
358   /* Copy string while removing trailing spaces */
359   (*p_psz_member_id)[max_size] = 0;
360   for (strip=true, j=max_size-1; j>=0; j--) {
361     if (strip && (pvd_member[j] == ' '))
362       continue;
363     strip = false;
364     (*p_psz_member_id)[j] = pvd_member[j];
365   }
366   if (strlen(*p_psz_member_id) == 0) {
367     free(*p_psz_member_id);
368     *p_psz_member_id = NULL;
369     return false;
370   }
371   return true;
372 }
373 
374 
375 /*!
376   Return the application ID.  NULL is returned in psz_app_id if there
377   is some problem in getting this.
378 */
379 bool
iso9660_ifs_get_application_id(iso9660_t * p_iso,cdio_utf8_t ** p_psz_app_id)380 iso9660_ifs_get_application_id(iso9660_t *p_iso,
381 			       /*out*/ cdio_utf8_t **p_psz_app_id)
382 {
383   return get_member_id(p_iso, p_psz_app_id,
384                        (char*)p_iso->pvd.application_id,
385                        (char*)p_iso->svd.application_id,
386                        ISO_MAX_APPLICATION_ID);
387 }
388 
389 /*!
390   Return the Joliet level recognized for p_iso.
391 */
iso9660_ifs_get_joliet_level(iso9660_t * p_iso)392 uint8_t iso9660_ifs_get_joliet_level(iso9660_t *p_iso)
393 {
394   if (!p_iso) return 0;
395   return p_iso->u_joliet_level;
396 }
397 
398 /*!
399    Return a string containing the preparer id with trailing
400    blanks removed.
401 */
402 bool
iso9660_ifs_get_preparer_id(iso9660_t * p_iso,cdio_utf8_t ** p_psz_preparer_id)403 iso9660_ifs_get_preparer_id(iso9660_t *p_iso,
404 			/*out*/ cdio_utf8_t **p_psz_preparer_id)
405 {
406   return get_member_id(p_iso, p_psz_preparer_id,
407                        (char*)p_iso->pvd.preparer_id,
408                        (char*)p_iso->svd.preparer_id,
409                        ISO_MAX_PREPARER_ID);
410 }
411 
412 /*!
413    Return a string containing the PVD's publisher id with trailing
414    blanks removed.
415 */
iso9660_ifs_get_publisher_id(iso9660_t * p_iso,cdio_utf8_t ** p_psz_publisher_id)416 bool iso9660_ifs_get_publisher_id(iso9660_t *p_iso,
417                                   /*out*/ cdio_utf8_t **p_psz_publisher_id)
418 {
419   return get_member_id(p_iso, p_psz_publisher_id,
420                        (char*)p_iso->pvd.publisher_id,
421                        (char*)p_iso->svd.publisher_id,
422                        ISO_MAX_PUBLISHER_ID);
423 }
424 
425 /*!
426    Return a string containing the PVD's publisher id with trailing
427    blanks removed.
428 */
iso9660_ifs_get_system_id(iso9660_t * p_iso,cdio_utf8_t ** p_psz_system_id)429 bool iso9660_ifs_get_system_id(iso9660_t *p_iso,
430 			       /*out*/ cdio_utf8_t **p_psz_system_id)
431 {
432   return get_member_id(p_iso, p_psz_system_id,
433                        (char*)p_iso->pvd.system_id,
434                        (char*)p_iso->svd.system_id,
435                        ISO_MAX_SYSTEM_ID);
436 }
437 
438 /*!
439    Return a string containing the PVD's publisher id with trailing
440    blanks removed.
441 */
iso9660_ifs_get_volume_id(iso9660_t * p_iso,cdio_utf8_t ** p_psz_volume_id)442 bool iso9660_ifs_get_volume_id(iso9660_t *p_iso,
443 			       /*out*/ cdio_utf8_t **p_psz_volume_id)
444 {
445   return get_member_id(p_iso, p_psz_volume_id,
446                        (char*)p_iso->pvd.volume_id,
447                        (char*)p_iso->svd.volume_id,
448                        ISO_MAX_VOLUME_ID);
449 }
450 
451 /*!
452    Return a string containing the PVD's publisher id with trailing
453    blanks removed.
454 */
iso9660_ifs_get_volumeset_id(iso9660_t * p_iso,cdio_utf8_t ** p_psz_volumeset_id)455 bool iso9660_ifs_get_volumeset_id(iso9660_t *p_iso,
456 				  /*out*/ cdio_utf8_t **p_psz_volumeset_id)
457 {
458   return get_member_id(p_iso, p_psz_volumeset_id,
459                        (char*)p_iso->pvd.volume_set_id,
460                        (char*)p_iso->svd.volume_set_id,
461                        ISO_MAX_VOLUMESET_ID);
462 }
463 
464 
465 /*!
466   Read the Primary Volume Descriptor for an ISO 9660 image.
467   True is returned if read, and false if there was an error.
468 */
469 static bool
iso9660_ifs_read_pvd_loglevel(const iso9660_t * p_iso,iso9660_pvd_t * p_pvd,cdio_log_level_t log_level)470 iso9660_ifs_read_pvd_loglevel (const iso9660_t *p_iso,
471 			       /*out*/ iso9660_pvd_t *p_pvd,
472 			       cdio_log_level_t log_level)
473 {
474   if (0 == iso9660_iso_seek_read (p_iso, p_pvd, ISO_PVD_SECTOR, 1)) {
475     cdio_log ( log_level, "error reading PVD sector (%d)", ISO_PVD_SECTOR );
476     return false;
477   }
478   return check_pvd(p_pvd, log_level);
479 }
480 
481 /*!
482   Read the Primary Volume Descriptor for an ISO 9660 image.
483   True is returned if read, and false if there was an error.
484 */
485 bool
iso9660_ifs_read_pvd(const iso9660_t * p_iso,iso9660_pvd_t * p_pvd)486 iso9660_ifs_read_pvd (const iso9660_t *p_iso, /*out*/ iso9660_pvd_t *p_pvd)
487 {
488   return iso9660_ifs_read_pvd_loglevel(p_iso, p_pvd, CDIO_LOG_WARN);
489 }
490 
491 
492 /*!
493   Read the Super block of an ISO 9660 image. This is the
494   Primary Volume Descriptor (PVD) and perhaps a Supplemental Volume
495   Descriptor if (Joliet) extensions are acceptable.
496 */
497 bool
iso9660_ifs_read_superblock(iso9660_t * p_iso,iso_extension_mask_t iso_extension_mask)498 iso9660_ifs_read_superblock (iso9660_t *p_iso,
499 			     iso_extension_mask_t iso_extension_mask)
500 {
501   iso9660_svd_t p_svd;  /* Secondary volume descriptor. */
502   int i;
503 
504   if (!p_iso || !iso9660_ifs_read_pvd(p_iso, &(p_iso->pvd)))
505     return false;
506 
507   p_iso->u_joliet_level = 0;
508 
509   /* There may be multiple Secondary Volume Descriptors (eg. El Torito + Joliet) */
510   for (i=1; (0 != iso9660_iso_seek_read (p_iso, &p_svd, ISO_PVD_SECTOR+i, 1)); i++) {
511     if (ISO_VD_END == from_711(p_svd.type) ) /* Last SVD */
512       break;
513     if ( ISO_VD_SUPPLEMENTARY == from_711(p_svd.type) ) {
514       /* We're only interested in Joliet => make sure the SVD isn't overwritten */
515       if (p_iso->u_joliet_level == 0)
516         memcpy(&(p_iso->svd), &p_svd, sizeof(iso9660_svd_t));
517       if (p_svd.escape_sequences[0] == 0x25
518 	  && p_svd.escape_sequences[1] == 0x2f) {
519 	switch (p_svd.escape_sequences[2]) {
520 	case 0x40:
521 	  if (iso_extension_mask & ISO_EXTENSION_JOLIET_LEVEL1)
522 	    p_iso->u_joliet_level = 1;
523 	  break;
524 	case 0x43:
525 	  if (iso_extension_mask & ISO_EXTENSION_JOLIET_LEVEL2)
526 	    p_iso->u_joliet_level = 2;
527 	  break;
528 	case 0x45:
529 	  if (iso_extension_mask & ISO_EXTENSION_JOLIET_LEVEL3)
530 	    p_iso->u_joliet_level = 3;
531 	  break;
532 	default:
533 	  cdio_info("Supplementary Volume Descriptor found, but not Joliet");
534 	}
535 	if (p_iso->u_joliet_level > 0) {
536 	  cdio_info("Found Extension: Joliet Level %d", p_iso->u_joliet_level);
537 	}
538       }
539     }
540   }
541 
542   return true;
543 }
544 
545 /*!
546   Read the Super block of an ISO 9660 image but determine framesize
547   and datastart and a possible additional offset. Generally here we are
548   not reading an ISO 9660 image but a CD-Image which contains an ISO 9660
549   filesystem.
550 */
551 bool
iso9660_ifs_fuzzy_read_superblock(iso9660_t * p_iso,iso_extension_mask_t iso_extension_mask,uint16_t i_fuzz)552 iso9660_ifs_fuzzy_read_superblock (iso9660_t *p_iso,
553 				   iso_extension_mask_t iso_extension_mask,
554 				   uint16_t i_fuzz)
555 {
556   /* Got some work to do to find ISO_STANDARD_ID ("CD001") */
557   unsigned int i;
558 
559   for (i=0; i<i_fuzz; i++) {
560     unsigned int j;
561     char *pvd = NULL;
562 
563     for (j = 0; j <= 1; j++ ) {
564       lsn_t lsn;
565       uint16_t k;
566       const uint16_t framesizes[] = { ISO_BLOCKSIZE, CDIO_CD_FRAMESIZE_RAW,
567 				      M2RAW_SECTOR_SIZE } ;
568 
569       /* We don't need to loop over a zero offset twice*/
570       if (0==i && j)
571 	continue;
572 
573       lsn = (j) ? ISO_PVD_SECTOR - i : ISO_PVD_SECTOR + i;
574 
575       for (k=0; k < 3; k++) {
576 	char *p, *q;
577 	char frame[CDIO_CD_FRAMESIZE_RAW] = {'\0',};
578 	p_iso->i_framesize = framesizes[k];
579 	p_iso->i_datastart = (ISO_BLOCKSIZE == framesizes[k]) ?
580 			      0 : CDIO_CD_SYNC_SIZE;
581 	p_iso->i_fuzzy_offset = 0;
582 	if (0 == iso9660_seek_read_framesize (p_iso, frame, lsn, 1,
583 					      p_iso->i_framesize)) {
584 	  return false;
585 	}
586 
587 	q = memchr(frame, 'C', p_iso->i_framesize);
588 	for ( p=q; p && p < frame + p_iso->i_framesize ; p=q+1 ) {
589 	  q = memchr(p, 'C', p_iso->i_framesize - (p - frame));
590 	  if ( !q || (pvd = strstr(q, ISO_STANDARD_ID)) )
591 	    break;
592 	}
593 
594 	if (pvd) {
595 	  /* Yay! Found something */
596 	  p_iso->i_fuzzy_offset = (pvd - frame - 1) -
597 	    ((ISO_PVD_SECTOR-lsn)*p_iso->i_framesize) ;
598 	  /* But is it *really* a PVD? */
599 	  if ( iso9660_ifs_read_pvd_loglevel(p_iso, &(p_iso->pvd),
600 					     CDIO_LOG_DEBUG) ) {
601 	    adjust_fuzzy_pvd(p_iso);
602 	    return true;
603 	  }
604 
605 	}
606       }
607     }
608   }
609   return false;
610 }
611 
612 
613 /*!
614   Read the Primary Volume Descriptor for of CD.
615 */
616 bool
iso9660_fs_read_pvd(const CdIo_t * p_cdio,iso9660_pvd_t * p_pvd)617 iso9660_fs_read_pvd(const CdIo_t *p_cdio, /*out*/ iso9660_pvd_t *p_pvd)
618 {
619   /* A bit of a hack, we'll assume track 1 contains ISO_PVD_SECTOR.*/
620   char buf[CDIO_CD_FRAMESIZE_RAW] = { 0, };
621   driver_return_code_t driver_return =
622     cdio_read_data_sectors (p_cdio, buf, ISO_PVD_SECTOR, ISO_BLOCKSIZE, 1);
623 
624   if (DRIVER_OP_SUCCESS != driver_return) {
625     cdio_warn ("error reading PVD sector (%d) error %d", ISO_PVD_SECTOR,
626 	       driver_return);
627     return false;
628   }
629 
630   /* The size of a PVD or SVD is smaller than a sector. So we
631      allocated a bigger block above (buf) and now we'll copy just
632      the part we need to save.
633    */
634   cdio_assert (sizeof(buf) >= sizeof (iso9660_pvd_t));
635   memcpy(p_pvd, buf, sizeof(iso9660_pvd_t));
636 
637   return check_pvd(p_pvd, CDIO_LOG_WARN);
638 }
639 
640 
641 /*!
642   Read the Super block of an ISO 9660 image. This is the
643   Primary Volume Descriptor (PVD) and perhaps a Supplemental Volume
644   Descriptor if (Joliet) extensions are acceptable.
645 */
646 bool
iso9660_fs_read_superblock(CdIo_t * p_cdio,iso_extension_mask_t iso_extension_mask)647 iso9660_fs_read_superblock (CdIo_t *p_cdio,
648 			    iso_extension_mask_t iso_extension_mask)
649 {
650   if (!p_cdio) return false;
651 
652   {
653     generic_img_private_t *p_env = (generic_img_private_t *) p_cdio->env;
654     iso9660_pvd_t         *p_pvd = &(p_env->pvd);
655     iso9660_svd_t         *p_svd = &(p_env->svd);
656     char buf[CDIO_CD_FRAMESIZE_RAW] = { 0, };
657     driver_return_code_t driver_return;
658 
659     if ( !iso9660_fs_read_pvd(p_cdio, p_pvd) )
660       return false;
661 
662     p_env->u_joliet_level = 0;
663 
664     driver_return =
665       cdio_read_data_sectors ( p_cdio, buf, ISO_PVD_SECTOR+1, ISO_BLOCKSIZE,
666 			       1 );
667 
668     if (DRIVER_OP_SUCCESS == driver_return) {
669       /* The size of a PVD or SVD is smaller than a sector. So we
670 	 allocated a bigger block above (buf) and now we'll copy just
671 	 the part we need to save.
672       */
673       cdio_assert (sizeof(buf) >= sizeof (iso9660_svd_t));
674       memcpy(p_svd, buf, sizeof(iso9660_svd_t));
675 
676       if ( ISO_VD_SUPPLEMENTARY == from_711(p_svd->type) ) {
677 	if (p_svd->escape_sequences[0] == 0x25
678 	    && p_svd->escape_sequences[1] == 0x2f) {
679 	  switch (p_svd->escape_sequences[2]) {
680 	  case 0x40:
681 	    if (iso_extension_mask & ISO_EXTENSION_JOLIET_LEVEL1)
682 	      p_env->u_joliet_level = 1;
683 	    break;
684 	  case 0x43:
685 	    if (iso_extension_mask & ISO_EXTENSION_JOLIET_LEVEL2)
686 	      p_env->u_joliet_level = 2;
687 	    break;
688 	  case 0x45:
689 	    if (iso_extension_mask & ISO_EXTENSION_JOLIET_LEVEL3)
690 	      p_env->u_joliet_level = 3;
691 	    break;
692 	  default:
693 	    cdio_info("Supplementary Volume Descriptor found, but not Joliet");
694 	  }
695 	  if (p_env->u_joliet_level > 0) {
696 	    cdio_info("Found Extension: Joliet Level %d",
697 		      p_env->u_joliet_level);
698 	  }
699 	}
700       }
701     }
702   }
703 
704   return true;
705 }
706 
707 /*!
708   Seek to a position and then read n blocks. Size read is returned.
709 */
710 static long int
iso9660_seek_read_framesize(const iso9660_t * p_iso,void * ptr,lsn_t start,long int size,uint16_t i_framesize)711 iso9660_seek_read_framesize (const iso9660_t *p_iso, void *ptr,
712 			     lsn_t start, long int size,
713 			     uint16_t i_framesize)
714 {
715   long int ret;
716   int64_t i_byte_offset;
717 
718   if (!p_iso) return 0;
719   i_byte_offset = (start * (int64_t)(p_iso->i_framesize))
720     + p_iso->i_fuzzy_offset + p_iso->i_datastart;
721 
722   ret = cdio_stream_seek (p_iso->stream, i_byte_offset, SEEK_SET);
723   if (ret!=0) return 0;
724   return cdio_stream_read (p_iso->stream, ptr, i_framesize, size);
725 }
726 
727 /*!
728   Seek to a position and then read n blocks. Size read is returned.
729 */
730 long int
iso9660_iso_seek_read(const iso9660_t * p_iso,void * ptr,lsn_t start,long int size)731 iso9660_iso_seek_read (const iso9660_t *p_iso, void *ptr, lsn_t start,
732 		       long int size)
733 {
734   return iso9660_seek_read_framesize(p_iso, ptr, start, size, ISO_BLOCKSIZE);
735 }
736 
737 
738 
739 /*!
740   Check for the end of a directory record list in a single directory
741   block.  If at the end, set the offset to start of the next block and
742   return "true". The caller often skips actions only when at the end
743   of a record list.
744 */
745 static bool
iso9660_check_dir_block_end(iso9660_dir_t * p_iso9660_dir,unsigned * offset)746 iso9660_check_dir_block_end(iso9660_dir_t *p_iso9660_dir, unsigned *offset)
747 {
748   if (!iso9660_get_dir_len(p_iso9660_dir))
749     {
750       /*
751 	 Length 0 indicates that no more directory records are in this
752 	 block. This matches how Linux and libburn's libisofs work.
753 
754 	 Note that assignment below does not exactly round up.
755 	 If (offset % ISO_BLOCKSIZE) == 0  then offset is incremented
756 	 by ISO_BLOCKSIZE, i.e. the block is skipped.
757       */
758       *offset += ISO_BLOCKSIZE - (*offset % ISO_BLOCKSIZE);
759       return true;
760     }
761 
762   if ((*offset + iso9660_get_dir_len(p_iso9660_dir) - 1) / ISO_BLOCKSIZE
763       != *offset / ISO_BLOCKSIZE)
764     {
765       /*
766 	 Directory record spans over block limit.
767 	 Hop to next block where a new record is supposed to begin,
768 	 if it is not after the end of the directory data.
769        */
770       *offset += ISO_BLOCKSIZE - (*offset % ISO_BLOCKSIZE);
771       return true;
772     }
773 
774   return false;
775 }
776 
777 
778 
779 static iso9660_stat_t *
_iso9660_dir_to_statbuf(iso9660_dir_t * p_iso9660_dir,bool_3way_t b_xa,uint8_t u_joliet_level)780 _iso9660_dir_to_statbuf (iso9660_dir_t *p_iso9660_dir, bool_3way_t b_xa,
781 			 uint8_t u_joliet_level)
782 {
783   uint8_t dir_len= iso9660_get_dir_len(p_iso9660_dir);
784   iso711_t i_fname;
785   unsigned int stat_len;
786   iso9660_stat_t *p_stat = NULL;
787 
788   if (!dir_len) return NULL;
789 
790   i_fname  = from_711(p_iso9660_dir->filename.len);
791 
792   /* .. string in statbuf is one longer than in p_iso9660_dir's listing '\1' */
793   stat_len      = sizeof(iso9660_stat_t)+i_fname+2;
794 
795   p_stat          = calloc(1, stat_len);
796   if (!p_stat)
797     {
798     cdio_warn("Couldn't calloc(1, %d)", stat_len);
799     return NULL;
800     }
801   p_stat->type    = (p_iso9660_dir->file_flags & ISO_DIRECTORY)
802     ? _STAT_DIR : _STAT_FILE;
803   p_stat->lsn     = from_733 (p_iso9660_dir->extent);
804   p_stat->size    = from_733 (p_iso9660_dir->size);
805   p_stat->secsize = _cdio_len2blocks (p_stat->size, ISO_BLOCKSIZE);
806   p_stat->rr.b3_rock = dunno; /*FIXME should do based on mask */
807   p_stat->b_xa    = false;
808 
809   {
810     char rr_fname[256] = "";
811 
812     int  i_rr_fname =
813 #ifdef HAVE_ROCK
814       get_rock_ridge_filename(p_iso9660_dir, rr_fname, p_stat);
815 #else
816       0;
817 #endif
818 
819     if (i_rr_fname > 0) {
820       if (i_rr_fname > i_fname) {
821 	/* realloc gives valgrind errors */
822 	iso9660_stat_t *p_stat_new =
823 	  calloc(1, sizeof(iso9660_stat_t)+i_rr_fname+2);
824         if (!p_stat_new)
825           {
826           cdio_warn("Couldn't calloc(1, %d)", (int)(sizeof(iso9660_stat_t)+i_rr_fname+2));
827 	  free(p_stat);
828           return NULL;
829           }
830 	memcpy(p_stat_new, p_stat, stat_len);
831 	free(p_stat);
832 	p_stat = p_stat_new;
833       }
834       strncpy(p_stat->filename, rr_fname, i_rr_fname+1);
835     } else {
836       if ('\0' == p_iso9660_dir->filename.str[1] && 1 == i_fname)
837 	strncpy (p_stat->filename, ".", strlen(".")+1);
838       else if ('\1' == p_iso9660_dir->filename.str[1] && 1 == i_fname)
839 	strncpy (p_stat->filename, "..", strlen("..")+1);
840 #ifdef HAVE_JOLIET
841       else if (u_joliet_level) {
842 	int i_inlen = i_fname;
843 	cdio_utf8_t *p_psz_out = NULL;
844 	if (cdio_charset_to_utf8(&p_iso9660_dir->filename.str[1], i_inlen,
845                              &p_psz_out, "UCS-2BE")) {
846           strncpy(p_stat->filename, p_psz_out, i_fname);
847           free(p_psz_out);
848         }
849         else {
850           free(p_stat);
851           return NULL;
852         }
853       }
854 #endif /*HAVE_JOLIET*/
855       else {
856 	strncpy (p_stat->filename, &p_iso9660_dir->filename.str[1], i_fname);
857       }
858     }
859   }
860 
861 
862   iso9660_get_dtime(&(p_iso9660_dir->recording_time), true, &(p_stat->tm));
863 
864   if (dir_len < sizeof (iso9660_dir_t)) {
865     iso9660_stat_free(p_stat);
866     return NULL;
867   }
868 
869 
870   {
871     int su_length = iso9660_get_dir_len(p_iso9660_dir)
872       - sizeof (iso9660_dir_t);
873     su_length -= i_fname;
874 
875     if (su_length % 2)
876       su_length--;
877 
878     if (su_length < 0 || su_length < sizeof (iso9660_xa_t))
879       return p_stat;
880 
881     if (nope == b_xa) {
882       return p_stat;
883     } else {
884       iso9660_xa_t *xa_data =
885 	(void *) (((char *) p_iso9660_dir)
886 		  + (iso9660_get_dir_len(p_iso9660_dir) - su_length));
887       cdio_log_level_t loglevel = (yep == b_xa)
888 	? CDIO_LOG_WARN : CDIO_LOG_INFO;
889 
890       if (xa_data->signature[0] != 'X'
891 	  || xa_data->signature[1] != 'A')
892 	{
893 	  cdio_log (loglevel,
894 		    "XA signature not found in ISO9660's system use area;"
895 		     " ignoring XA attributes for this file entry.");
896 	  cdio_debug ("%d %d %d, '%c%c' (%d, %d)",
897 		      iso9660_get_dir_len(p_iso9660_dir),
898 		      i_fname,
899 		      su_length,
900 		      xa_data->signature[0], xa_data->signature[1],
901 		      xa_data->signature[0], xa_data->signature[1]);
902 	  return p_stat;
903 	}
904       p_stat->b_xa = true;
905       p_stat->xa   = *xa_data;
906     }
907   }
908   return p_stat;
909 
910 }
911 
912 /*!
913   Return the directory name stored in the iso9660_dir_t
914 
915   A string is allocated: the caller must deallocate. This routine
916   can return NULL if memory allocation fails.
917  */
918 char *
iso9660_dir_to_name(const iso9660_dir_t * iso9660_dir)919 iso9660_dir_to_name (const iso9660_dir_t *iso9660_dir)
920 {
921   uint8_t len=iso9660_get_dir_len(iso9660_dir);
922 
923   if (!len) return NULL;
924 
925   cdio_assert (len >= sizeof (iso9660_dir_t));
926 
927   /* (iso9660_dir->file_flags & ISO_DIRECTORY) */
928 
929   if (iso9660_dir->filename.str[1] == '\0')
930     return strdup(".");
931   else if (iso9660_dir->filename.str[1] == '\1')
932     return strdup("..");
933   else {
934     return strdup(&iso9660_dir->filename.str[1]);
935   }
936 }
937 
938 /*
939    Return a pointer to a ISO 9660 stat buffer or NULL if there's an error
940 */
941 static iso9660_stat_t *
_fs_stat_root(CdIo_t * p_cdio)942 _fs_stat_root (CdIo_t *p_cdio)
943 {
944 
945   if (!p_cdio) return NULL;
946 
947   {
948     iso_extension_mask_t iso_extension_mask = ISO_EXTENSION_ALL;
949     generic_img_private_t *p_env = (generic_img_private_t *) p_cdio->env;
950     iso9660_dir_t *p_iso9660_dir;
951     iso9660_stat_t *p_stat;
952     bool_3way_t b_xa;
953 
954     if (!p_env->u_joliet_level)
955       iso_extension_mask &= ~ISO_EXTENSION_JOLIET;
956 
957     /* FIXME try also with Joliet.*/
958     if ( !iso9660_fs_read_superblock (p_cdio, iso_extension_mask) ) {
959       cdio_warn("Could not read ISO-9660 Superblock.");
960       return NULL;
961     }
962 
963     switch(cdio_get_discmode(p_cdio)) {
964     case CDIO_DISC_MODE_CD_XA:
965       b_xa = yep;
966       break;
967     case CDIO_DISC_MODE_CD_DATA:
968       b_xa = nope;
969       break;
970     default:
971       b_xa = dunno;
972     }
973 
974 #ifdef HAVE_JOLIET
975     p_iso9660_dir = p_env->u_joliet_level
976       ? &(p_env->svd.root_directory_record)
977       : &(p_env->pvd.root_directory_record) ;
978 #else
979     p_iso9660_dir = &(p_env->pvd.root_directory_record) ;
980 #endif
981 
982     p_stat = _iso9660_dir_to_statbuf (p_iso9660_dir, b_xa,
983 				      p_env->u_joliet_level);
984     return p_stat;
985   }
986 
987 }
988 
989 static iso9660_stat_t *
_ifs_stat_root(iso9660_t * p_iso)990 _ifs_stat_root (iso9660_t *p_iso)
991 {
992   iso9660_stat_t *p_stat;
993   iso9660_dir_t *p_iso9660_dir;
994 
995 #ifdef HAVE_JOLIET
996   p_iso9660_dir = p_iso->u_joliet_level
997     ? &(p_iso->svd.root_directory_record)
998     : &(p_iso->pvd.root_directory_record) ;
999 #else
1000   p_iso9660_dir = &(p_iso->pvd.root_directory_record) ;
1001 #endif
1002 
1003   p_stat = _iso9660_dir_to_statbuf (p_iso9660_dir, p_iso->b_xa,
1004 				    p_iso->u_joliet_level);
1005   return p_stat;
1006 }
1007 
1008 static iso9660_stat_t *
_fs_stat_traverse(const CdIo_t * p_cdio,const iso9660_stat_t * _root,char ** splitpath)1009 _fs_stat_traverse (const CdIo_t *p_cdio, const iso9660_stat_t *_root,
1010 		   char **splitpath)
1011 {
1012   unsigned offset = 0;
1013   uint8_t *_dirbuf = NULL;
1014   iso9660_stat_t *p_stat;
1015   generic_img_private_t *p_env = (generic_img_private_t *) p_cdio->env;
1016 
1017   if (!splitpath[0])
1018     {
1019       unsigned int len=sizeof(iso9660_stat_t) + strlen(_root->filename)+1;
1020       p_stat = calloc(1, len);
1021       cdio_assert (p_stat != NULL);
1022       memcpy(p_stat, _root, len);
1023       p_stat->rr.psz_symlink = calloc(1, p_stat->rr.i_symlink_max);
1024       cdio_assert (p_stat->rr.psz_symlink != NULL);
1025       memcpy(p_stat->rr.psz_symlink, _root->rr.psz_symlink,
1026 	     p_stat->rr.i_symlink_max);
1027       return p_stat;
1028     }
1029 
1030   if (_root->type == _STAT_FILE)
1031     return NULL;
1032 
1033   cdio_assert (_root->type == _STAT_DIR);
1034 
1035   _dirbuf = calloc(1, _root->secsize * ISO_BLOCKSIZE);
1036   if (!_dirbuf)
1037     {
1038     cdio_warn("Couldn't calloc(1, %d)", _root->secsize * ISO_BLOCKSIZE);
1039     return NULL;
1040     }
1041 
1042   if (cdio_read_data_sectors (p_cdio, _dirbuf, _root->lsn, ISO_BLOCKSIZE,
1043 			      _root->secsize))
1044       return NULL;
1045 
1046   while (offset < (_root->secsize * ISO_BLOCKSIZE))
1047     {
1048       iso9660_dir_t *p_iso9660_dir = (void *) &_dirbuf[offset];
1049       iso9660_stat_t *p_iso9660_stat;
1050       int cmp;
1051 
1052       if (iso9660_check_dir_block_end(p_iso9660_dir, &offset))
1053 	continue;
1054 
1055       p_iso9660_stat = _iso9660_dir_to_statbuf (p_iso9660_dir, dunno,
1056 					p_env->u_joliet_level);
1057 
1058       cmp = strcmp(splitpath[0], p_iso9660_stat->filename);
1059 
1060       if ( 0 != cmp && 0 == p_env->u_joliet_level
1061 	   && yep != p_iso9660_stat->rr.b3_rock ) {
1062 	char *trans_fname = NULL;
1063 	unsigned int i_trans_fname=strlen(p_iso9660_stat->filename);
1064 
1065 	if (i_trans_fname) {
1066 	  trans_fname = calloc(1, i_trans_fname+1);
1067 	  if (!trans_fname) {
1068 	    cdio_warn("can't allocate %lu bytes",
1069 		      (long unsigned int) strlen(p_iso9660_stat->filename));
1070 	    free(p_iso9660_stat);
1071 	    return NULL;
1072 	  }
1073 	  iso9660_name_translate_ext(p_iso9660_stat->filename, trans_fname,
1074 				     p_env->u_joliet_level);
1075 	  cmp = strcmp(splitpath[0], trans_fname);
1076 	  free(trans_fname);
1077 	}
1078       }
1079 
1080       if (!cmp) {
1081 	iso9660_stat_t *ret_stat
1082 	  = _fs_stat_traverse (p_cdio, p_iso9660_stat, &splitpath[1]);
1083 	iso9660_stat_free(p_iso9660_stat);
1084 	free (_dirbuf);
1085 	return ret_stat;
1086       }
1087 
1088       iso9660_stat_free(p_iso9660_stat);
1089 
1090       offset += iso9660_get_dir_len(p_iso9660_dir);
1091     }
1092 
1093   cdio_assert (offset == (_root->secsize * ISO_BLOCKSIZE));
1094 
1095   /* not found */
1096   free (_dirbuf);
1097   return NULL;
1098 }
1099 
1100 static iso9660_stat_t *
_fs_iso_stat_traverse(iso9660_t * p_iso,const iso9660_stat_t * _root,char ** splitpath)1101 _fs_iso_stat_traverse (iso9660_t *p_iso, const iso9660_stat_t *_root,
1102 		       char **splitpath)
1103 {
1104   unsigned offset = 0;
1105   uint8_t *_dirbuf = NULL;
1106   int ret;
1107 
1108   if (!splitpath[0])
1109     {
1110       iso9660_stat_t *p_stat;
1111       unsigned int len=sizeof(iso9660_stat_t) + strlen(_root->filename)+1;
1112       p_stat = calloc(1, len);
1113       cdio_assert (p_stat != NULL);
1114       memcpy(p_stat, _root, len);
1115       p_stat->rr.psz_symlink = calloc(1, p_stat->rr.i_symlink_max);
1116       cdio_assert (p_stat->rr.psz_symlink != NULL);
1117       memcpy(p_stat->rr.psz_symlink, _root->rr.psz_symlink,
1118 	     p_stat->rr.i_symlink_max);
1119       return p_stat;
1120     }
1121 
1122   if (_root->type == _STAT_FILE)
1123     return NULL;
1124 
1125   cdio_assert (_root->type == _STAT_DIR);
1126 
1127   _dirbuf = calloc(1, _root->secsize * ISO_BLOCKSIZE);
1128   if (!_dirbuf)
1129     {
1130     cdio_warn("Couldn't calloc(1, %d)", _root->secsize * ISO_BLOCKSIZE);
1131     return NULL;
1132     }
1133 
1134   ret = iso9660_iso_seek_read (p_iso, _dirbuf, _root->lsn, _root->secsize);
1135   if (ret!=ISO_BLOCKSIZE*_root->secsize) {
1136     free(_dirbuf);
1137     return NULL;
1138   }
1139 
1140   while (offset < (_root->secsize * ISO_BLOCKSIZE))
1141     {
1142       iso9660_dir_t *p_iso9660_dir = (void *) &_dirbuf[offset];
1143       iso9660_stat_t *p_stat;
1144       int cmp;
1145 
1146       if (iso9660_check_dir_block_end(p_iso9660_dir, &offset))
1147 	continue;
1148 
1149       p_stat = _iso9660_dir_to_statbuf (p_iso9660_dir, p_iso->b_xa,
1150 					p_iso->u_joliet_level);
1151 
1152       if (!p_stat) {
1153 	cdio_warn("Bad directory information for %s", splitpath[0]);
1154 	free(_dirbuf);
1155 	return NULL;
1156       }
1157 
1158       cmp = strcmp(splitpath[0], p_stat->filename);
1159 
1160       if ( 0 != cmp && 0 == p_iso->u_joliet_level
1161 	   && yep != p_stat->rr.b3_rock ) {
1162 	char *trans_fname = NULL;
1163 	unsigned int i_trans_fname=strlen(p_stat->filename);
1164 
1165 	if (i_trans_fname) {
1166 	  trans_fname = calloc(1, i_trans_fname+1);
1167 	  if (!trans_fname) {
1168 	    cdio_warn("can't allocate %lu bytes",
1169 		      (long unsigned int) strlen(p_stat->filename));
1170 	    free(p_stat);
1171 	    return NULL;
1172 	  }
1173 	  iso9660_name_translate_ext(p_stat->filename, trans_fname,
1174 				     p_iso->u_joliet_level);
1175 	  cmp = strcmp(splitpath[0], trans_fname);
1176 	  free(trans_fname);
1177 	}
1178       }
1179 
1180       if (!cmp) {
1181 	iso9660_stat_t *ret_stat
1182 	  = _fs_iso_stat_traverse (p_iso, p_stat, &splitpath[1]);
1183 	iso9660_stat_free(p_stat);
1184 	free (_dirbuf);
1185 	return ret_stat;
1186       }
1187       iso9660_stat_free(p_stat);
1188 
1189       offset += iso9660_get_dir_len(p_iso9660_dir);
1190     }
1191 
1192   cdio_assert (offset == (_root->secsize * ISO_BLOCKSIZE));
1193 
1194   /* not found */
1195   free (_dirbuf);
1196   return NULL;
1197 }
1198 
1199 /*!
1200   Return file status for psz_path. NULL is returned on error.
1201 
1202   @param p_cdio the CD object to read from
1203 
1204   @param psz_path filename path to look up and get information about
1205 
1206   @return ISO 9660 file information
1207 
1208   Important note:
1209 
1210   You make get different results looking up "/" versus "/." and the
1211   latter may give more complete information. "/" will take information
1212   from the PVD only, whereas "/." will force a directory read of "/" and
1213   find "." and in that Rock-Ridge information might be found which fills
1214   in more stat information. Ideally iso9660_fs_stat should be fixed.
1215   Patches anyone?
1216  */
1217 iso9660_stat_t *
iso9660_fs_stat(CdIo_t * p_cdio,const char psz_path[])1218 iso9660_fs_stat (CdIo_t *p_cdio, const char psz_path[])
1219 {
1220   iso9660_stat_t *p_root;
1221   char **p_psz_splitpath;
1222   iso9660_stat_t *p_stat;
1223 
1224   if (!p_cdio)   return NULL;
1225   if (!psz_path) return NULL;
1226 
1227   p_root = _fs_stat_root (p_cdio);
1228 
1229   if (!p_root)   return NULL;
1230 
1231   p_psz_splitpath = _cdio_strsplit (psz_path, '/');
1232   p_stat = _fs_stat_traverse (p_cdio, p_root, p_psz_splitpath);
1233   free(p_root);
1234   _cdio_strfreev (p_psz_splitpath);
1235 
1236   return p_stat;
1237 }
1238 
1239 typedef iso9660_stat_t * (stat_root_t) (void *p_image);
1240 typedef iso9660_stat_t * (stat_traverse_t)
1241   (const void *p_image, const iso9660_stat_t *_root, char **splitpath);
1242 
1243 /*!
1244   Get file status for psz_path into stat. NULL is returned on error.
1245   pathname version numbers in the ISO 9660
1246   name are dropped, i.e. ;1 is removed and if level 1 ISO-9660 names
1247   are lowercased.
1248  */
1249 static iso9660_stat_t *
fs_stat_translate(void * p_image,stat_root_t stat_root,stat_traverse_t stat_traverse,const char psz_path[])1250 fs_stat_translate (void *p_image, stat_root_t stat_root,
1251 		   stat_traverse_t stat_traverse,
1252 		   const char psz_path[])
1253 {
1254   iso9660_stat_t *p_root;
1255   char **p_psz_splitpath;
1256   iso9660_stat_t *p_stat;
1257 
1258   if (!p_image)  return NULL;
1259   if (!psz_path) return NULL;
1260 
1261   p_root = stat_root (p_image);
1262   if (!p_root) return NULL;
1263 
1264   p_psz_splitpath = _cdio_strsplit (psz_path, '/');
1265   p_stat = stat_traverse (p_image, p_root, p_psz_splitpath);
1266   free(p_root);
1267   _cdio_strfreev (p_psz_splitpath);
1268 
1269   return p_stat;
1270 }
1271 
1272 /*!
1273   Return file status for path name psz_path. NULL is returned on error.
1274   pathname version numbers in the ISO 9660 name are dropped, i.e. ;1
1275   is removed and if level 1 ISO-9660 names are lowercased.
1276 
1277   @param p_cdio the CD object to read from
1278 
1279   @param psz_path filename path to look up and get information about
1280 
1281   @return ISO 9660 file information.  The caller must free the
1282   returned result using iso9660_stat_free().
1283 
1284  */
1285 iso9660_stat_t *
iso9660_fs_stat_translate(CdIo_t * p_cdio,const char psz_path[])1286 iso9660_fs_stat_translate (CdIo_t *p_cdio, const char psz_path[])
1287 {
1288   return fs_stat_translate(p_cdio, (stat_root_t *) _fs_stat_root,
1289 			   (stat_traverse_t *) _fs_stat_traverse,
1290 			   psz_path);
1291 }
1292 
1293 /*!
1294   @param p_iso the ISO-9660 file image to get data from
1295 
1296   @param psz_path filename path translate
1297 
1298   @return file status for path name psz_path. NULL is returned on
1299   error.  pathname version numbers in the ISO 9660 name are dropped,
1300   i.e. ;1 is removed and if level 1 ISO-9660 names are lowercased.
1301   The caller must free the returned result using iso9660_stat_free().
1302  */
1303 iso9660_stat_t *
iso9660_ifs_stat_translate(iso9660_t * p_iso,const char psz_path[])1304 iso9660_ifs_stat_translate (iso9660_t *p_iso, const char psz_path[])
1305 {
1306   return fs_stat_translate(p_iso, (stat_root_t *) _ifs_stat_root,
1307 			   (stat_traverse_t *) _fs_iso_stat_traverse,
1308 			   psz_path);
1309 }
1310 
1311 
1312 /*!
1313 
1314   @param p_cdio the CD object to read from
1315 
1316   @param pzs_path path the look up
1317 
1318   @return file status for pathname. NULL is returned on error.
1319   The caller must free the returned result using iso9660_stat_free().
1320  */
1321 iso9660_stat_t *
iso9660_ifs_stat(iso9660_t * p_iso,const char psz_path[])1322 iso9660_ifs_stat (iso9660_t *p_iso, const char psz_path[])
1323 {
1324   iso9660_stat_t *p_root;
1325   char **splitpath;
1326   iso9660_stat_t *stat;
1327 
1328   if (!p_iso)    return NULL;
1329   if (!psz_path) return NULL;
1330 
1331   p_root = _ifs_stat_root (p_iso);
1332   if (!p_root) return NULL;
1333 
1334   splitpath = _cdio_strsplit (psz_path, '/');
1335   stat = _fs_iso_stat_traverse (p_iso, p_root, splitpath);
1336   free(p_root);
1337   _cdio_strfreev (splitpath);
1338 
1339   return stat;
1340 }
1341 
1342 /*!
1343   Read psz_path (a directory) and return a list of iso9660_stat_t
1344   pointers for the files inside that directory.
1345 
1346   @param p_cdio the CD object to read from
1347 
1348   @param pzs_path path the read the directory from.
1349 
1350   @return file status for psz_path. The caller must free the
1351   The caller must free the returned result using iso9660_stat_free().
1352 */
1353 CdioISO9660FileList_t *
iso9660_fs_readdir(CdIo_t * p_cdio,const char psz_path[])1354 iso9660_fs_readdir (CdIo_t *p_cdio, const char psz_path[])
1355 {
1356   generic_img_private_t *p_env;
1357   iso9660_stat_t *p_stat;
1358 
1359   if (!p_cdio)   return NULL;
1360   if (!psz_path) return NULL;
1361 
1362   p_env = (generic_img_private_t *) p_cdio->env;
1363 
1364   p_stat = iso9660_fs_stat (p_cdio, psz_path);
1365   if (!p_stat) return NULL;
1366 
1367   if (p_stat->type != _STAT_DIR) {
1368     iso9660_stat_free(p_stat);
1369     return NULL;
1370   }
1371 
1372   {
1373     unsigned offset = 0;
1374     uint8_t *_dirbuf = NULL;
1375     CdioISO9660DirList_t *retval = _cdio_list_new ();
1376 
1377     _dirbuf = calloc(1, p_stat->secsize * ISO_BLOCKSIZE);
1378     if (!_dirbuf)
1379       {
1380       cdio_warn("Couldn't calloc(1, %d)", p_stat->secsize * ISO_BLOCKSIZE);
1381       iso9660_stat_free(p_stat);
1382       iso9660_dirlist_free(retval);
1383       return NULL;
1384       }
1385 
1386     if (cdio_read_data_sectors (p_cdio, _dirbuf, p_stat->lsn,
1387 				ISO_BLOCKSIZE, p_stat->secsize)) {
1388       iso9660_stat_free(p_stat);
1389       iso9660_dirlist_free(retval);
1390       return NULL;
1391     }
1392 
1393     while (offset < (p_stat->secsize * ISO_BLOCKSIZE))
1394       {
1395 	iso9660_dir_t *p_iso9660_dir = (void *) &_dirbuf[offset];
1396 	iso9660_stat_t *p_iso9660_stat;
1397 
1398 	if (iso9660_check_dir_block_end(p_iso9660_dir, &offset))
1399   	  continue;
1400 
1401 	p_iso9660_stat = _iso9660_dir_to_statbuf(p_iso9660_dir, dunno,
1402 						 p_env->u_joliet_level);
1403 	_cdio_list_append (retval, p_iso9660_stat);
1404 
1405 	offset += iso9660_get_dir_len(p_iso9660_dir);
1406       }
1407 
1408     cdio_assert (offset == (p_stat->secsize * ISO_BLOCKSIZE));
1409 
1410     free(_dirbuf);
1411     iso9660_stat_free(p_stat);
1412     return retval;
1413   }
1414 }
1415 
1416 /*!
1417   Read psz_path (a directory) and return a list of iso9660_stat_t
1418   of the files inside that. The caller must free the returned result.
1419 */
1420 CdioISO9660FileList_t *
iso9660_ifs_readdir(iso9660_t * p_iso,const char psz_path[])1421 iso9660_ifs_readdir (iso9660_t *p_iso, const char psz_path[])
1422 {
1423   iso9660_stat_t *p_stat;
1424 
1425   if (!p_iso)    return NULL;
1426   if (!psz_path) return NULL;
1427 
1428   p_stat = iso9660_ifs_stat (p_iso, psz_path);
1429   if (!p_stat)   return NULL;
1430 
1431   if (p_stat->type != _STAT_DIR) {
1432     iso9660_stat_free(p_stat);
1433     return NULL;
1434   }
1435 
1436   {
1437     long int ret;
1438     unsigned offset = 0;
1439     uint8_t *_dirbuf = NULL;
1440     CdioList_t *retval = _cdio_list_new ();
1441     const size_t dirbuf_len = p_stat->secsize * ISO_BLOCKSIZE;
1442 
1443 
1444     if (!dirbuf_len)
1445       {
1446         cdio_warn("Invalid directory buffer sector size %u", p_stat->secsize);
1447 	iso9660_stat_free(p_stat);
1448 	_cdio_list_free (retval, true, NULL);
1449         return NULL;
1450       }
1451 
1452     _dirbuf = calloc(1, dirbuf_len);
1453     if (!_dirbuf)
1454       {
1455         cdio_warn("Couldn't calloc(1, %lu)", (unsigned long)dirbuf_len);
1456 	iso9660_stat_free(p_stat);
1457 	_cdio_list_free (retval, true, NULL);
1458         return NULL;
1459       }
1460 
1461     ret = iso9660_iso_seek_read (p_iso, _dirbuf, p_stat->lsn, p_stat->secsize);
1462     if (ret != dirbuf_len) 	  {
1463       _cdio_list_free (retval, true, NULL);
1464       iso9660_stat_free(p_stat);
1465       free (_dirbuf);
1466       return NULL;
1467     }
1468 
1469     while (offset < (dirbuf_len))
1470       {
1471 	iso9660_dir_t *p_iso9660_dir = (void *) &_dirbuf[offset];
1472 	iso9660_stat_t *p_iso9660_stat;
1473 
1474 	if (iso9660_check_dir_block_end(p_iso9660_dir, &offset))
1475 	  continue;
1476 
1477 	p_iso9660_stat = _iso9660_dir_to_statbuf(p_iso9660_dir, p_iso->b_xa,
1478 						 p_iso->u_joliet_level);
1479 
1480 	if (p_iso9660_stat)
1481 	  _cdio_list_append (retval, p_iso9660_stat);
1482 	else {
1483 	  cdio_warn("Invalid directory stat at offset %lu", (unsigned long)offset);
1484 	  break;
1485 	}
1486 
1487 	offset += iso9660_get_dir_len(p_iso9660_dir);
1488       }
1489 
1490     free (_dirbuf);
1491     iso9660_stat_free(p_stat);
1492 
1493     if (offset != dirbuf_len) {
1494       _cdio_list_free (retval, true, (CdioDataFree_t) iso9660_stat_free);
1495       return NULL;
1496     }
1497 
1498     return retval;
1499   }
1500 }
1501 
1502 typedef CdioISO9660FileList_t * (iso9660_readdir_t)
1503   (void *p_image,  const char * psz_path);
1504 
1505 CdioISO9660FileList_t *
iso9660_filelist_new(void)1506 iso9660_filelist_new(void) {
1507   return (CdioISO9660FileList_t *) _cdio_list_new ();
1508 }
1509 
1510 CdioISO9660DirList_t *
iso9660_dirlist_new(void)1511 iso9660_dirlist_new(void) {
1512   return (CdioISO9660FileList_t *) _cdio_list_new ();
1513 }
1514 
1515 static iso9660_stat_t *
find_lsn_recurse(void * p_image,iso9660_readdir_t iso9660_readdir,const char psz_path[],lsn_t lsn,char ** ppsz_full_filename)1516 find_lsn_recurse (void *p_image, iso9660_readdir_t iso9660_readdir,
1517 		  const char psz_path[], lsn_t lsn,
1518 		  /*out*/ char **ppsz_full_filename)
1519 {
1520   CdioISO9660FileList_t *entlist = iso9660_readdir (p_image, psz_path);
1521   CdioISO9660DirList_t *dirlist = iso9660_filelist_new();
1522   CdioListNode_t *entnode;
1523 
1524   cdio_assert (entlist != NULL);
1525 
1526   /* iterate over each entry in the directory */
1527 
1528   _CDIO_LIST_FOREACH (entnode, entlist)
1529     {
1530       iso9660_stat_t *statbuf = _cdio_list_node_data (entnode);
1531       const char *psz_filename  = (char *) statbuf->filename;
1532       unsigned int len = strlen(psz_path) + strlen(psz_filename)+2;
1533 
1534       if (*ppsz_full_filename != NULL) free(*ppsz_full_filename);
1535       *ppsz_full_filename = calloc(1, len);
1536       snprintf (*ppsz_full_filename, len, "%s%s/", psz_path, psz_filename);
1537 
1538       if (statbuf->type == _STAT_DIR
1539           && strcmp ((char *) statbuf->filename, ".")
1540           && strcmp ((char *) statbuf->filename, "..")) {
1541 	snprintf (*ppsz_full_filename, len, "%s%s/", psz_path, psz_filename);
1542         _cdio_list_append (dirlist, strdup(*ppsz_full_filename));
1543       }
1544 
1545       if (statbuf->lsn == lsn) {
1546 	const unsigned int len2 = sizeof(iso9660_stat_t)+strlen(statbuf->filename)+1;
1547 	iso9660_stat_t *ret_stat = calloc(1, len2);
1548 	if (!ret_stat)
1549 	  {
1550 	    iso9660_dirlist_free(dirlist);
1551 	    cdio_warn("Couldn't calloc(1, %d)", len2);
1552 	    free(*ppsz_full_filename);
1553 	    *ppsz_full_filename = NULL;
1554 	    return NULL;
1555 	  }
1556 	memcpy(ret_stat, statbuf, len2);
1557         iso9660_filelist_free (entlist);
1558 	iso9660_dirlist_free(dirlist);
1559         return ret_stat;
1560       }
1561 
1562     }
1563 
1564   iso9660_filelist_free (entlist);
1565 
1566   /* now recurse/descend over directories encountered */
1567 
1568   _CDIO_LIST_FOREACH (entnode, dirlist)
1569     {
1570       char *psz_path_prefix = _cdio_list_node_data (entnode);
1571       iso9660_stat_t *ret_stat;
1572       free(*ppsz_full_filename);
1573       *ppsz_full_filename = NULL;
1574       ret_stat = find_lsn_recurse (p_image, iso9660_readdir,
1575 				   psz_path_prefix, lsn,
1576 				   ppsz_full_filename);
1577 
1578       if (NULL != ret_stat) {
1579 	iso9660_dirlist_free(dirlist);
1580         return ret_stat;
1581       }
1582     }
1583 
1584   if (*ppsz_full_filename != NULL) {
1585     free(*ppsz_full_filename);
1586     *ppsz_full_filename = NULL;
1587   }
1588   iso9660_dirlist_free(dirlist);
1589   return NULL;
1590 }
1591 
1592 /*!
1593    Given a directory pointer, find the filesystem entry that contains
1594    lsn and return information about it.
1595 
1596    Returns stat_t of entry if we found lsn, or NULL otherwise.
1597  */
1598 iso9660_stat_t *
iso9660_fs_find_lsn(CdIo_t * p_cdio,lsn_t i_lsn)1599 iso9660_fs_find_lsn(CdIo_t *p_cdio, lsn_t i_lsn)
1600 {
1601   char *psz_full_filename = NULL;
1602   iso9660_stat_t * p_statbuf;
1603   p_statbuf = find_lsn_recurse (p_cdio, (iso9660_readdir_t *) iso9660_fs_readdir,
1604 				"/", i_lsn, &psz_full_filename);
1605   if (psz_full_filename != NULL)
1606     free(psz_full_filename);
1607   return p_statbuf;
1608 }
1609 
1610 /*!
1611    Given a directory pointer, find the filesystem entry that contains
1612    LSN and return information about it.
1613 
1614    @param p_iso the ISO-9660 file image to get data from.
1615    @param i_lsn the LSN to find
1616    @param ppsz_full_filename the place to store the name of the path that has LSN.
1617    On entry this should point to NULL. If not, the value will be freed.
1618    On exit a value is malloc'd and the caller is responsible for
1619    freeing the result.
1620 
1621    @return stat_t of entry if we found lsn, or NULL otherwise.
1622    Caller must free return value using iso9660_stat_free().
1623  */
1624 iso9660_stat_t *
iso9660_fs_find_lsn_with_path(CdIo_t * p_cdio,lsn_t i_lsn,char ** ppsz_full_filename)1625 iso9660_fs_find_lsn_with_path(CdIo_t *p_cdio, lsn_t i_lsn,
1626 			      /*out*/ char **ppsz_full_filename)
1627 {
1628   return find_lsn_recurse (p_cdio, (iso9660_readdir_t *) iso9660_fs_readdir,
1629 			   "/", i_lsn, ppsz_full_filename);
1630 }
1631 
1632 /*!
1633    Given a directory pointer, find the filesystem entry that contains
1634    lsn and return information about it.
1635 
1636    @param p_iso the ISO-9660 file image to get data from.
1637 
1638    @param i_lsn the LSN to find
1639 
1640    @return stat_t of entry if we found lsn, or NULL otherwise.
1641    Caller must free return value using iso9660_stat_free().
1642  */
1643 iso9660_stat_t *
iso9660_ifs_find_lsn(iso9660_t * p_iso,lsn_t i_lsn)1644 iso9660_ifs_find_lsn(iso9660_t *p_iso, lsn_t i_lsn)
1645 {
1646   char *psz_full_filename = NULL;
1647   iso9660_stat_t *ret  =
1648     find_lsn_recurse (p_iso, (iso9660_readdir_t *) iso9660_ifs_readdir,
1649 		      "/", i_lsn, &psz_full_filename);
1650   if (psz_full_filename != NULL)
1651     free(psz_full_filename);
1652   return ret;
1653 }
1654 
1655 /*!
1656    Given a directory pointer, find the filesystem entry that contains
1657    lsn and return information about it.
1658 
1659    @param p_iso pointer to iso_t
1660 
1661    @param i_lsn LSN to find
1662 
1663    @param ppsz_path  full path of lsn filename. On entry *ppsz_path should be
1664    NULL. On return it will be allocated an point to the full path of the
1665    file at lsn or NULL if the lsn is not found. You should deallocate
1666    *ppsz_path when you are done using it.
1667 
1668    @return stat_t of entry if we found lsn, or NULL otherwise.
1669    Caller must free return value using iso9660_stat_free().
1670  */
1671 iso9660_stat_t *
iso9660_ifs_find_lsn_with_path(iso9660_t * p_iso,lsn_t i_lsn,char ** ppsz_full_filename)1672 iso9660_ifs_find_lsn_with_path(iso9660_t *p_iso, lsn_t i_lsn,
1673 			       /*out*/ char **ppsz_full_filename)
1674 {
1675   return find_lsn_recurse (p_iso, (iso9660_readdir_t *) iso9660_ifs_readdir,
1676 			   "/", i_lsn, ppsz_full_filename);
1677 }
1678 
1679 /*!
1680   Free the passed iso9660_stat_t structure.
1681 
1682   @param p_stat iso9660 stat buffer to free.
1683 
1684  */
1685 void
iso9660_stat_free(iso9660_stat_t * p_stat)1686 iso9660_stat_free(iso9660_stat_t *p_stat)
1687 {
1688   if (p_stat != NULL) {
1689     if (p_stat->rr.psz_symlink) {
1690       CDIO_FREE_IF_NOT_NULL(p_stat->rr.psz_symlink);
1691     }
1692     free(p_stat);
1693   }
1694 }
1695 
1696 /*!
1697   Free the passed CdioISOC9660FileList_t structure.
1698 */
1699 void
iso9660_filelist_free(CdioISO9660FileList_t * p_filelist)1700 iso9660_filelist_free(CdioISO9660FileList_t *p_filelist) {
1701   _cdio_list_free(p_filelist, true, (CdioDataFree_t) iso9660_stat_free);
1702 }
1703 
1704 /*!
1705   Free the passed CdioISOC9660DirList_t structure.
1706 */
1707 void
iso9660_dirlist_free(CdioISO9660DirList_t * p_filelist)1708 iso9660_dirlist_free(CdioISO9660DirList_t *p_filelist) {
1709   _cdio_list_free(p_filelist, true, free);
1710 }
1711 
1712 
1713 /*!
1714   Return true if ISO 9660 image has extended attrributes (XA).
1715 */
1716 bool
iso9660_ifs_is_xa(const iso9660_t * p_iso)1717 iso9660_ifs_is_xa (const iso9660_t * p_iso)
1718 {
1719   if (!p_iso) return false;
1720   return yep == p_iso->b_xa;
1721 }
1722 
1723 static bool_3way_t
iso_have_rr_traverse(iso9660_t * p_iso,const iso9660_stat_t * _root,char ** splitpath,uint64_t * pu_file_limit)1724 iso_have_rr_traverse (iso9660_t *p_iso, const iso9660_stat_t *_root,
1725 		      char **splitpath, uint64_t *pu_file_limit)
1726 {
1727   unsigned offset = 0;
1728   uint8_t *_dirbuf = NULL;
1729   int ret;
1730   bool_3way_t have_rr = nope;
1731 
1732   if (!splitpath[0]) return false;
1733 
1734   if (_root->type == _STAT_FILE) return nope;
1735   if (*pu_file_limit == 0) return dunno;
1736 
1737   cdio_assert (_root->type == _STAT_DIR);
1738 
1739   _dirbuf = calloc(1, _root->secsize * ISO_BLOCKSIZE);
1740   if (!_dirbuf)
1741     {
1742     cdio_warn("Couldn't calloc(1, %d)", _root->secsize * ISO_BLOCKSIZE);
1743     return dunno;
1744     }
1745 
1746   ret = iso9660_iso_seek_read (p_iso, _dirbuf, _root->lsn, _root->secsize);
1747   if (ret!=ISO_BLOCKSIZE*_root->secsize) {
1748     free(_dirbuf);
1749     return false;
1750   }
1751 
1752   while (offset < (_root->secsize * ISO_BLOCKSIZE))
1753     {
1754       iso9660_dir_t *p_iso9660_dir = (void *) &_dirbuf[offset];
1755       iso9660_stat_t *p_stat;
1756       unsigned int i_last_component = 1;
1757 
1758       if (iso9660_check_dir_block_end(p_iso9660_dir, &offset))
1759 	continue;
1760 
1761       p_stat = _iso9660_dir_to_statbuf (p_iso9660_dir, p_iso->b_xa,
1762 					p_iso->u_joliet_level);
1763       have_rr = p_stat->rr.b3_rock;
1764       if ( have_rr != yep) {
1765 	if (strlen(splitpath[0]) == 0)
1766 	  have_rr = false;
1767 	else
1768 	  have_rr = iso_have_rr_traverse (p_iso, p_stat, &splitpath[i_last_component],
1769 					  pu_file_limit);
1770       }
1771       free(p_stat);
1772       if (have_rr != nope) {
1773 	free (_dirbuf);
1774 	return have_rr;
1775       }
1776 
1777       offset += iso9660_get_dir_len(p_iso9660_dir);
1778       *pu_file_limit = (*pu_file_limit)-1;
1779       if ((*pu_file_limit) == 0) {
1780 	free (_dirbuf);
1781 	return dunno;
1782       }
1783     }
1784 
1785   cdio_assert (offset == (_root->secsize * ISO_BLOCKSIZE));
1786 
1787   /* not found */
1788   free (_dirbuf);
1789   return nope;
1790 }
1791 
1792 /*!
1793   Return "yup" if any file has Rock-Ridge extensions. Warning: this can
1794   be time consuming. On an ISO 9600 image with lots of files but no Rock-Ridge
1795   extensions, the entire directory structure will be scanned up to u_file_limit.
1796 
1797   @param p_iso the ISO-9660 file image to get data from
1798 
1799   @param u_file_limit the maximimum number of (non-rock-ridge) files
1800   to consider before giving up and returning "dunno".
1801 
1802   "dunno" can also be returned if there was some error encountered
1803   such as not being able to allocate memory in processing.
1804 
1805 */
1806 extern bool_3way_t
iso9660_have_rr(iso9660_t * p_iso,uint64_t u_file_limit)1807 iso9660_have_rr(iso9660_t *p_iso, uint64_t u_file_limit)
1808 {
1809   iso9660_stat_t *p_root;
1810   char *p_psz_splitpath[2] = {strdup("/"), strdup("")};
1811   bool_3way_t is_rr = nope;
1812 
1813   if (!p_iso) return false;
1814 
1815   p_root = _ifs_stat_root (p_iso);
1816   if (!p_root) return dunno;
1817 
1818   if (u_file_limit == 0) u_file_limit = UINT64_MAX;
1819 
1820   is_rr = iso_have_rr_traverse (p_iso, p_root, p_psz_splitpath, &u_file_limit);
1821   free(p_root);
1822   free(p_psz_splitpath[0]);
1823   free(p_psz_splitpath[1]);
1824 
1825   return is_rr;
1826 }
1827