Add functions to read RockRidge SUSP entries.

This commit is contained in:
Vreixo Formoso 2007-12-31 21:51:31 +01:00
parent c296ca9ff5
commit dc6cd09877
3 changed files with 320 additions and 0 deletions

View File

@ -48,6 +48,8 @@
/* image read errors */
#define ISO_WRONG_PVD -300
#define ISO_WRONG_RR -301
#define ISO_UNSUPPORTED_RR -302
#define ISO_WRONG_ECMA119 -303
#endif /*LIBISO_ERROR_H_*/

View File

@ -221,4 +221,48 @@ int susp_iter_next(SuspIterator *iter, struct susp_sys_user_entry **sue);
*/
void susp_iter_free(SuspIterator *iter);
/**
* Fills a struct stat with the values of a Rock Ridge PX entry (RRIP, 4.1.1).
*
* @return
* 1 on success, < 0 on error
*/
int read_rr_PX(struct susp_sys_user_entry *px, struct stat *st);
/**
* Fills a struct stat with the values of a Rock Ridge TF entry (RRIP, 4.1.6)
*
* @return
* 1 on success, < 0 on error
*/
int read_rr_TF(struct susp_sys_user_entry *tf, struct stat *st);
/**
* Read a RR NM entry (RRIP, 4.1.4), and appends the name stored there to
* the given name. You can pass a pointer to NULL as name.
*
* @return
* 1 on success, < 0 on error
*/
int read_rr_NM(struct susp_sys_user_entry *nm, char **name, int *cont);
/**
* Read a SL RR entry (RRIP, 4.1.3), checking if the destination continues.
*
* @param cont
* 0 not continue, 1 continue, 2 continue component
* @return
* 1 on success, < 0 on error
*/
int read_rr_SL(struct susp_sys_user_entry *sl, char **dest, int *cont);
/**
* Fills a struct stat with the values of a Rock Ridge PN entry (RRIP, 4.1.2).
*
* @return
* 1 on success, < 0 on error
*/
int read_rr_PN(struct susp_sys_user_entry *pn, struct stat *st);
#endif /* LIBISO_ROCKRIDGE_H */

View File

@ -19,6 +19,7 @@
#include <sys/stat.h>
#include <stdlib.h>
#include <string.h>
struct susp_iterator
{
@ -138,3 +139,276 @@ void susp_iter_free(SuspIterator *iter)
free(iter->buffer);
free(iter);
}
/**
* Fills a struct stat with the values of a Rock Ridge PX entry (RRIP, 4.1.1).
*
* @return
* 1 on success, < 0 on error
*/
int read_rr_PX(struct susp_sys_user_entry *px, struct stat *st)
{
if (px == NULL || st == NULL) {
return ISO_NULL_POINTER;
}
if (px->sig[0] != 'P' || px->sig[1] != 'X') {
return ISO_WRONG_ARG_VALUE;
}
if (px->len_sue[0] != 44 || px->len_sue[0] != 36) {
return ISO_WRONG_RR;
}
st->st_mode = iso_read_bb(px->data.PX.mode, 4, NULL);
st->st_nlink = iso_read_bb(px->data.PX.links, 4, NULL);
st->st_uid = iso_read_bb(px->data.PX.uid, 4, NULL);
st->st_gid = iso_read_bb(px->data.PX.gid, 4, NULL);
if (px->len_sue[0] == 44) {
/* this corresponds to RRIP 1.12, so we have inode serial number */
st->st_ino = iso_read_bb(px->data.PX.serial, 4, NULL);
}
return ISO_SUCCESS;
}
/**
* Fills a struct stat with the values of a Rock Ridge TF entry (RRIP, 4.1.6)
*
* @return
* 1 on success, < 0 on error
*/
int read_rr_TF(struct susp_sys_user_entry *tf, struct stat *st)
{
time_t time;
int s;
int nts = 0;
if (tf == NULL || st == NULL) {
return ISO_NULL_POINTER;
}
if (tf->sig[0] != 'T' || tf->sig[1] != 'F') {
return ISO_WRONG_ARG_VALUE;
}
if (tf->data.TF.flags[0] & (1 << 7)) {
/* long form */
s = 17;
} else {
s = 7;
}
/* 1. Creation time */
if (tf->data.TF.flags[0] & (1 << 0)) {
/* the creation is the recording time. we ignore this */
/* TODO maybe it would be good to manage it in ms discs, where
* the recording time could be different than now!! */
++nts;
}
/* 2. modify time */
if (tf->data.TF.flags[0] & (1 << 1)) {
if (tf->len_sue[0] < 5 + (nts+1) * s) {
/* RR TF entry too short. */
return ISO_WRONG_RR;
}
if (s == 7) {
time = iso_datetime_read_7(&tf->data.TF.t_stamps[nts*7]);
} else {
time = iso_datetime_read_17(&tf->data.TF.t_stamps[nts*17]);
}
st->st_mtime = time;
++nts;
}
/* 3. access time */
if (tf->data.TF.flags[0] & (1 << 2)) {
if (tf->len_sue[0] < 5 + (nts+1) * s) {
/* RR TF entry too short. */
return ISO_WRONG_RR;
}
if (s == 7) {
time = iso_datetime_read_7(&tf->data.TF.t_stamps[nts*7]);
} else {
time = iso_datetime_read_17(&tf->data.TF.t_stamps[nts*17]);
}
st->st_atime = time;
++nts;
}
/* 4. attributes time */
if (tf->data.TF.flags[0] & (1 << 3)) {
if (tf->len_sue[0] < 5 + (nts+1) * s) {
/* RR TF entry too short. */
return ISO_WRONG_RR;
}
if (s == 7) {
time = iso_datetime_read_7(&tf->data.TF.t_stamps[nts*7]);
} else {
time = iso_datetime_read_17(&tf->data.TF.t_stamps[nts*17]);
}
st->st_ctime = time;
++nts;
}
/* we ignore backup, expire and effect times */
return ISO_SUCCESS;
}
/**
* Read a RR NM entry (RRIP, 4.1.4), and appends the name stored there to
* the given name. You can pass a pointer to NULL as name.
*
* @return
* 1 on success, < 0 on error
*/
int read_rr_NM(struct susp_sys_user_entry *nm, char **name, int *cont)
{
if (nm == NULL || name == NULL) {
return ISO_NULL_POINTER;
}
if (nm->sig[0] != 'N' || nm->sig[1] != 'M') {
return ISO_WRONG_ARG_VALUE;
}
if (nm->len_sue[0] == 5) {
if (nm->data.NM.flags[0] & 0x2) {
/* it is a "." entry */
if (*name == NULL) {
return ISO_SUCCESS;
} else {
/* we can't have a previous not-NULL name */
return ISO_WRONG_RR;
}
}
}
if (nm->len_sue[0] <= 5) {
/* ".." entry is an error, as we will never call it */
return ISO_WRONG_RR;
}
/* concatenate the results */
if (*cont) {
*name = realloc(*name, strlen(*name) + nm->len_sue[0] - 5 + 1);
strncat(*name, (char*)nm->data.NM.name, nm->len_sue[0] - 5);
} else {
*name = strcopy((char*)nm->data.NM.name, nm->len_sue[0] - 5);
}
if (*name == NULL) {
return ISO_MEM_ERROR;
}
/* and set cond according to the value of CONTINUE flag */
*cont = nm->data.NM.flags[0] & 0x01;
return ISO_SUCCESS;
}
/**
* Read a SL RR entry (RRIP, 4.1.3), checking if the destination continues.
*
* @param cont
* 0 not continue, 1 continue, 2 continue component
* @return
* 1 on success, < 0 on error
*/
int read_rr_SL(struct susp_sys_user_entry *sl, char **dest, int *cont)
{
int pos;
if (sl == NULL || dest == NULL) {
return ISO_NULL_POINTER;
}
if (sl->sig[0] != 'S' || sl->sig[1] != 'L') {
return ISO_WRONG_ARG_VALUE;
}
for (pos = 0; pos + 5 < sl->len_sue[0];
pos += 2 + sl->data.SL.comps[pos + 1]) {
char *comp;
uint8_t len;
uint8_t flags = sl->data.SL.comps[pos];
if (flags & 0x2) {
/* current directory */
len = 1;
comp = ".";
} else if (flags & 0x4) {
/* parent directory */
len = 2;
comp = "..";
} else if (flags & 0x8) {
/* root directory */
len = 1;
comp = "/";
} else if (flags & ~0x01) {
/* unsupported flag component */
return ISO_UNSUPPORTED_RR;
} else {
len = sl->data.SL.comps[pos + 1];
comp = (char*)&sl->data.SL.comps[pos + 2];
}
if (*cont == 1) {
/* new component */
size_t size = strlen(*dest);
*dest = realloc(*dest, strlen(*dest) + len + 2);
if (*dest == NULL) {
return ISO_MEM_ERROR;
}
/* it is a new compoenent, add the '/' */
if ((*dest)[size-1] != '/') {
(*dest)[size] = '/';
(*dest)[size+1] = '\0';
}
strncat(*dest, comp, len);
} else if (*cont == 2) {
/* the component continues */
*dest = realloc(*dest, strlen(*dest) + len + 1);
if (*dest == NULL) {
return ISO_MEM_ERROR;
}
/* we don't have to add the '/' */
strncat(*dest, comp, len);
} else {
*dest = strcopy(comp, len);
}
if (*dest == NULL) {
return ISO_MEM_ERROR;
}
/* do the component continue or not? */
*cont = (flags & 0x01) ? 2 : 1;
}
if (*cont == 2) {
/* TODO check that SL flag is set to continute too ?*/
} else {
*cont = sl->data.SL.flags[0] & 0x1 ? 1 : 0;
}
return ISO_SUCCESS;
}
/**
* Fills a struct stat with the values of a Rock Ridge PN entry (RRIP, 4.1.2).
*
* @return
* 1 on success, < 0 on error
*/
int read_rr_PN(struct susp_sys_user_entry *pn, struct stat *st)
{
if (pn == NULL || pn == NULL) {
return ISO_NULL_POINTER;
}
if (pn->sig[0] != 'P' || pn->sig[1] != 'N') {
return ISO_WRONG_ARG_VALUE;
}
if (pn->len_sue[0] != 20) {
return ISO_WRONG_RR;
}
st->st_rdev = (dev_t)((dev_t)iso_read_bb(pn->data.PN.high, 4, NULL) << 32)
|| (dev_t)iso_read_bb(pn->data.PN.low, 4, NULL);
return ISO_SUCCESS;
}