Blame lib/iso9660/iso9660_fs.c

Packit dd8086
/*
Packit dd8086
  Copyright (C) 2003-2008, 2011-2015, 2017 Rocky Bernstein <rocky@gnu.org>
Packit dd8086
  Copyright (C) 2001 Herbert Valerio Riedel <hvr@gnu.org>
Packit dd8086
Packit dd8086
  This program is free software: you can redistribute it and/or modify
Packit dd8086
  it under the terms of the GNU General Public License as published by
Packit dd8086
  the Free Software Foundation, either version 3 of the License, or
Packit dd8086
  (at your option) any later version.
Packit dd8086
Packit dd8086
  This program is distributed in the hope that it will be useful,
Packit dd8086
  but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit dd8086
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit dd8086
  GNU General Public License for more details.
Packit dd8086
Packit dd8086
  You should have received a copy of the GNU General Public License
Packit dd8086
  along with this program.  If not, see <http://www.gnu.org/licenses/>.
Packit dd8086
*/
Packit dd8086
/* iso9660 filesystem-based routines */
Packit dd8086
Packit dd8086
/* FIXME: _cdio_list_free for iso9660 statbuf is insufficient because it doesn't
Packit dd8086
   free bits that are allocated inside the data. */
Packit dd8086
Packit dd8086

Packit dd8086
#if defined(HAVE_CONFIG_H) && !defined(__CDIO_CONFIG_H__)
Packit dd8086
#include "config.h"
Packit dd8086
#define __CDIO_CONFIG_H__ 1
Packit dd8086
#endif
Packit dd8086
Packit dd8086
#ifdef HAVE_STDBOOL_H
Packit dd8086
# include <stdbool.h>
Packit dd8086
#endif
Packit dd8086
Packit dd8086
#ifdef HAVE_STDIO_H
Packit dd8086
#include <stdio.h>
Packit dd8086
#endif
Packit dd8086
Packit dd8086
#ifdef HAVE_STRING_H
Packit dd8086
#include <string.h>
Packit dd8086
#endif
Packit dd8086
Packit dd8086
#ifdef HAVE_ERRNO_H
Packit dd8086
#include <errno.h>
Packit dd8086
#endif
Packit dd8086
Packit dd8086
#ifdef HAVE_LANGINFO_CODESET
Packit dd8086
#include <langinfo.h>
Packit dd8086
#endif
Packit dd8086
Packit dd8086
#include <cdio/cdio.h>
Packit dd8086
#include <cdio/bytesex.h>
Packit dd8086
#include <cdio/iso9660.h>
Packit dd8086
#include <cdio/util.h>
Packit dd8086
#include <cdio/utf8.h>
Packit dd8086
Packit dd8086
/* Private headers */
Packit dd8086
#include "cdio_assert.h"
Packit dd8086
#include "_cdio_stdio.h"
Packit dd8086
#include "cdio_private.h"
Packit dd8086
Packit dd8086
/** Implementation of iso9660_t type */
Packit dd8086
struct _iso9660_s {
Packit dd8086
  CdioDataSource_t *stream; /**< Stream pointer */
Packit dd8086
  bool_3way_t b_xa;         /**< true if has XA attributes. */
Packit dd8086
  bool_3way_t b_mode2;      /**< true if has mode 2, false for mode 1. */
Packit dd8086
  uint8_t  u_joliet_level;  /**< 0 = no Joliet extensions.
Packit dd8086
			         1-3: Joliet level. */
Packit dd8086
  iso9660_pvd_t pvd;
Packit dd8086
  iso9660_svd_t svd;
Packit dd8086
  iso_extension_mask_t iso_extension_mask; /**< What extensions we
Packit dd8086
					        tolerate. */
Packit dd8086
  uint32_t i_datastart;     /**< Usually 0 when i_framesize is ISO_BLOCKSIZE.
Packit dd8086
			         This is the normal condition. But in a fuzzy
Packit dd8086
			         read we may be reading a CD-image
Packit dd8086
			         and not a true ISO 9660 image this might be
Packit dd8086
			         CDIO_CD_SYNC_SIZE
Packit dd8086
                            */
Packit dd8086
  uint32_t i_framesize;     /**< Usually ISO_BLOCKSIZE (2048), but in a
Packit dd8086
			        fuzzy read, we may be reading a CD-image
Packit dd8086
			        and not a true ISO 9660 image this might
Packit dd8086
			        be CDIO_CD_FRAMESIZE_RAW (2352) or
Packit dd8086
			        M2RAW_SECTOR_SIZE (2336).
Packit dd8086
                            */
Packit dd8086
  int i_fuzzy_offset;       /**< Adjustment in bytes to make ISO_STANDARD_ID
Packit dd8086
			         ("CD001") come out as ISO_PVD_SECTOR
Packit dd8086
			         (frame 16).  Normally this should be 0
Packit dd8086
			         for an ISO 9660 image, but if one is
Packit dd8086
			         say reading a BIN/CUE or cdrdao BIN/TOC
Packit dd8086
			         without having the CUE or TOC and
Packit dd8086
			         trying to extract an ISO-9660
Packit dd8086
			         filesystem inside that it may be
Packit dd8086
			         different.
Packit dd8086
			     */
Packit dd8086
    bool b_have_superblock; /**< Superblock has been read in? */
Packit dd8086
Packit dd8086
};
Packit dd8086
Packit dd8086
static long int iso9660_seek_read_framesize (const iso9660_t *p_iso,
Packit dd8086
					     void *ptr, lsn_t start,
Packit dd8086
					     long int size,
Packit dd8086
					     uint16_t i_framesize);
Packit dd8086
Packit dd8086
/* Adjust the p_iso's i_datastart, i_byte_offset and i_framesize
Packit dd8086
   based on whether we find a frame header or not.
Packit dd8086
*/
Packit dd8086
static void
Packit dd8086
adjust_fuzzy_pvd( iso9660_t *p_iso )
Packit dd8086
{
Packit dd8086
  long int i_byte_offset;
Packit dd8086
Packit dd8086
  if (!p_iso) return;
Packit dd8086
Packit dd8086
  i_byte_offset = (ISO_PVD_SECTOR * p_iso->i_framesize)
Packit dd8086
    + p_iso->i_fuzzy_offset + p_iso->i_datastart;
Packit dd8086
Packit dd8086
  /* If we have a raw 2352-byte frame then we should expect to see a sync
Packit dd8086
     frame and a header.
Packit dd8086
   */
Packit dd8086
  if (CDIO_CD_FRAMESIZE_RAW == p_iso->i_framesize) {
Packit dd8086
    char buf[CDIO_CD_SYNC_SIZE + CDIO_CD_HEADER_SIZE + CDIO_CD_SUBHEADER_SIZE];
Packit dd8086
Packit dd8086
    i_byte_offset -= CDIO_CD_SYNC_SIZE + CDIO_CD_HEADER_SIZE + CDIO_CD_SUBHEADER_SIZE;
Packit dd8086
Packit dd8086
    if ( DRIVER_OP_SUCCESS != cdio_stream_seek (p_iso->stream, i_byte_offset,
Packit dd8086
						SEEK_SET) )
Packit dd8086
      return;
Packit dd8086
    if (sizeof(buf) == cdio_stream_read (p_iso->stream, buf, sizeof(buf), 1)) {
Packit dd8086
      /* Does the sector frame header suggest Mode 1 format? */
Packit dd8086
      if (!memcmp(CDIO_SECTOR_SYNC_HEADER, buf+CDIO_CD_SUBHEADER_SIZE,
Packit dd8086
		  CDIO_CD_SYNC_SIZE)) {
Packit dd8086
	if (buf[14+CDIO_CD_SUBHEADER_SIZE] != 0x16) {
Packit dd8086
	  cdio_warn ("Expecting the PVD sector header MSF to be 0x16, is: %x",
Packit dd8086
		     buf[14]);
Packit dd8086
	}
Packit dd8086
	if (buf[15+CDIO_CD_SUBHEADER_SIZE] != 0x1) {
Packit dd8086
	  cdio_warn ("Expecting the PVD sector mode to be Mode 1 is: %x",
Packit dd8086
		     buf[15]);
Packit dd8086
	}
Packit dd8086
	p_iso->b_mode2 = nope;
Packit dd8086
	p_iso->b_xa = nope;
Packit dd8086
      } else if (!memcmp(CDIO_SECTOR_SYNC_HEADER, buf, CDIO_CD_SYNC_SIZE)) {
Packit dd8086
	/* Frame header indicates Mode 2 Form 1*/
Packit dd8086
	if (buf[14] != 0x16) {
Packit dd8086
	  cdio_warn ("Expecting the PVD sector header MSF to be 0x16, is: %x",
Packit dd8086
		     buf[14]);
Packit dd8086
	}
Packit dd8086
	if (buf[15] != 0x2) {
Packit dd8086
	  cdio_warn ("Expecting the PVD sector mode to be Mode 2 is: %x",
Packit dd8086
		     buf[15]);
Packit dd8086
	}
Packit dd8086
	p_iso->b_mode2 = yep;
Packit dd8086
	/* Do do: check Mode 2 Form 2? */
Packit dd8086
      } else {
Packit dd8086
	  /* Has no frame header */
Packit dd8086
	  p_iso->i_framesize = M2RAW_SECTOR_SIZE;
Packit dd8086
	  p_iso->i_fuzzy_offset = (CDIO_CD_FRAMESIZE_RAW - M2RAW_SECTOR_SIZE)
Packit dd8086
	    * ISO_PVD_SECTOR + p_iso->i_fuzzy_offset + p_iso->i_datastart;
Packit dd8086
	  p_iso->i_datastart = 0;
Packit dd8086
	}
Packit dd8086
    }
Packit dd8086
  }
Packit dd8086
Packit dd8086
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Open an ISO 9660 image for reading in either fuzzy mode or not.
Packit dd8086
*/
Packit dd8086
static iso9660_t *
Packit dd8086
iso9660_open_ext_private (const char *psz_path,
Packit dd8086
			  iso_extension_mask_t iso_extension_mask,
Packit dd8086
			  uint16_t i_fuzz, bool b_fuzzy)
Packit dd8086
{
Packit dd8086
  iso9660_t *p_iso = (iso9660_t *) calloc(1, sizeof(iso9660_t)) ;
Packit dd8086
Packit dd8086
  if (!p_iso) return NULL;
Packit dd8086
Packit dd8086
  p_iso->stream = cdio_stdio_new( psz_path );
Packit dd8086
  if (NULL == p_iso->stream)
Packit dd8086
    goto error;
Packit dd8086
Packit dd8086
  p_iso->i_framesize = ISO_BLOCKSIZE;
Packit dd8086
Packit dd8086
  p_iso->b_have_superblock = (b_fuzzy)
Packit dd8086
    ? iso9660_ifs_fuzzy_read_superblock(p_iso, iso_extension_mask, i_fuzz)
Packit dd8086
    : iso9660_ifs_read_superblock(p_iso, iso_extension_mask) ;
Packit dd8086
Packit dd8086
  if ( ! p_iso->b_have_superblock ) goto error;
Packit dd8086
Packit dd8086
  /* Determine if image has XA attributes. */
Packit dd8086
Packit dd8086
  p_iso->b_xa = strncmp ((char *) &(p_iso->pvd) + ISO_XA_MARKER_OFFSET,
Packit dd8086
			 ISO_XA_MARKER_STRING,
Packit dd8086
			 sizeof (ISO_XA_MARKER_STRING))
Packit dd8086
    ? nope : yep;
Packit dd8086
Packit dd8086
  p_iso->iso_extension_mask = iso_extension_mask;
Packit dd8086
  return p_iso;
Packit dd8086
Packit dd8086
 error:
Packit dd8086
  if (p_iso && p_iso->stream) cdio_stdio_destroy(p_iso->stream);
Packit dd8086
  free(p_iso);
Packit dd8086
Packit dd8086
  return NULL;
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Open an ISO 9660 image for reading. Maybe in the future we will have
Packit dd8086
  a mode. NULL is returned on error.
Packit dd8086
Packit dd8086
  @param psz_path full path of ISO9660 file.
Packit dd8086
Packit dd8086
  @return a IS9660 structure  is unconditionally returned. The caller
Packit dd8086
  should call iso9660_close() when done.
Packit dd8086
*/
Packit dd8086
iso9660_t *
Packit dd8086
iso9660_open (const char *psz_path /*, mode*/)
Packit dd8086
{
Packit dd8086
  return iso9660_open_ext(psz_path, ISO_EXTENSION_NONE);
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Open an ISO 9660 image for reading allowing various ISO 9660
Packit dd8086
  extensions.  Maybe in the future we will have a mode. NULL is
Packit dd8086
  returned on error.
Packit dd8086
Packit dd8086
  @see iso9660_open_fuzzy
Packit dd8086
*/
Packit dd8086
iso9660_t *
Packit dd8086
iso9660_open_ext (const char *psz_path,
Packit dd8086
		  iso_extension_mask_t iso_extension_mask)
Packit dd8086
{
Packit dd8086
  return iso9660_open_ext_private(psz_path, iso_extension_mask, 0, false);
Packit dd8086
}
Packit dd8086
Packit dd8086
Packit dd8086
/*! Open an ISO 9660 image for "fuzzy" reading. This means that we
Packit dd8086
  will try to guess various internal offset based on internal
Packit dd8086
  checks. This may be useful when trying to read an ISO 9660 image
Packit dd8086
  contained in a file format that libiso9660 doesn't know natively
Packit dd8086
  (or knows imperfectly.)
Packit dd8086
Packit dd8086
  Some tolerence allowed for positioning the ISO 9660 image. We scan
Packit dd8086
  for STANDARD_ID and use that to set the eventual offset to adjust
Packit dd8086
  by (as long as that is <= i_fuzz).
Packit dd8086
Packit dd8086
  Maybe in the future we will have a mode. NULL is returned on error.
Packit dd8086
Packit dd8086
  @see iso9660_open, @see iso9660_fuzzy_ext
Packit dd8086
*/
Packit dd8086
iso9660_t *
Packit dd8086
iso9660_open_fuzzy (const char *psz_path, uint16_t i_fuzz /*, mode*/)
Packit dd8086
{
Packit dd8086
  return iso9660_open_fuzzy_ext(psz_path, ISO_EXTENSION_NONE, i_fuzz);
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Open an ISO 9660 image for reading with some tolerence for positioning
Packit dd8086
  of the ISO9660 image. We scan for ISO_STANDARD_ID and use that to set
Packit dd8086
  the eventual offset to adjust by (as long as that is <= i_fuzz).
Packit dd8086
Packit dd8086
  Maybe in the future we will have a mode. NULL is returned on error.
Packit dd8086
Packit dd8086
  @see iso9660_open_ext @see iso9660_open_fuzzy
Packit dd8086
*/
Packit dd8086
iso9660_t *
Packit dd8086
iso9660_open_fuzzy_ext (const char *psz_path,
Packit dd8086
			iso_extension_mask_t iso_extension_mask,
Packit dd8086
			uint16_t i_fuzz)
Packit dd8086
{
Packit dd8086
  return iso9660_open_ext_private(psz_path, iso_extension_mask, i_fuzz,
Packit dd8086
				  true);
Packit dd8086
}
Packit dd8086
Packit dd8086
/*! Close previously opened ISO 9660 image and free resources
Packit dd8086
    associated with the image. Call this when done using using an ISO
Packit dd8086
    9660 image.
Packit dd8086
Packit dd8086
    @return true is unconditionally returned. If there was an error
Packit dd8086
    false would be returned.
Packit dd8086
*/
Packit dd8086
bool
Packit dd8086
iso9660_close (iso9660_t *p_iso)
Packit dd8086
{
Packit dd8086
  if (NULL != p_iso) {
Packit dd8086
    cdio_stdio_destroy(p_iso->stream);
Packit dd8086
    p_iso->stream = NULL;
Packit dd8086
    free(p_iso);
Packit dd8086
  }
Packit dd8086
  return true;
Packit dd8086
}
Packit dd8086
Packit dd8086
static bool
Packit dd8086
check_pvd (const iso9660_pvd_t *p_pvd, cdio_log_level_t log_level)
Packit dd8086
{
Packit dd8086
  if ( ISO_VD_PRIMARY != from_711(p_pvd->type) ) {
Packit dd8086
    cdio_log (log_level, "unexpected PVD type %d", p_pvd->type);
Packit dd8086
    return false;
Packit dd8086
  }
Packit dd8086
Packit dd8086
  if (strncmp (p_pvd->id, ISO_STANDARD_ID, strlen (ISO_STANDARD_ID)))
Packit dd8086
    {
Packit dd8086
      cdio_log (log_level, "unexpected ID encountered (expected `"
Packit dd8086
		ISO_STANDARD_ID "', got `%.5s')", p_pvd->id);
Packit dd8086
      return false;
Packit dd8086
    }
Packit dd8086
  return true;
Packit dd8086
}
Packit dd8086
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Core procedure for the iso9660_ifs_get_###_id() calls.
Packit dd8086
  pvd_member/svd_member is a pointer to an achar_t or dchar_t
Packit dd8086
  ID string which we can superset as char.
Packit dd8086
  If the Joliet converted string is the same as the achar_t/dchar_t
Packit dd8086
  one, we fall back to using the latter, as it may be longer.
Packit dd8086
*/
Packit dd8086
static inline bool
Packit dd8086
get_member_id(iso9660_t *p_iso, cdio_utf8_t **p_psz_member_id,
Packit dd8086
              char* pvd_member, char* svd_member, size_t max_size)
Packit dd8086
{
Packit dd8086
  int j;
Packit dd8086
  bool strip;
Packit dd8086
Packit dd8086
  if (!p_iso) {
Packit dd8086
    *p_psz_member_id = NULL;
Packit dd8086
    return false;
Packit dd8086
  }
Packit dd8086
#ifdef HAVE_JOLIET
Packit dd8086
  if (p_iso->u_joliet_level) {
Packit dd8086
    /* Translate USC-2 string from Secondary Volume Descriptor */
Packit dd8086
    if (cdio_charset_to_utf8(svd_member, max_size,
Packit dd8086
                            p_psz_member_id, "UCS-2BE")) {
Packit dd8086
      /* NB: *p_psz_member_id is never NULL on success. */
Packit dd8086
      if (strncmp(*p_psz_member_id, pvd_member,
Packit dd8086
                  strlen(*p_psz_member_id)) != 0) {
Packit dd8086
        /* Strip trailing spaces */
Packit dd8086
        for (j = strlen(*p_psz_member_id)-1; j >= 0; j--) {
Packit dd8086
          if ((*p_psz_member_id)[j] != ' ')
Packit dd8086
            break;
Packit dd8086
          (*p_psz_member_id)[j] = '\0';
Packit dd8086
        }
Packit dd8086
        if ((*p_psz_member_id)[0] != 0) {
Packit dd8086
          /* Joliet string is not empty and differs from
Packit dd8086
             non Joliet one => use it */
Packit dd8086
          return true;
Packit dd8086
        }
Packit dd8086
      }
Packit dd8086
      /* Joliet string was either empty or same */
Packit dd8086
      free(*p_psz_member_id);
Packit dd8086
    }
Packit dd8086
  }
Packit dd8086
#endif /*HAVE_JOLIET*/
Packit dd8086
  *p_psz_member_id = calloc(max_size+1, sizeof(cdio_utf8_t));
Packit dd8086
  if (!*p_psz_member_id) {
Packit dd8086
    cdio_warn("Memory allocation error");
Packit dd8086
    return false;
Packit dd8086
  }
Packit dd8086
  /* Copy string while removing trailing spaces */
Packit dd8086
  (*p_psz_member_id)[max_size] = 0;
Packit dd8086
  for (strip=true, j=max_size-1; j>=0; j--) {
Packit dd8086
    if (strip && (pvd_member[j] == ' '))
Packit dd8086
      continue;
Packit dd8086
    strip = false;
Packit dd8086
    (*p_psz_member_id)[j] = pvd_member[j];
Packit dd8086
  }
Packit dd8086
  if (strlen(*p_psz_member_id) == 0) {
Packit dd8086
    free(*p_psz_member_id);
Packit dd8086
    *p_psz_member_id = NULL;
Packit dd8086
    return false;
Packit dd8086
  }
Packit dd8086
  return true;
Packit dd8086
}
Packit dd8086
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Return the application ID.  NULL is returned in psz_app_id if there
Packit dd8086
  is some problem in getting this.
Packit dd8086
*/
Packit dd8086
bool
Packit dd8086
iso9660_ifs_get_application_id(iso9660_t *p_iso,
Packit dd8086
			       /*out*/ cdio_utf8_t **p_psz_app_id)
Packit dd8086
{
Packit dd8086
  return get_member_id(p_iso, p_psz_app_id,
Packit dd8086
                       (char*)p_iso->pvd.application_id,
Packit dd8086
                       (char*)p_iso->svd.application_id,
Packit dd8086
                       ISO_MAX_APPLICATION_ID);
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Return the Joliet level recognized for p_iso.
Packit dd8086
*/
Packit dd8086
uint8_t iso9660_ifs_get_joliet_level(iso9660_t *p_iso)
Packit dd8086
{
Packit dd8086
  if (!p_iso) return 0;
Packit dd8086
  return p_iso->u_joliet_level;
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
   Return a string containing the preparer id with trailing
Packit dd8086
   blanks removed.
Packit dd8086
*/
Packit dd8086
bool
Packit dd8086
iso9660_ifs_get_preparer_id(iso9660_t *p_iso,
Packit dd8086
			/*out*/ cdio_utf8_t **p_psz_preparer_id)
Packit dd8086
{
Packit dd8086
  return get_member_id(p_iso, p_psz_preparer_id,
Packit dd8086
                       (char*)p_iso->pvd.preparer_id,
Packit dd8086
                       (char*)p_iso->svd.preparer_id,
Packit dd8086
                       ISO_MAX_PREPARER_ID);
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
   Return a string containing the PVD's publisher id with trailing
Packit dd8086
   blanks removed.
Packit dd8086
*/
Packit dd8086
bool iso9660_ifs_get_publisher_id(iso9660_t *p_iso,
Packit dd8086
                                  /*out*/ cdio_utf8_t **p_psz_publisher_id)
Packit dd8086
{
Packit dd8086
  return get_member_id(p_iso, p_psz_publisher_id,
Packit dd8086
                       (char*)p_iso->pvd.publisher_id,
Packit dd8086
                       (char*)p_iso->svd.publisher_id,
Packit dd8086
                       ISO_MAX_PUBLISHER_ID);
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
   Return a string containing the PVD's publisher id with trailing
Packit dd8086
   blanks removed.
Packit dd8086
*/
Packit dd8086
bool iso9660_ifs_get_system_id(iso9660_t *p_iso,
Packit dd8086
			       /*out*/ cdio_utf8_t **p_psz_system_id)
Packit dd8086
{
Packit dd8086
  return get_member_id(p_iso, p_psz_system_id,
Packit dd8086
                       (char*)p_iso->pvd.system_id,
Packit dd8086
                       (char*)p_iso->svd.system_id,
Packit dd8086
                       ISO_MAX_SYSTEM_ID);
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
   Return a string containing the PVD's publisher id with trailing
Packit dd8086
   blanks removed.
Packit dd8086
*/
Packit dd8086
bool iso9660_ifs_get_volume_id(iso9660_t *p_iso,
Packit dd8086
			       /*out*/ cdio_utf8_t **p_psz_volume_id)
Packit dd8086
{
Packit dd8086
  return get_member_id(p_iso, p_psz_volume_id,
Packit dd8086
                       (char*)p_iso->pvd.volume_id,
Packit dd8086
                       (char*)p_iso->svd.volume_id,
Packit dd8086
                       ISO_MAX_VOLUME_ID);
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
   Return a string containing the PVD's publisher id with trailing
Packit dd8086
   blanks removed.
Packit dd8086
*/
Packit dd8086
bool iso9660_ifs_get_volumeset_id(iso9660_t *p_iso,
Packit dd8086
				  /*out*/ cdio_utf8_t **p_psz_volumeset_id)
Packit dd8086
{
Packit dd8086
  return get_member_id(p_iso, p_psz_volumeset_id,
Packit dd8086
                       (char*)p_iso->pvd.volume_set_id,
Packit dd8086
                       (char*)p_iso->svd.volume_set_id,
Packit dd8086
                       ISO_MAX_VOLUMESET_ID);
Packit dd8086
}
Packit dd8086
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Read the Primary Volume Descriptor for an ISO 9660 image.
Packit dd8086
  True is returned if read, and false if there was an error.
Packit dd8086
*/
Packit dd8086
static bool
Packit dd8086
iso9660_ifs_read_pvd_loglevel (const iso9660_t *p_iso,
Packit dd8086
			       /*out*/ iso9660_pvd_t *p_pvd,
Packit dd8086
			       cdio_log_level_t log_level)
Packit dd8086
{
Packit dd8086
  if (0 == iso9660_iso_seek_read (p_iso, p_pvd, ISO_PVD_SECTOR, 1)) {
Packit dd8086
    cdio_log ( log_level, "error reading PVD sector (%d)", ISO_PVD_SECTOR );
Packit dd8086
    return false;
Packit dd8086
  }
Packit dd8086
  return check_pvd(p_pvd, log_level);
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Read the Primary Volume Descriptor for an ISO 9660 image.
Packit dd8086
  True is returned if read, and false if there was an error.
Packit dd8086
*/
Packit dd8086
bool
Packit dd8086
iso9660_ifs_read_pvd (const iso9660_t *p_iso, /*out*/ iso9660_pvd_t *p_pvd)
Packit dd8086
{
Packit dd8086
  return iso9660_ifs_read_pvd_loglevel(p_iso, p_pvd, CDIO_LOG_WARN);
Packit dd8086
}
Packit dd8086
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Read the Super block of an ISO 9660 image. This is the
Packit dd8086
  Primary Volume Descriptor (PVD) and perhaps a Supplemental Volume
Packit dd8086
  Descriptor if (Joliet) extensions are acceptable.
Packit dd8086
*/
Packit dd8086
bool
Packit dd8086
iso9660_ifs_read_superblock (iso9660_t *p_iso,
Packit dd8086
			     iso_extension_mask_t iso_extension_mask)
Packit dd8086
{
Packit dd8086
  iso9660_svd_t p_svd;  /* Secondary volume descriptor. */
Packit dd8086
  int i;
Packit dd8086
Packit dd8086
  if (!p_iso || !iso9660_ifs_read_pvd(p_iso, &(p_iso->pvd)))
Packit dd8086
    return false;
Packit dd8086
Packit dd8086
  p_iso->u_joliet_level = 0;
Packit dd8086
Packit dd8086
  /* There may be multiple Secondary Volume Descriptors (eg. El Torito + Joliet) */
Packit dd8086
  for (i=1; (0 != iso9660_iso_seek_read (p_iso, &p_svd, ISO_PVD_SECTOR+i, 1)); i++) {
Packit dd8086
    if (ISO_VD_END == from_711(p_svd.type) ) /* Last SVD */
Packit dd8086
      break;
Packit dd8086
    if ( ISO_VD_SUPPLEMENTARY == from_711(p_svd.type) ) {
Packit dd8086
      /* We're only interested in Joliet => make sure the SVD isn't overwritten */
Packit dd8086
      if (p_iso->u_joliet_level == 0)
Packit dd8086
        memcpy(&(p_iso->svd), &p_svd, sizeof(iso9660_svd_t));
Packit dd8086
      if (p_svd.escape_sequences[0] == 0x25
Packit dd8086
	  && p_svd.escape_sequences[1] == 0x2f) {
Packit dd8086
	switch (p_svd.escape_sequences[2]) {
Packit dd8086
	case 0x40:
Packit dd8086
	  if (iso_extension_mask & ISO_EXTENSION_JOLIET_LEVEL1)
Packit dd8086
	    p_iso->u_joliet_level = 1;
Packit dd8086
	  break;
Packit dd8086
	case 0x43:
Packit dd8086
	  if (iso_extension_mask & ISO_EXTENSION_JOLIET_LEVEL2)
Packit dd8086
	    p_iso->u_joliet_level = 2;
Packit dd8086
	  break;
Packit dd8086
	case 0x45:
Packit dd8086
	  if (iso_extension_mask & ISO_EXTENSION_JOLIET_LEVEL3)
Packit dd8086
	    p_iso->u_joliet_level = 3;
Packit dd8086
	  break;
Packit dd8086
	default:
Packit dd8086
	  cdio_info("Supplementary Volume Descriptor found, but not Joliet");
Packit dd8086
	}
Packit dd8086
	if (p_iso->u_joliet_level > 0) {
Packit dd8086
	  cdio_info("Found Extension: Joliet Level %d", p_iso->u_joliet_level);
Packit dd8086
	}
Packit dd8086
      }
Packit dd8086
    }
Packit dd8086
  }
Packit dd8086
Packit dd8086
  return true;
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Read the Super block of an ISO 9660 image but determine framesize
Packit dd8086
  and datastart and a possible additional offset. Generally here we are
Packit dd8086
  not reading an ISO 9660 image but a CD-Image which contains an ISO 9660
Packit dd8086
  filesystem.
Packit dd8086
*/
Packit dd8086
bool
Packit dd8086
iso9660_ifs_fuzzy_read_superblock (iso9660_t *p_iso,
Packit dd8086
				   iso_extension_mask_t iso_extension_mask,
Packit dd8086
				   uint16_t i_fuzz)
Packit dd8086
{
Packit dd8086
  /* Got some work to do to find ISO_STANDARD_ID ("CD001") */
Packit dd8086
  unsigned int i;
Packit dd8086
Packit dd8086
  for (i=0; i
Packit dd8086
    unsigned int j;
Packit dd8086
    char *pvd = NULL;
Packit dd8086
Packit dd8086
    for (j = 0; j <= 1; j++ ) {
Packit dd8086
      lsn_t lsn;
Packit dd8086
      uint16_t k;
Packit dd8086
      const uint16_t framesizes[] = { ISO_BLOCKSIZE, CDIO_CD_FRAMESIZE_RAW,
Packit dd8086
				      M2RAW_SECTOR_SIZE } ;
Packit dd8086
Packit dd8086
      /* We don't need to loop over a zero offset twice*/
Packit dd8086
      if (0==i && j)
Packit dd8086
	continue;
Packit dd8086
Packit dd8086
      lsn = (j) ? ISO_PVD_SECTOR - i : ISO_PVD_SECTOR + i;
Packit dd8086
Packit dd8086
      for (k=0; k < 3; k++) {
Packit dd8086
	char *p, *q;
Packit dd8086
	char frame[CDIO_CD_FRAMESIZE_RAW] = {'\0',};
Packit dd8086
	p_iso->i_framesize = framesizes[k];
Packit dd8086
	p_iso->i_datastart = (ISO_BLOCKSIZE == framesizes[k]) ?
Packit dd8086
			      0 : CDIO_CD_SYNC_SIZE;
Packit dd8086
	p_iso->i_fuzzy_offset = 0;
Packit dd8086
	if (0 == iso9660_seek_read_framesize (p_iso, frame, lsn, 1,
Packit dd8086
					      p_iso->i_framesize)) {
Packit dd8086
	  return false;
Packit dd8086
	}
Packit dd8086
Packit dd8086
	q = memchr(frame, 'C', p_iso->i_framesize);
Packit dd8086
	for ( p=q; p && p < frame + p_iso->i_framesize ; p=q+1 ) {
Packit dd8086
	  q = memchr(p, 'C', p_iso->i_framesize - (p - frame));
Packit dd8086
	  if ( !q || (pvd = strstr(q, ISO_STANDARD_ID)) )
Packit dd8086
	    break;
Packit dd8086
	}
Packit dd8086
Packit dd8086
	if (pvd) {
Packit dd8086
	  /* Yay! Found something */
Packit dd8086
	  p_iso->i_fuzzy_offset = (pvd - frame - 1) -
Packit dd8086
	    ((ISO_PVD_SECTOR-lsn)*p_iso->i_framesize) ;
Packit dd8086
	  /* But is it *really* a PVD? */
Packit dd8086
	  if ( iso9660_ifs_read_pvd_loglevel(p_iso, &(p_iso->pvd),
Packit dd8086
					     CDIO_LOG_DEBUG) ) {
Packit dd8086
	    adjust_fuzzy_pvd(p_iso);
Packit dd8086
	    return true;
Packit dd8086
	  }
Packit dd8086
Packit dd8086
	}
Packit dd8086
      }
Packit dd8086
    }
Packit dd8086
  }
Packit dd8086
  return false;
Packit dd8086
}
Packit dd8086
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Read the Primary Volume Descriptor for of CD.
Packit dd8086
*/
Packit dd8086
bool
Packit dd8086
iso9660_fs_read_pvd(const CdIo_t *p_cdio, /*out*/ iso9660_pvd_t *p_pvd)
Packit dd8086
{
Packit dd8086
  /* A bit of a hack, we'll assume track 1 contains ISO_PVD_SECTOR.*/
Packit dd8086
  char buf[CDIO_CD_FRAMESIZE_RAW] = { 0, };
Packit dd8086
  driver_return_code_t driver_return =
Packit dd8086
    cdio_read_data_sectors (p_cdio, buf, ISO_PVD_SECTOR, ISO_BLOCKSIZE, 1);
Packit dd8086
Packit dd8086
  if (DRIVER_OP_SUCCESS != driver_return) {
Packit dd8086
    cdio_warn ("error reading PVD sector (%d) error %d", ISO_PVD_SECTOR,
Packit dd8086
	       driver_return);
Packit dd8086
    return false;
Packit dd8086
  }
Packit dd8086
Packit dd8086
  /* The size of a PVD or SVD is smaller than a sector. So we
Packit dd8086
     allocated a bigger block above (buf) and now we'll copy just
Packit dd8086
     the part we need to save.
Packit dd8086
   */
Packit dd8086
  cdio_assert (sizeof(buf) >= sizeof (iso9660_pvd_t));
Packit dd8086
  memcpy(p_pvd, buf, sizeof(iso9660_pvd_t));
Packit dd8086
Packit dd8086
  return check_pvd(p_pvd, CDIO_LOG_WARN);
Packit dd8086
}
Packit dd8086
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Read the Super block of an ISO 9660 image. This is the
Packit dd8086
  Primary Volume Descriptor (PVD) and perhaps a Supplemental Volume
Packit dd8086
  Descriptor if (Joliet) extensions are acceptable.
Packit dd8086
*/
Packit dd8086
bool
Packit dd8086
iso9660_fs_read_superblock (CdIo_t *p_cdio,
Packit dd8086
			    iso_extension_mask_t iso_extension_mask)
Packit dd8086
{
Packit dd8086
  if (!p_cdio) return false;
Packit dd8086
Packit dd8086
  {
Packit dd8086
    generic_img_private_t *p_env = (generic_img_private_t *) p_cdio->env;
Packit dd8086
    iso9660_pvd_t         *p_pvd = &(p_env->pvd);
Packit dd8086
    iso9660_svd_t         *p_svd = &(p_env->svd);
Packit dd8086
    char buf[CDIO_CD_FRAMESIZE_RAW] = { 0, };
Packit dd8086
    driver_return_code_t driver_return;
Packit dd8086
Packit dd8086
    if ( !iso9660_fs_read_pvd(p_cdio, p_pvd) )
Packit dd8086
      return false;
Packit dd8086
Packit dd8086
    p_env->u_joliet_level = 0;
Packit dd8086
Packit dd8086
    driver_return =
Packit dd8086
      cdio_read_data_sectors ( p_cdio, buf, ISO_PVD_SECTOR+1, ISO_BLOCKSIZE,
Packit dd8086
			       1 );
Packit dd8086
Packit dd8086
    if (DRIVER_OP_SUCCESS == driver_return) {
Packit dd8086
      /* The size of a PVD or SVD is smaller than a sector. So we
Packit dd8086
	 allocated a bigger block above (buf) and now we'll copy just
Packit dd8086
	 the part we need to save.
Packit dd8086
      */
Packit dd8086
      cdio_assert (sizeof(buf) >= sizeof (iso9660_svd_t));
Packit dd8086
      memcpy(p_svd, buf, sizeof(iso9660_svd_t));
Packit dd8086
Packit dd8086
      if ( ISO_VD_SUPPLEMENTARY == from_711(p_svd->type) ) {
Packit dd8086
	if (p_svd->escape_sequences[0] == 0x25
Packit dd8086
	    && p_svd->escape_sequences[1] == 0x2f) {
Packit dd8086
	  switch (p_svd->escape_sequences[2]) {
Packit dd8086
	  case 0x40:
Packit dd8086
	    if (iso_extension_mask & ISO_EXTENSION_JOLIET_LEVEL1)
Packit dd8086
	      p_env->u_joliet_level = 1;
Packit dd8086
	    break;
Packit dd8086
	  case 0x43:
Packit dd8086
	    if (iso_extension_mask & ISO_EXTENSION_JOLIET_LEVEL2)
Packit dd8086
	      p_env->u_joliet_level = 2;
Packit dd8086
	    break;
Packit dd8086
	  case 0x45:
Packit dd8086
	    if (iso_extension_mask & ISO_EXTENSION_JOLIET_LEVEL3)
Packit dd8086
	      p_env->u_joliet_level = 3;
Packit dd8086
	    break;
Packit dd8086
	  default:
Packit dd8086
	    cdio_info("Supplementary Volume Descriptor found, but not Joliet");
Packit dd8086
	  }
Packit dd8086
	  if (p_env->u_joliet_level > 0) {
Packit dd8086
	    cdio_info("Found Extension: Joliet Level %d",
Packit dd8086
		      p_env->u_joliet_level);
Packit dd8086
	  }
Packit dd8086
	}
Packit dd8086
      }
Packit dd8086
    }
Packit dd8086
  }
Packit dd8086
Packit dd8086
  return true;
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Seek to a position and then read n blocks. Size read is returned.
Packit dd8086
*/
Packit dd8086
static long int
Packit dd8086
iso9660_seek_read_framesize (const iso9660_t *p_iso, void *ptr,
Packit dd8086
			     lsn_t start, long int size,
Packit dd8086
			     uint16_t i_framesize)
Packit dd8086
{
Packit dd8086
  long int ret;
Packit dd8086
  int64_t i_byte_offset;
Packit dd8086
Packit dd8086
  if (!p_iso) return 0;
Packit dd8086
  i_byte_offset = (start * (int64_t)(p_iso->i_framesize))
Packit dd8086
    + p_iso->i_fuzzy_offset + p_iso->i_datastart;
Packit dd8086
Packit dd8086
  ret = cdio_stream_seek (p_iso->stream, i_byte_offset, SEEK_SET);
Packit dd8086
  if (ret!=0) return 0;
Packit dd8086
  return cdio_stream_read (p_iso->stream, ptr, i_framesize, size);
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Seek to a position and then read n blocks. Size read is returned.
Packit dd8086
*/
Packit dd8086
long int
Packit dd8086
iso9660_iso_seek_read (const iso9660_t *p_iso, void *ptr, lsn_t start,
Packit dd8086
		       long int size)
Packit dd8086
{
Packit dd8086
  return iso9660_seek_read_framesize(p_iso, ptr, start, size, ISO_BLOCKSIZE);
Packit dd8086
}
Packit dd8086
Packit dd8086
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Check for the end of a directory record list in a single directory
Packit dd8086
  block.  If at the end, set the offset to start of the next block and
Packit dd8086
  return "true". The caller often skips actions only when at the end
Packit dd8086
  of a record list.
Packit dd8086
*/
Packit dd8086
static bool
Packit dd8086
iso9660_check_dir_block_end(iso9660_dir_t *p_iso9660_dir, unsigned *offset)
Packit dd8086
{
Packit dd8086
  if (!iso9660_get_dir_len(p_iso9660_dir))
Packit dd8086
    {
Packit dd8086
      /*
Packit dd8086
	 Length 0 indicates that no more directory records are in this
Packit dd8086
	 block. This matches how Linux and libburn's libisofs work.
Packit dd8086
Packit dd8086
	 Note that assignment below does not exactly round up.
Packit dd8086
	 If (offset % ISO_BLOCKSIZE) == 0  then offset is incremented
Packit dd8086
	 by ISO_BLOCKSIZE, i.e. the block is skipped.
Packit dd8086
      */
Packit dd8086
      *offset += ISO_BLOCKSIZE - (*offset % ISO_BLOCKSIZE);
Packit dd8086
      return true;
Packit dd8086
    }
Packit dd8086
Packit dd8086
  if ((*offset + iso9660_get_dir_len(p_iso9660_dir) - 1) / ISO_BLOCKSIZE
Packit dd8086
      != *offset / ISO_BLOCKSIZE)
Packit dd8086
    {
Packit dd8086
      /*
Packit dd8086
	 Directory record spans over block limit.
Packit dd8086
	 Hop to next block where a new record is supposed to begin,
Packit dd8086
	 if it is not after the end of the directory data.
Packit dd8086
       */
Packit dd8086
      *offset += ISO_BLOCKSIZE - (*offset % ISO_BLOCKSIZE);
Packit dd8086
      return true;
Packit dd8086
    }
Packit dd8086
Packit dd8086
  return false;
Packit dd8086
}
Packit dd8086
Packit dd8086
Packit dd8086
Packit dd8086
static iso9660_stat_t *
Packit dd8086
_iso9660_dir_to_statbuf (iso9660_dir_t *p_iso9660_dir, bool_3way_t b_xa,
Packit dd8086
			 uint8_t u_joliet_level)
Packit dd8086
{
Packit dd8086
  uint8_t dir_len= iso9660_get_dir_len(p_iso9660_dir);
Packit dd8086
  iso711_t i_fname;
Packit dd8086
  unsigned int stat_len;
Packit dd8086
  iso9660_stat_t *p_stat = NULL;
Packit dd8086
  bool err;
Packit dd8086
Packit dd8086
  if (!dir_len) return NULL;
Packit dd8086
Packit dd8086
  i_fname  = from_711(p_iso9660_dir->filename.len);
Packit dd8086
Packit dd8086
  /* .. string in statbuf is one longer than in p_iso9660_dir's listing '\1' */
Packit dd8086
  stat_len      = sizeof(iso9660_stat_t)+i_fname+2;
Packit dd8086
Packit dd8086
  p_stat          = calloc(1, stat_len);
Packit dd8086
  if (!p_stat)
Packit dd8086
    {
Packit dd8086
    cdio_warn("Couldn't calloc(1, %d)", stat_len);
Packit dd8086
    return NULL;
Packit dd8086
    }
Packit dd8086
  p_stat->type    = (p_iso9660_dir->file_flags & ISO_DIRECTORY)
Packit dd8086
    ? _STAT_DIR : _STAT_FILE;
Packit dd8086
  p_stat->lsn     = from_733_with_err (p_iso9660_dir->extent, &err;;
Packit dd8086
  if (err) {
Packit dd8086
    free(p_stat);
Packit dd8086
    return NULL;
Packit dd8086
  }
Packit dd8086
  p_stat->size    = from_733_with_err (p_iso9660_dir->size, &err;;
Packit dd8086
  if (err) {
Packit dd8086
    free(p_stat);
Packit dd8086
    return NULL;
Packit dd8086
  }
Packit dd8086
  p_stat->secsize = _cdio_len2blocks (p_stat->size, ISO_BLOCKSIZE);
Packit dd8086
  p_stat->rr.b3_rock = dunno; /*FIXME should do based on mask */
Packit dd8086
  p_stat->b_xa    = false;
Packit dd8086
Packit dd8086
  {
Packit dd8086
    char rr_fname[256] = "";
Packit dd8086
Packit dd8086
    int  i_rr_fname =
Packit dd8086
#ifdef HAVE_ROCK
Packit dd8086
      get_rock_ridge_filename(p_iso9660_dir, rr_fname, p_stat);
Packit dd8086
#else
Packit dd8086
      0;
Packit dd8086
#endif
Packit dd8086
Packit dd8086
    if (i_rr_fname > 0) {
Packit dd8086
      if (i_rr_fname > i_fname) {
Packit dd8086
	/* realloc gives valgrind errors */
Packit dd8086
	iso9660_stat_t *p_stat_new =
Packit dd8086
	  calloc(1, sizeof(iso9660_stat_t)+i_rr_fname+2);
Packit dd8086
        if (!p_stat_new)
Packit dd8086
          {
Packit dd8086
          cdio_warn("Couldn't calloc(1, %d)", (int)(sizeof(iso9660_stat_t)+i_rr_fname+2));
Packit dd8086
	  free(p_stat);
Packit dd8086
          return NULL;
Packit dd8086
          }
Packit dd8086
	memcpy(p_stat_new, p_stat, stat_len);
Packit dd8086
	free(p_stat);
Packit dd8086
	p_stat = p_stat_new;
Packit dd8086
      }
Packit dd8086
      strncpy(p_stat->filename, rr_fname, i_rr_fname+1);
Packit dd8086
    } else {
Packit dd8086
      if ('\0' == p_iso9660_dir->filename.str[1] && 1 == i_fname)
Packit dd8086
	strncpy (p_stat->filename, ".", sizeof("."));
Packit dd8086
      else if ('\1' == p_iso9660_dir->filename.str[1] && 1 == i_fname)
Packit dd8086
	strncpy (p_stat->filename, "..", sizeof(".."));
Packit dd8086
#ifdef HAVE_JOLIET
Packit dd8086
      else if (u_joliet_level) {
Packit dd8086
	int i_inlen = i_fname;
Packit dd8086
	cdio_utf8_t *p_psz_out = NULL;
Packit dd8086
	if (cdio_charset_to_utf8(&p_iso9660_dir->filename.str[1], i_inlen,
Packit dd8086
                             &p_psz_out, "UCS-2BE")) {
Packit dd8086
          strncpy(p_stat->filename, p_psz_out, i_fname);
Packit dd8086
          free(p_psz_out);
Packit dd8086
        }
Packit dd8086
        else {
Packit dd8086
          free(p_stat);
Packit dd8086
          return NULL;
Packit dd8086
        }
Packit dd8086
      }
Packit dd8086
#endif /*HAVE_JOLIET*/
Packit dd8086
      else {
Packit dd8086
	strncpy (p_stat->filename, &p_iso9660_dir->filename.str[1], i_fname);
Packit dd8086
      }
Packit dd8086
    }
Packit dd8086
  }
Packit dd8086
Packit dd8086
Packit dd8086
  iso9660_get_dtime(&(p_iso9660_dir->recording_time), true, &(p_stat->tm));
Packit dd8086
Packit dd8086
  if (dir_len < sizeof (iso9660_dir_t)) {
Packit dd8086
    iso9660_stat_free(p_stat);
Packit dd8086
    return NULL;
Packit dd8086
  }
Packit dd8086
Packit dd8086
Packit dd8086
  {
Packit dd8086
    int su_length = iso9660_get_dir_len(p_iso9660_dir)
Packit dd8086
      - sizeof (iso9660_dir_t);
Packit dd8086
    su_length -= i_fname;
Packit dd8086
Packit dd8086
    if (su_length % 2)
Packit dd8086
      su_length--;
Packit dd8086
Packit dd8086
    if (su_length < 0 || su_length < sizeof (iso9660_xa_t))
Packit dd8086
      return p_stat;
Packit dd8086
Packit dd8086
    if (nope == b_xa) {
Packit dd8086
      return p_stat;
Packit dd8086
    } else {
Packit dd8086
      iso9660_xa_t *xa_data =
Packit dd8086
	(void *) (((char *) p_iso9660_dir)
Packit dd8086
		  + (iso9660_get_dir_len(p_iso9660_dir) - su_length));
Packit dd8086
      cdio_log_level_t loglevel = (yep == b_xa)
Packit dd8086
	? CDIO_LOG_WARN : CDIO_LOG_INFO;
Packit dd8086
Packit dd8086
      if (xa_data->signature[0] != 'X'
Packit dd8086
	  || xa_data->signature[1] != 'A')
Packit dd8086
	{
Packit dd8086
	  cdio_log (loglevel,
Packit dd8086
		    "XA signature not found in ISO9660's system use area;"
Packit dd8086
		     " ignoring XA attributes for this file entry.");
Packit dd8086
	  cdio_debug ("%d %d %d, '%c%c' (%d, %d)",
Packit dd8086
		      iso9660_get_dir_len(p_iso9660_dir),
Packit dd8086
		      i_fname,
Packit dd8086
		      su_length,
Packit dd8086
		      xa_data->signature[0], xa_data->signature[1],
Packit dd8086
		      xa_data->signature[0], xa_data->signature[1]);
Packit dd8086
	  return p_stat;
Packit dd8086
	}
Packit dd8086
      p_stat->b_xa = true;
Packit dd8086
      p_stat->xa   = *xa_data;
Packit dd8086
    }
Packit dd8086
  }
Packit dd8086
  return p_stat;
Packit dd8086
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Return the directory name stored in the iso9660_dir_t
Packit dd8086
Packit dd8086
  A string is allocated: the caller must deallocate. This routine
Packit dd8086
  can return NULL if memory allocation fails.
Packit dd8086
 */
Packit dd8086
char *
Packit dd8086
iso9660_dir_to_name (const iso9660_dir_t *iso9660_dir)
Packit dd8086
{
Packit dd8086
  uint8_t len=iso9660_get_dir_len(iso9660_dir);
Packit dd8086
Packit dd8086
  if (!len) return NULL;
Packit dd8086
Packit dd8086
  cdio_assert (len >= sizeof (iso9660_dir_t));
Packit dd8086
Packit dd8086
  /* (iso9660_dir->file_flags & ISO_DIRECTORY) */
Packit dd8086
Packit dd8086
  if (iso9660_dir->filename.str[1] == '\0')
Packit dd8086
    return strdup(".");
Packit dd8086
  else if (iso9660_dir->filename.str[1] == '\1')
Packit dd8086
    return strdup("..");
Packit dd8086
  else {
Packit dd8086
    return strdup(&iso9660_dir->filename.str[1]);
Packit dd8086
  }
Packit dd8086
}
Packit dd8086
Packit dd8086
/*
Packit dd8086
   Return a pointer to a ISO 9660 stat buffer or NULL if there's an error
Packit dd8086
*/
Packit dd8086
static iso9660_stat_t *
Packit dd8086
_fs_stat_root (CdIo_t *p_cdio)
Packit dd8086
{
Packit dd8086
Packit dd8086
  if (!p_cdio) return NULL;
Packit dd8086
Packit dd8086
  {
Packit dd8086
    iso_extension_mask_t iso_extension_mask = ISO_EXTENSION_ALL;
Packit dd8086
    generic_img_private_t *p_env = (generic_img_private_t *) p_cdio->env;
Packit dd8086
    iso9660_dir_t *p_iso9660_dir;
Packit dd8086
    iso9660_stat_t *p_stat;
Packit dd8086
    bool_3way_t b_xa;
Packit dd8086
Packit dd8086
    if (!p_env->u_joliet_level)
Packit dd8086
      iso_extension_mask &= ~ISO_EXTENSION_JOLIET;
Packit dd8086
Packit dd8086
    /* FIXME try also with Joliet.*/
Packit dd8086
    if ( !iso9660_fs_read_superblock (p_cdio, iso_extension_mask) ) {
Packit dd8086
      cdio_warn("Could not read ISO-9660 Superblock.");
Packit dd8086
      return NULL;
Packit dd8086
    }
Packit dd8086
Packit dd8086
    switch(cdio_get_discmode(p_cdio)) {
Packit dd8086
    case CDIO_DISC_MODE_CD_XA:
Packit dd8086
      b_xa = yep;
Packit dd8086
      break;
Packit dd8086
    case CDIO_DISC_MODE_CD_DATA:
Packit dd8086
      b_xa = nope;
Packit dd8086
      break;
Packit dd8086
    default:
Packit dd8086
      b_xa = dunno;
Packit dd8086
    }
Packit dd8086
Packit dd8086
#ifdef HAVE_JOLIET
Packit dd8086
    p_iso9660_dir = p_env->u_joliet_level
Packit dd8086
      ? &(p_env->svd.root_directory_record)
Packit dd8086
      : &(p_env->pvd.root_directory_record) ;
Packit dd8086
#else
Packit dd8086
    p_iso9660_dir = &(p_env->pvd.root_directory_record) ;
Packit dd8086
#endif
Packit dd8086
Packit dd8086
    p_stat = _iso9660_dir_to_statbuf (p_iso9660_dir, b_xa,
Packit dd8086
				      p_env->u_joliet_level);
Packit dd8086
    return p_stat;
Packit dd8086
  }
Packit dd8086
Packit dd8086
}
Packit dd8086
Packit dd8086
static iso9660_stat_t *
Packit dd8086
_ifs_stat_root (iso9660_t *p_iso)
Packit dd8086
{
Packit dd8086
  iso9660_stat_t *p_stat;
Packit dd8086
  iso9660_dir_t *p_iso9660_dir;
Packit dd8086
Packit dd8086
#ifdef HAVE_JOLIET
Packit dd8086
  p_iso9660_dir = p_iso->u_joliet_level
Packit dd8086
    ? &(p_iso->svd.root_directory_record)
Packit dd8086
    : &(p_iso->pvd.root_directory_record) ;
Packit dd8086
#else
Packit dd8086
  p_iso9660_dir = &(p_iso->pvd.root_directory_record) ;
Packit dd8086
#endif
Packit dd8086
Packit dd8086
  p_stat = _iso9660_dir_to_statbuf (p_iso9660_dir, p_iso->b_xa,
Packit dd8086
				    p_iso->u_joliet_level);
Packit dd8086
  return p_stat;
Packit dd8086
}
Packit dd8086
Packit dd8086
static iso9660_stat_t *
Packit dd8086
_fs_stat_traverse (const CdIo_t *p_cdio, const iso9660_stat_t *_root,
Packit dd8086
		   char **splitpath)
Packit dd8086
{
Packit dd8086
  unsigned offset = 0;
Packit dd8086
  uint8_t *_dirbuf = NULL;
Packit dd8086
  iso9660_stat_t *p_stat;
Packit dd8086
  generic_img_private_t *p_env = (generic_img_private_t *) p_cdio->env;
Packit dd8086
Packit dd8086
  if (!splitpath[0])
Packit dd8086
    {
Packit dd8086
      unsigned int len=sizeof(iso9660_stat_t) + strlen(_root->filename)+1;
Packit dd8086
      p_stat = calloc(1, len);
Packit dd8086
      cdio_assert (p_stat != NULL);
Packit dd8086
      memcpy(p_stat, _root, len);
Packit dd8086
      p_stat->rr.psz_symlink = calloc(1, p_stat->rr.i_symlink_max);
Packit dd8086
      cdio_assert (p_stat->rr.psz_symlink != NULL);
Packit dd8086
      memcpy(p_stat->rr.psz_symlink, _root->rr.psz_symlink,
Packit dd8086
	     p_stat->rr.i_symlink_max);
Packit dd8086
      return p_stat;
Packit dd8086
    }
Packit dd8086
Packit dd8086
  if (_root->type == _STAT_FILE)
Packit dd8086
    return NULL;
Packit dd8086
Packit dd8086
  cdio_assert (_root->type == _STAT_DIR);
Packit dd8086
Packit dd8086
  _dirbuf = calloc(1, _root->secsize * ISO_BLOCKSIZE);
Packit dd8086
  if (!_dirbuf)
Packit dd8086
    {
Packit dd8086
    cdio_warn("Couldn't calloc(1, %d)", _root->secsize * ISO_BLOCKSIZE);
Packit dd8086
    return NULL;
Packit dd8086
    }
Packit dd8086
Packit dd8086
  if (cdio_read_data_sectors (p_cdio, _dirbuf, _root->lsn, ISO_BLOCKSIZE,
Packit dd8086
			      _root->secsize))
Packit dd8086
      return NULL;
Packit dd8086
Packit dd8086
  while (offset < (_root->secsize * ISO_BLOCKSIZE))
Packit dd8086
    {
Packit dd8086
      iso9660_dir_t *p_iso9660_dir = (void *) &_dirbuf[offset];
Packit dd8086
      iso9660_stat_t *p_iso9660_stat;
Packit dd8086
      int cmp;
Packit dd8086
Packit dd8086
      if (iso9660_check_dir_block_end(p_iso9660_dir, &offset))
Packit dd8086
	continue;
Packit dd8086
Packit dd8086
      p_iso9660_stat = _iso9660_dir_to_statbuf (p_iso9660_dir, dunno,
Packit dd8086
					p_env->u_joliet_level);
Packit dd8086
Packit dd8086
      cmp = strcmp(splitpath[0], p_iso9660_stat->filename);
Packit dd8086
Packit dd8086
      if ( 0 != cmp && 0 == p_env->u_joliet_level
Packit dd8086
	   && yep != p_iso9660_stat->rr.b3_rock ) {
Packit dd8086
	char *trans_fname = NULL;
Packit dd8086
	unsigned int i_trans_fname=strlen(p_iso9660_stat->filename);
Packit dd8086
Packit dd8086
	if (i_trans_fname) {
Packit dd8086
	  trans_fname = calloc(1, i_trans_fname+1);
Packit dd8086
	  if (!trans_fname) {
Packit dd8086
	    cdio_warn("can't allocate %lu bytes",
Packit dd8086
		      (long unsigned int) strlen(p_iso9660_stat->filename));
Packit dd8086
	    free(p_iso9660_stat);
Packit dd8086
	    return NULL;
Packit dd8086
	  }
Packit dd8086
	  iso9660_name_translate_ext(p_iso9660_stat->filename, trans_fname,
Packit dd8086
				     p_env->u_joliet_level);
Packit dd8086
	  cmp = strcmp(splitpath[0], trans_fname);
Packit dd8086
	  free(trans_fname);
Packit dd8086
	}
Packit dd8086
      }
Packit dd8086
Packit dd8086
      if (!cmp) {
Packit dd8086
	iso9660_stat_t *ret_stat
Packit dd8086
	  = _fs_stat_traverse (p_cdio, p_iso9660_stat, &splitpath[1]);
Packit dd8086
	iso9660_stat_free(p_iso9660_stat);
Packit dd8086
	free (_dirbuf);
Packit dd8086
	return ret_stat;
Packit dd8086
      }
Packit dd8086
Packit dd8086
      iso9660_stat_free(p_iso9660_stat);
Packit dd8086
Packit dd8086
      offset += iso9660_get_dir_len(p_iso9660_dir);
Packit dd8086
    }
Packit dd8086
Packit dd8086
  cdio_assert (offset == (_root->secsize * ISO_BLOCKSIZE));
Packit dd8086
Packit dd8086
  /* not found */
Packit dd8086
  free (_dirbuf);
Packit dd8086
  return NULL;
Packit dd8086
}
Packit dd8086
Packit dd8086
static iso9660_stat_t *
Packit dd8086
_fs_iso_stat_traverse (iso9660_t *p_iso, const iso9660_stat_t *_root,
Packit dd8086
		       char **splitpath)
Packit dd8086
{
Packit dd8086
  unsigned offset = 0;
Packit dd8086
  uint8_t *_dirbuf = NULL;
Packit dd8086
  int ret;
Packit dd8086
Packit dd8086
  if (!splitpath[0])
Packit dd8086
    {
Packit dd8086
      iso9660_stat_t *p_stat;
Packit dd8086
      unsigned int len=sizeof(iso9660_stat_t) + strlen(_root->filename)+1;
Packit dd8086
      p_stat = calloc(1, len);
Packit dd8086
      cdio_assert (p_stat != NULL);
Packit dd8086
      memcpy(p_stat, _root, len);
Packit dd8086
      p_stat->rr.psz_symlink = calloc(1, p_stat->rr.i_symlink_max);
Packit dd8086
      cdio_assert (p_stat->rr.psz_symlink != NULL);
Packit dd8086
      memcpy(p_stat->rr.psz_symlink, _root->rr.psz_symlink,
Packit dd8086
	     p_stat->rr.i_symlink_max);
Packit dd8086
      return p_stat;
Packit dd8086
    }
Packit dd8086
Packit dd8086
  if (_root->type == _STAT_FILE)
Packit dd8086
    return NULL;
Packit dd8086
Packit dd8086
  cdio_assert (_root->type == _STAT_DIR);
Packit dd8086
Packit dd8086
  _dirbuf = calloc(1, _root->secsize * ISO_BLOCKSIZE);
Packit dd8086
  if (!_dirbuf)
Packit dd8086
    {
Packit dd8086
    cdio_warn("Couldn't calloc(1, %d)", _root->secsize * ISO_BLOCKSIZE);
Packit dd8086
    return NULL;
Packit dd8086
    }
Packit dd8086
Packit dd8086
  ret = iso9660_iso_seek_read (p_iso, _dirbuf, _root->lsn, _root->secsize);
Packit dd8086
  if (ret!=ISO_BLOCKSIZE*_root->secsize) {
Packit dd8086
    free(_dirbuf);
Packit dd8086
    return NULL;
Packit dd8086
  }
Packit dd8086
Packit dd8086
  while (offset < (_root->secsize * ISO_BLOCKSIZE))
Packit dd8086
    {
Packit dd8086
      iso9660_dir_t *p_iso9660_dir = (void *) &_dirbuf[offset];
Packit dd8086
      iso9660_stat_t *p_stat;
Packit dd8086
      int cmp;
Packit dd8086
Packit dd8086
      if (iso9660_check_dir_block_end(p_iso9660_dir, &offset))
Packit dd8086
	continue;
Packit dd8086
Packit dd8086
      p_stat = _iso9660_dir_to_statbuf (p_iso9660_dir, p_iso->b_xa,
Packit dd8086
					p_iso->u_joliet_level);
Packit dd8086
Packit dd8086
      if (!p_stat) {
Packit dd8086
	cdio_warn("Bad directory information for %s", splitpath[0]);
Packit dd8086
	free(_dirbuf);
Packit dd8086
	return NULL;
Packit dd8086
      }
Packit dd8086
Packit dd8086
      cmp = strcmp(splitpath[0], p_stat->filename);
Packit dd8086
Packit dd8086
      if ( 0 != cmp && 0 == p_iso->u_joliet_level
Packit dd8086
	   && yep != p_stat->rr.b3_rock ) {
Packit dd8086
	char *trans_fname = NULL;
Packit dd8086
	unsigned int i_trans_fname=strlen(p_stat->filename);
Packit dd8086
Packit dd8086
	if (i_trans_fname) {
Packit dd8086
	  trans_fname = calloc(1, i_trans_fname+1);
Packit dd8086
	  if (!trans_fname) {
Packit dd8086
	    cdio_warn("can't allocate %lu bytes",
Packit dd8086
		      (long unsigned int) strlen(p_stat->filename));
Packit dd8086
	    free(p_stat);
Packit dd8086
	    return NULL;
Packit dd8086
	  }
Packit dd8086
	  iso9660_name_translate_ext(p_stat->filename, trans_fname,
Packit dd8086
				     p_iso->u_joliet_level);
Packit dd8086
	  cmp = strcmp(splitpath[0], trans_fname);
Packit dd8086
	  free(trans_fname);
Packit dd8086
	}
Packit dd8086
      }
Packit dd8086
Packit dd8086
      if (!cmp) {
Packit dd8086
	iso9660_stat_t *ret_stat
Packit dd8086
	  = _fs_iso_stat_traverse (p_iso, p_stat, &splitpath[1]);
Packit dd8086
	iso9660_stat_free(p_stat);
Packit dd8086
	free (_dirbuf);
Packit dd8086
	return ret_stat;
Packit dd8086
      }
Packit dd8086
      iso9660_stat_free(p_stat);
Packit dd8086
Packit dd8086
      offset += iso9660_get_dir_len(p_iso9660_dir);
Packit dd8086
    }
Packit dd8086
Packit dd8086
  cdio_assert (offset == (_root->secsize * ISO_BLOCKSIZE));
Packit dd8086
Packit dd8086
  /* not found */
Packit dd8086
  free (_dirbuf);
Packit dd8086
  return NULL;
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Return file status for psz_path. NULL is returned on error.
Packit dd8086
Packit dd8086
  @param p_cdio the CD object to read from
Packit dd8086
Packit dd8086
  @param psz_path filename path to look up and get information about
Packit dd8086
Packit dd8086
  @return ISO 9660 file information
Packit dd8086
Packit dd8086
  Important note:
Packit dd8086
Packit dd8086
  You make get different results looking up "/" versus "/." and the
Packit dd8086
  latter may give more complete information. "/" will take information
Packit dd8086
  from the PVD only, whereas "/." will force a directory read of "/" and
Packit dd8086
  find "." and in that Rock-Ridge information might be found which fills
Packit dd8086
  in more stat information. Ideally iso9660_fs_stat should be fixed.
Packit dd8086
  Patches anyone?
Packit dd8086
 */
Packit dd8086
iso9660_stat_t *
Packit dd8086
iso9660_fs_stat (CdIo_t *p_cdio, const char psz_path[])
Packit dd8086
{
Packit dd8086
  iso9660_stat_t *p_root;
Packit dd8086
  char **p_psz_splitpath;
Packit dd8086
  iso9660_stat_t *p_stat;
Packit dd8086
Packit dd8086
  if (!p_cdio)   return NULL;
Packit dd8086
  if (!psz_path) return NULL;
Packit dd8086
Packit dd8086
  p_root = _fs_stat_root (p_cdio);
Packit dd8086
Packit dd8086
  if (!p_root)   return NULL;
Packit dd8086
Packit dd8086
  p_psz_splitpath = _cdio_strsplit (psz_path, '/');
Packit dd8086
  p_stat = _fs_stat_traverse (p_cdio, p_root, p_psz_splitpath);
Packit dd8086
  free(p_root);
Packit dd8086
  _cdio_strfreev (p_psz_splitpath);
Packit dd8086
Packit dd8086
  return p_stat;
Packit dd8086
}
Packit dd8086
Packit dd8086
typedef iso9660_stat_t * (stat_root_t) (void *p_image);
Packit dd8086
typedef iso9660_stat_t * (stat_traverse_t)
Packit dd8086
  (const void *p_image, const iso9660_stat_t *_root, char **splitpath);
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Get file status for psz_path into stat. NULL is returned on error.
Packit dd8086
  pathname version numbers in the ISO 9660
Packit dd8086
  name are dropped, i.e. ;1 is removed and if level 1 ISO-9660 names
Packit dd8086
  are lowercased.
Packit dd8086
 */
Packit dd8086
static iso9660_stat_t *
Packit dd8086
fs_stat_translate (void *p_image, stat_root_t stat_root,
Packit dd8086
		   stat_traverse_t stat_traverse,
Packit dd8086
		   const char psz_path[])
Packit dd8086
{
Packit dd8086
  iso9660_stat_t *p_root;
Packit dd8086
  char **p_psz_splitpath;
Packit dd8086
  iso9660_stat_t *p_stat;
Packit dd8086
Packit dd8086
  if (!p_image)  return NULL;
Packit dd8086
  if (!psz_path) return NULL;
Packit dd8086
Packit dd8086
  p_root = stat_root (p_image);
Packit dd8086
  if (!p_root) return NULL;
Packit dd8086
Packit dd8086
  p_psz_splitpath = _cdio_strsplit (psz_path, '/');
Packit dd8086
  p_stat = stat_traverse (p_image, p_root, p_psz_splitpath);
Packit dd8086
  free(p_root);
Packit dd8086
  _cdio_strfreev (p_psz_splitpath);
Packit dd8086
Packit dd8086
  return p_stat;
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Return file status for path name psz_path. NULL is returned on error.
Packit dd8086
  pathname version numbers in the ISO 9660 name are dropped, i.e. ;1
Packit dd8086
  is removed and if level 1 ISO-9660 names are lowercased.
Packit dd8086
Packit dd8086
  @param p_cdio the CD object to read from
Packit dd8086
Packit dd8086
  @param psz_path filename path to look up and get information about
Packit dd8086
Packit dd8086
  @return ISO 9660 file information.  The caller must free the
Packit dd8086
  returned result using iso9660_stat_free().
Packit dd8086
Packit dd8086
 */
Packit dd8086
iso9660_stat_t *
Packit dd8086
iso9660_fs_stat_translate (CdIo_t *p_cdio, const char psz_path[])
Packit dd8086
{
Packit dd8086
  return fs_stat_translate(p_cdio, (stat_root_t *) _fs_stat_root,
Packit dd8086
			   (stat_traverse_t *) _fs_stat_traverse,
Packit dd8086
			   psz_path);
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  @param p_iso the ISO-9660 file image to get data from
Packit dd8086
Packit dd8086
  @param psz_path filename path translate
Packit dd8086
Packit dd8086
  @return file status for path name psz_path. NULL is returned on
Packit dd8086
  error.  pathname version numbers in the ISO 9660 name are dropped,
Packit dd8086
  i.e. ;1 is removed and if level 1 ISO-9660 names are lowercased.
Packit dd8086
  The caller must free the returned result using iso9660_stat_free().
Packit dd8086
 */
Packit dd8086
iso9660_stat_t *
Packit dd8086
iso9660_ifs_stat_translate (iso9660_t *p_iso, const char psz_path[])
Packit dd8086
{
Packit dd8086
  return fs_stat_translate(p_iso, (stat_root_t *) _ifs_stat_root,
Packit dd8086
			   (stat_traverse_t *) _fs_iso_stat_traverse,
Packit dd8086
			   psz_path);
Packit dd8086
}
Packit dd8086
Packit dd8086
Packit dd8086
/*!
Packit dd8086
Packit dd8086
  @param p_cdio the CD object to read from
Packit dd8086
Packit dd8086
  @param pzs_path path the look up
Packit dd8086
Packit dd8086
  @return file status for pathname. NULL is returned on error.
Packit dd8086
  The caller must free the returned result using iso9660_stat_free().
Packit dd8086
 */
Packit dd8086
iso9660_stat_t *
Packit dd8086
iso9660_ifs_stat (iso9660_t *p_iso, const char psz_path[])
Packit dd8086
{
Packit dd8086
  iso9660_stat_t *p_root;
Packit dd8086
  char **splitpath;
Packit dd8086
  iso9660_stat_t *stat;
Packit dd8086
Packit dd8086
  if (!p_iso)    return NULL;
Packit dd8086
  if (!psz_path) return NULL;
Packit dd8086
Packit dd8086
  p_root = _ifs_stat_root (p_iso);
Packit dd8086
  if (!p_root) return NULL;
Packit dd8086
Packit dd8086
  splitpath = _cdio_strsplit (psz_path, '/');
Packit dd8086
  stat = _fs_iso_stat_traverse (p_iso, p_root, splitpath);
Packit dd8086
  free(p_root);
Packit dd8086
  _cdio_strfreev (splitpath);
Packit dd8086
Packit dd8086
  return stat;
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Read psz_path (a directory) and return a list of iso9660_stat_t
Packit dd8086
  pointers for the files inside that directory.
Packit dd8086
Packit dd8086
  @param p_cdio the CD object to read from
Packit dd8086
Packit dd8086
  @param pzs_path path the read the directory from.
Packit dd8086
Packit dd8086
  @return file status for psz_path. The caller must free the
Packit dd8086
  The caller must free the returned result using iso9660_stat_free().
Packit dd8086
*/
Packit dd8086
CdioISO9660FileList_t *
Packit dd8086
iso9660_fs_readdir (CdIo_t *p_cdio, const char psz_path[])
Packit dd8086
{
Packit dd8086
  generic_img_private_t *p_env;
Packit dd8086
  iso9660_stat_t *p_stat;
Packit dd8086
Packit dd8086
  if (!p_cdio)   return NULL;
Packit dd8086
  if (!psz_path) return NULL;
Packit dd8086
Packit dd8086
  p_env = (generic_img_private_t *) p_cdio->env;
Packit dd8086
Packit dd8086
  p_stat = iso9660_fs_stat (p_cdio, psz_path);
Packit dd8086
  if (!p_stat) return NULL;
Packit dd8086
Packit dd8086
  if (p_stat->type != _STAT_DIR) {
Packit dd8086
    iso9660_stat_free(p_stat);
Packit dd8086
    return NULL;
Packit dd8086
  }
Packit dd8086
Packit dd8086
  {
Packit dd8086
    unsigned offset = 0;
Packit dd8086
    uint8_t *_dirbuf = NULL;
Packit dd8086
    CdioISO9660DirList_t *retval = _cdio_list_new ();
Packit dd8086
Packit dd8086
    _dirbuf = calloc(1, p_stat->secsize * ISO_BLOCKSIZE);
Packit dd8086
    if (!_dirbuf)
Packit dd8086
      {
Packit dd8086
      cdio_warn("Couldn't calloc(1, %d)", p_stat->secsize * ISO_BLOCKSIZE);
Packit dd8086
      iso9660_stat_free(p_stat);
Packit dd8086
      iso9660_dirlist_free(retval);
Packit dd8086
      return NULL;
Packit dd8086
      }
Packit dd8086
Packit dd8086
    if (cdio_read_data_sectors (p_cdio, _dirbuf, p_stat->lsn,
Packit dd8086
				ISO_BLOCKSIZE, p_stat->secsize)) {
Packit dd8086
      iso9660_stat_free(p_stat);
Packit dd8086
      iso9660_dirlist_free(retval);
Packit dd8086
      return NULL;
Packit dd8086
    }
Packit dd8086
Packit dd8086
    while (offset < (p_stat->secsize * ISO_BLOCKSIZE))
Packit dd8086
      {
Packit dd8086
	iso9660_dir_t *p_iso9660_dir = (void *) &_dirbuf[offset];
Packit dd8086
	iso9660_stat_t *p_iso9660_stat;
Packit dd8086
Packit dd8086
	if (iso9660_check_dir_block_end(p_iso9660_dir, &offset))
Packit dd8086
  	  continue;
Packit dd8086
Packit dd8086
	p_iso9660_stat = _iso9660_dir_to_statbuf(p_iso9660_dir, dunno,
Packit dd8086
						 p_env->u_joliet_level);
Packit dd8086
	_cdio_list_append (retval, p_iso9660_stat);
Packit dd8086
Packit dd8086
	offset += iso9660_get_dir_len(p_iso9660_dir);
Packit dd8086
      }
Packit dd8086
Packit dd8086
    cdio_assert (offset == (p_stat->secsize * ISO_BLOCKSIZE));
Packit dd8086
Packit dd8086
    free(_dirbuf);
Packit dd8086
    iso9660_stat_free(p_stat);
Packit dd8086
    return retval;
Packit dd8086
  }
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Read psz_path (a directory) and return a list of iso9660_stat_t
Packit dd8086
  of the files inside that. The caller must free the returned result.
Packit dd8086
*/
Packit dd8086
CdioISO9660FileList_t *
Packit dd8086
iso9660_ifs_readdir (iso9660_t *p_iso, const char psz_path[])
Packit dd8086
{
Packit dd8086
  iso9660_stat_t *p_stat;
Packit dd8086
Packit dd8086
  if (!p_iso)    return NULL;
Packit dd8086
  if (!psz_path) return NULL;
Packit dd8086
Packit dd8086
  p_stat = iso9660_ifs_stat (p_iso, psz_path);
Packit dd8086
  if (!p_stat)   return NULL;
Packit dd8086
Packit dd8086
  if (p_stat->type != _STAT_DIR) {
Packit dd8086
    iso9660_stat_free(p_stat);
Packit dd8086
    return NULL;
Packit dd8086
  }
Packit dd8086
Packit dd8086
  {
Packit dd8086
    long int ret;
Packit dd8086
    unsigned offset = 0;
Packit dd8086
    uint8_t *_dirbuf = NULL;
Packit dd8086
    CdioList_t *retval = _cdio_list_new ();
Packit dd8086
    const size_t dirbuf_len = p_stat->secsize * ISO_BLOCKSIZE;
Packit dd8086
Packit dd8086
Packit dd8086
    if (!dirbuf_len)
Packit dd8086
      {
Packit dd8086
        cdio_warn("Invalid directory buffer sector size %u", p_stat->secsize);
Packit dd8086
	iso9660_stat_free(p_stat);
Packit dd8086
	_cdio_list_free (retval, true, NULL);
Packit dd8086
        return NULL;
Packit dd8086
      }
Packit dd8086
Packit dd8086
    _dirbuf = calloc(1, dirbuf_len);
Packit dd8086
    if (!_dirbuf)
Packit dd8086
      {
Packit dd8086
        cdio_warn("Couldn't calloc(1, %lu)", (unsigned long)dirbuf_len);
Packit dd8086
	iso9660_stat_free(p_stat);
Packit dd8086
	_cdio_list_free (retval, true, NULL);
Packit dd8086
        return NULL;
Packit dd8086
      }
Packit dd8086
Packit dd8086
    ret = iso9660_iso_seek_read (p_iso, _dirbuf, p_stat->lsn, p_stat->secsize);
Packit dd8086
    if (ret != dirbuf_len) 	  {
Packit dd8086
      _cdio_list_free (retval, true, NULL);
Packit dd8086
      iso9660_stat_free(p_stat);
Packit dd8086
      free (_dirbuf);
Packit dd8086
      return NULL;
Packit dd8086
    }
Packit dd8086
Packit dd8086
    while (offset < (dirbuf_len))
Packit dd8086
      {
Packit dd8086
	iso9660_dir_t *p_iso9660_dir = (void *) &_dirbuf[offset];
Packit dd8086
	iso9660_stat_t *p_iso9660_stat;
Packit dd8086
Packit dd8086
	if (iso9660_check_dir_block_end(p_iso9660_dir, &offset))
Packit dd8086
	  continue;
Packit dd8086
Packit dd8086
	p_iso9660_stat = _iso9660_dir_to_statbuf(p_iso9660_dir, p_iso->b_xa,
Packit dd8086
						 p_iso->u_joliet_level);
Packit dd8086
Packit dd8086
	if (p_iso9660_stat)
Packit dd8086
	  _cdio_list_append (retval, p_iso9660_stat);
Packit dd8086
	else {
Packit dd8086
	  cdio_warn("Invalid directory stat at offset %lu", (unsigned long)offset);
Packit dd8086
	  break;
Packit dd8086
	}
Packit dd8086
Packit dd8086
	offset += iso9660_get_dir_len(p_iso9660_dir);
Packit dd8086
      }
Packit dd8086
Packit dd8086
    free (_dirbuf);
Packit dd8086
    iso9660_stat_free(p_stat);
Packit dd8086
Packit dd8086
    if (offset != dirbuf_len) {
Packit dd8086
      _cdio_list_free (retval, true, (CdioDataFree_t) iso9660_stat_free);
Packit dd8086
      return NULL;
Packit dd8086
    }
Packit dd8086
Packit dd8086
    return retval;
Packit dd8086
  }
Packit dd8086
}
Packit dd8086
Packit dd8086
typedef CdioISO9660FileList_t * (iso9660_readdir_t)
Packit dd8086
  (void *p_image,  const char * psz_path);
Packit dd8086
Packit dd8086
CdioISO9660FileList_t *
Packit dd8086
iso9660_filelist_new(void) {
Packit dd8086
  return (CdioISO9660FileList_t *) _cdio_list_new ();
Packit dd8086
}
Packit dd8086
Packit dd8086
CdioISO9660DirList_t *
Packit dd8086
iso9660_dirlist_new(void) {
Packit dd8086
  return (CdioISO9660FileList_t *) _cdio_list_new ();
Packit dd8086
}
Packit dd8086
Packit dd8086
static iso9660_stat_t *
Packit dd8086
find_lsn_recurse (void *p_image, iso9660_readdir_t iso9660_readdir,
Packit dd8086
		  const char psz_path[], lsn_t lsn,
Packit dd8086
		  /*out*/ char **ppsz_full_filename)
Packit dd8086
{
Packit dd8086
  CdioISO9660FileList_t *entlist = iso9660_readdir (p_image, psz_path);
Packit dd8086
  CdioISO9660DirList_t *dirlist = iso9660_filelist_new();
Packit dd8086
  CdioListNode_t *entnode;
Packit dd8086
Packit dd8086
  cdio_assert (entlist != NULL);
Packit dd8086
Packit dd8086
  /* iterate over each entry in the directory */
Packit dd8086
Packit dd8086
  _CDIO_LIST_FOREACH (entnode, entlist)
Packit dd8086
    {
Packit dd8086
      iso9660_stat_t *statbuf = _cdio_list_node_data (entnode);
Packit dd8086
      const char *psz_filename  = (char *) statbuf->filename;
Packit dd8086
      unsigned int len = strlen(psz_path) + strlen(psz_filename)+2;
Packit dd8086
Packit dd8086
      if (*ppsz_full_filename != NULL) free(*ppsz_full_filename);
Packit dd8086
      *ppsz_full_filename = calloc(1, len);
Packit dd8086
      snprintf (*ppsz_full_filename, len, "%s%s/", psz_path, psz_filename);
Packit dd8086
Packit dd8086
      if (statbuf->type == _STAT_DIR
Packit dd8086
          && strcmp ((char *) statbuf->filename, ".")
Packit dd8086
          && strcmp ((char *) statbuf->filename, "..")) {
Packit dd8086
	snprintf (*ppsz_full_filename, len, "%s%s/", psz_path, psz_filename);
Packit dd8086
        _cdio_list_append (dirlist, strdup(*ppsz_full_filename));
Packit dd8086
      }
Packit dd8086
Packit dd8086
      if (statbuf->lsn == lsn) {
Packit dd8086
	const unsigned int len2 = sizeof(iso9660_stat_t)+strlen(statbuf->filename)+1;
Packit dd8086
	iso9660_stat_t *ret_stat = calloc(1, len2);
Packit dd8086
	if (!ret_stat)
Packit dd8086
	  {
Packit dd8086
	    iso9660_dirlist_free(dirlist);
Packit dd8086
	    cdio_warn("Couldn't calloc(1, %d)", len2);
Packit dd8086
	    free(*ppsz_full_filename);
Packit dd8086
	    *ppsz_full_filename = NULL;
Packit dd8086
	    return NULL;
Packit dd8086
	  }
Packit dd8086
	memcpy(ret_stat, statbuf, len2);
Packit dd8086
        iso9660_filelist_free (entlist);
Packit dd8086
	iso9660_dirlist_free(dirlist);
Packit dd8086
        return ret_stat;
Packit dd8086
      }
Packit dd8086
Packit dd8086
    }
Packit dd8086
Packit dd8086
  iso9660_filelist_free (entlist);
Packit dd8086
Packit dd8086
  /* now recurse/descend over directories encountered */
Packit dd8086
Packit dd8086
  _CDIO_LIST_FOREACH (entnode, dirlist)
Packit dd8086
    {
Packit dd8086
      char *psz_path_prefix = _cdio_list_node_data (entnode);
Packit dd8086
      iso9660_stat_t *ret_stat;
Packit dd8086
      free(*ppsz_full_filename);
Packit dd8086
      *ppsz_full_filename = NULL;
Packit dd8086
      ret_stat = find_lsn_recurse (p_image, iso9660_readdir,
Packit dd8086
				   psz_path_prefix, lsn,
Packit dd8086
				   ppsz_full_filename);
Packit dd8086
Packit dd8086
      if (NULL != ret_stat) {
Packit dd8086
	iso9660_dirlist_free(dirlist);
Packit dd8086
        return ret_stat;
Packit dd8086
      }
Packit dd8086
    }
Packit dd8086
Packit dd8086
  if (*ppsz_full_filename != NULL) {
Packit dd8086
    free(*ppsz_full_filename);
Packit dd8086
    *ppsz_full_filename = NULL;
Packit dd8086
  }
Packit dd8086
  iso9660_dirlist_free(dirlist);
Packit dd8086
  return NULL;
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
   Given a directory pointer, find the filesystem entry that contains
Packit dd8086
   lsn and return information about it.
Packit dd8086
Packit dd8086
   Returns stat_t of entry if we found lsn, or NULL otherwise.
Packit dd8086
 */
Packit dd8086
iso9660_stat_t *
Packit dd8086
iso9660_fs_find_lsn(CdIo_t *p_cdio, lsn_t i_lsn)
Packit dd8086
{
Packit dd8086
  char *psz_full_filename = NULL;
Packit dd8086
  iso9660_stat_t * p_statbuf;
Packit dd8086
  p_statbuf = find_lsn_recurse (p_cdio, (iso9660_readdir_t *) iso9660_fs_readdir,
Packit dd8086
				"/", i_lsn, &psz_full_filename);
Packit dd8086
  if (psz_full_filename != NULL)
Packit dd8086
    free(psz_full_filename);
Packit dd8086
  return p_statbuf;
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
   Given a directory pointer, find the filesystem entry that contains
Packit dd8086
   LSN and return information about it.
Packit dd8086
Packit dd8086
   @param p_iso the ISO-9660 file image to get data from.
Packit dd8086
   @param i_lsn the LSN to find
Packit dd8086
   @param ppsz_full_filename the place to store the name of the path that has LSN.
Packit dd8086
   On entry this should point to NULL. If not, the value will be freed.
Packit dd8086
   On exit a value is malloc'd and the caller is responsible for
Packit dd8086
   freeing the result.
Packit dd8086
Packit dd8086
   @return stat_t of entry if we found lsn, or NULL otherwise.
Packit dd8086
   Caller must free return value using iso9660_stat_free().
Packit dd8086
 */
Packit dd8086
iso9660_stat_t *
Packit dd8086
iso9660_fs_find_lsn_with_path(CdIo_t *p_cdio, lsn_t i_lsn,
Packit dd8086
			      /*out*/ char **ppsz_full_filename)
Packit dd8086
{
Packit dd8086
  return find_lsn_recurse (p_cdio, (iso9660_readdir_t *) iso9660_fs_readdir,
Packit dd8086
			   "/", i_lsn, ppsz_full_filename);
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
   Given a directory pointer, find the filesystem entry that contains
Packit dd8086
   lsn and return information about it.
Packit dd8086
Packit dd8086
   @param p_iso the ISO-9660 file image to get data from.
Packit dd8086
Packit dd8086
   @param i_lsn the LSN to find
Packit dd8086
Packit dd8086
   @return stat_t of entry if we found lsn, or NULL otherwise.
Packit dd8086
   Caller must free return value using iso9660_stat_free().
Packit dd8086
 */
Packit dd8086
iso9660_stat_t *
Packit dd8086
iso9660_ifs_find_lsn(iso9660_t *p_iso, lsn_t i_lsn)
Packit dd8086
{
Packit dd8086
  char *psz_full_filename = NULL;
Packit dd8086
  iso9660_stat_t *ret  =
Packit dd8086
    find_lsn_recurse (p_iso, (iso9660_readdir_t *) iso9660_ifs_readdir,
Packit dd8086
		      "/", i_lsn, &psz_full_filename);
Packit dd8086
  if (psz_full_filename != NULL)
Packit dd8086
    free(psz_full_filename);
Packit dd8086
  return ret;
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
   Given a directory pointer, find the filesystem entry that contains
Packit dd8086
   lsn and return information about it.
Packit dd8086
Packit dd8086
   @param p_iso pointer to iso_t
Packit dd8086
Packit dd8086
   @param i_lsn LSN to find
Packit dd8086
Packit dd8086
   @param ppsz_path  full path of lsn filename. On entry *ppsz_path should be
Packit dd8086
   NULL. On return it will be allocated an point to the full path of the
Packit dd8086
   file at lsn or NULL if the lsn is not found. You should deallocate
Packit dd8086
   *ppsz_path when you are done using it.
Packit dd8086
Packit dd8086
   @return stat_t of entry if we found lsn, or NULL otherwise.
Packit dd8086
   Caller must free return value using iso9660_stat_free().
Packit dd8086
 */
Packit dd8086
iso9660_stat_t *
Packit dd8086
iso9660_ifs_find_lsn_with_path(iso9660_t *p_iso, lsn_t i_lsn,
Packit dd8086
			       /*out*/ char **ppsz_full_filename)
Packit dd8086
{
Packit dd8086
  return find_lsn_recurse (p_iso, (iso9660_readdir_t *) iso9660_ifs_readdir,
Packit dd8086
			   "/", i_lsn, ppsz_full_filename);
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Free the passed iso9660_stat_t structure.
Packit dd8086
Packit dd8086
  @param p_stat iso9660 stat buffer to free.
Packit dd8086
Packit dd8086
 */
Packit dd8086
void
Packit dd8086
iso9660_stat_free(iso9660_stat_t *p_stat)
Packit dd8086
{
Packit dd8086
  if (p_stat != NULL) {
Packit dd8086
    if (p_stat->rr.psz_symlink) {
Packit dd8086
      CDIO_FREE_IF_NOT_NULL(p_stat->rr.psz_symlink);
Packit dd8086
    }
Packit dd8086
    free(p_stat);
Packit dd8086
  }
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Free the passed CdioISOC9660FileList_t structure.
Packit dd8086
*/
Packit dd8086
void
Packit dd8086
iso9660_filelist_free(CdioISO9660FileList_t *p_filelist) {
Packit dd8086
  _cdio_list_free(p_filelist, true, (CdioDataFree_t) iso9660_stat_free);
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Free the passed CdioISOC9660DirList_t structure.
Packit dd8086
*/
Packit dd8086
void
Packit dd8086
iso9660_dirlist_free(CdioISO9660DirList_t *p_filelist) {
Packit dd8086
  _cdio_list_free(p_filelist, true, free);
Packit dd8086
}
Packit dd8086
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Return true if ISO 9660 image has extended attrributes (XA).
Packit dd8086
*/
Packit dd8086
bool
Packit dd8086
iso9660_ifs_is_xa (const iso9660_t * p_iso)
Packit dd8086
{
Packit dd8086
  if (!p_iso) return false;
Packit dd8086
  return yep == p_iso->b_xa;
Packit dd8086
}
Packit dd8086
Packit dd8086
static bool_3way_t
Packit dd8086
iso_have_rr_traverse (iso9660_t *p_iso, const iso9660_stat_t *_root,
Packit dd8086
		      char **splitpath, uint64_t *pu_file_limit)
Packit dd8086
{
Packit dd8086
  unsigned offset = 0;
Packit dd8086
  uint8_t *_dirbuf = NULL;
Packit dd8086
  int ret;
Packit dd8086
  bool_3way_t have_rr = nope;
Packit dd8086
Packit dd8086
  if (!splitpath[0]) return false;
Packit dd8086
Packit dd8086
  if (_root->type == _STAT_FILE) return nope;
Packit dd8086
  if (*pu_file_limit == 0) return dunno;
Packit dd8086
Packit dd8086
  cdio_assert (_root->type == _STAT_DIR);
Packit dd8086
Packit dd8086
  _dirbuf = calloc(1, _root->secsize * ISO_BLOCKSIZE);
Packit dd8086
  if (!_dirbuf)
Packit dd8086
    {
Packit dd8086
    cdio_warn("Couldn't calloc(1, %d)", _root->secsize * ISO_BLOCKSIZE);
Packit dd8086
    return dunno;
Packit dd8086
    }
Packit dd8086
Packit dd8086
  ret = iso9660_iso_seek_read (p_iso, _dirbuf, _root->lsn, _root->secsize);
Packit dd8086
  if (ret!=ISO_BLOCKSIZE*_root->secsize) {
Packit dd8086
    free(_dirbuf);
Packit dd8086
    return false;
Packit dd8086
  }
Packit dd8086
Packit dd8086
  while (offset < (_root->secsize * ISO_BLOCKSIZE))
Packit dd8086
    {
Packit dd8086
      iso9660_dir_t *p_iso9660_dir = (void *) &_dirbuf[offset];
Packit dd8086
      iso9660_stat_t *p_stat;
Packit dd8086
      unsigned int i_last_component = 1;
Packit dd8086
Packit dd8086
      if (iso9660_check_dir_block_end(p_iso9660_dir, &offset))
Packit dd8086
	continue;
Packit dd8086
Packit dd8086
      p_stat = _iso9660_dir_to_statbuf (p_iso9660_dir, p_iso->b_xa,
Packit dd8086
					p_iso->u_joliet_level);
Packit dd8086
      have_rr = p_stat->rr.b3_rock;
Packit dd8086
      if ( have_rr != yep) {
Packit dd8086
	if (strlen(splitpath[0]) == 0)
Packit dd8086
	  have_rr = false;
Packit dd8086
	else
Packit dd8086
	  have_rr = iso_have_rr_traverse (p_iso, p_stat, &splitpath[i_last_component],
Packit dd8086
					  pu_file_limit);
Packit dd8086
      }
Packit dd8086
      free(p_stat);
Packit dd8086
      if (have_rr != nope) {
Packit dd8086
	free (_dirbuf);
Packit dd8086
	return have_rr;
Packit dd8086
      }
Packit dd8086
Packit dd8086
      offset += iso9660_get_dir_len(p_iso9660_dir);
Packit dd8086
      *pu_file_limit = (*pu_file_limit)-1;
Packit dd8086
      if ((*pu_file_limit) == 0) {
Packit dd8086
	free (_dirbuf);
Packit dd8086
	return dunno;
Packit dd8086
      }
Packit dd8086
    }
Packit dd8086
Packit dd8086
  cdio_assert (offset == (_root->secsize * ISO_BLOCKSIZE));
Packit dd8086
Packit dd8086
  /* not found */
Packit dd8086
  free (_dirbuf);
Packit dd8086
  return nope;
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Return "yup" if any file has Rock-Ridge extensions. Warning: this can
Packit dd8086
  be time consuming. On an ISO 9600 image with lots of files but no Rock-Ridge
Packit dd8086
  extensions, the entire directory structure will be scanned up to u_file_limit.
Packit dd8086
Packit dd8086
  @param p_iso the ISO-9660 file image to get data from
Packit dd8086
Packit dd8086
  @param u_file_limit the maximimum number of (non-rock-ridge) files
Packit dd8086
  to consider before giving up and returning "dunno".
Packit dd8086
Packit dd8086
  "dunno" can also be returned if there was some error encountered
Packit dd8086
  such as not being able to allocate memory in processing.
Packit dd8086
Packit dd8086
*/
Packit dd8086
extern bool_3way_t
Packit dd8086
iso9660_have_rr(iso9660_t *p_iso, uint64_t u_file_limit)
Packit dd8086
{
Packit dd8086
  iso9660_stat_t *p_root;
Packit dd8086
  char *p_psz_splitpath[2] = {strdup("/"), strdup("")};
Packit dd8086
  bool_3way_t is_rr = nope;
Packit dd8086
Packit dd8086
  if (!p_iso) return false;
Packit dd8086
Packit dd8086
  p_root = _ifs_stat_root (p_iso);
Packit dd8086
  if (!p_root) return dunno;
Packit dd8086
Packit dd8086
  if (u_file_limit == 0) u_file_limit = UINT64_MAX;
Packit dd8086
Packit dd8086
  is_rr = iso_have_rr_traverse (p_iso, p_root, p_psz_splitpath, &u_file_limit);
Packit dd8086
  free(p_root);
Packit dd8086
  free(p_psz_splitpath[0]);
Packit dd8086
  free(p_psz_splitpath[1]);
Packit dd8086
Packit dd8086
  return is_rr;
Packit dd8086
}