Example #1
0
/*! 
  Read pathname (a directory) and return a list of iso9660_stat_t
  of the files inside that. The caller must free the returned result.
*/
CdioList_t * 
iso9660_ifs_readdir (iso9660_t *p_iso, const char pathname[])
{
  iso9660_stat_t *p_stat;

  if (!p_iso)    return NULL;
  if (!pathname) return NULL;

  p_stat = iso9660_ifs_stat (p_iso, pathname);
  if (!p_stat)   return NULL;

  if (p_stat->type != _STAT_DIR) {
    free(p_stat);
    return NULL;
  }

  {
    long int ret;
    unsigned offset = 0;
    uint8_t *_dirbuf = NULL;
    CdioList_t *retval = _cdio_list_new ();

    if (p_stat->size != ISO_BLOCKSIZE * p_stat->secsize)
      {
	cdio_warn ("bad size for ISO9660 directory (%ud) should be (%lu)!",
		   (unsigned int) p_stat->size, 
		   (unsigned long int) ISO_BLOCKSIZE * p_stat->secsize);
      }

    _dirbuf = _cdio_malloc (p_stat->secsize * ISO_BLOCKSIZE);

    ret = iso9660_iso_seek_read (p_iso, _dirbuf, p_stat->lsn, p_stat->secsize);
    if (ret != ISO_BLOCKSIZE*p_stat->secsize) return NULL;
    
    while (offset < (p_stat->secsize * ISO_BLOCKSIZE))
      {
	iso9660_dir_t *p_iso9660_dir = (void *) &_dirbuf[offset];
	iso9660_stat_t *p_iso9660_stat;
	
	if (!iso9660_get_dir_len(p_iso9660_dir))
	  {
	    offset++;
	    continue;
	  }

	p_iso9660_stat = _iso9660_dir_to_statbuf(p_iso9660_dir, true,
						 p_iso->i_joliet_level);
	_cdio_list_append (retval, p_iso9660_stat);

	offset += iso9660_get_dir_len(p_iso9660_dir);
      }

    cdio_assert (offset == (p_stat->secsize * ISO_BLOCKSIZE));

    free (_dirbuf);
    free (p_stat);
    return retval;
  }
}
Example #2
0
void * /* list of char* -- caller must free it */
iso9660_fs_readdir (const CdIo *cdio, const char pathname[], bool is_mode2)
{
  iso9660_stat_t stat;

  cdio_assert (cdio != NULL);
  cdio_assert (pathname != NULL);

  if (iso9660_fs_stat (cdio, pathname, &stat, is_mode2))
    return NULL;

  if (stat.type != _STAT_DIR)
    return NULL;

  {
    unsigned offset = 0;
    uint8_t *_dirbuf = NULL;
    CdioList *retval = _cdio_list_new ();

    if (stat.size != ISO_BLOCKSIZE * stat.secsize)
      {
	cdio_warn ("bad size for ISO9660 directory (%ud) should be (%lu)!",
		   (unsigned) stat.size, 
		   (unsigned long int) ISO_BLOCKSIZE * stat.secsize);
      }

    _dirbuf = _cdio_malloc (stat.secsize * ISO_BLOCKSIZE);

    if (is_mode2) {
      if (cdio_read_mode2_sectors (cdio, _dirbuf, stat.lsn, false, 
				   stat.secsize))
	cdio_assert_not_reached ();
    } else {
      if (cdio_read_mode1_sectors (cdio, _dirbuf, stat.lsn, false,
				   stat.secsize))
	cdio_assert_not_reached ();
    }

    while (offset < (stat.secsize * ISO_BLOCKSIZE))
      {
	const iso9660_dir_t *idr = (void *) &_dirbuf[offset];

	if (!iso9660_get_dir_len(idr))
	  {
	    offset++;
	    continue;
	  }

	_cdio_list_append (retval, _idr2name (idr));

	offset += iso9660_get_dir_len(idr);
      }

    cdio_assert (offset == (stat.secsize * ISO_BLOCKSIZE));

    free (_dirbuf);
    return retval;
  }
}
Example #3
0
static void
print_iso9660_recurse (CdIo_t *p_cdio, const char pathname[], 
		       cdio_fs_anal_t fs)
{
  CdioList_t *p_entlist;
  CdioList_t *p_dirlist =  _cdio_list_new ();
  CdioListNode_t *entnode;
  uint8_t i_joliet_level;

  i_joliet_level = (opts.no_joliet) 
    ? 0
    : cdio_get_joliet_level(p_cdio);

  p_entlist = iso9660_fs_readdir (p_cdio, pathname, false);
    
  printf ("%s:\n", pathname);

  if (NULL == p_entlist) {
    report( stderr, "Error getting above directory information\n" );
    return;
  }

  /* Iterate over files in this directory */
  
  _CDIO_LIST_FOREACH (entnode, p_entlist)
    {
      iso9660_stat_t *p_statbuf = _cdio_list_node_data (entnode);
      char *psz_iso_name = p_statbuf->filename;
      char _fullname[4096] = { 0, };
      char translated_name[MAX_ISONAME+1];

      if (yep != p_statbuf->rr.b3_rock || 1 == opts.no_rock_ridge) {
	iso9660_name_translate_ext(psz_iso_name, translated_name, 
				   i_joliet_level);
      }
  
      
      snprintf (_fullname, sizeof (_fullname), "%s%s", pathname, 
		psz_iso_name);
  
      strncat (_fullname, "/", sizeof (_fullname));

      if (p_statbuf->type == _STAT_DIR
          && strcmp (psz_iso_name, ".") 
          && strcmp (psz_iso_name, ".."))
        _cdio_list_append (p_dirlist, strdup (_fullname));

      print_fs_attrs(p_statbuf, 0 == opts.no_rock_ridge, fs & CDIO_FS_ANAL_XA, 
		     psz_iso_name, translated_name);
      if (p_statbuf->rr.i_symlink) {
	free(p_statbuf->rr.psz_symlink);
	p_statbuf->rr.i_symlink = 0;
      }
    }
Example #4
0
static iso9660_stat_t *
find_lsn_recurse (void *p_image, iso9660_readdir_t iso9660_readdir,
		  const char psz_path[], lsn_t lsn,
		  /*out*/ char **ppsz_full_filename)
{
  CdioList_t *entlist = iso9660_readdir (p_image, psz_path);
  CdioList_t *dirlist =  _cdio_list_new ();
  CdioListNode_t *entnode;
    
  cdio_assert (entlist != NULL);

  /* iterate over each entry in the directory */
  
  _CDIO_LIST_FOREACH (entnode, entlist)
    {
      iso9660_stat_t *statbuf = _cdio_list_node_data (entnode);
      const char *psz_filename  = (char *) statbuf->filename;
      const unsigned int len = strlen(psz_path) + strlen(psz_filename)+2;
      
      if (*ppsz_full_filename != NULL) free(*ppsz_full_filename);
      *ppsz_full_filename = calloc(1, len);
      snprintf (*ppsz_full_filename, len, "%s%s/", psz_path, psz_filename);

      if (statbuf->type == _STAT_DIR
          && strcmp ((char *) statbuf->filename, ".") 
          && strcmp ((char *) statbuf->filename, "..")) {
        _cdio_list_append (dirlist, strdup(*ppsz_full_filename));
      }

      if (statbuf->lsn == lsn) {
	unsigned int len=sizeof(iso9660_stat_t)+strlen(statbuf->filename)+1;
	iso9660_stat_t *ret_stat = calloc(1, len);
	if (!ret_stat)
	  {
          cdio_warn("Couldn't calloc(1, %d)", len);
          return NULL;
	  }
	memcpy(ret_stat, statbuf, len);
        _cdio_list_free (entlist, true);
        _cdio_list_free (dirlist, true);
        return ret_stat;
      }
      
    }
Example #5
0
static iso9660_stat_t *
find_fs_lsn_recurse (CdIo_t *p_cdio, const char pathname[], lsn_t lsn)
{
  CdioList_t *entlist = iso9660_fs_readdir (p_cdio, pathname, true);
  CdioList_t *dirlist =  _cdio_list_new ();
  CdioListNode_t *entnode;
    
  cdio_assert (entlist != NULL);

  /* iterate over each entry in the directory */
  
  _CDIO_LIST_FOREACH (entnode, entlist)
    {
      iso9660_stat_t *statbuf = _cdio_list_node_data (entnode);
      char _fullname[4096] = { 0, };
      char *filename = (char *) statbuf->filename;

      snprintf (_fullname, sizeof (_fullname), "%s%s", pathname, filename);
  
      strncat (_fullname, "/", sizeof (_fullname));

      if (statbuf->type == _STAT_DIR
          && strcmp ((char *) statbuf->filename, ".") 
          && strcmp ((char *) statbuf->filename, ".."))
        _cdio_list_append (dirlist, strdup (_fullname));

      if (statbuf->lsn == lsn) {
	unsigned int len=sizeof(iso9660_stat_t)+strlen(statbuf->filename)+1;
	iso9660_stat_t *ret_stat = _cdio_malloc(len);
	memcpy(ret_stat, statbuf, len);
        _cdio_list_free (entlist, true);
        _cdio_list_free (dirlist, true);
        return ret_stat;
      }
      
    }
Example #6
0
static bool
find_fs_lsn_recurse (const CdIo *cdio, const char pathname[], 
		     /*out*/ iso9660_stat_t *statbuf, lsn_t lsn)
{
  CdioList *entlist = iso9660_fs_readdir (cdio, pathname, true);
  CdioList *dirlist =  _cdio_list_new ();
  CdioListNode *entnode;
    
  cdio_assert (entlist != NULL);

  /* iterate over each entry in the directory */
  
  _CDIO_LIST_FOREACH (entnode, entlist)
    {
      char *name = _cdio_list_node_data (entnode);
      char _fullname[4096] = { 0, };

      snprintf (_fullname, sizeof (_fullname), "%s%s", pathname, name);
  
      if (iso9660_fs_stat (cdio, _fullname, statbuf, true))
        cdio_assert_not_reached ();

      strncat (_fullname, "/", sizeof (_fullname));

      if (statbuf->type == _STAT_DIR
          && strcmp (name, ".") 
          && strcmp (name, ".."))
        _cdio_list_append (dirlist, strdup (_fullname));

      if (statbuf->lsn == lsn) {
        _cdio_list_free (entlist, true);
        _cdio_list_free (dirlist, true);
        return true;
      }
      
    }
Example #7
0
/*! 
  Read psz_path (a directory) and return a list of iso9660_stat_t
  of the files inside that. The caller must free the returned result.

  b_mode2 is historical. It is not used.
*/
CdioList_t * 
iso9660_fs_readdir (CdIo_t *p_cdio, const char psz_path[], bool b_mode2)
{
  generic_img_private_t *p_env;
  iso9660_stat_t *p_stat;

  if (!p_cdio)   return NULL;
  if (!psz_path) return NULL;

  p_env = (generic_img_private_t *) p_cdio->env;

  p_stat = iso9660_fs_stat (p_cdio, psz_path);
  if (!p_stat) return NULL;

  if (p_stat->type != _STAT_DIR) {
    free(p_stat->rr.psz_symlink);
    free(p_stat);
    return NULL;
  }

  {
    unsigned offset = 0;
    uint8_t *_dirbuf = NULL;
    CdioList_t *retval = _cdio_list_new ();

    if (p_stat->size != ISO_BLOCKSIZE * p_stat->secsize)
      {
	cdio_warn ("bad size for ISO9660 directory (%ud) should be (%lu)!",
		   (unsigned) p_stat->size, 
		   (unsigned long int) ISO_BLOCKSIZE * p_stat->secsize);
      }

    _dirbuf = calloc(1, p_stat->secsize * ISO_BLOCKSIZE);
    if (!_dirbuf)
      {
      cdio_warn("Couldn't calloc(1, %d)", p_stat->secsize * ISO_BLOCKSIZE);
      return NULL;
      }

    if (cdio_read_data_sectors (p_cdio, _dirbuf, p_stat->lsn, 
				ISO_BLOCKSIZE, p_stat->secsize))
	return NULL;

    while (offset < (p_stat->secsize * ISO_BLOCKSIZE))
      {
	iso9660_dir_t *p_iso9660_dir = (void *) &_dirbuf[offset];
	iso9660_stat_t *p_iso9660_stat;
	
	if (!iso9660_get_dir_len(p_iso9660_dir))
	  {
	    offset++;
	    continue;
	  }

	p_iso9660_stat = _iso9660_dir_to_statbuf(p_iso9660_dir, dunno,
						 p_env->i_joliet_level);
	_cdio_list_append (retval, p_iso9660_stat);

	offset += iso9660_get_dir_len(p_iso9660_dir);
      }

    cdio_assert (offset == (p_stat->secsize * ISO_BLOCKSIZE));

    free (_dirbuf);
    free (p_stat);
    return retval;
  }
}
Example #8
0
/*!
  Read psz_path (a directory) and return a list of iso9660_stat_t
  of the files inside that. The caller must free the returned result.
*/
CdioList_t *
iso9660_ifs_readdir (iso9660_t *p_iso, const char psz_path[])
{
  iso9660_stat_t *p_stat;

  if (!p_iso)    return NULL;
  if (!psz_path) return NULL;

  p_stat = iso9660_ifs_stat (p_iso, psz_path);
  if (!p_stat)   return NULL;

  if (p_stat->type != _STAT_DIR) {
    free(p_stat->rr.psz_symlink);
    free(p_stat);
    return NULL;
  }

  {
    long int ret;
    unsigned offset = 0;
    uint8_t *_dirbuf = NULL;
    CdioList_t *retval = _cdio_list_new ();

    _dirbuf = calloc(1, p_stat->secsize * ISO_BLOCKSIZE);
    if (!_dirbuf)
      {
        cdio_warn("Couldn't calloc(1, %d)", p_stat->secsize * ISO_BLOCKSIZE);
        return NULL;
      }

    ret = iso9660_iso_seek_read (p_iso, _dirbuf, p_stat->lsn, p_stat->secsize);
    if (ret != ISO_BLOCKSIZE*p_stat->secsize)
	  {
	    free (_dirbuf);
	    return NULL;
	  }

    while (offset < (p_stat->secsize * ISO_BLOCKSIZE))
      {
	iso9660_dir_t *p_iso9660_dir = (void *) &_dirbuf[offset];
	iso9660_stat_t *p_iso9660_stat;

	if (!iso9660_get_dir_len(p_iso9660_dir))
	  {
	    offset++;
	    continue;
	  }

	p_iso9660_stat = _iso9660_dir_to_statbuf(p_iso9660_dir, p_iso->b_xa,
						 p_iso->u_joliet_level);

	if (p_iso9660_stat)
	  _cdio_list_append (retval, p_iso9660_stat);

	offset += iso9660_get_dir_len(p_iso9660_dir);
      }

    free (_dirbuf);

    if (offset != (p_stat->secsize * ISO_BLOCKSIZE)) {
      free (p_stat);
      _cdio_list_free (retval, true);
      return NULL;
    }

    free (p_stat->rr.psz_symlink);
    free (p_stat);
    return retval;
  }
}
Example #9
0
/* Updates internal track TOC, so we can later 
   simulate ioctl(CDROMREADTOCENTRY).
 */
static void
_register_mapping (_img_private_t *env, lsn_t start_lsn, uint32_t sec_count,
		   uint64_t img_offset, uint32_t blocksize,
		   track_format_t track_format, bool track_green)
{
  const int track_num=env->gen.i_tracks;
  track_info_t  *this_track=&(env->tocent[env->gen.i_tracks]);
  _mapping_t *_map = calloc(1, sizeof (_mapping_t));

  _map->start_lsn  = start_lsn;
  _map->sec_count  = sec_count;
  _map->img_offset = img_offset;
  _map->blocksize  = blocksize;

  if (!env->mapping) env->mapping = _cdio_list_new ();
  _cdio_list_append (env->mapping, _map);

  env->size = MAX (env->size, (start_lsn + sec_count));

  /* Update *this_track and track_num. These structures are
     in a sense redundant witht the obj->mapping list. Perhaps one
     or the other can be eliminated.
   */

  cdio_lba_to_msf (cdio_lsn_to_lba(start_lsn), &(this_track->start_msf));
  this_track->start_lba = cdio_msf_to_lba(&this_track->start_msf);
  this_track->track_num = track_num+1;
  this_track->blocksize = blocksize;
  if (env->is_cues) 
    this_track->datastart = img_offset;
  else 
    this_track->datastart = 0;

  if (track_green) 
    this_track->datastart += CDIO_CD_SUBHEADER_SIZE;
      
  this_track->sec_count = sec_count;

  this_track->track_format= track_format;
  this_track->track_green = track_green;

  switch (this_track->track_format) {
  case TRACK_FORMAT_AUDIO:
    this_track->blocksize   = CDIO_CD_FRAMESIZE_RAW;
    this_track->datasize    = CDIO_CD_FRAMESIZE_RAW;
    /*this_track->datastart   = 0;*/
    this_track->endsize     = 0;
    break;
  case TRACK_FORMAT_CDI:
    this_track->datasize=CDIO_CD_FRAMESIZE;
    break;
  case TRACK_FORMAT_XA:
    if (track_green) {
      this_track->blocksize = CDIO_CD_FRAMESIZE;
      /*this_track->datastart = CDIO_CD_SYNC_SIZE + CDIO_CD_HEADER_SIZE;*/
      this_track->datasize  = M2RAW_SECTOR_SIZE;
      this_track->endsize   = 0;
    } else {
      /*this_track->datastart = CDIO_CD_SYNC_SIZE + CDIO_CD_HEADER_SIZE +
	CDIO_CD_SUBHEADER_SIZE;*/
      this_track->datasize  = CDIO_CD_FRAMESIZE;
      this_track->endsize   = CDIO_CD_SYNC_SIZE + CDIO_CD_ECC_SIZE;
    }
    break;
  case TRACK_FORMAT_DATA:
    if (track_green) {
      /*this_track->datastart = CDIO_CD_SYNC_SIZE + CDIO_CD_HEADER_SIZE;*/
      this_track->datasize  = CDIO_CD_FRAMESIZE;
      this_track->endsize   = CDIO_CD_EDC_SIZE + CDIO_CD_M1F1_ZERO_SIZE 
	  + CDIO_CD_ECC_SIZE;
    } else {
      /* Is the below correct? */
      /*this_track->datastart = 0;*/
      this_track->datasize  = CDIO_CD_FRAMESIZE;
      this_track->endsize   = 0;  
    }
    break;
  default:
    /*this_track->datasize=CDIO_CD_FRAMESIZE_RAW;*/
    cdio_warn ("track %d has unknown format %d",
	       env->gen.i_tracks, this_track->track_format);
  }
  
  env->gen.i_tracks++;

  cdio_debug ("start lsn: %lu sector count: %0lu -> %8ld (%08lx)", 
	      (long unsigned int) start_lsn, 
	      (long unsigned int) sec_count, 
	      (long unsigned int) img_offset,
	      (long unsigned int) img_offset);
}
Example #10
0
static void
print_iso9660_recurse (iso9660_t *p_iso, const char psz_path[])
{
  CdioList_t *entlist;
  CdioList_t *dirlist =  _cdio_list_new ();
  CdioListNode_t *entnode;
  uint8_t i_joliet_level = iso9660_ifs_get_joliet_level(p_iso);
  char *translated_name = (char *) malloc(4096);
  size_t translated_name_size = 4096;
  entlist = iso9660_ifs_readdir (p_iso, psz_path);
    
  if (opts.print_iso9660) {
    printf ("%s:\n", psz_path);
  }

  if (NULL == entlist) {
    report( stderr, "Error getting above directory information\n" );
    return;
  }

  /* Iterate over files in this directory */
  
  _CDIO_LIST_FOREACH (entnode, entlist)
    {
      iso9660_stat_t *p_statbuf = _cdio_list_node_data (entnode);
      char *psz_iso_name = p_statbuf->filename;
      char _fullname[4096] = { 0, };
       if (strlen(psz_iso_name) >= translated_name_size) {
         translated_name_size = strlen(psz_iso_name)+1;
         free(translated_name);
         translated_name = (char *) malloc(translated_name_size);
         if (!translated_name) {
           report( stderr, "Error allocating memory\n" );
           return;
         }
       }

      if (yep != p_statbuf->rr.b3_rock || 1 == opts.no_rock_ridge) {
	iso9660_name_translate_ext(psz_iso_name, translated_name, 
				   i_joliet_level);
	snprintf (_fullname, sizeof (_fullname), "%s%s", psz_path, 
		  translated_name);
      } else {
	snprintf (_fullname, sizeof (_fullname), "%s%s", psz_path, 
		  psz_iso_name);
      }
      
      strncat (_fullname, "/", sizeof (_fullname));

      if (p_statbuf->type == _STAT_DIR
          && strcmp (psz_iso_name, ".") 
          && strcmp (psz_iso_name, ".."))
        _cdio_list_append (dirlist, strdup (_fullname));

      if (opts.print_iso9660) {
	print_fs_attrs(p_statbuf, 
		       0 == opts.no_rock_ridge,
		       iso9660_ifs_is_xa(p_iso) && 0 == opts.no_xa,
		       psz_iso_name, translated_name);
      } else 
	if ( strcmp (psz_iso_name, ".") && strcmp (psz_iso_name, ".."))
	  printf("%9u %s%s\n", (unsigned int) p_statbuf->size, psz_path, 
		 yep == p_statbuf->rr.b3_rock 
		 ? psz_iso_name : translated_name);
      if (p_statbuf->rr.i_symlink) {
	free(p_statbuf->rr.psz_symlink);
	p_statbuf->rr.i_symlink = 0;
      }
    }
Example #11
0
static void
print_iso9660_recurse (CdIo_t *p_cdio, const char pathname[], 
		       cdio_fs_anal_t fs, 
		       bool b_mode2)
{
  CdioList_t *entlist;
  CdioList_t *dirlist =  _cdio_list_new ();
  CdioListNode_t *entnode;
  uint8_t i_joliet_level;

  i_joliet_level = (opts.no_joliet) 
    ? 0
    : cdio_get_joliet_level(p_cdio);

  entlist = iso9660_fs_readdir (p_cdio, pathname, b_mode2);
    
  sprintf (temp_msg, "%s:\n", pathname);
  report(stdout, temp_msg);

  if (NULL == entlist) {
    report( stderr, "Error getting above directory information\n" );
    return;
  }

  /* Iterate over files in this directory */
  
  _CDIO_LIST_FOREACH (entnode, entlist)
    {
      iso9660_stat_t *statbuf = _cdio_list_node_data (entnode);
      char *iso_name = statbuf->filename;
      char _fullname[4096] = { 0, };
      char translated_name[MAX_ISONAME+1];
#define DATESTR_SIZE 30
      char date_str[DATESTR_SIZE];

      iso9660_name_translate_ext(iso_name, translated_name, i_joliet_level);
      
      snprintf (_fullname, sizeof (_fullname), "%s%s", pathname, 
		iso_name);
  
      strncat (_fullname, "/", sizeof (_fullname));

      if (statbuf->type == _STAT_DIR
          && strcmp (iso_name, ".") 
          && strcmp (iso_name, ".."))
        _cdio_list_append (dirlist, strdup (_fullname));

      if (fs & CDIO_FS_ANAL_XA) {
	sprintf (temp_msg, "  %c %s %d %d [fn %.2d] [LSN %6lu] ",
		 (statbuf->type == _STAT_DIR) ? 'd' : '-',
		 iso9660_get_xa_attr_str (statbuf->xa.attributes),
		 uint16_from_be (statbuf->xa.user_id),
		 uint16_from_be (statbuf->xa.group_id),
		 statbuf->xa.filenum,
		 (long unsigned int) statbuf->lsn);
    report(stdout, temp_msg);
	
	if (uint16_from_be(statbuf->xa.attributes) & XA_ATTR_MODE2FORM2) {
	  sprintf (temp_msg, "%9u (%9u)",
		  (unsigned int) statbuf->secsize * M2F2_SECTOR_SIZE,
		  (unsigned int) statbuf->size);
      report(stdout, temp_msg);
	} else {
	  printf ("%9u", (unsigned int) statbuf->size);
	}
      }
      strftime(date_str, DATESTR_SIZE, "%b %d %Y %H:%M ", &statbuf->tm);
      sprintf (temp_msg, " %s %s\n", date_str, translated_name);
      report(stdout, temp_msg);
    }
Example #12
0
/*! 
  Read pathname (a directory) and return a list of iso9660_stat_t
  of the files inside that. The caller must free the returned result.
*/
CdioList_t * 
iso9660_fs_readdir (CdIo_t *p_cdio, const char pathname[], bool b_mode2)
{
  iso9660_stat_t *p_stat;
  generic_img_private_t *p_env = (generic_img_private_t *) p_cdio->env;

  if (!p_cdio)   return NULL;
  if (!pathname) return NULL;

  p_stat = iso9660_fs_stat (p_cdio, pathname);
  if (!p_stat) return NULL;

  if (p_stat->type != _STAT_DIR) {
    free(p_stat);
    return NULL;
  }

  {
    unsigned offset = 0;
    uint8_t *_dirbuf = NULL;
    CdioList_t *retval = _cdio_list_new ();

    if (p_stat->size != ISO_BLOCKSIZE * p_stat->secsize)
      {
	cdio_warn ("bad size for ISO9660 directory (%ud) should be (%lu)!",
		   (unsigned) p_stat->size, 
		   (unsigned long int) ISO_BLOCKSIZE * p_stat->secsize);
      }

    _dirbuf = _cdio_malloc (p_stat->secsize * ISO_BLOCKSIZE);

    if (b_mode2) {
      if (cdio_read_mode2_sectors (p_cdio, _dirbuf, p_stat->lsn, false, 
				   p_stat->secsize))
	cdio_assert_not_reached ();
    } else {
      if (cdio_read_mode1_sectors (p_cdio, _dirbuf, p_stat->lsn, false,
				   p_stat->secsize))
	cdio_assert_not_reached ();
    }

    while (offset < (p_stat->secsize * ISO_BLOCKSIZE))
      {
	iso9660_dir_t *p_iso9660_dir = (void *) &_dirbuf[offset];
	iso9660_stat_t *p_iso9660_stat;
	
	if (!iso9660_get_dir_len(p_iso9660_dir))
	  {
	    offset++;
	    continue;
	  }

	p_iso9660_stat = _iso9660_dir_to_statbuf(p_iso9660_dir, b_mode2, 
						 p_env->i_joliet_level);
	_cdio_list_append (retval, p_iso9660_stat);

	offset += iso9660_get_dir_len(p_iso9660_dir);
      }

    cdio_assert (offset == (p_stat->secsize * ISO_BLOCKSIZE));

    free (_dirbuf);
    free (p_stat);
    return retval;
  }
}