Blame lib/iso9660/rock.c

Packit dd8086
/*
Packit dd8086
  Copyright (C) 2005, 2008, 2010-2011, 2014, 2017 Rocky Bernstein
Packit dd8086
  <rocky@gnu.org>
Packit dd8086
Packit dd8086
  Adapted from GNU/Linux fs/isofs/rock.c (C) 1992, 1993 Eric Youngdale
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
/* Rock Ridge Extensions to iso9660 */
Packit dd8086
Packit dd8086

Packit dd8086
#ifdef HAVE_CONFIG_H
Packit dd8086
# include "config.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_STDLIB_H
Packit dd8086
# include <stdlib.h>
Packit dd8086
#endif
Packit dd8086
Packit dd8086
#ifdef HAVE_SYS_STAT_H
Packit dd8086
# include <sys/stat.h>
Packit dd8086
#endif
Packit dd8086
Packit dd8086
#include <cdio/iso9660.h>
Packit dd8086
#include <cdio/logging.h>
Packit dd8086
#include <cdio/bytesex.h>
Packit dd8086
#include "filemode.h"
Packit dd8086
Packit dd8086
#define CDIO_MKDEV(ma,mi)	((ma)<<16 | (mi))
Packit dd8086
Packit dd8086
enum iso_rock_enums iso_rock_enums;
Packit dd8086
iso_rock_nm_flag_t iso_rock_nm_flag;
Packit dd8086
iso_rock_sl_flag_t iso_rock_sl_flag;
Packit dd8086
iso_rock_tf_flag_t iso_rock_tf_flag;
Packit dd8086
Packit dd8086
/* Our own realloc routine tailored for the iso9660_stat_t symlink
Packit dd8086
   field.  I can't figure out how to make realloc() work without
Packit dd8086
   valgrind complaint.
Packit dd8086
*/
Packit dd8086
static bool
Packit dd8086
realloc_symlink(/*in/out*/ iso9660_stat_t *p_stat, uint8_t i_grow)
Packit dd8086
{
Packit dd8086
  if (!p_stat->rr.i_symlink) {
Packit dd8086
    const uint16_t i_max = 2*i_grow+1;
Packit dd8086
    p_stat->rr.psz_symlink = (char *) calloc(1, i_max);
Packit dd8086
    p_stat->rr.i_symlink_max = i_max;
Packit dd8086
    return (NULL != p_stat->rr.psz_symlink);
Packit dd8086
  } else {
Packit dd8086
    unsigned int i_needed = p_stat->rr.i_symlink + i_grow ;
Packit dd8086
    if ( i_needed <= p_stat->rr.i_symlink_max)
Packit dd8086
      return true;
Packit dd8086
    else {
Packit dd8086
      char * psz_newsymlink = (char *) calloc(1, 2*i_needed);
Packit dd8086
      if (!psz_newsymlink) return false;
Packit dd8086
      p_stat->rr.i_symlink_max = 2*i_needed;
Packit dd8086
      memcpy(psz_newsymlink, p_stat->rr.psz_symlink, p_stat->rr.i_symlink);
Packit dd8086
      free(p_stat->rr.psz_symlink);
Packit dd8086
      p_stat->rr.psz_symlink = psz_newsymlink;
Packit dd8086
      return true;
Packit dd8086
    }
Packit dd8086
  }
Packit dd8086
}
Packit dd8086
Packit dd8086
/* These functions are designed to read the system areas of a directory record
Packit dd8086
 * and extract relevant information.  There are different functions provided
Packit dd8086
 * depending upon what information we need at the time.  One function fills
Packit dd8086
 * out an inode structure, a second one extracts a filename, a third one
Packit dd8086
 * returns a symbolic link name, and a fourth one returns the extent number
Packit dd8086
 * for the file. */
Packit dd8086
Packit dd8086
#define SIG(A,B) ((A) | ((B) << 8)) /* isonum_721() */
Packit dd8086
Packit dd8086
Packit dd8086
/* This is a way of ensuring that we have something in the system
Packit dd8086
   use fields that is compatible with Rock Ridge */
Packit dd8086
#define CHECK_SP(FAIL)	       			\
Packit dd8086
      if(rr->u.SP.magic[0] != 0xbe) FAIL;	\
Packit dd8086
      if(rr->u.SP.magic[1] != 0xef) FAIL;       \
Packit dd8086
      p_stat->rr.s_rock_offset = rr->u.SP.skip;
Packit dd8086
/* We define a series of macros because each function must do exactly the
Packit dd8086
   same thing in certain places.  We use the macros to ensure that everything
Packit dd8086
   is done correctly */
Packit dd8086
Packit dd8086
#define CONTINUE_DECLS \
Packit dd8086
  int cont_extent = 0, cont_offset = 0, cont_size = 0;   \
Packit dd8086
  void *buffer = NULL
Packit dd8086
Packit dd8086
#define CHECK_CE				 \
Packit dd8086
  { cont_extent = from_733(*rr->u.CE.extent);	 \
Packit dd8086
    cont_offset = from_733(*rr->u.CE.offset);	 \
Packit dd8086
    cont_size = from_733(*rr->u.CE.size);	 \
Packit dd8086
    (void)cont_extent; (void)cont_offset, (void)cont_size; }
Packit dd8086
Packit dd8086
#define SETUP_ROCK_RIDGE(DE,CHR,LEN)	      		      	\
Packit dd8086
  {								\
Packit dd8086
    LEN= sizeof(iso9660_dir_t) + DE->filename.len;		\
Packit dd8086
    if(LEN & 1) LEN++;						\
Packit dd8086
    CHR = ((unsigned char *) DE) + LEN;				\
Packit dd8086
    LEN = *((unsigned char *) DE) - LEN;			\
Packit dd8086
    if (0xff != p_stat->rr.s_rock_offset)			\
Packit dd8086
      {								\
Packit dd8086
	LEN -= p_stat->rr.s_rock_offset;		       	\
Packit dd8086
	CHR += p_stat->rr.s_rock_offset;		       	\
Packit dd8086
	if (LEN<0) LEN=0;					\
Packit dd8086
      }								\
Packit dd8086
  }
Packit dd8086
Packit dd8086
/* Copy a long or short time from the iso_rock_tf_t into
Packit dd8086
   the specified field of a iso_rock_statbuf_t.
Packit dd8086
   non-paramater variables are p_stat, rr, and cnt.
Packit dd8086
*/
Packit dd8086
#define add_time(FLAG, TIME_FIELD)				  \
Packit dd8086
  if (rr->u.TF.flags & FLAG) {					  \
Packit dd8086
    p_stat->rr.TIME_FIELD.b_used = true;			  \
Packit dd8086
    p_stat->rr.TIME_FIELD.b_longdate =				  \
Packit dd8086
      (0 != (rr->u.TF.flags & ISO_ROCK_TF_LONG_FORM));		  \
Packit dd8086
    if (p_stat->rr.TIME_FIELD.b_longdate) {			  \
Packit dd8086
      memcpy(&(p_stat->rr.TIME_FIELD.t.ltime),			  \
Packit dd8086
	     &(rr->u.TF.time_bytes[cnt]),			  \
Packit dd8086
	     sizeof(iso9660_ltime_t)); 				  \
Packit dd8086
      cnt += sizeof(iso9660_ltime_t);				  \
Packit dd8086
    } else {							  \
Packit dd8086
      memcpy(&(p_stat->rr.TIME_FIELD.t.dtime),			  \
Packit dd8086
	     &(rr->u.TF.time_bytes[cnt]),			  \
Packit dd8086
	     sizeof(iso9660_dtime_t)); 				  \
Packit dd8086
      cnt += sizeof(iso9660_dtime_t);				  \
Packit dd8086
    }								  \
Packit dd8086
  }
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Get
Packit dd8086
  @return length of name field; 0: not found, -1: to be ignored
Packit dd8086
*/
Packit dd8086
int
Packit dd8086
get_rock_ridge_filename(iso9660_dir_t * p_iso9660_dir,
Packit dd8086
			/*out*/ char * psz_name,
Packit dd8086
			/*in/out*/ iso9660_stat_t *p_stat)
Packit dd8086
{
Packit dd8086
  int len;
Packit dd8086
  unsigned char *chr;
Packit dd8086
  int symlink_len = 0;
Packit dd8086
  CONTINUE_DECLS;
Packit dd8086
  int i_namelen = 0;
Packit dd8086
  int truncate=0;
Packit dd8086
Packit dd8086
  if (!p_stat || nope == p_stat->rr.b3_rock) return 0;
Packit dd8086
  *psz_name = 0;
Packit dd8086
Packit dd8086
  SETUP_ROCK_RIDGE(p_iso9660_dir, chr, len);
Packit dd8086
  /*repeat:*/
Packit dd8086
  {
Packit dd8086
    iso_extension_record_t * rr;
Packit dd8086
    int sig;
Packit dd8086
    int rootflag;
Packit dd8086
Packit dd8086
    while (len > 1){ /* There may be one byte for padding somewhere */
Packit dd8086
      rr = (iso_extension_record_t *) chr;
Packit dd8086
      sig = *chr+(*(chr+1) << 8);
Packit dd8086
Packit dd8086
      /* We used to check for some vaid values of SIG, specifically
Packit dd8086
	 SP, CE, ER, RR, PX, PN, SL, NM, CL, PL, TF, and ZF.
Packit dd8086
	 However there are various extensions to this set. So we
Packit dd8086
	 skip checking now.
Packit dd8086
      */
Packit dd8086
Packit dd8086
      if (rr->len == 0) goto out; /* Something got screwed up here */
Packit dd8086
      chr += rr->len;
Packit dd8086
      len -= rr->len;
Packit dd8086
Packit dd8086
      switch(sig){
Packit dd8086
      case SIG('S','P'):
Packit dd8086
	CHECK_SP(goto out);
Packit dd8086
	break;
Packit dd8086
      case SIG('C','E'):
Packit dd8086
	{
Packit dd8086
	  iso711_t i_fname = from_711(p_iso9660_dir->filename.len);
Packit dd8086
	  if ('\0' == p_iso9660_dir->filename.str[1] && 1 == i_fname)
Packit dd8086
	    break;
Packit dd8086
	  if ('\1' == p_iso9660_dir->filename.str[1] && 1 == i_fname)
Packit dd8086
	    break;
Packit dd8086
	}
Packit dd8086
	CHECK_CE;
Packit dd8086
	break;
Packit dd8086
      case SIG('E','R'):
Packit dd8086
	p_stat->rr.b3_rock = yep;
Packit dd8086
	cdio_debug("ISO 9660 Extensions: ");
Packit dd8086
	{
Packit dd8086
	  int p;
Packit dd8086
	  for(p=0;p<rr->u.ER.len_id;p++) cdio_debug("%c",rr->u.ER.data[p]);
Packit dd8086
	}
Packit dd8086
	break;
Packit dd8086
      case SIG('N','M'):
Packit dd8086
	/* Alternate name */
Packit dd8086
	p_stat->rr.b3_rock = yep;
Packit dd8086
	if (truncate) break;
Packit dd8086
	if (rr->u.NM.flags & ISO_ROCK_NM_PARENT) {
Packit dd8086
	  i_namelen = sizeof("..");
Packit dd8086
	  strncat(psz_name, "..", i_namelen);
Packit dd8086
	  break;
Packit dd8086
	} else if (rr->u.NM.flags & ISO_ROCK_NM_CURRENT) {
Packit dd8086
	  i_namelen = sizeof(".");
Packit dd8086
	  strncat(psz_name, ".", i_namelen);
Packit dd8086
	  break;
Packit dd8086
	}
Packit dd8086
Packit dd8086
	if (rr->u.NM.flags & ~1) {
Packit dd8086
	  cdio_info("Unsupported NM flag settings (%d)",rr->u.NM.flags);
Packit dd8086
	  break;
Packit dd8086
	}
Packit dd8086
	if((strlen(psz_name) + rr->len - 5) >= 254) {
Packit dd8086
	  truncate = 1;
Packit dd8086
	  break;
Packit dd8086
	}
Packit dd8086
	strncat(psz_name, rr->u.NM.name, rr->len - 5);
Packit dd8086
	i_namelen += rr->len - 5;
Packit dd8086
	break;
Packit dd8086
      case SIG('P','X'):
Packit dd8086
	/* POSIX file attributes */
Packit dd8086
	p_stat->rr.st_mode   = from_733(rr->u.PX.st_mode);
Packit dd8086
	p_stat->rr.st_nlinks = from_733(rr->u.PX.st_nlinks);
Packit dd8086
	p_stat->rr.st_uid    = from_733(rr->u.PX.st_uid);
Packit dd8086
	p_stat->rr.st_gid    = from_733(rr->u.PX.st_gid);
Packit dd8086
	p_stat->rr.b3_rock    = yep;
Packit dd8086
	break;
Packit dd8086
      case SIG('S','L'):
Packit dd8086
	{
Packit dd8086
	  /* Symbolic link */
Packit dd8086
	  uint8_t slen;
Packit dd8086
	  iso_rock_sl_part_t * p_sl;
Packit dd8086
	  iso_rock_sl_part_t * p_oldsl;
Packit dd8086
	  slen = rr->len - 5;
Packit dd8086
	  p_sl = &rr->u.SL.link;
Packit dd8086
	  p_stat->rr.i_symlink = symlink_len;
Packit dd8086
	  while (slen > 1){
Packit dd8086
	    rootflag = 0;
Packit dd8086
	    switch(p_sl->flags &~1){
Packit dd8086
	    case 0:
Packit dd8086
	      realloc_symlink(p_stat, p_sl->len);
Packit dd8086
	      memcpy(&(p_stat->rr.psz_symlink[p_stat->rr.i_symlink]),
Packit dd8086
		     p_sl->text, p_sl->len);
Packit dd8086
	      p_stat->rr.i_symlink += p_sl->len;
Packit dd8086
	      break;
Packit dd8086
	    case 4:
Packit dd8086
	      realloc_symlink(p_stat, 1);
Packit dd8086
	      p_stat->rr.psz_symlink[p_stat->rr.i_symlink++] = '.';
Packit dd8086
	      /* continue into next case. */
Packit dd8086
	    case 2:
Packit dd8086
	      realloc_symlink(p_stat, 1);
Packit dd8086
	      p_stat->rr.psz_symlink[p_stat->rr.i_symlink++] = '.';
Packit dd8086
	      break;
Packit dd8086
	    case 8:
Packit dd8086
	      rootflag = 1;
Packit dd8086
	      realloc_symlink(p_stat, 1);
Packit dd8086
	      p_stat->rr.psz_symlink[p_stat->rr.i_symlink++] = '/';
Packit dd8086
	      break;
Packit dd8086
	    default:
Packit dd8086
	      cdio_warn("Symlink component flag not implemented");
Packit dd8086
	    }
Packit dd8086
	    slen -= p_sl->len + 2;
Packit dd8086
	    p_oldsl = p_sl;
Packit dd8086
	    p_sl = (iso_rock_sl_part_t *) (((char *) p_sl) + p_sl->len + 2);
Packit dd8086
Packit dd8086
	    if (slen < 2) {
Packit dd8086
	      if (((rr->u.SL.flags & 1) != 0) && ((p_oldsl->flags & 1) == 0))
Packit dd8086
		p_stat->rr.i_symlink += 1;
Packit dd8086
	      break;
Packit dd8086
	    }
Packit dd8086
Packit dd8086
	    /*
Packit dd8086
	     * If this component record isn't continued, then append a '/'.
Packit dd8086
	     */
Packit dd8086
	    if (!rootflag && (p_oldsl->flags & 1) == 0) {
Packit dd8086
	      realloc_symlink(p_stat, 1);
Packit dd8086
	      p_stat->rr.psz_symlink[p_stat->rr.i_symlink++] = '/';
Packit dd8086
	    }
Packit dd8086
	  }
Packit dd8086
	}
Packit dd8086
	symlink_len = p_stat->rr.i_symlink;
Packit dd8086
	realloc_symlink(p_stat, 1);
Packit dd8086
	p_stat->rr.psz_symlink[symlink_len]='\0';
Packit dd8086
	break;
Packit dd8086
      case SIG('R','E'):
Packit dd8086
	free(buffer);
Packit dd8086
	return -1;
Packit dd8086
      case SIG('T','F'):
Packit dd8086
	/* Time stamp(s) for a file */
Packit dd8086
	{
Packit dd8086
	  int cnt = 0;
Packit dd8086
	  add_time(ISO_ROCK_TF_CREATE,     create);
Packit dd8086
	  add_time(ISO_ROCK_TF_MODIFY,     modify);
Packit dd8086
	  add_time(ISO_ROCK_TF_ACCESS,     access);
Packit dd8086
	  add_time(ISO_ROCK_TF_ATTRIBUTES, attributes);
Packit dd8086
	  add_time(ISO_ROCK_TF_BACKUP,     backup);
Packit dd8086
	  add_time(ISO_ROCK_TF_EXPIRATION, expiration);
Packit dd8086
	  add_time(ISO_ROCK_TF_EFFECTIVE,  effective);
Packit dd8086
	  p_stat->rr.b3_rock = yep;
Packit dd8086
	  break;
Packit dd8086
	}
Packit dd8086
      default:
Packit dd8086
	break;
Packit dd8086
      }
Packit dd8086
    }
Packit dd8086
  }
Packit dd8086
  free(buffer);
Packit dd8086
  return i_namelen; /* If 0, this file did not have a NM field */
Packit dd8086
 out:
Packit dd8086
  free(buffer);
Packit dd8086
  return 0;
Packit dd8086
}
Packit dd8086
Packit dd8086
static int
Packit dd8086
parse_rock_ridge_stat_internal(iso9660_dir_t *p_iso9660_dir,
Packit dd8086
			       iso9660_stat_t *p_stat, int regard_xa)
Packit dd8086
{
Packit dd8086
  int len;
Packit dd8086
  unsigned char * chr;
Packit dd8086
  int symlink_len = 0;
Packit dd8086
  CONTINUE_DECLS;
Packit dd8086
Packit dd8086
  if (nope == p_stat->rr.b3_rock) return 0;
Packit dd8086
Packit dd8086
  SETUP_ROCK_RIDGE(p_iso9660_dir, chr, len);
Packit dd8086
  if (regard_xa)
Packit dd8086
    {
Packit dd8086
      chr+=14;
Packit dd8086
      len-=14;
Packit dd8086
      if (len<0) len=0;
Packit dd8086
    }
Packit dd8086
Packit dd8086
  /* repeat:*/
Packit dd8086
  {
Packit dd8086
    int sig;
Packit dd8086
    iso_extension_record_t * rr;
Packit dd8086
    int rootflag;
Packit dd8086
Packit dd8086
    while (len > 1){ /* There may be one byte for padding somewhere */
Packit dd8086
      rr = (iso_extension_record_t *) chr;
Packit dd8086
      if (rr->len == 0) goto out; /* Something got screwed up here */
Packit dd8086
      sig = from_721(*chr);
Packit dd8086
      chr += rr->len;
Packit dd8086
      len -= rr->len;
Packit dd8086
Packit dd8086
      switch(sig){
Packit dd8086
      case SIG('S','P'):
Packit dd8086
	CHECK_SP(goto out);
Packit dd8086
	break;
Packit dd8086
      case SIG('C','E'):
Packit dd8086
	CHECK_CE;
Packit dd8086
	break;
Packit dd8086
      case SIG('E','R'):
Packit dd8086
	p_stat->rr.b3_rock = yep;
Packit dd8086
	cdio_debug("ISO 9660 Extensions: ");
Packit dd8086
	{ int p;
Packit dd8086
	  for(p=0;p<rr->u.ER.len_id;p++) cdio_debug("%c",rr->u.ER.data[p]);
Packit dd8086
	}
Packit dd8086
	break;
Packit dd8086
      case SIG('P','X'):
Packit dd8086
	p_stat->rr.st_mode   = from_733(rr->u.PX.st_mode);
Packit dd8086
	p_stat->rr.st_nlinks = from_733(rr->u.PX.st_nlinks);
Packit dd8086
	p_stat->rr.st_uid    = from_733(rr->u.PX.st_uid);
Packit dd8086
	p_stat->rr.st_gid    = from_733(rr->u.PX.st_gid);
Packit dd8086
	break;
Packit dd8086
      case SIG('P','N'):
Packit dd8086
	/* Device major,minor number */
Packit dd8086
	{ int32_t high, low;
Packit dd8086
	  high = from_733(rr->u.PN.dev_high);
Packit dd8086
	  low = from_733(rr->u.PN.dev_low);
Packit dd8086
	  /*
Packit dd8086
	   * The Rock Ridge standard specifies that if sizeof(dev_t) <= 4,
Packit dd8086
	   * then the high field is unused, and the device number is completely
Packit dd8086
	   * stored in the low field.  Some writers may ignore this subtlety,
Packit dd8086
	   * and as a result we test to see if the entire device number is
Packit dd8086
	   * stored in the low field, and use that.
Packit dd8086
	   */
Packit dd8086
	  if((low & ~0xff) && high == 0) {
Packit dd8086
	    p_stat->rr.i_rdev = CDIO_MKDEV(low >> 8, low & 0xff);
Packit dd8086
	  } else {
Packit dd8086
	    p_stat->rr.i_rdev = CDIO_MKDEV(high, low);
Packit dd8086
	  }
Packit dd8086
	}
Packit dd8086
	break;
Packit dd8086
      case SIG('T','F'):
Packit dd8086
	/* Time stamp(s) for a file */
Packit dd8086
	{
Packit dd8086
	  int cnt = 0;
Packit dd8086
	  add_time(ISO_ROCK_TF_CREATE,     create);
Packit dd8086
	  add_time(ISO_ROCK_TF_MODIFY,     modify);
Packit dd8086
	  add_time(ISO_ROCK_TF_ACCESS,     access);
Packit dd8086
	  add_time(ISO_ROCK_TF_ATTRIBUTES, attributes);
Packit dd8086
	  add_time(ISO_ROCK_TF_BACKUP,     backup);
Packit dd8086
	  add_time(ISO_ROCK_TF_EXPIRATION, expiration);
Packit dd8086
	  add_time(ISO_ROCK_TF_EFFECTIVE,  effective);
Packit dd8086
	  p_stat->rr.b3_rock = yep;
Packit dd8086
	  break;
Packit dd8086
	}
Packit dd8086
      case SIG('S','L'):
Packit dd8086
	{
Packit dd8086
	  /* Symbolic link */
Packit dd8086
	  uint8_t slen;
Packit dd8086
	  iso_rock_sl_part_t * p_sl;
Packit dd8086
	  iso_rock_sl_part_t * p_oldsl;
Packit dd8086
	  slen = rr->len - 5;
Packit dd8086
	  p_sl = &rr->u.SL.link;
Packit dd8086
	  p_stat->rr.i_symlink = symlink_len;
Packit dd8086
	  while (slen > 1){
Packit dd8086
	    rootflag = 0;
Packit dd8086
	    switch(p_sl->flags &~1){
Packit dd8086
	    case 0:
Packit dd8086
	      realloc_symlink(p_stat, p_sl->len);
Packit dd8086
	      if (p_sl->text && p_sl->len)
Packit dd8086
		memcpy(&(p_stat->rr.psz_symlink[p_stat->rr.i_symlink]),
Packit dd8086
		       p_sl->text, p_sl->len);
Packit dd8086
	      p_stat->rr.i_symlink += p_sl->len;
Packit dd8086
	      break;
Packit dd8086
	    case 4:
Packit dd8086
	      realloc_symlink(p_stat, 1);
Packit dd8086
	      p_stat->rr.psz_symlink[p_stat->rr.i_symlink++] = '.';
Packit dd8086
	      /* continue into next case. */
Packit dd8086
	    case 2:
Packit dd8086
	      realloc_symlink(p_stat, 1);
Packit dd8086
	      p_stat->rr.psz_symlink[p_stat->rr.i_symlink++] = '.';
Packit dd8086
	      break;
Packit dd8086
	    case 8:
Packit dd8086
	      rootflag = 1;
Packit dd8086
	      realloc_symlink(p_stat, 1);
Packit dd8086
	      p_stat->rr.psz_symlink[p_stat->rr.i_symlink++] = '/';
Packit dd8086
	      p_stat->rr.i_symlink++;
Packit dd8086
	      break;
Packit dd8086
	    default:
Packit dd8086
	      cdio_warn("Symlink component flag not implemented");
Packit dd8086
	    }
Packit dd8086
	    slen -= p_sl->len + 2;
Packit dd8086
	    p_oldsl = p_sl;
Packit dd8086
	    p_sl = (iso_rock_sl_part_t *) (((char *) p_sl) + p_sl->len + 2);
Packit dd8086
Packit dd8086
	    if (slen < 2) {
Packit dd8086
	      if (((rr->u.SL.flags & 1) != 0) && ((p_oldsl->flags & 1) == 0))
Packit dd8086
		p_stat->rr.i_symlink += 1;
Packit dd8086
	      break;
Packit dd8086
	    }
Packit dd8086
Packit dd8086
	    /*
Packit dd8086
	     * If this component record isn't continued, then append a '/'.
Packit dd8086
	     */
Packit dd8086
	    if (!rootflag && (p_oldsl->flags & 1) == 0) {
Packit dd8086
	      realloc_symlink(p_stat, 1);
Packit dd8086
	      p_stat->rr.psz_symlink[p_stat->rr.i_symlink++] = '/';
Packit dd8086
	    }
Packit dd8086
	  }
Packit dd8086
	}
Packit dd8086
	symlink_len = p_stat->rr.i_symlink;
Packit dd8086
	realloc_symlink(p_stat, 1);
Packit dd8086
	p_stat->rr.psz_symlink[symlink_len]='\0';
Packit dd8086
	break;
Packit dd8086
      case SIG('R','E'):
Packit dd8086
	cdio_warn("Attempt to read p_stat for relocated directory");
Packit dd8086
	goto out;
Packit dd8086
#ifdef FINISHED
Packit dd8086
      case SIG('C','L'):
Packit dd8086
	{
Packit dd8086
	  iso9660_stat_t * reloc;
Packit dd8086
	  ISOFS_I(p_stat)->i_first_extent = from_733(rr->u.CL.location);
Packit dd8086
	  reloc = isofs_iget(p_stat->rr.i_sb, p_stat->rr.i_first_extent, 0);
Packit dd8086
	  if (!reloc)
Packit dd8086
	    goto out;
Packit dd8086
	  p_stat->rr.st_mode   = reloc->st_mode;
Packit dd8086
	  p_stat->rr.st_nlinks = reloc->st_nlinks;
Packit dd8086
	  p_stat->rr.st_uid    = reloc->st_uid;
Packit dd8086
	  p_stat->rr.st_gid    = reloc->st_gid;
Packit dd8086
	  p_stat->rr.i_rdev    = reloc->i_rdev;
Packit dd8086
	  p_stat->rr.i_symlink = reloc->i_symlink;
Packit dd8086
	  p_stat->rr.i_blocks  = reloc->i_blocks;
Packit dd8086
	  p_stat->rr.i_atime   = reloc->i_atime;
Packit dd8086
	  p_stat->rr.i_ctime   = reloc->i_ctime;
Packit dd8086
	  p_stat->rr.i_mtime   = reloc->i_mtime;
Packit dd8086
	  iput(reloc);
Packit dd8086
	}
Packit dd8086
	break;
Packit dd8086
#endif
Packit dd8086
      default:
Packit dd8086
	break;
Packit dd8086
      }
Packit dd8086
    }
Packit dd8086
  }
Packit dd8086
 out:
Packit dd8086
  free(buffer);
Packit dd8086
  return 0;
Packit dd8086
}
Packit dd8086
Packit dd8086
int
Packit dd8086
parse_rock_ridge_stat(iso9660_dir_t *p_iso9660_dir,
Packit dd8086
		      /*out*/ iso9660_stat_t *p_stat)
Packit dd8086
{
Packit dd8086
  int result;
Packit dd8086
Packit dd8086
  if (!p_stat) return 0;
Packit dd8086
Packit dd8086
  result = parse_rock_ridge_stat_internal(p_iso9660_dir, p_stat, 0);
Packit dd8086
  /* if Rock-Ridge flag was reset and we didn't look for attributes
Packit dd8086
   * behind eventual XA attributes, have a look there */
Packit dd8086
  if (0xFF == p_stat->rr.s_rock_offset && nope != p_stat->rr.b3_rock) {
Packit dd8086
    result = parse_rock_ridge_stat_internal(p_iso9660_dir, p_stat, 14);
Packit dd8086
  }
Packit dd8086
  return result;
Packit dd8086
}
Packit dd8086
Packit dd8086
#define BUF_COUNT 16
Packit dd8086
#define BUF_SIZE sizeof("drwxrwxrwx")
Packit dd8086
Packit dd8086
/* Return a pointer to a internal free buffer */
Packit dd8086
static char *
Packit dd8086
_getbuf (void)
Packit dd8086
{
Packit dd8086
  static char _buf[BUF_COUNT][BUF_SIZE];
Packit dd8086
  static int _i = -1;
Packit dd8086
Packit dd8086
  _i++;
Packit dd8086
  _i %= BUF_COUNT;
Packit dd8086
Packit dd8086
  memset (_buf[_i], 0, BUF_SIZE);
Packit dd8086
Packit dd8086
  return _buf[_i];
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Returns a string which interpreting the POSIX mode st_mode.
Packit dd8086
  For example:
Packit dd8086
  \verbatim
Packit dd8086
  drwxrws---
Packit dd8086
  -rw-rw-r--
Packit dd8086
  lrwxrwxrwx
Packit dd8086
  \endverbatim
Packit dd8086
Packit dd8086
  A description of the characters in the string follows
Packit dd8086
  The 1st character is either "b" for a block device,
Packit dd8086
  "c" for a character device, "d" if the entry is a directory, "l" for
Packit dd8086
  a symbolic link, "p" for a pipe or FIFO, "s" for a "socket",
Packit dd8086
  or "-" if none of the these.
Packit dd8086
Packit dd8086
  The 2nd to 4th characters refer to permissions for a user while the
Packit dd8086
  the 5th to 7th characters refer to permissions for a group while, and
Packit dd8086
  the 8th to 10h characters refer to permissions for everyone.
Packit dd8086
Packit dd8086
  In each of these triplets the first character (2, 5, 8) is "r" if
Packit dd8086
  the entry is allowed to be read.
Packit dd8086
Packit dd8086
  The second character of a triplet (3, 6, 9) is "w" if the entry is
Packit dd8086
  allowed to be written.
Packit dd8086
Packit dd8086
  The third character of a triplet (4, 7, 10) is "x" if the entry is
Packit dd8086
  executable but not user (for character 4) or group (for characters
Packit dd8086
  6) settable and "s" if the item has the corresponding user/group set.
Packit dd8086
Packit dd8086
  For a directory having an executable property on ("x" or "s") means
Packit dd8086
  the directory is allowed to be listed or "searched". If the execute
Packit dd8086
  property is not allowed for a group or user but the corresponding
Packit dd8086
  group/user is set "S" indicates this. If none of these properties
Packit dd8086
  holds the "-" indicates this.
Packit dd8086
*/
Packit dd8086
const char *
Packit dd8086
iso9660_get_rock_attr_str(posix_mode_t st_mode)
Packit dd8086
{
Packit dd8086
  char *result = _getbuf();
Packit dd8086
Packit dd8086
  if (S_ISBLK(st_mode))
Packit dd8086
    result[ 0] = 'b';
Packit dd8086
  else if (S_ISDIR(st_mode))
Packit dd8086
    result[ 0] = 'd';
Packit dd8086
  else if (S_ISCHR(st_mode))
Packit dd8086
    result[ 0] = 'c';
Packit dd8086
  else if (S_ISLNK(st_mode))
Packit dd8086
    result[ 0] = 'l';
Packit dd8086
  else if (S_ISFIFO(st_mode))
Packit dd8086
    result[ 0] = 'p';
Packit dd8086
  else if (S_ISSOCK(st_mode))
Packit dd8086
    result[ 0] = 's';
Packit dd8086
  /* May eventually fill in others.. */
Packit dd8086
  else
Packit dd8086
    result[ 0] = '-';
Packit dd8086
Packit dd8086
  result[ 1] = (st_mode & ISO_ROCK_IRUSR) ? 'r' : '-';
Packit dd8086
  result[ 2] = (st_mode & ISO_ROCK_IWUSR) ? 'w' : '-';
Packit dd8086
Packit dd8086
  if (st_mode & ISO_ROCK_ISUID)
Packit dd8086
    result[ 3] = (st_mode & ISO_ROCK_IXUSR) ? 's' : 'S';
Packit dd8086
  else
Packit dd8086
    result[ 3] = (st_mode & ISO_ROCK_IXUSR) ? 'x' : '-';
Packit dd8086
Packit dd8086
  result[ 4] = (st_mode & ISO_ROCK_IRGRP) ? 'r' : '-';
Packit dd8086
  result[ 5] = (st_mode & ISO_ROCK_IWGRP) ? 'w' : '-';
Packit dd8086
Packit dd8086
  if (st_mode & ISO_ROCK_ISGID)
Packit dd8086
    result[ 6] = (st_mode & ISO_ROCK_IXGRP) ? 's' : 'S';
Packit dd8086
  else
Packit dd8086
    result[ 6] = (st_mode & ISO_ROCK_IXGRP) ? 'x' : '-';
Packit dd8086
Packit dd8086
  result[ 7] = (st_mode & ISO_ROCK_IROTH) ? 'r' : '-';
Packit dd8086
  result[ 8] = (st_mode & ISO_ROCK_IWOTH) ? 'w' : '-';
Packit dd8086
  result[ 9] = (st_mode & ISO_ROCK_IXOTH) ? 'x' : '-';
Packit dd8086
Packit dd8086
  result[11] = '\0';
Packit dd8086
Packit dd8086
  return result;
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Returns POSIX mode bitstring for a given file.
Packit dd8086
*/
Packit dd8086
mode_t
Packit dd8086
iso9660_get_posix_filemode_from_rock(const iso_rock_statbuf_t *rr)
Packit dd8086
{
Packit dd8086
  return (mode_t) rr->st_mode;
Packit dd8086
}