First pinch of libisofs rewrite

This commit is contained in:
Mario Danic
2006-08-24 19:23:37 +00:00
parent 176e1654ff
commit 48d76e844e
16 changed files with 1610 additions and 3065 deletions

View File

@ -1,409 +1,217 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
/* vim: set noet ts=8 sts=8 sw=8 : */
#include <dirent.h>
#include <stdio.h>
/**
* \file tree.c
*
* Implement filesystem trees.
*/
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <assert.h>
#include <dirent.h>
#include <libgen.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <err.h>
#include <stdio.h>
#include "libisofs.h"
#include "tree.h"
#include "util.h"
#include "volume.h"
struct iso_tree_dir *iso_tree_new_root(struct iso_volume *volume)
static void
set_default_stat(struct stat *s)
{
struct iso_tree_dir *dir;
time_t now = time(NULL);
assert(volume);
dir = calloc(1, sizeof(struct iso_tree_dir));
dir->attrib.st_mode = S_IFDIR;
dir->volume = volume;
return dir;
memset(s, 0, sizeof(struct stat));
s->st_mode = 0777 | S_IFREG;
s->st_atime = s->st_mtime = s->st_ctime = now;
}
void iso_tree_free(struct iso_tree_dir *root)
static struct stat
get_attrib(const struct iso_tree_node *node)
{
int i;
assert(root);
/* Free names. */
free(root->name.full);
free(root->name.iso1);
free(root->name.iso2);
free(root->name.rockridge);
free(root->name.joliet);
/* Free the children. */
for (i = 0; i < root->nchildren; i++)
iso_tree_free(root->children[i]);
free(root->children);
/* Free all files. */
for (i = 0; i < root->nfiles; i++) {
struct iso_tree_file *file = root->files[i];
free(file->path);
free(file->name.full);
free(file->name.iso1);
free(file->name.iso2);
free(file->name.rockridge);
free(file->name.joliet);
free(file);
}
free(root->files);
if (root->writer_data) {
fprintf(stderr, "Warning: freeing a directory with non-NULL "
"writer_data\n");
}
/* Free ourself. */
free(root);
}
struct iso_tree_file *iso_tree_add_new_file(struct iso_tree_dir *parent,
const char *name)
{
struct iso_tree_file *file;
assert(parent && name);
file = calloc(1, sizeof(struct iso_tree_file));
file->path = calloc(1, 1);
file->parent = parent;
file->volume = parent->volume;
file->attrib = parent->attrib;
file->attrib.st_mode &= ~S_IFMT;
file->attrib.st_mode |= S_IFREG;
file->attrib.st_size = 0;
iso_tree_file_set_name(file, name);
/* Add the new file to the parent directory */
parent->nfiles++;
parent->files = realloc(parent->files, sizeof(void *) * parent->nfiles);
parent->files[parent->nfiles - 1] = file;
return file;
}
struct iso_tree_file *iso_tree_add_file(struct iso_tree_dir *parent,
const char *path)
{
struct iso_tree_file *file;
struct stat st;
int statret;
const char *name;
assert( parent != NULL && path != NULL );
statret = lstat(path, &st);
if (statret == -1) {
fprintf(stderr, "couldn't stat file %s: %s\n",
path, strerror(errno));
return NULL;
if (node) {
return node->attrib;
}
/* Set up path, parent and volume. */
file = calloc(1, sizeof(struct iso_tree_file));
file->path = strdup(path);
file->parent = parent;
file->volume = parent->volume;
file->attrib = st;
/* find the last component in the path */
name = strrchr(path, '/');
if (name == NULL) {
name = path;
} else {
name++;
}
iso_tree_file_set_name(file, name);
if (!S_ISREG(st.st_mode)) {
file->attrib.st_size = 0;
}
/* Add the new file to the parent directory */
parent->nfiles++;
parent->files = realloc(parent->files, sizeof(void *) * parent->nfiles);
parent->files[parent->nfiles - 1] = file;
return file;
set_default_stat(&st);
return st;
}
struct iso_tree_dir *iso_tree_add_dir(struct iso_tree_dir *parent,
const char *path)
static void
append_node(struct iso_tree_node *parent,
struct iso_tree_node *child)
{
struct iso_tree_dir *dir;
struct stat st;
int statret;
char *pathcpy;
char *name;
assert( parent && path );
statret = stat(path, &st);
if (statret == -1) {
fprintf(stderr, "couldn't stat directory %s: %s\n",
path, strerror(errno));
return NULL;
}
dir = calloc(1, sizeof(struct iso_tree_dir));
dir->parent = parent;
dir->volume = parent->volume;
dir->attrib = st;
/* find the last component in the path. We need to copy the path because
* we modify it if there is a trailing slash. */
pathcpy = strdup(path);
name = strrchr(pathcpy, '/');
if (name == &pathcpy[strlen(pathcpy) - 1]) {
/* get rid of the trailing slash */
*name = '\0';
name = strrchr(pathcpy, '/');
}
if (name == NULL) {
name = pathcpy;
} else {
name++;
}
iso_tree_dir_set_name(dir, name);
free(pathcpy);
assert((!parent || S_ISDIR(parent->attrib.st_mode)) && child);
if (!parent)
return;
parent->nchildren++;
parent->children = realloc(parent->children,
parent->nchildren * sizeof(void*));
parent->children[parent->nchildren - 1] = dir;
return dir;
parent->children =
realloc(parent->children, parent->nchildren * sizeof(void*));
parent->children[parent->nchildren-1] = child;
}
struct iso_tree_dir *iso_tree_radd_dir(struct iso_tree_dir *parent,
const char *path)
struct iso_tree_node*
iso_tree_new_root(struct iso_volume *vol)
{
struct iso_tree_dir *nparent;
assert(vol);
if (vol->root) {
iso_tree_free(vol->root);
}
vol->root = calloc(1, sizeof(struct iso_tree_node));
vol->root->volume = vol;
set_default_stat(&vol->root->attrib);
vol->root->attrib.st_mode = S_IFDIR | 0777;
vol->root->loc.type = LIBISO_NONE;
return vol->root;
}
struct iso_tree_node*
iso_tree_add_new_file(struct iso_tree_node *parent, const char *name)
{
struct iso_tree_node *f = calloc(1, sizeof(struct iso_tree_node));
assert((!parent || S_ISDIR(parent->attrib.st_mode)) && name);
f->volume = parent ? parent->volume : NULL;
f->parent = parent;
f->name = parent ? towcs(name) : NULL;
f->attrib = get_attrib(parent);
f->attrib.st_mode = 0777 | S_IFREG;
f->loc.type = LIBISO_NONE;
append_node(parent, f);
return f;
}
struct iso_tree_node*
iso_tree_add_new_dir(struct iso_tree_node *parent, const char *name)
{
struct iso_tree_node *d = iso_tree_add_new_file(parent, name);
assert((!parent || S_ISDIR(parent->attrib.st_mode)) && name);
d->attrib.st_mode = (d->attrib.st_mode & ~S_IFMT) | S_IFDIR;
return d;
}
struct iso_tree_node*
iso_tree_add_node(struct iso_tree_node *parent, const char *path)
{
char *p;
struct stat st;
int statret;
struct iso_tree_node *ret;
assert((!parent || S_ISDIR(parent->attrib.st_mode)) && path);
if (lstat(path, &st) == -1)
return NULL;
p = strdup(path); /* because basename() might modify its arg */
/* it doesn't matter if we add a file or directory since we modify
* attrib anyway. */
ret = iso_tree_add_new_file(parent, basename(p));
ret->attrib = st;
ret->loc.type = LIBISO_FILESYS;
ret->loc.path = strdup(path);
free(p);
return ret;
}
struct iso_tree_node*
iso_tree_radd_dir (struct iso_tree_node *parent, const char *path)
{
struct iso_tree_node *new;
DIR *dir;
struct dirent *ent;
assert( parent && path );
statret = stat(path, &st);
assert((!parent || S_ISDIR(parent->attrib.st_mode)) && path);
nparent = iso_tree_add_dir(parent, path);
new = iso_tree_add_node(parent, path);
if (!new || !S_ISDIR(new->attrib.st_mode)) {
return new;
}
/* Open the directory for reading and iterate over the directory
entries. */
dir = opendir(path);
if (!dir) {
fprintf(stderr, "couldn't open directory %s: %s\n",
path, strerror(errno));
return NULL;
warn("couldn't open directory %s: %s\n", path, strerror(errno));
return new;
}
while ((ent = readdir(dir))) {
char *child;
char child[strlen(ent->d_name) + strlen(path) + 2];
/* Skip current and parent directory entries. */
if (strcmp(ent->d_name, ".") == 0 ||
strcmp(ent->d_name, "..") == 0)
strcmp(ent->d_name, "..") == 0)
continue;
/* Build the child's full pathname. */
child = iso_pathname(path, ent->d_name);
/* Skip to the next entry on errors. */
if (stat(child, &st) != 0)
continue;
if (S_ISDIR(st.st_mode)) {
iso_tree_radd_dir(nparent, child);
} else {
iso_tree_add_file(nparent, child);
}
free(child);
sprintf(child, "%s/%s", path, ent->d_name);
iso_tree_radd_dir(new, child);
}
closedir(dir);
return nparent;
return new;
}
struct iso_tree_dir *iso_tree_add_new_dir(struct iso_tree_dir *parent,
const char *name)
void
iso_tree_free(struct iso_tree_node *root)
{
struct iso_tree_dir *dir;
size_t i;
assert( parent && name );
dir = calloc(1, sizeof(struct iso_tree_dir));
dir->parent = parent;
dir->volume = parent->volume;
iso_tree_dir_set_name(dir, name);
dir->attrib = parent->attrib;
dir->attrib.st_mtime = time(NULL);
dir->attrib.st_atime = time(NULL);
dir->attrib.st_ctime = time(NULL);
/* add the new directory to parent */
parent->nchildren++;
parent->children = realloc(parent->children,
parent->nchildren * sizeof(void*));
parent->children[parent->nchildren - 1] = dir;
return dir;
}
void iso_tree_file_set_name(struct iso_tree_file *file, const char *name)
{
file->name.full = strdup(name);
file->name.iso1 = iso_1_fileid(name);
file->name.iso2 = iso_2_fileid(name);
file->name.rockridge = iso_p_filename(name);
file->name.joliet = iso_j_id(file->name.full);
}
char *iso_tree_node_get_name_nconst(const struct iso_tree_node *node,
enum iso_name_version ver)
{
if (ver == ISO_NAME_ISO) {
if (node->volume->iso_level == 1) {
return node->name.iso1;
} else {
return node->name.iso2;
}
for (i=0; i < root->nchildren; i++) {
iso_tree_free(root->children[i]);
}
switch (ver) {
case ISO_NAME_FULL:
return node->name.full;
case ISO_NAME_ISO:
if (node->volume->iso_level == 1) {
return node->name.iso1;
} else {
return node->name.iso2;
}
case ISO_NAME_ISO_L1:
return node->name.iso1;
case ISO_NAME_ISO_L2:
return node->name.iso2;
case ISO_NAME_ROCKRIDGE:
return node->name.rockridge;
case ISO_NAME_JOLIET:
return (char*) node->name.joliet;
}
assert(0);
return NULL; /* just to shut up warnings */
free(root->name);
free(root->children);
free(root);
}
const char *iso_tree_node_get_name(const struct iso_tree_node *node,
enum iso_name_version ver)
void
iso_tree_print(const struct iso_tree_node *root, int spaces)
{
return iso_tree_node_get_name_nconst(node, ver);
}
size_t i;
char sp[spaces+1];
void iso_tree_dir_set_name(struct iso_tree_dir *dir, const char *name)
{
dir->name.full = strdup(name);
/* Level 1 directory is a string of d-characters of maximum size 8. */
dir->name.iso1 = iso_d_str(name, 8, 0);
/* Level 2 directory is a string of d-characters of maximum size 31. */
dir->name.iso2 = iso_d_str(name, 31, 0);
dir->name.rockridge = iso_p_dirname(name);
dir->name.joliet = iso_j_id(dir->name.full);
}
memset(sp, ' ', spaces);
sp[spaces] = '\0';
/* Compares file names for use with qsort. */
int iso_node_cmp(const void *v1, const void *v2)
{
struct iso_tree_node **f1 = (struct iso_tree_node **)v1;
struct iso_tree_node **f2 = (struct iso_tree_node **)v2;
return strcmp(iso_tree_node_get_name(*f1, ISO_NAME_FULL),
iso_tree_node_get_name(*f2, ISO_NAME_FULL));
}
int iso_node_cmp_iso(const void *v1, const void *v2)
{
struct iso_tree_node **f1 = (struct iso_tree_node **)v1;
struct iso_tree_node **f2 = (struct iso_tree_node **)v2;
return strcmp(iso_tree_node_get_name(*f1, ISO_NAME_ISO),
iso_tree_node_get_name(*f2, ISO_NAME_ISO));
}
int iso_node_cmp_joliet(const void *v1, const void *v2)
{
struct iso_tree_node **f1 = (struct iso_tree_node **)v1;
struct iso_tree_node **f2 = (struct iso_tree_node **)v2;
return ucscmp((uint16_t*)iso_tree_node_get_name(*f1, ISO_NAME_JOLIET),
(uint16_t*)iso_tree_node_get_name(*f2, ISO_NAME_JOLIET));
}
void iso_tree_sort(struct iso_tree_dir *root)
{
int i;
qsort(root->files, root->nfiles, sizeof(struct iso_tree_file *),
iso_node_cmp);
qsort(root->children, root->nchildren, sizeof(struct iso_tree_dir *),
iso_node_cmp);
for (i = 0; i < root->nchildren; i++)
iso_tree_sort(root->children[i]);
}
void iso_tree_print(const struct iso_tree_dir *root, int spaces)
{
iso_tree_print_verbose(root, NULL, NULL, NULL, spaces);
}
void iso_tree_print_verbose(const struct iso_tree_dir *root,
print_dir_callback dc, print_file_callback fc,
void *data, int spaces)
{
int i, j;
for (i = 0; i < spaces; i++)
printf(" ");
/* Root directory doesn't have a name. */
if (root->name.full != NULL)
printf("%s", iso_tree_node_get_name(ISO_NODE(root),
ISO_NAME_ISO));
printf("/\n");
if (dc) dc(root, data, spaces);
spaces += 2;
for (j = 0; j < root->nchildren; j++) {
iso_tree_print_verbose(root->children[j], dc, fc, data,
spaces);
}
for (j = 0; j < root->nfiles; j++) {
for (i = 0; i < spaces; i++)
printf(" ");
printf("%s\n",
iso_tree_node_get_name(ISO_NODE(root->files[j]),
ISO_NAME_ISO));
if (fc) fc(root->files[j], data, spaces);
printf("%s%ls\n", sp, root->name);
for (i=0; i < root->nchildren; i++) {
iso_tree_print(root->children[i], spaces+2);
}
}
void
iso_tree_print_verbose(const struct iso_tree_node *root,
print_dir_callback dir,
print_file_callback file,
void *callback_data,
int spaces)
{
size_t i;
(S_ISDIR(root->attrib.st_mode) ? dir : file)
(root, callback_data, spaces);
for (i=0; i < root->nchildren; i++) {
iso_tree_print_verbose(root->children[i], dir,
file, callback_data, spaces+2);
}
}
void
iso_tree_node_set_name(struct iso_tree_node *file, const char *name)
{
free(file->name);
file->name = towcs(name);
}