Read Volume Descriptors and identify RR extensions, if any.
This commit is contained in:
parent
e18f5d8898
commit
263770ab4f
@ -30,3 +30,4 @@ demo/tree
|
|||||||
demo/ecma119tree
|
demo/ecma119tree
|
||||||
demo/iso
|
demo/iso
|
||||||
demo/catbuffer
|
demo/catbuffer
|
||||||
|
demo/isoread
|
||||||
|
@ -42,6 +42,7 @@ src_libisofs_la_SOURCES = \
|
|||||||
src/buffer.c \
|
src/buffer.c \
|
||||||
src/rockridge.h \
|
src/rockridge.h \
|
||||||
src/rockridge.c \
|
src/rockridge.c \
|
||||||
|
src/rockridge_read.c \
|
||||||
src/data_source.c
|
src/data_source.c
|
||||||
libinclude_HEADERS = \
|
libinclude_HEADERS = \
|
||||||
src/libisofs.h
|
src/libisofs.h
|
||||||
@ -55,7 +56,8 @@ noinst_PROGRAMS = \
|
|||||||
demo/catbuffer \
|
demo/catbuffer \
|
||||||
demo/tree \
|
demo/tree \
|
||||||
demo/ecma119tree \
|
demo/ecma119tree \
|
||||||
demo/iso
|
demo/iso \
|
||||||
|
demo/isoread
|
||||||
|
|
||||||
demo_lsl_CPPFLAGS = -Isrc
|
demo_lsl_CPPFLAGS = -Isrc
|
||||||
demo_lsl_LDADD = $(src_libisofs_la_OBJECTS) $(THREAD_LIBS)
|
demo_lsl_LDADD = $(src_libisofs_la_OBJECTS) $(THREAD_LIBS)
|
||||||
@ -81,6 +83,10 @@ demo_iso_CPPFLAGS = -Isrc
|
|||||||
demo_iso_LDADD = $(src_libisofs_la_OBJECTS) $(THREAD_LIBS)
|
demo_iso_LDADD = $(src_libisofs_la_OBJECTS) $(THREAD_LIBS)
|
||||||
demo_iso_SOURCES = demo/iso.c
|
demo_iso_SOURCES = demo/iso.c
|
||||||
|
|
||||||
|
demo_isoread_CPPFLAGS = -Isrc
|
||||||
|
demo_isoread_LDADD = $(src_libisofs_la_OBJECTS) $(THREAD_LIBS)
|
||||||
|
demo_isoread_SOURCES = demo/iso_read.c
|
||||||
|
|
||||||
|
|
||||||
## Build unit test
|
## Build unit test
|
||||||
|
|
||||||
|
61
demo/iso_read.c
Normal file
61
demo/iso_read.c
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* Little program to output the contents of an iso image.
|
||||||
|
* Note that this is not an API example, but a little program for test
|
||||||
|
* purposes.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "messages.h"
|
||||||
|
#include "libisofs.h"
|
||||||
|
#include "fs_image.h"
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
IsoImageFilesystem *fs;
|
||||||
|
IsoDataSource *src;
|
||||||
|
struct iso_read_opts opts = {
|
||||||
|
0, /* block */
|
||||||
|
0, /* norock */
|
||||||
|
0, /* nojoliet */
|
||||||
|
0, /* preferjoliet */
|
||||||
|
0, /* uid; */
|
||||||
|
0, /* gid; */
|
||||||
|
0, /* mode */
|
||||||
|
NULL, /* messenger */
|
||||||
|
"UTF-8" /* input_charset */
|
||||||
|
};
|
||||||
|
|
||||||
|
if (argc != 2) {
|
||||||
|
printf ("You need to specify a valid path\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = libiso_msgs_new(&opts.messenger, 0);
|
||||||
|
if (result <= 0) {
|
||||||
|
printf ("Can't create messenger\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
libiso_msgs_set_severities(opts.messenger, LIBISO_MSGS_SEV_NEVER,
|
||||||
|
LIBISO_MSGS_SEV_ALL, "", 0);
|
||||||
|
|
||||||
|
result = iso_data_source_new_from_file(argv[1], &src);
|
||||||
|
if (result < 0) {
|
||||||
|
printf ("Error creating data source\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = iso_image_filesystem_new(src, &opts, &fs);
|
||||||
|
if (result < 0) {
|
||||||
|
printf ("Error creating filesystem\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
iso_filesystem_unref((IsoFilesystem*)fs);
|
||||||
|
iso_data_source_unref(src);
|
||||||
|
return 0;
|
||||||
|
}
|
@ -47,6 +47,7 @@
|
|||||||
|
|
||||||
/* image read errors */
|
/* image read errors */
|
||||||
#define ISO_WRONG_PVD -300
|
#define ISO_WRONG_PVD -300
|
||||||
|
#define ISO_WRONG_RR -301
|
||||||
|
|
||||||
|
|
||||||
#endif /*LIBISO_ERROR_H_*/
|
#endif /*LIBISO_ERROR_H_*/
|
||||||
|
233
src/fs_image.c
233
src/fs_image.c
@ -14,6 +14,8 @@
|
|||||||
#include "fs_image.h"
|
#include "fs_image.h"
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
#include "ecma119.h"
|
#include "ecma119.h"
|
||||||
|
#include "messages.h"
|
||||||
|
#include "rockridge.h"
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -98,7 +100,10 @@ typedef struct
|
|||||||
* RR version being used in image.
|
* RR version being used in image.
|
||||||
* 0 no RR extension, 1 RRIP 1.10, 2 RRIP 1.12
|
* 0 no RR extension, 1 RRIP 1.10, 2 RRIP 1.12
|
||||||
*/
|
*/
|
||||||
unsigned int rr_version : 2;
|
enum read_rr_ext rr_version;
|
||||||
|
|
||||||
|
/** If Joliet extensions are available on image */
|
||||||
|
unsigned int joliet : 1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Number of blocks of the volume, as reported in the PVM.
|
* Number of blocks of the volume, as reported in the PVM.
|
||||||
@ -181,13 +186,141 @@ void ifs_fs_free(IsoFilesystem *fs)
|
|||||||
free(data);
|
free(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read the SUSP system user entries of the "." entry of the root directory,
|
||||||
|
* indentifying when Rock Ridge extensions are being used.
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
int read_root_susp_entries(_ImageFsData *data, uint32_t block)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
unsigned char buffer[2048];
|
||||||
|
struct ecma119_dir_record *record;
|
||||||
|
struct susp_sys_user_entry *sue;
|
||||||
|
SuspIterator *iter;
|
||||||
|
|
||||||
|
ret = data->src->read_block(data->src, block, buffer);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* record will be the "." directory entry for the root record */
|
||||||
|
record = (struct ecma119_dir_record *)buffer;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO
|
||||||
|
* SUSP specification claims that for CD-ROM XA the SP entry
|
||||||
|
* is not at position BP 1, but at BP 15. Is that used?
|
||||||
|
* In that case, we need to set info->len_skp to 15!!
|
||||||
|
*/
|
||||||
|
|
||||||
|
iter = susp_iter_new(data->src, record, data->len_skp, data->messenger);
|
||||||
|
if (iter == NULL) {
|
||||||
|
return ISO_MEM_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* first entry must be an SP system use entry */
|
||||||
|
ret = susp_iter_next(iter, &sue);
|
||||||
|
if (ret < 0) {
|
||||||
|
/* error */
|
||||||
|
susp_iter_free(iter);
|
||||||
|
return ret;
|
||||||
|
} else if (ret == 0 || !SUSP_SIG(sue, 'S', 'P') ) {
|
||||||
|
iso_msg_debug(data->messenger, "SUSP/RR is not being used.");
|
||||||
|
susp_iter_free(iter);
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* it is a SP system use entry */
|
||||||
|
if (sue->version[0] != 1 || sue->data.SP.be[0] != 0xBE
|
||||||
|
|| sue->data.SP.ef[0] != 0xEF) {
|
||||||
|
|
||||||
|
iso_msg_sorry(data->messenger, LIBISO_SUSP_WRONG, "SUSP SP system use "
|
||||||
|
"entry seems to be wrong. Ignoring Rock Ridge Extensions.");
|
||||||
|
susp_iter_free(iter);
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
iso_msg_debug(data->messenger, "SUSP/RR is being used.");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The LEN_SKP field, defined in IEEE 1281, SUSP. 5.3, specifies the
|
||||||
|
* number of bytes to be skipped within each System Use field.
|
||||||
|
* I think this will be always 0, but given that support this standard
|
||||||
|
* feature is easy...
|
||||||
|
*/
|
||||||
|
data->len_skp = sue->data.SP.len_skp[0];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ok, now search for ER entry.
|
||||||
|
* Just notice that the attributes for root dir are read elsewhere.
|
||||||
|
*
|
||||||
|
* TODO if several ER are present, we need to identify the position of
|
||||||
|
* what refers to RR, and then look for corresponding ES entry in
|
||||||
|
* each directory record. I have not implemented this (it's not used,
|
||||||
|
* no?), but if we finally need it, it can be easily implemented in
|
||||||
|
* the iterator, transparently for the rest of the code.
|
||||||
|
*/
|
||||||
|
while ((ret = susp_iter_next(iter, &sue)) > 0) {
|
||||||
|
|
||||||
|
/* ignore entries from different version */
|
||||||
|
if (sue->version[0] != 1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (SUSP_SIG(sue, 'E', 'R')) {
|
||||||
|
|
||||||
|
if (data->rr_version) {
|
||||||
|
iso_msg_warn(data->messenger, LIBISO_SUSP_MULTIPLE_ER,
|
||||||
|
"More than one ER has found. This is not supported. "
|
||||||
|
"It will be ignored, but can cause problems. "
|
||||||
|
"Please notify us about this.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* it seems that Rock Ridge can be identified with any
|
||||||
|
* of the following
|
||||||
|
*/
|
||||||
|
if ( sue->data.ER.len_id[0] == 10 &&
|
||||||
|
!strncmp((char*)sue->data.ER.ext_id, "RRIP_1991A", 10) ) {
|
||||||
|
|
||||||
|
iso_msg_debug(data->messenger,
|
||||||
|
"Suitable Rock Ridge ER found. Version 1.10.");
|
||||||
|
data->rr_version = RR_EXT_110;
|
||||||
|
|
||||||
|
} else if ( (sue->data.ER.len_id[0] == 10 &&
|
||||||
|
!strncmp((char*)sue->data.ER.ext_id, "IEEE_P1282", 10))
|
||||||
|
|| (sue->data.ER.len_id[0] == 9 &&
|
||||||
|
!strncmp((char*)sue->data.ER.ext_id, "IEEE_1282", 9)) ) {
|
||||||
|
|
||||||
|
iso_msg_debug(data->messenger,
|
||||||
|
"Suitable Rock Ridge ER found. Version 1.12.");
|
||||||
|
data->rr_version = RR_EXT_112;
|
||||||
|
//TODO check also version?
|
||||||
|
} else {
|
||||||
|
iso_msg_warn(data->messenger, LIBISO_SUSP_MULTIPLE_ER,
|
||||||
|
"Not Rock Ridge ER found.\n"
|
||||||
|
"That will be ignored, but can cause problems in "
|
||||||
|
"image reading. Please notify us about this");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
susp_iter_free(iter);
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
int read_pvm(_ImageFsData *data, uint32_t block)
|
int read_pvm(_ImageFsData *data, uint32_t block)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
struct ecma119_pri_vol_desc *pvm;
|
struct ecma119_pri_vol_desc *pvm;
|
||||||
struct ecma119_dir_record *rootdr;
|
struct ecma119_dir_record *rootdr;
|
||||||
unsigned char buffer[BLOCK_SIZE];
|
uint8_t buffer[BLOCK_SIZE];
|
||||||
|
|
||||||
/* read PVM */
|
/* read PVM */
|
||||||
ret = data->src->read_block(data->src, block, buffer);
|
ret = data->src->read_block(data->src, block, buffer);
|
||||||
@ -199,10 +332,10 @@ int read_pvm(_ImageFsData *data, uint32_t block)
|
|||||||
|
|
||||||
/* sanity checks */
|
/* sanity checks */
|
||||||
if (pvm->vol_desc_type[0] != 1 || pvm->vol_desc_version[0] != 1
|
if (pvm->vol_desc_type[0] != 1 || pvm->vol_desc_version[0] != 1
|
||||||
|| strncmp((char*)pvm->std_identifier, "CD001", 5)
|
|| strncmp((char*)pvm->std_identifier, "CD001", 5)
|
||||||
|| pvm->file_structure_version[0] != 1 ) {
|
|| pvm->file_structure_version[0] != 1) {
|
||||||
|
|
||||||
return ISO_WRONG_PVD;
|
return ISO_WRONG_PVD;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ok, it is a valid PVD */
|
/* ok, it is a valid PVD */
|
||||||
@ -238,8 +371,10 @@ int iso_image_filesystem_new(IsoDataSource *src, struct iso_read_opts *opts,
|
|||||||
IsoImageFilesystem **fs)
|
IsoImageFilesystem **fs)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
uint32_t block;
|
||||||
IsoImageFilesystem *ifs;
|
IsoImageFilesystem *ifs;
|
||||||
_ImageFsData *data;
|
_ImageFsData *data;
|
||||||
|
uint8_t buffer[BLOCK_SIZE];
|
||||||
|
|
||||||
if (src == NULL || opts == NULL || fs == NULL) {
|
if (src == NULL || opts == NULL || fs == NULL) {
|
||||||
return ISO_NULL_POINTER;
|
return ISO_NULL_POINTER;
|
||||||
@ -265,7 +400,7 @@ int iso_image_filesystem_new(IsoDataSource *src, struct iso_read_opts *opts,
|
|||||||
data->gid = opts->gid;
|
data->gid = opts->gid;
|
||||||
data->uid = opts->uid;
|
data->uid = opts->uid;
|
||||||
data->mode = opts->mode & ~S_IFMT;
|
data->mode = opts->mode & ~S_IFMT;
|
||||||
data->input_charset = strdup("UTF-8"); //TODO strdup(opts->input_charset);
|
data->input_charset = strdup(opts->input_charset);
|
||||||
data->messenger = opts->messenger;
|
data->messenger = opts->messenger;
|
||||||
|
|
||||||
ifs->open = ifs_fs_open;
|
ifs->open = ifs_fs_open;
|
||||||
@ -286,24 +421,100 @@ int iso_image_filesystem_new(IsoDataSource *src, struct iso_read_opts *opts,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* 3. read next volume descriptors */
|
/* 3. read next volume descriptors */
|
||||||
// TODO
|
block = opts->block + 17;
|
||||||
|
do {
|
||||||
|
ret = src->read_block(src, block, buffer);
|
||||||
|
if (ret < 0) {
|
||||||
|
/* cleanup and exit */
|
||||||
|
goto fs_cleanup;
|
||||||
|
}
|
||||||
|
switch (buffer[0]) {
|
||||||
|
case 0:
|
||||||
|
/*
|
||||||
|
* This is a boot record
|
||||||
|
* Here we handle el-torito
|
||||||
|
*/
|
||||||
|
//TODO add support for El-Torito
|
||||||
|
iso_msg_hint(data->messenger, LIBISO_UNSUPPORTED_VD,
|
||||||
|
"El-Torito extensions not supported yet");
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
/* suplementary volume descritor */
|
||||||
|
// TODO support Joliet
|
||||||
|
iso_msg_hint(data->messenger, LIBISO_UNSUPPORTED_VD,
|
||||||
|
"Joliet extensions not supported yet");
|
||||||
|
break;
|
||||||
|
case 255:
|
||||||
|
/*
|
||||||
|
* volume set terminator
|
||||||
|
* ignore, as it's checked in loop end condition
|
||||||
|
*/
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
iso_msg_hint(data->messenger, LIBISO_UNSUPPORTED_VD,
|
||||||
|
"Ignoring Volume descriptor %x.", buffer[0]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
block++;
|
||||||
|
} while (buffer[0] != 255);
|
||||||
|
|
||||||
/* 4. check if RR extensions are being used */
|
/* 4. check if RR extensions are being used */
|
||||||
//TODO
|
ret = read_root_susp_entries(data, data->iso_root_block);
|
||||||
//ret = read_root_susp_entries(info, volume->root, data->iso_root_block);
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* user doesn't want to read RR extensions */
|
||||||
|
if (opts->norock) {
|
||||||
|
data->rr = RR_EXT_NO;
|
||||||
|
} else {
|
||||||
|
data->rr = data->rr_version;
|
||||||
|
}
|
||||||
|
|
||||||
/* select what tree to read */
|
/* select what tree to read */
|
||||||
//TODO
|
if (data->rr) {
|
||||||
|
/* RR extensions are available */
|
||||||
|
if (opts->preferjoliet && data->joliet) {
|
||||||
|
/* if user prefers joliet, that is used */
|
||||||
|
iso_msg_debug(data->messenger, "Reading Joliet extensions.");
|
||||||
|
//data->get_name = ucs2str;
|
||||||
|
data->rr = RR_EXT_NO;
|
||||||
|
//data->root_dir_block = joliet root
|
||||||
|
/* root_dir_block already contains root for joliet */
|
||||||
|
//TODO add joliet support
|
||||||
|
goto fs_cleanup;
|
||||||
|
} else {
|
||||||
|
/* RR will be used */
|
||||||
|
iso_msg_debug(data->messenger, "Reading Rock Ridge extensions.");
|
||||||
|
//data->root_dir_block = info.iso_root_block;
|
||||||
|
data->get_name = strcopy;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* RR extensions are not available */
|
||||||
|
if (opts->preferjoliet && data->joliet) {
|
||||||
|
/* joliet will be used */
|
||||||
|
iso_msg_debug(data->messenger, "Reading Joliet extensions.");
|
||||||
|
//data->get_name = ucs2str;
|
||||||
|
//data->root_dir_block = joliet root
|
||||||
|
/* root_dir_block already contains root for joliet */
|
||||||
|
//TODO add joliet support
|
||||||
|
goto fs_cleanup;
|
||||||
|
} else {
|
||||||
|
/* default to plain iso */
|
||||||
|
iso_msg_debug(data->messenger, "Reading plain ISO-9660 tree.");
|
||||||
|
//data->root_dir_block = info.iso_root_block;
|
||||||
|
data->get_name = strcopy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* and finally return. Note that we keep the DataSource opened */
|
/* and finally return. Note that we keep the DataSource opened */
|
||||||
|
|
||||||
*fs = ifs;
|
*fs = ifs;
|
||||||
return ISO_SUCCESS;
|
return ISO_SUCCESS;
|
||||||
|
|
||||||
fs_cleanup: ;
|
fs_cleanup: ;
|
||||||
ifs_fs_free((IsoFilesystem*)ifs);
|
ifs_fs_free((IsoFilesystem*)ifs);
|
||||||
free(ifs);
|
free(ifs);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -42,11 +42,14 @@ struct iso_read_opts
|
|||||||
* different on a multisession disc.
|
* different on a multisession disc.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
unsigned int norock :1; /*< Do not read Rock Ridge extensions */
|
unsigned int norock : 1; /*< Do not read Rock Ridge extensions */
|
||||||
// unsigned int nojoliet:1; /*< Do not read Joliet extensions */
|
unsigned int nojoliet : 1; /*< Do not read Joliet extensions */
|
||||||
// unsigned int preferjoliet:1;
|
|
||||||
/*< When both Joliet and RR extensions are present, the RR
|
/**
|
||||||
* tree is used. If you prefer using Joliet, set this to 1. */
|
* When both Joliet and RR extensions are present, the RR tree is used.
|
||||||
|
* If you prefer using Joliet, set this to 1.
|
||||||
|
*/
|
||||||
|
unsigned int preferjoliet : 1;
|
||||||
|
|
||||||
uid_t uid; /**< Default uid when no RR */
|
uid_t uid; /**< Default uid when no RR */
|
||||||
gid_t gid; /**< Default uid when no RR */
|
gid_t gid; /**< Default uid when no RR */
|
||||||
|
116
src/rockridge.h
116
src/rockridge.h
@ -27,6 +27,9 @@
|
|||||||
#define LIBISO_ROCKRIDGE_H
|
#define LIBISO_ROCKRIDGE_H
|
||||||
|
|
||||||
#include "ecma119.h"
|
#include "ecma119.h"
|
||||||
|
#include "messages.h"
|
||||||
|
|
||||||
|
#define SUSP_SIG(entry, a, b) ((entry->sig[0] == a) && (entry->sig[1] == b))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This contains the information about the System Use Fields (SUSP, 4.1),
|
* This contains the information about the System Use Fields (SUSP, 4.1),
|
||||||
@ -51,6 +54,89 @@ struct susp_info
|
|||||||
uint8_t **ce_susp_fields;
|
uint8_t **ce_susp_fields;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* SUSP 5.1 */
|
||||||
|
struct susp_CE {
|
||||||
|
uint8_t block[8];
|
||||||
|
uint8_t offset[8];
|
||||||
|
uint8_t len[8];
|
||||||
|
};
|
||||||
|
|
||||||
|
/* SUSP 5.3 */
|
||||||
|
struct susp_SP {
|
||||||
|
uint8_t be[1];
|
||||||
|
uint8_t ef[1];
|
||||||
|
uint8_t len_skp[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
/* SUSP 5.5 */
|
||||||
|
struct susp_ER {
|
||||||
|
uint8_t len_id[1];
|
||||||
|
uint8_t len_des[1];
|
||||||
|
uint8_t len_src[1];
|
||||||
|
uint8_t ext_ver[1];
|
||||||
|
uint8_t ext_id[1]; /*< up to len_id bytes */
|
||||||
|
/* ext_des, ext_src */
|
||||||
|
};
|
||||||
|
|
||||||
|
/** POSIX file attributes (RRIP, 4.1.1) */
|
||||||
|
struct rr_PX {
|
||||||
|
uint8_t mode[8];
|
||||||
|
uint8_t links[8];
|
||||||
|
uint8_t uid[8];
|
||||||
|
uint8_t gid[8];
|
||||||
|
uint8_t serial[8];
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Time stamps for a file (RRIP, 4.1.6) */
|
||||||
|
struct rr_TF {
|
||||||
|
uint8_t flags[1];
|
||||||
|
uint8_t t_stamps[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Info for character and block device (RRIP, 4.1.2) */
|
||||||
|
struct rr_PN {
|
||||||
|
uint8_t high[8];
|
||||||
|
uint8_t low[8];
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Alternate name (RRIP, 4.1.4) */
|
||||||
|
struct rr_NM {
|
||||||
|
uint8_t flags[1];
|
||||||
|
uint8_t name[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Link for a relocated directory (RRIP, 4.1.5.1) */
|
||||||
|
struct rr_CL {
|
||||||
|
uint8_t child_loc[8];
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Sim link (RRIP, 4.1.3) */
|
||||||
|
struct rr_SL {
|
||||||
|
uint8_t flags[1];
|
||||||
|
uint8_t comps[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Struct for a SUSP System User Entry (SUSP, 4.1)
|
||||||
|
*/
|
||||||
|
struct susp_sys_user_entry
|
||||||
|
{
|
||||||
|
uint8_t sig[2];
|
||||||
|
uint8_t len_sue[1];
|
||||||
|
uint8_t version[1];
|
||||||
|
union {
|
||||||
|
struct susp_CE CE;
|
||||||
|
struct susp_SP SP;
|
||||||
|
struct susp_ER ER;
|
||||||
|
struct rr_PX PX;
|
||||||
|
struct rr_TF TF;
|
||||||
|
struct rr_PN PN;
|
||||||
|
struct rr_NM NM;
|
||||||
|
struct rr_CL CL;
|
||||||
|
struct rr_SL SL;
|
||||||
|
} data; /* 5 to 4+len_sue */
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compute the length needed for write all RR and SUSP entries for a given
|
* Compute the length needed for write all RR and SUSP entries for a given
|
||||||
* node.
|
* node.
|
||||||
@ -105,4 +191,34 @@ void rrip_write_susp_fields(Ecma119Image *t, struct susp_info *info,
|
|||||||
*/
|
*/
|
||||||
int rrip_write_ce_fields(Ecma119Image *t, struct susp_info *info);
|
int rrip_write_ce_fields(Ecma119Image *t, struct susp_info *info);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The SUSP iterator is used to iterate over the System User Entries
|
||||||
|
* of a ECMA-168 directory record.
|
||||||
|
* It takes care about Continuation Areas, handles the end of the different
|
||||||
|
* system user entries and skip padding areas. Thus, using an iteration
|
||||||
|
* we are accessing just to the meaning entries.
|
||||||
|
*/
|
||||||
|
typedef struct susp_iterator SuspIterator;
|
||||||
|
|
||||||
|
SuspIterator *
|
||||||
|
susp_iter_new(IsoDataSource *src, struct ecma119_dir_record *record,
|
||||||
|
uint8_t len_skp, IsoMessenger *msgr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the next SUSP System User Entry using given iterator.
|
||||||
|
*
|
||||||
|
* @param sue
|
||||||
|
* Pointer to the next susp entry. It refers to an internal buffer and
|
||||||
|
* it's not guaranteed to be allocated after calling susp_iter_next()
|
||||||
|
* again. Thus, if you need to keep some entry you have to do a copy.
|
||||||
|
* @return
|
||||||
|
* 1 on success, 0 if no more entries, < 0 error
|
||||||
|
*/
|
||||||
|
int susp_iter_next(SuspIterator *iter, struct susp_sys_user_entry **sue);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free a given susp iterator.
|
||||||
|
*/
|
||||||
|
void susp_iter_free(SuspIterator *iter);
|
||||||
|
|
||||||
#endif /* LIBISO_ROCKRIDGE_H */
|
#endif /* LIBISO_ROCKRIDGE_H */
|
||||||
|
140
src/rockridge_read.c
Normal file
140
src/rockridge_read.c
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2007 Vreixo Formoso
|
||||||
|
*
|
||||||
|
* This file is part of the libisofs project; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation. See COPYING file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file contains functions related to the reading of SUSP and
|
||||||
|
* Rock Ridge extensions on an ECMA-119 image.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libisofs.h"
|
||||||
|
#include "ecma119.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "rockridge.h"
|
||||||
|
#include "error.h"
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
struct susp_iterator
|
||||||
|
{
|
||||||
|
uint8_t* base;
|
||||||
|
int pos;
|
||||||
|
int size;
|
||||||
|
IsoDataSource *src;
|
||||||
|
IsoMessenger *msgr;
|
||||||
|
|
||||||
|
/* block and offset for next continuation area */
|
||||||
|
uint32_t ce_block;
|
||||||
|
uint32_t ce_off;
|
||||||
|
|
||||||
|
/** Length of the next continuation area, 0 if no more CA are specified */
|
||||||
|
uint32_t ce_len;
|
||||||
|
|
||||||
|
uint8_t *buffer; /*< If there are continuation areas */
|
||||||
|
};
|
||||||
|
|
||||||
|
SuspIterator*
|
||||||
|
susp_iter_new(IsoDataSource *src, struct ecma119_dir_record *record,
|
||||||
|
uint8_t len_skp, IsoMessenger *msgr)
|
||||||
|
{
|
||||||
|
int pad = (record->len_fi[0] + 1) % 2;
|
||||||
|
struct susp_iterator *iter = malloc(sizeof(struct susp_iterator));
|
||||||
|
if (iter == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
iter->base = record->file_id + record->len_fi[0] + pad;
|
||||||
|
iter->pos = len_skp; /* 0 in most cases */
|
||||||
|
iter->size = record->len_dr[0] - record->len_fi[0] - 33 - pad;
|
||||||
|
iter->src = src;
|
||||||
|
iter->msgr = msgr;
|
||||||
|
|
||||||
|
iter->ce_len = 0;
|
||||||
|
iter->buffer = NULL;
|
||||||
|
|
||||||
|
return iter;
|
||||||
|
}
|
||||||
|
|
||||||
|
int susp_iter_next(SuspIterator *iter, struct susp_sys_user_entry **sue)
|
||||||
|
{
|
||||||
|
struct susp_sys_user_entry *entry;
|
||||||
|
|
||||||
|
entry = (struct susp_sys_user_entry*)(iter->base + iter->pos);
|
||||||
|
|
||||||
|
if ( (iter->pos + 4 > iter->size) || (SUSP_SIG(entry, 'S', 'T'))) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* End of the System Use Area or Continuation Area.
|
||||||
|
* Note that ST is not needed when the space left is less than 4.
|
||||||
|
* (IEEE 1281, SUSP. section 4)
|
||||||
|
*/
|
||||||
|
if (iter->ce_len) {
|
||||||
|
uint32_t block;
|
||||||
|
int nblocks;
|
||||||
|
|
||||||
|
/* A CE has found, there is another continuation area */
|
||||||
|
nblocks = div_up(iter->ce_off + iter->ce_len, BLOCK_SIZE);
|
||||||
|
iter->buffer = realloc(iter->buffer, nblocks * BLOCK_SIZE);
|
||||||
|
|
||||||
|
/* read all blocks needed to cache the full CE */
|
||||||
|
for (block = 0; block < nblocks; ++block) {
|
||||||
|
int ret;
|
||||||
|
ret = iter->src->read_block(iter->src, iter->ce_block + block,
|
||||||
|
iter->buffer + block * BLOCK_SIZE);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
iter->base = iter->buffer + iter->ce_off;
|
||||||
|
iter->pos = 0;
|
||||||
|
iter->size = iter->ce_len;
|
||||||
|
iter->ce_len = 0;
|
||||||
|
entry = (struct susp_sys_user_entry*)iter->base;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry->len_sue[0] == 0) {
|
||||||
|
/* a wrong image with this lead us to a infinity loop */
|
||||||
|
iso_msg_sorry(iter->msgr, LIBISO_RR_ERROR,
|
||||||
|
"Damaged RR/SUSP information.");
|
||||||
|
return ISO_WRONG_RR;
|
||||||
|
}
|
||||||
|
|
||||||
|
iter->pos += entry->len_sue[0];
|
||||||
|
|
||||||
|
if (SUSP_SIG(entry, 'C', 'E')) {
|
||||||
|
/* Continuation entry */
|
||||||
|
if (iter->ce_len) {
|
||||||
|
iso_msg_sorry(iter->msgr, LIBISO_RR_ERROR, "More than one CE "
|
||||||
|
"System user entry has found in a single System Use field or "
|
||||||
|
"continuation area. This breaks SUSP standard and it's not "
|
||||||
|
"supported. Ignoring last CE. Maybe the image is damaged.");
|
||||||
|
} else {
|
||||||
|
iter->ce_block = iso_read_bb(entry->data.CE.block, 4, NULL);
|
||||||
|
iter->ce_off = iso_read_bb(entry->data.CE.offset, 4, NULL);
|
||||||
|
iter->ce_len = iso_read_bb(entry->data.CE.len, 4, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* we don't want to return CE entry to the user */
|
||||||
|
return susp_iter_next(iter, sue);
|
||||||
|
} else if (SUSP_SIG(entry, 'P', 'D')) {
|
||||||
|
/* skip padding */
|
||||||
|
return susp_iter_next(iter, sue);
|
||||||
|
}
|
||||||
|
|
||||||
|
*sue = entry;
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void susp_iter_free(SuspIterator *iter)
|
||||||
|
{
|
||||||
|
free(iter->buffer);
|
||||||
|
free(iter);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user