Merge in more Rock Ridge code. Not working yet. Hopefully not much

breakage. (But there may be some especially on less-POSIX OS's.)
This commit is contained in:
rocky
2005-02-13 22:03:00 +00:00
parent 1a2e7f3da8
commit 2f11a30fb3
5 changed files with 451 additions and 43 deletions

View File

@@ -1,5 +1,5 @@
/* /*
$Id: iso9660.h,v 1.64 2005/02/13 00:20:05 rocky Exp $ $Id: iso9660.h,v 1.65 2005/02/13 22:03:00 rocky Exp $
Copyright (C) 2000 Herbert Valerio Riedel <hvr@gnu.org> Copyright (C) 2000 Herbert Valerio Riedel <hvr@gnu.org>
Copyright (C) 2003, 2004, 2005 Rocky Bernstein <rocky@panix.com> Copyright (C) 2003, 2004, 2005 Rocky Bernstein <rocky@panix.com>
@@ -255,6 +255,8 @@ struct iso9660_ltime_s {
} GNUC_PACKED; } GNUC_PACKED;
typedef struct iso9660_ltime_s iso9660_ltime_t; typedef struct iso9660_ltime_s iso9660_ltime_t;
typedef struct iso9660_dir_s iso9660_dir_t;
typedef struct iso9660_stat_s iso9660_stat_t;
#include <cdio/rock.h> #include <cdio/rock.h>
@@ -302,8 +304,6 @@ struct iso9660_dir_s {
char filename[EMPTY_ARRAY_SIZE]; char filename[EMPTY_ARRAY_SIZE];
} GNUC_PACKED; } GNUC_PACKED;
typedef struct iso9660_dir_s iso9660_dir_t;
/*! /*!
\brief ISO-9660 Primary Volume Descriptor. \brief ISO-9660 Primary Volume Descriptor.
*/ */
@@ -521,6 +521,23 @@ PRAGMA_END_PACKED
@see iso9660_dir @see iso9660_dir
*/ */
struct iso9660_stat_s { /* big endian!! */ struct iso9660_stat_s { /* big endian!! */
bool b_rock; /**< has Rock Ridge extension.
If not true then the next 7 feilds
aren't used.
*/
mode_t st_mode; /**< protection */
nlink_t st_nlinks; /**< number of hard links */
uid_t st_uid; /**< user ID of owner */
gid_t st_gid; /**< group ID of owner */
uint8_t s_rock_offset;
int i_size;
#if 0
time_t st_atime; /**< time of last access */
time_t st_mtime; /**< time of last modification */
time_t st_ctime; /**< time of last change */
#endif
/* Non Ridge-specific fields */
struct tm tm; /**< time on entry */ struct tm tm; /**< time on entry */
lsn_t lsn; /**< start logical sector number */ lsn_t lsn; /**< start logical sector number */
uint32_t size; /**< total size in bytes */ uint32_t size; /**< total size in bytes */
@@ -530,9 +547,6 @@ struct iso9660_stat_s { /* big endian!! */
char filename[EMPTY_ARRAY_SIZE]; /**< filename */ char filename[EMPTY_ARRAY_SIZE]; /**< filename */
}; };
typedef struct iso9660_stat_s iso9660_stat_t;
/** A mask used in iso9660_ifs_read_vd which allows what kinds /** A mask used in iso9660_ifs_read_vd which allows what kinds
of extensions we allow, eg. Joliet, Rock Ridge, etc. */ of extensions we allow, eg. Joliet, Rock Ridge, etc. */
typedef uint8_t iso_extension_mask_t; typedef uint8_t iso_extension_mask_t;

View File

@@ -1,12 +1,10 @@
/* /*
$Id: rock.h,v 1.1 2005/02/13 00:20:05 rocky Exp $ $Id: rock.h,v 1.2 2005/02/13 22:03:00 rocky Exp $
Copyright (C) 2005 Rocky Bernstein <rocky@panix.com> Copyright (C) 2005 Rocky Bernstein <rocky@panix.com>
See also rock.c by Eric Youngdale (1993) from GNU/Linux and in cdrtools. See also rock.c by Eric Youngdale (1993) from GNU/Linux
This is This is Copyright 1993 Yggdrasil Computing, Incorporated
Copyright 1993 Yggdrasil Computing, Incorporated
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or the Free Software Foundation; either version 2 of the License, or
@@ -70,15 +68,41 @@ extern enum cdio_rock_enums {
PRAGMA_BEGIN_PACKED PRAGMA_BEGIN_PACKED
/*! The next two structs are used by the system-use-sharing protocol
(SUSP), in which the Rock Ridge extensions are embedded. It is
quite possible that other extensions are present on the disk, and
this is fine as long as they all use SUSP. */
/*! system-use-sharing protocol */
typedef struct iso_su_sp_s{
unsigned char magic[2];
uint8_t skip;
} GNUC_PACKED iso_su_sp_t;
/*! system-use extension record */
typedef struct iso_su_er_s {
iso711_t len_id; /**< Identifier length. Value 10?. */
unsigned char len_des;
unsigned char len_src;
iso711_t ext_ver; /**< Extension version. Value 1? */
char data[EMPTY_ARRAY_SIZE];
} GNUC_PACKED iso_su_er_t;
typedef struct iso_su_ce_s {
char extent[8];
char offset[8];
char size[8];
} iso_su_ce_t;
/*! POSIX file attributes, PX. See Section 4.1.2 */ /*! POSIX file attributes, PX. See Section 4.1.2 */
typedef struct iso_rock_px_s { typedef struct iso_rock_px_s {
iso733_t st_mode; /*! file mode permissions; same as st_mode iso733_t st_mode; /*! file mode permissions; same as st_mode
of POSIX:5.6.1 */ of POSIX:5.6.1 */
iso733_t st_links; /*! number of links to file; same as st_links iso733_t st_nlinks; /*! number of links to file; same as st_nlinks
of POSIX:5.6.1 */ of POSIX:5.6.1 */
iso733_t st_uid; /*! user id owner of file; same as st_uid iso733_t st_uid; /*! user id owner of file; same as st_uid
of POSIX:5.6.1 */ of POSIX:5.6.1 */
iso733_t gid; /*! group id of file; same as st_gid of iso733_t st_gid; /*! group id of file; same as st_gid of
of POSIX:5.6.1 */ of POSIX:5.6.1 */
} GNUC_PACKED iso_rock_px_t ; } GNUC_PACKED iso_rock_px_t ;
@@ -97,11 +121,29 @@ typedef struct iso_rock_pn_s {
7.2.3 encoded */ 7.2.3 encoded */
} GNUC_PACKED iso_rock_pn_t ; } GNUC_PACKED iso_rock_pn_t ;
/*! Symbolic link. See Section 4.1.3 */ /*! These are the bits and their meanings for flags in the SL structure. */
typedef struct iso_rock_sl_s { typedef enum {
ISO_ROCK_SL_CONTINUE = 1,
ISO_ROCK_SL_CURRENT = 2,
ISO_ROCK_SL_PARENT = 4,
ISO_ROCK_SL_ROOT = 8
} iso_rock_sl_flag_t;
#define ISO_ROCK_SL_CONTINUE 1
#define ISO_ROCK_SL_CURRENT 2
#define ISO_ROCK_SL_PARENT 4
#define ISO_ROCK_SL_ROOT 8
typedef struct iso_rock_sl_part_s {
unsigned char flags; unsigned char flags;
unsigned char len; unsigned char len;
char text[EMPTY_ARRAY_SIZE]; char text[EMPTY_ARRAY_SIZE];
} GNUC_PACKED iso_rock_sl_part_t ;
/*! Symbolic link. See Section 4.1.3 */
typedef struct iso_rock_sl_s {
unsigned char flags;
iso_rock_sl_part_t link;
} GNUC_PACKED iso_rock_sl_t ; } GNUC_PACKED iso_rock_sl_t ;
/*! Alternate name. See Section 4.1.4 */ /*! Alternate name. See Section 4.1.4 */
@@ -120,7 +162,7 @@ typedef struct iso_rock_pl_s {
char location[1]; char location[1];
} GNUC_PACKED iso_rock_pl_t ; } GNUC_PACKED iso_rock_pl_t ;
/* These are the bits and their meanings for flags in the TF structure. */ /*! These are the bits and their meanings for flags in the TF structure. */
typedef enum { typedef enum {
ISO_ROCK_TF_CREATE = 1, ISO_ROCK_TF_CREATE = 1,
ISO_ROCK_TF_MODIFY = 2, ISO_ROCK_TF_MODIFY = 2,
@@ -155,35 +197,38 @@ typedef struct iso_rock_sf_s {
uint8_t table_depth; uint8_t table_depth;
} GNUC_PACKED iso_rock_sf_t ; } GNUC_PACKED iso_rock_sf_t ;
/*! GNU/Linux-specific extension for transparent decompression. */ typedef struct iso_extension_record_s {
typedef struct iso_rock_zf_s {
char algorithm[2];
char parms[2];
char real_size[8];
} GNUC_PACKED iso_rock_zf_t ;
typedef struct iso_rock_ridge_s {
char signature[2]; /**< signature word; either 'SP', 'CE', 'ER', 'RR', char signature[2]; /**< signature word; either 'SP', 'CE', 'ER', 'RR',
'PX', 'PN', 'SL', 'NM', 'CL', 'PL', 'TF', or 'PX', 'PN', 'SL', 'NM', 'CL', 'PL', 'TF', or
'ZF' */ 'ZF' */
iso711_t len; /** length of system-user area - 44 for PX iso711_t len; /**< length of system-user area - 44 for PX
20 for PN, 5+strlen(text) for SL. */ 20 for PN, 5+strlen(text) for SL, 21 for
iso711_t version; /** version number - value 1 */ SF, etc. */
iso711_t version; /**< version number - value 1 */
union{ union{
iso_rock_px_t PX; iso_su_sp_t SP; /**< system-use-sharing protocol - not
iso_rock_pn_t PN; strictly part of Rock Ridge */
iso_rock_sl_t SL; iso_su_er_t ER; /**< system-use extension packet - not
iso_rock_nm_t NM; strictly part of Rock Ridge */
iso_rock_cl_t CL; iso_su_ce_t CE; /**< system-use - strictly part of Rock Ridge */
iso_rock_pl_t PL; iso_rock_px_t PX; /**< Rock Ridge POSIX file attributes */
iso_rock_tf_t TF; iso_rock_pn_t PN; /**< Rock Ridge POSIX device number */
iso_rock_zf_t SF; iso_rock_sl_t SL; /**< Rock Ridge symbolic link */
iso_rock_zf_t ZF; iso_rock_nm_t NM; /**< Rock Ridge alternate name */
iso_rock_cl_t CL; /**< Rock Ridge child link */
iso_rock_pl_t PL; /**< Rock Ridge parent link */
iso_rock_tf_t TF; /**< Rock Ridge timestamp(s) for a file */
} u; } u;
} GNUC_PACKED iso_rock_ridge_t; } GNUC_PACKED iso_extension_record_t;
PRAGMA_END_PACKED PRAGMA_END_PACKED
/*! return length of name field; 0: not found, -1: to be ignored */
int get_rock_ridge_filename(iso9660_dir_t * de, /*out*/ char * retname,
/*out*/ iso9660_stat_t *p_stat);
int parse_rock_ridge_stat(iso9660_dir_t *de, /*out*/ iso9660_stat_t *p_stat);
#endif /* __ISO_ROCK_H__ */ #endif /* __ISO_ROCK_H__ */
/* /*

View File

@@ -1,4 +1,4 @@
# $Id: Makefile.am,v 1.4 2005/01/27 03:26:37 rocky Exp $ # $Id: Makefile.am,v 1.5 2005/02/13 22:03:00 rocky Exp $
# #
# Copyright (C) 2003, 2004, 2005 Rocky Bernstein <rocky@panix.com> # Copyright (C) 2003, 2004, 2005 Rocky Bernstein <rocky@panix.com>
# #
@@ -56,6 +56,7 @@ libiso9660_la_SOURCES = \
iso9660.c \ iso9660.c \
iso9660_private.h \ iso9660_private.h \
iso9660_fs.c \ iso9660_fs.c \
rock.c \
xa.c xa.c
libiso9660_la_LIBADD = @LIBCDIO_LIBS@ libiso9660_la_LIBADD = @LIBCDIO_LIBS@

View File

@@ -1,5 +1,5 @@
/* /*
$Id: iso9660_fs.c,v 1.12 2005/02/12 10:23:18 rocky Exp $ $Id: iso9660_fs.c,v 1.13 2005/02/13 22:03:00 rocky Exp $
Copyright (C) 2001 Herbert Valerio Riedel <hvr@gnu.org> Copyright (C) 2001 Herbert Valerio Riedel <hvr@gnu.org>
Copyright (C) 2003, 2004, 2005 Rocky Bernstein <rocky@panix.com> Copyright (C) 2003, 2004, 2005 Rocky Bernstein <rocky@panix.com>
@@ -18,6 +18,7 @@
along with this program; if not, write to the Free Software along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
/* iso9660 filesystem-based routines */
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
# include "config.h" # include "config.h"
@@ -51,7 +52,7 @@
#include <stdio.h> #include <stdio.h>
static const char _rcsid[] = "$Id: iso9660_fs.c,v 1.12 2005/02/12 10:23:18 rocky Exp $"; static const char _rcsid[] = "$Id: iso9660_fs.c,v 1.13 2005/02/13 22:03:00 rocky Exp $";
/* Implementation of iso9660_t type */ /* Implementation of iso9660_t type */
struct _iso9660_s { struct _iso9660_s {
@@ -517,7 +518,7 @@ bool iso9660_ifs_get_volumeset_id(iso9660_t *p_iso,
return true; return true;
} }
#endif /*HAVE_JOLIET*/ #endif /*HAVE_JOLIET*/
*p_psz_volumeset_id = iso9660_get_volume_id( &(p_iso->pvd) ); *p_psz_volumeset_id = iso9660_get_volumeset_id( &(p_iso->pvd) );
return *p_psz_volumeset_id != NULL && strlen(*p_psz_volumeset_id); return *p_psz_volumeset_id != NULL && strlen(*p_psz_volumeset_id);
} }

347
lib/iso9660/rock.c Normal file
View File

@@ -0,0 +1,347 @@
/*
$Id: rock.c,v 1.1 2005/02/13 22:03:00 rocky Exp $
Copyright (C) 2005 Rocky Bernstein <rocky@panix.com>
Adapted from GNU/Linux fs/isofs/rock.c (C) 1992, 1993 Eric Youngdale
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* Rock Ridge Extensions to iso9660 */
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#ifdef HAVE_STRING_H
# include <string.h>
#endif
#ifdef HAVE_STDLIB_H
# include <stdlib.h>
#endif
#include <cdio/iso9660.h>
#include <cdio/logging.h>
#include <cdio/bytesex.h>
/* These functions are designed to read the system areas of a directory record
* and extract relevant information. There are different functions provided
* depending upon what information we need at the time. One function fills
* out an inode structure, a second one extracts a filename, a third one
* returns a symbolic link name, and a fourth one returns the extent number
* for the file. */
#define SIG(A,B) ((A) | ((B) << 8)) /* isonum_721() */
/* This is a way of ensuring that we have something in the system
use fields that is compatible with Rock Ridge */
#define CHECK_SP(FAIL) \
if(rr->u.SP.magic[0] != 0xbe) FAIL; \
if(rr->u.SP.magic[1] != 0xef) FAIL; \
p_stat->s_rock_offset = rr->u.SP.skip;
/* We define a series of macros because each function must do exactly the
same thing in certain places. We use the macros to ensure that everything
is done correctly */
#define CONTINUE_DECLS \
int cont_extent = 0, cont_offset = 0, cont_size = 0; \
void *buffer = NULL
#define CHECK_CE \
{cont_extent = from_733(*rr->u.CE.extent); \
cont_offset = from_733(*rr->u.CE.offset); \
cont_size = from_733(*rr->u.CE.size);}
#define SETUP_ROCK_RIDGE(DE,CHR,LEN) \
{ \
LEN= sizeof(iso9660_dir_t) + DE->filename_len; \
if(LEN & 1) LEN++; \
CHR = ((unsigned char *) DE) + LEN; \
LEN = *((unsigned char *) DE) - LEN; \
if (0xff != p_stat->s_rock_offset) \
{ \
LEN -= p_stat->s_rock_offset; \
CHR += p_stat->s_rock_offset; \
if (LEN<0) LEN=0; \
} \
}
/*! return length of name field; 0: not found, -1: to be ignored */
int
get_rock_ridge_filename(iso9660_dir_t * de, /*out*/ char * retname,
/*out*/ iso9660_stat_t *p_stat)
{
int len;
unsigned char *chr;
CONTINUE_DECLS;
int retnamlen = 0, truncate=0;
if (!p_stat || !p_stat->b_rock) return 0;
*retname = 0;
SETUP_ROCK_RIDGE(de, chr, len);
/* repeat:*/
{
iso_extension_record_t * rr;
int sig;
while (len > 1){ /* There may be one byte for padding somewhere */
rr = (iso_extension_record_t *) chr;
if (rr->len == 0) goto out; /* Something got screwed up here */
sig = from_721(*chr);
chr += rr->len;
len -= rr->len;
switch(sig){
case SIG('S','P'):
CHECK_SP(goto out);
break;
case SIG('C','E'):
CHECK_CE;
break;
case SIG('N','M'):
if (truncate) break;
/*
* If the flags are 2 or 4, this indicates '.' or '..'.
* We don't want to do anything with this, because it
* screws up the code that calls us. We don't really
* care anyways, since we can just use the non-RR
* name.
*/
if (rr->u.NM.flags & 6) {
break;
}
if (rr->u.NM.flags & ~1) {
cdio_info("Unsupported NM flag settings (%d)",rr->u.NM.flags);
break;
}
if((strlen(retname) + rr->len - 5) >= 254) {
truncate = 1;
break;
}
strncat(retname, rr->u.NM.name, rr->len - 5);
retnamlen += rr->len - 5;
break;
case SIG('R','E'):
free(buffer);
return -1;
default:
break;
}
}
}
free(buffer);
return retnamlen; /* If 0, this file did not have a NM field */
out:
free(buffer);
return 0;
}
static int
parse_rock_ridge_stat_internal(iso9660_dir_t *de,
iso9660_stat_t *p_stat, int regard_xa)
{
int len;
unsigned char * chr;
int symlink_len = 0;
CONTINUE_DECLS;
if (!p_stat->b_rock) return 0;
SETUP_ROCK_RIDGE(de, chr, len);
if (regard_xa)
{
chr+=14;
len-=14;
if (len<0) len=0;
}
/* repeat:*/
{
int sig;
iso_extension_record_t * rr;
int rootflag;
while (len > 1){ /* There may be one byte for padding somewhere */
rr = (iso_extension_record_t *) chr;
if (rr->len == 0) goto out; /* Something got screwed up here */
sig = from_721(*chr);
chr += rr->len;
len -= rr->len;
switch(sig){
case SIG('S','P'):
CHECK_SP(goto out);
break;
case SIG('C','E'):
CHECK_CE;
break;
case SIG('E','R'):
p_stat->b_rock = 1;
cdio_debug("ISO 9660 Extensions: ");
{ int p;
for(p=0;p<rr->u.ER.len_id;p++) cdio_debug("%c",rr->u.ER.data[p]);
}
break;
case SIG('P','X'):
p_stat->st_mode = from_733(rr->u.PX.st_mode);
p_stat->st_nlinks = from_733(rr->u.PX.st_nlinks);
p_stat->st_uid = from_733(rr->u.PX.st_uid);
p_stat->st_gid = from_733(rr->u.PX.st_gid);
break;
#ifdef DEV_FINISHED
case SIG('P','N'):
{ int high, low;
high = from_733(*rr->u.PN.dev_high);
low = from_733(*rr->u.PN.dev_low);
/*
* The Rock Ridge standard specifies that if sizeof(dev_t) <= 4,
* then the high field is unused, and the device number is completely
* stored in the low field. Some writers may ignore this subtlety,
* and as a result we test to see if the entire device number is
* stored in the low field, and use that.
*/
if((low & ~0xff) && high == 0) {
p_stat->i_rdev = MKDEV(low >> 8, low & 0xff);
} else {
p_stat->i_rdev = MKDEV(high, low);
}
}
break;
#endif
#if TIME_FINISHED
case SIG('T','F'):
{
int cnt = 0; /* Rock ridge never appears on a High Sierra disk */
/* Some RRIP writers incorrectly place ctime in the
ISO_ROCK_TF_CREATE field. Try to handle this correctly for
either case. */
if(rr->u.TF.flags & ISO_ROCK_TF_CREATE) {
p_stat->i_ctime.tv_sec = iso_date(rr->u.TF.times[cnt++].time, 0);
p_stat->i_ctime.tv_nsec = 0;
}
if(rr->u.TF.flags & ISO_ROCK_TF_MODIFY) {
p_stat->i_mtime.tv_sec = iso_date(rr->u.TF.times[cnt++].time, 0);
p_stat->i_mtime.tv_nsec = 0;
}
if(rr->u.TF.flags & ISO_ROCK_TF_ACCESS) {
p_stat->i_atime.tv_sec = iso_date(rr->u.TF.times[cnt++].time, 0);
p_stat->i_atime.tv_nsec = 0;
}
if(rr->u.TF.flags & ISO_ROCK_TF_ATTRIBUTES) {
p_stat->i_ctime.tv_sec = iso_date(rr->u.TF.times[cnt++].time, 0);
p_stat->i_ctime.tv_nsec = 0;
}
break;
}
#endif /* TIME_FINISHED */
case SIG('S','L'):
{int slen;
iso_rock_sl_part_t *slp;
iso_rock_sl_part_t *oldslp;
slen = rr->len - 5;
slp = &rr->u.SL.link;
p_stat->i_size = symlink_len;
while (slen > 1){
rootflag = 0;
switch(slp->flags &~1){
case 0:
p_stat->i_size += slp->len;
break;
case 2:
p_stat->i_size += 1;
break;
case 4:
p_stat->i_size += 2;
break;
case 8:
rootflag = 1;
p_stat->i_size += 1;
break;
default:
cdio_info("Symlink component flag not implemented");
}
slen -= slp->len + 2;
oldslp = slp;
slp = (iso_rock_sl_part_t *) (((char *) slp) + slp->len + 2);
if(slen < 2) {
if( ((rr->u.SL.flags & 1) != 0)
&& ((oldslp->flags & 1) == 0) ) p_stat->i_size += 1;
break;
}
/*
* If this component record isn't continued, then append a '/'.
*/
if (!rootflag && (oldslp->flags & 1) == 0)
p_stat->i_size += 1;
}
}
symlink_len = p_stat->i_size;
break;
case SIG('R','E'):
cdio_warn("Attempt to read p_stat for relocated directory");
goto out;
#if FINISHED
case SIG('C','L'):
{
iso9660_stat_t * reloc;
ISOFS_I(p_stat)->i_first_extent = from_733(rr->u.CL.location);
reloc = isofs_iget(p_stat->i_sb, p_stat->i_first_extent, 0);
if (!reloc)
goto out;
p_stat->st_mode = reloc->st_mode;
p_stat->st_nlinks = reloc->st_nlinks;
p_stat->st_uid = reloc->st_uid;
p_stat->st_gid = reloc->st_gid;
p_stat->i_rdev = reloc->i_rdev;
p_stat->i_size = reloc->i_size;
p_stat->i_blocks = reloc->i_blocks;
p_stat->i_atime = reloc->i_atime;
p_stat->i_ctime = reloc->i_ctime;
p_stat->i_mtime = reloc->i_mtime;
iput(reloc);
}
break;
#endif
default:
break;
}
}
}
out:
free(buffer);
return 0;
}
int
parse_rock_ridge_stat(iso9660_dir_t *de, /*out*/ iso9660_stat_t *p_stat)
{
int result;
if (!p_stat) return 0;
result = parse_rock_ridge_stat_internal(de, p_stat, 0);
/* if Rock-Ridge flag was reset and we didn't look for attributes
* behind eventual XA attributes, have a look there */
if (0xFF == p_stat->s_rock_offset && p_stat->b_rock) {
result = parse_rock_ridge_stat_internal(de, p_stat, 14);
}
return result;
}