libisofs-legacy/libisofs/rockridge.c
2006-08-15 20:37:04 +00:00

300 lines
6.6 KiB
C
Executable File

/* vim: set noet ts=8 sts=8 sw=8 : */
#include "rockridge.h"
#include "tree.h"
#include "util.h"
#include "volume.h"
#include "ecma119.h"
#include "susp.h"
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <unistd.h>
#include <sys/stat.h>
/* create a PX field from the permissions on the current node. */
unsigned char *rrip_make_PX(struct ecma119_write_target *t,
struct iso_tree_node *node)
{
unsigned char *PX = malloc(44);
PX[0] = 'P';
PX[1] = 'X';
PX[2] = 44;
PX[3] = 1;
iso_bb(&PX[4], node->attrib.st_mode, 4);
iso_bb(&PX[12], node->attrib.st_nlink, 4);
iso_bb(&PX[20], node->attrib.st_uid, 4);
iso_bb(&PX[28], node->attrib.st_gid, 4);
iso_bb(&PX[36], node->attrib.st_ino, 4);
return PX;
}
/** See IEEE 1282 4.1.1 */
void rrip_add_PX(struct ecma119_write_target *t, struct iso_tree_node *node)
{
susp_append(t, node, rrip_make_PX(t, node));
}
void rrip_add_PX_dir(struct ecma119_write_target *t, struct iso_tree_dir *dir)
{
susp_append(t, ISO_NODE(dir), rrip_make_PX(t, ISO_NODE(dir)));
susp_append_self(t, dir, rrip_make_PX(t, ISO_NODE(dir)));
susp_append_parent(t, dir, rrip_make_PX(t, ISO_NODE(dir)));
}
void rrip_add_PN(struct ecma119_write_target *t, struct iso_tree_node *node)
{
unsigned char *PN = malloc(20);
PN[0] = 'P';
PN[1] = 'N';
PN[2] = 20;
PN[3] = 1;
iso_bb(&PN[4], node->attrib.st_dev >> 32, 4);
iso_bb(&PN[12], node->attrib.st_dev & 0xffffffff, 4);
susp_append(t, node, PN);
}
static void rrip_SL_append_comp(int *n, unsigned char ***comps,
char *s, int size, char fl)
{
unsigned char *comp = malloc(size + 2);
(*n)++;
comp[0] = fl;
comp[1] = size;
*comps = realloc(*comps, (*n) * sizeof(void*));
(*comps)[(*n) - 1] = comp;
if (size) {
memcpy(&comp[2], s, size);
}
}
static void rrip_SL_add_component(char *prev, char *cur, int *n_comp,
unsigned char ***comps)
{
int size = cur - prev;
if (size == 0) {
rrip_SL_append_comp(n_comp, comps, prev, 0, 1 << 3);
return;
}
if (size == 1 && prev[0] == '.') {
rrip_SL_append_comp(n_comp, comps, prev, 0, 1 << 1);
return;
}
if (size == 2 && !strncmp(prev, "..", 2)) {
rrip_SL_append_comp(n_comp, comps, prev, 0, 1 << 2);
return;
}
/* we can't make a component any bigger than 250 (is this really a
problem)? because then it won't fit inside the SL field */
while (size > 248) {
size -= 248;
rrip_SL_append_comp(n_comp, comps, prev, 248, 1 << 0);
}
rrip_SL_append_comp(n_comp, comps, prev, size, 0);
}
void rrip_add_SL(struct ecma119_write_target *t, struct iso_tree_node *node)
{
int ret, pathsize = 0;
char *path = NULL, *cur, *prev;
struct iso_tree_file *file = (struct iso_tree_file *)node;
int i, j;
unsigned char **comp = NULL;
int n_comp = 0;
int total_comp_len = 0;
int written = 0, pos;
unsigned char *SL;
do {
pathsize += 128;
path = realloc(path, pathsize);
ret = readlink(file->path, path, pathsize);
} while (ret == pathsize);
if (ret == -1) {
fprintf(stderr, "Error: couldn't read symlink: %s\n",
strerror(errno));
return;
}
path[ret] = '\0';
prev = path;
for (cur = strchr(path, '/'); cur && *cur; cur = strchr(cur, '/')) {
rrip_SL_add_component(prev, cur, &n_comp, &comp);
cur++;
prev = cur;
}
/* if there was no trailing '/', we need to add the last component. */
if (prev == path || prev != &path[ret - 1]) {
rrip_SL_add_component(prev, &path[ret], &n_comp, &comp);
}
for (i = 0; i < n_comp; i++) {
total_comp_len += comp[i][1] + 2;
if (total_comp_len > 250) {
total_comp_len -= comp[i][1] + 2;
SL = malloc(total_comp_len + 5);
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];
}
susp_append(t, node, SL);
written = i - 1;
total_comp_len = comp[i][1];
}
}
SL = malloc(total_comp_len + 5);
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_comp; j++) {
memcpy(&SL[pos], comp[j], comp[j][1] + 2);
pos += comp[j][1] + 2;
}
susp_append(t, node, SL);
free(path);
/* free the components */
for (i = 0; i < n_comp; i++) {
free(comp[i]);
}
free(comp);
}
static void rrip_add_NM_single(struct ecma119_write_target *t,
struct iso_tree_node *node,
char *name, int size, int flags)
{
unsigned char *NM = malloc(size + 5);
NM[0] = 'N';
NM[1] = 'M';
NM[2] = size + 5;
NM[3] = 1;
NM[4] = flags;
if (size) {
memcpy(&NM[5], name, size);
}
susp_append(t, node, NM);
}
void rrip_add_NM(struct ecma119_write_target *t, struct iso_tree_node *node)
{
struct iso_tree_file *file = (struct iso_tree_file *)node;
int len = strlen(file->name.rockridge);
char *pos = file->name.rockridge;
if (len == 1 && pos[0] == '.') {
rrip_add_NM_single(t, node, pos, 0, 1 << 1);
return;
}
if (len == 2 && !strncmp(pos, "..", 2)) {
rrip_add_NM_single(t, node, pos, 0, 1 << 2);
return;
}
while (len > 250) {
rrip_add_NM_single(t, node, pos, 250, 1);
len -= 250;
pos += 250;
}
rrip_add_NM_single(t, node, pos, len, 0);
}
void rrip_add_CL(struct ecma119_write_target *t, struct iso_tree_node *node)
{
unsigned char *CL = calloc(1, 12);
CL[0] = 'C';
CL[1] = 'L';
CL[2] = 12;
CL[3] = 1;
susp_append(t, node, CL);
}
void rrip_add_PL(struct ecma119_write_target *t, struct iso_tree_dir *node)
{
unsigned char *PL = calloc(1, 12);
PL[0] = 'P';
PL[1] = 'L';
PL[2] = 12;
PL[3] = 1;
susp_append_parent(t, node, PL);
}
void rrip_add_RE(struct ecma119_write_target *t, struct iso_tree_node *node)
{
unsigned char *RE = malloc(4);
RE[0] = 'R';
RE[1] = 'E';
RE[2] = 4;
RE[3] = 1;
susp_append(t, node, RE);
}
void rrip_add_TF(struct ecma119_write_target *t, struct iso_tree_node *node)
{
unsigned char *TF = malloc(5 + 3 * 17);
TF[0] = 'T';
TF[1] = 'F';
TF[2] = 5 + 3 * 17;
TF[3] = 1;
TF[4] = (1 << 1) | (1 << 2) | (1 << 3) | (1 << 7);
iso_datetime_17(&TF[5], node->attrib.st_mtime);
iso_datetime_17(&TF[22], node->attrib.st_atime);
iso_datetime_17(&TF[39], node->attrib.st_ctime);
susp_append(t, node, TF);
}
void rrip_finalize(struct ecma119_write_target *t, struct iso_tree_dir *dir)
{
struct dir_write_info *inf;
struct file_write_info *finf;
int i;
inf = dir->writer_data;
if (dir->parent != inf->real_parent) {
unsigned char *PL = susp_find(&inf->parent_susp, "PL");
iso_bb(&PL[4], inf->real_parent->block, 4);
}
for (i = 0; i < dir->nfiles; i++) {
finf = dir->files[i]->writer_data;
if (finf->real_me) {
unsigned char *CL = susp_find(&finf->susp, "CL");
iso_bb(&CL[4], finf->real_me->block, 4);
}
}
for (i = 0; i < dir->nchildren; i++) {
rrip_finalize(t, dir->children[i]);
}
}