|
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 |
}
|