|
|
|
@ -14,6 +14,452 @@
|
|
|
|
|
|
|
|
|
|
#include <string.h> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static |
|
|
|
|
int susp_append(Ecma119Image *t, struct susp_info *susp, uint8_t *data) |
|
|
|
|
{ |
|
|
|
|
susp->n_susp_fields++; |
|
|
|
|
susp->susp_fields = realloc(susp->susp_fields, |
|
|
|
|
sizeof(void*) * susp->n_susp_fields); |
|
|
|
|
if (susp->susp_fields == NULL) { |
|
|
|
|
return ISO_MEM_ERROR; |
|
|
|
|
} |
|
|
|
|
susp->susp_fields[susp->n_susp_fields - 1] = data; |
|
|
|
|
susp->suf_len += data[2]; |
|
|
|
|
return ISO_SUCCESS; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static |
|
|
|
|
int susp_append_ce(Ecma119Image *t, struct susp_info *susp, uint8_t *data) |
|
|
|
|
{ |
|
|
|
|
susp->n_ce_susp_fields++; |
|
|
|
|
susp->ce_susp_fields = realloc(susp->ce_susp_fields, |
|
|
|
|
sizeof(void*) * susp->n_ce_susp_fields); |
|
|
|
|
if (susp->ce_susp_fields == NULL) { |
|
|
|
|
return ISO_MEM_ERROR; |
|
|
|
|
} |
|
|
|
|
susp->ce_susp_fields[susp->n_ce_susp_fields - 1] = data; |
|
|
|
|
susp->ce_len += data[2]; |
|
|
|
|
return ISO_SUCCESS; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Add a PX System Use Entry. The PX System Use Entry is used to add POSIX
|
|
|
|
|
* file attributes, such as access permissions or user and group id, to a
|
|
|
|
|
* ECMA 119 directory record. (RRIP, 4.1.1) |
|
|
|
|
*/ |
|
|
|
|
static |
|
|
|
|
int rrip_add_PX(Ecma119Image *t, Ecma119Node *n, struct susp_info *susp) |
|
|
|
|
{ |
|
|
|
|
uint8_t *PX = malloc(44); |
|
|
|
|
if (PX == NULL) { |
|
|
|
|
return ISO_MEM_ERROR; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
PX[0] = 'P'; |
|
|
|
|
PX[1] = 'X'; |
|
|
|
|
PX[2] = 44; |
|
|
|
|
PX[3] = 1; |
|
|
|
|
iso_bb(&PX[4], n->node->mode, 4); |
|
|
|
|
// TODO support nlink and ino
|
|
|
|
|
// TODO n->node->nlink
|
|
|
|
|
iso_bb(&PX[12], 1, 4); |
|
|
|
|
iso_bb(&PX[20], n->node->uid, 4); |
|
|
|
|
iso_bb(&PX[28], n->node->gid, 4); |
|
|
|
|
// TODO n->node->ino
|
|
|
|
|
iso_bb(&PX[36], (int)n->node, 4); |
|
|
|
|
|
|
|
|
|
return susp_append(t, susp, PX); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Add to the given tree node a TF System Use Entry, used to record some |
|
|
|
|
* time stamps related to the file (RRIP, 4.1.6). |
|
|
|
|
*/ |
|
|
|
|
static |
|
|
|
|
int rrip_add_TF(Ecma119Image *t, Ecma119Node *n, struct susp_info *susp) |
|
|
|
|
{ |
|
|
|
|
uint8_t *TF = malloc(5 + 3 * 7); |
|
|
|
|
if (TF == NULL) { |
|
|
|
|
return ISO_MEM_ERROR; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
TF[0] = 'T'; |
|
|
|
|
TF[1] = 'F'; |
|
|
|
|
TF[2] = 5 + 3 * 7; |
|
|
|
|
TF[3] = 1; |
|
|
|
|
TF[4] = (1 << 1) | (1 << 2) | (1 << 3); |
|
|
|
|
iso_datetime_7(&TF[5], n->node->mtime); |
|
|
|
|
iso_datetime_7(&TF[12], n->node->atime); |
|
|
|
|
iso_datetime_7(&TF[19], n->node->ctime); |
|
|
|
|
return susp_append(t, susp, TF); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Add a PL System Use Entry, used to record the location of the original
|
|
|
|
|
* parent directory of a directory which has been relocated. |
|
|
|
|
*
|
|
|
|
|
* This is special because it doesn't modify the susp fields of the directory |
|
|
|
|
* that gets passed to it; it modifies the susp fields of the ".." entry in |
|
|
|
|
* that directory. |
|
|
|
|
*
|
|
|
|
|
* See RRIP, 4.1.5.2 for more details. |
|
|
|
|
*/ |
|
|
|
|
static |
|
|
|
|
int rrip_add_PL(Ecma119Image *t, Ecma119Node *n, struct susp_info *susp) |
|
|
|
|
{ |
|
|
|
|
uint8_t *PL; |
|
|
|
|
|
|
|
|
|
if (n->type != ECMA119_DIR || n->info.dir.real_parent == NULL) { |
|
|
|
|
/* should never occur */ |
|
|
|
|
return ISO_ERROR; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
PL = malloc(12); |
|
|
|
|
if (PL == NULL) { |
|
|
|
|
return ISO_MEM_ERROR; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
PL[0] = 'P'; |
|
|
|
|
PL[1] = 'L'; |
|
|
|
|
PL[2] = 12; |
|
|
|
|
PL[3] = 1; |
|
|
|
|
|
|
|
|
|
/* write the location of the real parent, already computed */ |
|
|
|
|
iso_bb(&PL[4], n->info.dir.real_parent->info.dir.block, 4); |
|
|
|
|
return susp_append(t, susp, PL); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Add a RE System Use Entry to the given tree node. The purpose of the
|
|
|
|
|
* this System Use Entry is to indicate to an RRIP-compliant receiving |
|
|
|
|
* system that the Directory Record in which an "RE" System Use Entry is
|
|
|
|
|
* recorded has been relocated from another position in the original
|
|
|
|
|
* Directory Hierarchy. |
|
|
|
|
*
|
|
|
|
|
* See RRIP, 4.1.5.3 for more details. |
|
|
|
|
*/ |
|
|
|
|
static |
|
|
|
|
int rrip_add_RE(Ecma119Image *t, Ecma119Node *n, struct susp_info *susp) |
|
|
|
|
{ |
|
|
|
|
uint8_t *RE = malloc(4); |
|
|
|
|
if (RE == NULL) { |
|
|
|
|
return ISO_MEM_ERROR; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
RE[0] = 'R'; |
|
|
|
|
RE[1] = 'E'; |
|
|
|
|
RE[2] = 4; |
|
|
|
|
RE[3] = 1; |
|
|
|
|
return susp_append(t, susp, RE); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Add a PN System Use Entry to the given tree node.
|
|
|
|
|
* The PN System Use Entry is used to store the device number, and it's |
|
|
|
|
* mandatory if the tree node corresponds to a character or block device. |
|
|
|
|
*
|
|
|
|
|
* See RRIP, 4.1.2 for more details. |
|
|
|
|
*/ |
|
|
|
|
static |
|
|
|
|
int rrip_add_PN(Ecma119Image *t, Ecma119Node *n, struct susp_info *susp) |
|
|
|
|
{ |
|
|
|
|
IsoSpecial *node; |
|
|
|
|
uint8_t *PN; |
|
|
|
|
|
|
|
|
|
node = (IsoSpecial*)n->node; |
|
|
|
|
if (node->node.type != LIBISO_SPECIAL) { |
|
|
|
|
/* should never occur */ |
|
|
|
|
return ISO_ERROR; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
PN = malloc(20); |
|
|
|
|
if (PN == NULL) { |
|
|
|
|
return ISO_MEM_ERROR; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
PN[0] = 'P'; |
|
|
|
|
PN[1] = 'N'; |
|
|
|
|
PN[2] = 20; |
|
|
|
|
PN[3] = 1; |
|
|
|
|
iso_bb(&PN[4], node->dev >> 32, 4); |
|
|
|
|
iso_bb(&PN[12], node->dev & 0xffffffff, 4); |
|
|
|
|
return susp_append(t, susp, PN); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Add to the given tree node a CL System Use Entry, that is used to record
|
|
|
|
|
* the new location of a directory which has been relocated. |
|
|
|
|
*
|
|
|
|
|
* See RRIP, 4.1.5.1 for more details. |
|
|
|
|
*/ |
|
|
|
|
static |
|
|
|
|
int rrip_add_CL(Ecma119Image *t, Ecma119Node *n, struct susp_info *susp) |
|
|
|
|
{ |
|
|
|
|
uint8_t *CL; |
|
|
|
|
if (n->type != ECMA119_PLACEHOLDER) { |
|
|
|
|
/* should never occur */ |
|
|
|
|
return ISO_ERROR; |
|
|
|
|
} |
|
|
|
|
CL = malloc(12); |
|
|
|
|
if (CL == NULL) { |
|
|
|
|
return ISO_MEM_ERROR; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
CL[0] = 'C'; |
|
|
|
|
CL[1] = 'L'; |
|
|
|
|
CL[2] = 12; |
|
|
|
|
CL[3] = 1; |
|
|
|
|
iso_bb(&CL[4], n->info.real_me->info.dir.block, 4); |
|
|
|
|
return susp_append(t, susp, CL); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Add a NM System Use Entry to the given tree node. The purpose of this |
|
|
|
|
* System Use Entry is to store the content of an Alternate Name to support
|
|
|
|
|
* POSIX-style or other names.
|
|
|
|
|
*
|
|
|
|
|
* See RRIP, 4.1.4 for more details. |
|
|
|
|
*
|
|
|
|
|
* @param size |
|
|
|
|
* Length of the name to be included into the NM |
|
|
|
|
* @param flags |
|
|
|
|
* @param ce |
|
|
|
|
* Whether to add or not to CE |
|
|
|
|
*/ |
|
|
|
|
static |
|
|
|
|
int rrip_add_NM(Ecma119Image *t, struct susp_info *susp, |
|
|
|
|
char *name, int size, int flags, int ce) |
|
|
|
|
{ |
|
|
|
|
uint8_t *NM = malloc(size + 5); |
|
|
|
|
if (NM == NULL) { |
|
|
|
|
return ISO_MEM_ERROR; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
NM[0] = 'N'; |
|
|
|
|
NM[1] = 'M'; |
|
|
|
|
NM[2] = size + 5; |
|
|
|
|
NM[3] = 1; |
|
|
|
|
NM[4] = flags; |
|
|
|
|
if (size) { |
|
|
|
|
memcpy(&NM[5], name, size); |
|
|
|
|
} |
|
|
|
|
if (ce) { |
|
|
|
|
return susp_append_ce(t, susp, NM); |
|
|
|
|
} else { |
|
|
|
|
return susp_append(t, susp, NM); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Add a new SL component (RRIP, 4.1.3.1) to a list of components. |
|
|
|
|
*
|
|
|
|
|
* @param n |
|
|
|
|
* Number of components. It will be updated. |
|
|
|
|
* @param compos |
|
|
|
|
* Pointer to the list of components. |
|
|
|
|
* @param s |
|
|
|
|
* The component content |
|
|
|
|
* @param size |
|
|
|
|
* Size of the component content |
|
|
|
|
* @param fl |
|
|
|
|
* Flags |
|
|
|
|
* @return |
|
|
|
|
* 1 on success, < 0 on error |
|
|
|
|
*/ |
|
|
|
|
static
|
|
|
|
|
int rrip_SL_append_comp(size_t *n, uint8_t ***comps, |
|
|
|
|
char *s, int size, char fl) |
|
|
|
|
{ |
|
|
|
|
uint8_t *comp = malloc(size + 2); |
|
|
|
|
if (comp == NULL) { |
|
|
|
|
return ISO_MEM_ERROR; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
(*n)++; |
|
|
|
|
comp[0] = fl; |
|
|
|
|
comp[1] = size; |
|
|
|
|
*comps = realloc(*comps, (*n) * sizeof(void*)); |
|
|
|
|
if (*comps == NULL) { |
|
|
|
|
free(comp); |
|
|
|
|
return ISO_MEM_ERROR; |
|
|
|
|
} |
|
|
|
|
(*comps)[(*n) - 1] = comp; |
|
|
|
|
|
|
|
|
|
if (size) { |
|
|
|
|
memcpy(&comp[2], s, size); |
|
|
|
|
} |
|
|
|
|
return ISO_SUCCESS; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Add a SL System Use Entry to the given tree node. This is used to store
|
|
|
|
|
* the content of a symbolic link, and is mandatory if the tree node |
|
|
|
|
* indicates a symbolic link (RRIP, 4.1.3). |
|
|
|
|
*
|
|
|
|
|
* @param comp |
|
|
|
|
* Components of the SL System Use Entry. If they don't fit in a single |
|
|
|
|
* SL, more than one SL will be added. |
|
|
|
|
* @param n |
|
|
|
|
* Number of components in comp |
|
|
|
|
* @param ce |
|
|
|
|
* Whether to add to a continuation area or system use field. |
|
|
|
|
*/ |
|
|
|
|
static |
|
|
|
|
int rrip_add_SL(Ecma119Image *t, struct susp_info *susp, |
|
|
|
|
uint8_t **comp, size_t n, int ce) |
|
|
|
|
{ |
|
|
|
|
int ret, i, j; |
|
|
|
|
|
|
|
|
|
int total_comp_len = 0; |
|
|
|
|
size_t pos, written = 0; |
|
|
|
|
|
|
|
|
|
uint8_t *SL; |
|
|
|
|
|
|
|
|
|
for (i = 0; i < n; i++) { |
|
|
|
|
|
|
|
|
|
total_comp_len += comp[i][1] + 2; |
|
|
|
|
if (total_comp_len > 250) { |
|
|
|
|
/* we need a new SL entry */ |
|
|
|
|
total_comp_len -= comp[i][1] + 2; |
|
|
|
|
SL = malloc(total_comp_len + 5); |
|
|
|
|
if (SL == NULL) { |
|
|
|
|
return ISO_MEM_ERROR; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
SL[0] = 'S'; |
|
|
|
|
SL[1] = 'L'; |
|
|
|
|
SL[2] = total_comp_len + 5; |
|
|
|
|
SL[3] = 1; |
|
|
|
|
SL[4] = 1; /* CONTINUE */ |
|
|
|
|
pos = 5; |
|
|
|
|
for (j = written; j < i; j++) { |
|
|
|
|
memcpy(&SL[pos], comp[j], comp[j][2]); |
|
|
|
|
pos += comp[j][2]; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* In this case we are sure we're writting to CE. Check for |
|
|
|
|
* debug purposes |
|
|
|
|
*/ |
|
|
|
|
if (ce == 0) { |
|
|
|
|
return ISO_ERROR; /* unexpected */ |
|
|
|
|
} |
|
|
|
|
ret = susp_append_ce(t, susp, SL); |
|
|
|
|
if (ret < 0) { |
|
|
|
|
return ret; |
|
|
|
|
} |
|
|
|
|
written = i - 1; |
|
|
|
|
total_comp_len = comp[i][1]; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
SL = malloc(total_comp_len + 5); |
|
|
|
|
if (SL == NULL) { |
|
|
|
|
return ISO_MEM_ERROR; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
SL[0] = 'S'; |
|
|
|
|
SL[1] = 'L'; |
|
|
|
|
SL[2] = total_comp_len + 5; |
|
|
|
|
SL[3] = 1; |
|
|
|
|
SL[4] = 0; |
|
|
|
|
pos = 5; |
|
|
|
|
|
|
|
|
|
for (j = written; j < n; j++) { |
|
|
|
|
memcpy(&SL[pos], comp[j], comp[j][1] + 2); |
|
|
|
|
pos += comp[j][1] + 2; |
|
|
|
|
} |
|
|
|
|
if (ce) { |
|
|
|
|
ret = susp_append_ce(t, susp, SL); |
|
|
|
|
} else { |
|
|
|
|
ret = susp_append(t, susp, SL); |
|
|
|
|
} |
|
|
|
|
return ret; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Add a SUSP "ER" System Use Entry to identify the Rock Ridge specification. |
|
|
|
|
*
|
|
|
|
|
* The "ER" System Use Entry is used to uniquely identify a specification |
|
|
|
|
* compliant with SUSP. This method adds to the given tree node "." entry |
|
|
|
|
* the "ER" corresponding to the RR protocol. |
|
|
|
|
*
|
|
|
|
|
* See SUSP, 5.5 and RRIP, 4.3 for more details. |
|
|
|
|
*/ |
|
|
|
|
static |
|
|
|
|
int rrip_add_ER(Ecma119Image *t, struct susp_info *susp) |
|
|
|
|
{ |
|
|
|
|
unsigned char *ER = malloc(182); |
|
|
|
|
if (ER == NULL) { |
|
|
|
|
return ISO_MEM_ERROR; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ER[0] = 'E'; |
|
|
|
|
ER[1] = 'R'; |
|
|
|
|
ER[2] = 182; |
|
|
|
|
ER[3] = 1; |
|
|
|
|
ER[4] = 9; |
|
|
|
|
ER[5] = 72; |
|
|
|
|
ER[6] = 93; |
|
|
|
|
ER[7] = 1; |
|
|
|
|
memcpy(&ER[8], "IEEE_1282", 9); |
|
|
|
|
memcpy(&ER[17], "THE IEEE 1282 PROTOCOL PROVIDES SUPPORT FOR POSIX " |
|
|
|
|
"FILE SYSTEM SEMANTICS.", 72); |
|
|
|
|
memcpy(&ER[89], "PLEASE CONTACT THE IEEE STANDARDS DEPARTMENT, " |
|
|
|
|
"PISCATAWAY, NJ, USA FOR THE 1282 SPECIFICATION.", 93); |
|
|
|
|
|
|
|
|
|
/** This always goes to continuation area */ |
|
|
|
|
return susp_append_ce(t, susp, ER); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Add a CE System Use Entry to the given tree node. A "CE" is used to add |
|
|
|
|
* a continuation area, where additional System Use Entry can be written. |
|
|
|
|
* (SUSP, 5.1). |
|
|
|
|
*/ |
|
|
|
|
static |
|
|
|
|
int susp_add_CE(Ecma119Image *t, size_t ce_len, struct susp_info *susp) |
|
|
|
|
{ |
|
|
|
|
uint8_t *CE = malloc(28); |
|
|
|
|
if (CE == NULL) { |
|
|
|
|
return ISO_MEM_ERROR; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
CE[0] = 'C'; |
|
|
|
|
CE[1] = 'E'; |
|
|
|
|
CE[2] = 28; |
|
|
|
|
CE[3] = 1; |
|
|
|
|
iso_bb(&CE[4], susp->ce_block, 4); |
|
|
|
|
iso_bb(&CE[12], susp->ce_len, 4); |
|
|
|
|
iso_bb(&CE[20], ce_len, 4); |
|
|
|
|
|
|
|
|
|
return susp_append(t, susp, CE); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Add a SP System Use Entry. The SP provide an identifier that the SUSP is
|
|
|
|
|
* used within the volume. The SP shall be recorded in the "." entry of the
|
|
|
|
|
* root directory. See SUSP, 5.3 for more details. |
|
|
|
|
*/ |
|
|
|
|
static |
|
|
|
|
int susp_add_SP(Ecma119Image *t, struct susp_info *susp) |
|
|
|
|
{ |
|
|
|
|
unsigned char *SP = malloc(7); |
|
|
|
|
if (SP == NULL) { |
|
|
|
|
return ISO_MEM_ERROR; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
SP[0] = 'S'; |
|
|
|
|
SP[1] = 'P'; |
|
|
|
|
SP[2] = (char)7; |
|
|
|
|
SP[3] = (char)1; |
|
|
|
|
SP[4] = 0xbe; |
|
|
|
|
SP[5] = 0xef; |
|
|
|
|
SP[6] = 0; |
|
|
|
|
return susp_append(t, susp, SP); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Compute the length needed for write all RR and SUSP entries for a given |
|
|
|
|
* node. |
|
|
|
@ -33,7 +479,12 @@ size_t rrip_calc_len(Ecma119Image *t, Ecma119Node *n, int type,
|
|
|
|
|
{ |
|
|
|
|
size_t su_size; |
|
|
|
|
|
|
|
|
|
/* space min is 255 - 33 - 37 = 185 */ |
|
|
|
|
/* space min is 255 - 33 - 37 = 185
|
|
|
|
|
* At the same time, it is always an odd number, but we need to pad it |
|
|
|
|
* propertly to ensure the length of a directory record is a even number |
|
|
|
|
* (ECMA-119, 9.1.13). Thus, in fact the real space is always space - 1 |
|
|
|
|
*/ |
|
|
|
|
space--; |
|
|
|
|
|
|
|
|
|
/* PX and TF, we are sure they always fit in SUA */ |
|
|
|
|
su_size = 44 + 26; |
|
|
|
@ -118,10 +569,13 @@ size_t rrip_calc_len(Ecma119Image *t, Ecma119Node *n, int type,
|
|
|
|
|
su_size = space; |
|
|
|
|
cew = 1; |
|
|
|
|
} |
|
|
|
|
}
|
|
|
|
|
} else { |
|
|
|
|
} else { |
|
|
|
|
sl_len += clen; |
|
|
|
|
} |
|
|
|
|
}
|
|
|
|
|
if (cew) { |
|
|
|
|
if (sl_len + clen > 255) { |
|
|
|
|
/* we need an addition SL entry */ |
|
|
|
|
/* we need an additional SL entry */ |
|
|
|
|
if (clen > 250) { |
|
|
|
|
/*
|
|
|
|
|
* case 1, component too large to fit in a
|
|
|
|
@ -199,11 +653,384 @@ size_t rrip_calc_len(Ecma119Image *t, Ecma119Node *n, int type,
|
|
|
|
|
return su_size; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Free all info in a struct susp_info. |
|
|
|
|
*/ |
|
|
|
|
static |
|
|
|
|
void susp_info_free(struct susp_info* susp) |
|
|
|
|
{ |
|
|
|
|
size_t i; |
|
|
|
|
|
|
|
|
|
for (i = 0; i < susp->n_susp_fields; ++i) { |
|
|
|
|
free(susp->susp_fields[i]); |
|
|
|
|
} |
|
|
|
|
free(susp->susp_fields); |
|
|
|
|
|
|
|
|
|
for (i = 0; i < susp->n_ce_susp_fields; ++i) { |
|
|
|
|
free(susp->ce_susp_fields[i]); |
|
|
|
|
} |
|
|
|
|
free(susp->ce_susp_fields); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Fill a struct susp_info with the RR/SUSP entries needed for a given |
|
|
|
|
* node. |
|
|
|
|
*
|
|
|
|
|
* @param type |
|
|
|
|
* 0 normal entry, 1 "." entry for that node (it is a dir), 2 ".." |
|
|
|
|
* for that node (i.e., it will refer to the parent) |
|
|
|
|
* @param space |
|
|
|
|
* Available space in the System Use Area for the directory record. |
|
|
|
|
* @param info |
|
|
|
|
* Pointer to the struct susp_info where the entries will be stored. |
|
|
|
|
* If some entries need to go to a Continuation Area, they will be added |
|
|
|
|
* to the existing ce_susp_fields, and ce_len will be incremented |
|
|
|
|
* propertly. Please ensure ce_block is initialized propertly. |
|
|
|
|
* @return |
|
|
|
|
* 1 success, < 0 error |
|
|
|
|
*/ |
|
|
|
|
int rrip_get_susp_fields(Ecma119Image *t, Ecma119Node *n, int type,
|
|
|
|
|
size_t space, struct susp_info *info) |
|
|
|
|
{ |
|
|
|
|
//TODO to implement
|
|
|
|
|
return -1; |
|
|
|
|
int ret; |
|
|
|
|
size_t i; |
|
|
|
|
Ecma119Node *node; |
|
|
|
|
|
|
|
|
|
if (t == NULL || n == NULL || info == NULL) { |
|
|
|
|
return ISO_NULL_POINTER; |
|
|
|
|
} |
|
|
|
|
if (type < 0 || type > 2 || space < 185) { |
|
|
|
|
/* space min is 255 - 33 - 37 = 185 */ |
|
|
|
|
return ISO_WRONG_ARG_VALUE; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (type == 2 && n->parent != NULL) { |
|
|
|
|
node = n->parent; |
|
|
|
|
} else { |
|
|
|
|
node = n; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* space min is 255 - 33 - 37 = 185
|
|
|
|
|
* At the same time, it is always an odd number, but we need to pad it |
|
|
|
|
* propertly to ensure the length of a directory record is a even number |
|
|
|
|
* (ECMA-119, 9.1.13). Thus, in fact the real space is always space - 1 |
|
|
|
|
*/ |
|
|
|
|
space--; |
|
|
|
|
|
|
|
|
|
/* PX and TF, we are sure they always fit in SUA */ |
|
|
|
|
ret = rrip_add_PX(t, node, info); |
|
|
|
|
if (ret < 0) { |
|
|
|
|
goto add_susp_cleanup; |
|
|
|
|
} |
|
|
|
|
ret = rrip_add_TF(t, node, info); |
|
|
|
|
if (ret < 0) { |
|
|
|
|
goto add_susp_cleanup; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (n->type == ECMA119_DIR) { |
|
|
|
|
if (n->info.dir.real_parent != NULL) { |
|
|
|
|
/* it is a reallocated entry */ |
|
|
|
|
if (type == 2) { |
|
|
|
|
/*
|
|
|
|
|
* we need to add a PL entry |
|
|
|
|
* Note that we pass "n" as parameter, not "node"
|
|
|
|
|
*/ |
|
|
|
|
ret = rrip_add_PL(t, n, info); |
|
|
|
|
if (ret < 0) { |
|
|
|
|
goto add_susp_cleanup; |
|
|
|
|
} |
|
|
|
|
} else if (type == 0) { |
|
|
|
|
/* we need to add a RE entry */ |
|
|
|
|
ret = rrip_add_RE(t, node, info); |
|
|
|
|
if (ret < 0) { |
|
|
|
|
goto add_susp_cleanup; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} else if (n->type == ECMA119_SPECIAL) { |
|
|
|
|
if (S_ISBLK(n->node->mode) || S_ISCHR(n->node->mode)) { |
|
|
|
|
/* block or char device, we need a PN entry */ |
|
|
|
|
ret = rrip_add_PN(t, node, info); |
|
|
|
|
if (ret < 0) { |
|
|
|
|
goto add_susp_cleanup; |
|
|
|
|
} |
|
|
|
|
}
|
|
|
|
|
} else if (n->type == ECMA119_PLACEHOLDER) { |
|
|
|
|
/* we need the CL entry */ |
|
|
|
|
ret = rrip_add_CL(t, node, info); |
|
|
|
|
if (ret < 0) { |
|
|
|
|
goto add_susp_cleanup; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (type == 0) { |
|
|
|
|
char *name; |
|
|
|
|
size_t sua_free; /* free space in the SUA */ |
|
|
|
|
int nm_type = 0; /* 0 whole entry in SUA, 1 part in CE */ |
|
|
|
|
size_t ce_len = 0; /* len of the CE */ |
|
|
|
|
size_t namelen; |
|
|
|
|
|
|
|
|
|
/* this two are only defined for symlinks */ |
|
|
|
|
uint8_t **comps = NULL; /* components of the SL field */ |
|
|
|
|
size_t n_comp = 0; /* number of components */ |
|
|
|
|
|
|
|
|
|
// TODO handle output stream
|
|
|
|
|
name = n->node->name; |
|
|
|
|
namelen = strlen(name); |
|
|
|
|
|
|
|
|
|
sua_free = space - info->suf_len; |
|
|
|
|
|
|
|
|
|
/* NM entry */ |
|
|
|
|
if (5 + namelen <= sua_free) { |
|
|
|
|
/* ok, it fits in System Use Area */ |
|
|
|
|
sua_free -= (5 + namelen); |
|
|
|
|
nm_type = 0; |
|
|
|
|
} else { |
|
|
|
|
/* the NM will be divided in a CE */ |
|
|
|
|
sua_free = 0; |
|
|
|
|
nm_type = 1; |
|
|
|
|
namelen = namelen - (sua_free - 5 - 28); |
|
|
|
|
ce_len = 5 + namelen; |
|
|
|
|
} |
|
|
|
|
if (n->type == ECMA119_SYMLINK) { |
|
|
|
|
/*
|
|
|
|
|
* for symlinks, we also need to write the SL |
|
|
|
|
*/ |
|
|
|
|
char *cur, *prev; |
|
|
|
|
size_t sl_len = 5; |
|
|
|
|
int cew = (nm_type == 1); /* are we writing to CE? */ |
|
|
|
|
|
|
|
|
|
prev = ((IsoSymlink*)n->node)->dest; |
|
|
|
|
cur = strchr(prev, '/'); |
|
|
|
|
while (1) { |
|
|
|
|
size_t clen; |
|
|
|
|
char cflag = 0; /* component flag (RRIP, 4.1.3.1) */ |
|
|
|
|
if (cur) { |
|
|
|
|
clen = cur - prev; |
|
|
|
|
} else { |
|
|
|
|
/* last component */ |
|
|
|
|
clen = strlen(prev); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (clen == 0) { |
|
|
|
|
/* this refers to the roor directory, '/' */ |
|
|
|
|
cflag = 1 << 3; |
|
|
|
|
} if (clen == 1 && prev[0] == '.') { |
|
|
|
|
clen = 0; |
|
|
|
|
cflag = 1 << 1; |
|
|
|
|
} else if (clen == 2 && prev[0] == '.' && prev[1] == '.') { |
|
|
|
|
clen = 0; |
|
|
|
|
cflag = 1 << 2; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* flags and len for each component record (RRIP, 4.1.3.1) */ |
|
|
|
|
clen += 2; |
|
|
|
|
|
|
|
|
|
if (!cew) { |
|
|
|
|
/* we are still writing to the SUA */ |
|
|
|
|
if (sl_len + clen > sua_free) { |
|
|
|
|
/*
|
|
|
|
|
* ok, we need a Continuation Area anyway |
|
|
|
|
* TODO this can be handled better, but for now SL |
|
|
|
|
* will be completelly moved into the CA |
|
|
|
|
*/ |
|
|
|
|
if (28 <= sua_free) { |
|
|
|
|
/* the CE entry fills without reducing NM */ |
|
|
|
|
sua_free -= 28; //TODO needed?
|
|
|
|
|
cew = 1; |
|
|
|
|
} else { |
|
|
|
|
/* we need to reduce NM */ |
|
|
|
|
nm_type = 1; |
|
|
|
|
ce_len = (28 - sua_free) + 5; |
|
|
|
|
sua_free = 0;//su_size = space;
|
|
|
|
|
cew = 1; |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
/* add the component */ |
|
|
|
|
ret = rrip_SL_append_comp(&n_comp, &comps, prev,
|
|
|
|
|
clen - 2, cflag); |
|
|
|
|
if (ret < 0) { |
|
|
|
|
goto add_susp_cleanup; |
|
|
|
|
} |
|
|
|
|
sl_len += clen; |
|
|
|
|
} |
|
|
|
|
}
|
|
|
|
|
if (cew) { |
|
|
|
|
if (sl_len + clen > 255) { |
|
|
|
|
/* we need an addition SL entry */ |
|
|
|
|
if (clen > 250) { |
|
|
|
|
/*
|
|
|
|
|
* case 1, component too large to fit in a
|
|
|
|
|
* single SL entry. Thus, the component need |
|
|
|
|
* to be divided anyway. |
|
|
|
|
* Note than clen can be up to 255 + 2 = 257. |
|
|
|
|
*
|
|
|
|
|
* First, we check how many bytes fit in current |
|
|
|
|
* SL field
|
|
|
|
|
*/ |
|
|
|
|
int fit = 255 - sl_len - 2; |
|
|
|
|
if (clen - 250 <= fit) { |
|
|
|
|
/*
|
|
|
|
|
* the component can be divided between this |
|
|
|
|
* and another SL entry |
|
|
|
|
*/ |
|
|
|
|
ret = rrip_SL_append_comp(&n_comp, &comps,
|
|
|
|
|
prev, fit, cflag); |
|
|
|
|
if (ret < 0) { |
|
|
|
|
goto add_susp_cleanup; |
|
|
|
|
} |
|
|
|
|
/*
|
|
|
|
|
* and another component, that will go in
|
|
|
|
|
* other SL entry |
|
|
|
|
*/ |
|
|
|
|
ret = rrip_SL_append_comp(&n_comp, &comps,
|
|
|
|
|
prev + fit,
|
|
|
|
|
clen - fit - 2,
|
|
|
|
|
cflag); |
|
|
|
|
if (ret < 0) { |
|
|
|
|
goto add_susp_cleanup; |
|
|
|
|
} |
|
|
|
|
ce_len += 255; /* this SL, full */ |
|
|
|
|
sl_len = 5 + (clen - fit); |
|
|
|
|
} else { |
|
|
|
|
/*
|
|
|
|
|
* the component will need a 2rd SL entry in |
|
|
|
|
* any case, so we prefer to don't write
|
|
|
|
|
* anything in this SL |
|
|
|
|
*/ |
|
|
|
|
ret = rrip_SL_append_comp(&n_comp, &comps,
|
|
|
|
|
prev, 250 - 2,
|
|
|
|
|
cflag); |
|
|
|
|
if (ret < 0) { |
|
|
|
|
goto add_susp_cleanup; |
|
|
|
|
} |
|
|
|
|
ce_len += sl_len + 255; |
|
|
|
|
sl_len = 5 + (clen - 250); |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
/* case 2, create a new SL entry */ |
|
|
|
|
ret = rrip_SL_append_comp(&n_comp, &comps, prev,
|
|
|
|
|
clen - 2, cflag); |
|
|
|
|
if (ret < 0) { |
|
|
|
|
goto add_susp_cleanup; |
|
|
|
|
} |
|
|
|
|
ce_len += sl_len; |
|
|
|
|
sl_len = 5 + clen; |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
/* the component fit in the SL entry */ |
|
|
|
|
ret = rrip_SL_append_comp(&n_comp, &comps, prev,
|
|
|
|
|
clen - 2, cflag); |
|
|
|
|
if (ret < 0) { |
|
|
|
|
goto add_susp_cleanup; |
|
|
|
|
} |
|
|
|
|
sl_len += clen; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!cur || cur[1] == '\0') { |
|
|
|
|
/* cur[1] can be \0 if dest ends with '/' */ |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
prev = cur + 1; |
|
|
|
|
cur = strchr(prev, '/'); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (cew) { |
|
|
|
|
ce_len += sl_len; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* We we reach here: |
|
|
|
|
* - We know if NM fill in the SUA (nm_type == 0) |
|
|
|
|
* - If SL needs an to be written in CE (ce_len > 0) |
|
|
|
|
* - The components for SL entry (or entries) |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
if (nm_type == 0) { |
|
|
|
|
/* the full NM fills in SUA */ |
|
|
|
|
ret = rrip_add_NM(t, info, name, strlen(name), 0, 0); |
|
|
|
|
if (ret < 0) { |
|
|
|
|
goto add_susp_cleanup; |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
/* Write the NM part that fits in SUA... */ |
|
|
|
|
size_t len = info->suf_len - 28 - 5; |
|
|
|
|
ret = rrip_add_NM(t, info, name, len, 1, 0); |
|
|
|
|
if (ret < 0) { |
|
|
|
|
goto add_susp_cleanup; |
|
|
|
|
} |
|
|
|
|
/*
|
|
|
|
|
* ..and the part that goes to continuation area. Note that CE |
|
|
|
|
* entry in SUA in added below
|
|
|
|
|
*/ |
|
|
|
|
name += len; |
|
|
|
|
ret = rrip_add_NM(t, info, name, strlen(name), 0, 0); |
|
|
|
|
if (ret < 0) { |
|
|
|
|
goto add_susp_cleanup; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (ce_len > 0) { |
|
|
|
|
/* Add the CE entry */ |
|
|
|
|
ret = susp_add_CE(t, ce_len, info); |
|
|
|
|
if (ret < 0) { |
|
|
|
|
goto add_susp_cleanup; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (n->type == ECMA119_SYMLINK) { |
|
|
|
|
|
|
|
|
|
/* add the SL entry (or entries) */ |
|
|
|
|
ret = rrip_add_SL(t, info, comps, n_comp, (ce_len > 0)); |
|
|
|
|
|
|
|
|
|
/* free the components */ |
|
|
|
|
for (i = 0; i < n_comp; i++) { |
|
|
|
|
free(comps[i]); |
|
|
|
|
} |
|
|
|
|
free(comps); |
|
|
|
|
|
|
|
|
|
if (ret < 0) { |
|
|
|
|
goto add_susp_cleanup; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
|
|
/* "." or ".." entry */ |
|
|
|
|
|
|
|
|
|
/* write the NM entry */ |
|
|
|
|
ret = rrip_add_NM(t, info, NULL, 0, 1 << type, 0); |
|
|
|
|
if (ret < 0) { |
|
|
|
|
goto add_susp_cleanup; |
|
|
|
|
} |
|
|
|
|
if (type == 1 && n->parent == NULL) { |
|
|
|
|
/*
|
|
|
|
|
* "." for root directory
|
|
|
|
|
* we need to write SP and ER entries. The first fits in SUA, |
|
|
|
|
* ER needs a Continuation Area, thus we also need a CE entry |
|
|
|
|
*/ |
|
|
|
|
ret = susp_add_SP(t, info); |
|
|
|
|
if (ret < 0) { |
|
|
|
|
goto add_susp_cleanup; |
|
|
|
|
} |
|
|
|
|
ret = susp_add_CE(t, 182, info); /* 182 is ER length */ |
|
|
|
|
if (ret < 0) { |
|
|
|
|
goto add_susp_cleanup; |
|
|
|
|
} |
|
|
|
|
ret = rrip_add_ER(t, info); |
|
|
|
|
if (ret < 0) { |
|
|
|
|
goto add_susp_cleanup; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return ISO_SUCCESS; |
|
|
|
|
|
|
|
|
|
add_susp_cleanup:; |
|
|
|
|
susp_info_free(info); |
|
|
|
|
return ret; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void rrip_write_susp_fields(Ecma119Image *t, struct susp_info *info,
|
|
|
|
|