Marked libisofs SVN copy as outdated (use bzr on lp)
This commit is contained in:
662
libisofs_outdated/attic/libisofs/tree.c
Normal file
662
libisofs_outdated/attic/libisofs/tree.c
Normal file
@ -0,0 +1,662 @@
|
||||
/* vim: set noet ts=8 sts=8 sw=8 : */
|
||||
|
||||
/**
|
||||
* \file tree.c
|
||||
*
|
||||
* Implement filesystem trees.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.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 "tree.h"
|
||||
#include "exclude.h"
|
||||
|
||||
static void
|
||||
set_default_stat(struct stat *s)
|
||||
{
|
||||
time_t now = time(NULL);
|
||||
|
||||
memset(s, 0, sizeof(struct stat));
|
||||
s->st_mode = 0555;
|
||||
s->st_atime = s->st_mtime = s->st_ctime = now;
|
||||
}
|
||||
|
||||
void
|
||||
iso_tree_add_child(struct iso_tree_node_dir *parent,
|
||||
struct iso_tree_node *child)
|
||||
{
|
||||
assert(parent && child);
|
||||
assert(!child->parent);
|
||||
|
||||
parent->nchildren++;
|
||||
parent->children =
|
||||
realloc(parent->children, parent->nchildren * sizeof(void*));
|
||||
parent->children[parent->nchildren-1] = child;
|
||||
child->parent = parent;
|
||||
}
|
||||
|
||||
struct iso_tree_node_dir*
|
||||
iso_tree_new_root()
|
||||
{
|
||||
struct iso_tree_node_dir *root;
|
||||
|
||||
root = calloc(1, sizeof(struct iso_tree_node_dir));
|
||||
|
||||
set_default_stat(&root->node.attrib);
|
||||
root->node.refcount = 1;
|
||||
root->node.attrib.st_mode = S_IFDIR | 0777;
|
||||
root->node.type = LIBISO_NODE_DIR;
|
||||
return root;
|
||||
}
|
||||
|
||||
struct iso_tree_node*
|
||||
iso_tree_add_file(struct iso_tree_node_dir *parent, const char *path)
|
||||
{
|
||||
struct iso_tree_node_file *f;
|
||||
char *p;
|
||||
struct stat st;
|
||||
|
||||
assert( parent && path);
|
||||
|
||||
if (lstat(path, &st) == -1) {
|
||||
libisofs_errno = NO_FILE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( !S_ISREG(st.st_mode) ) {
|
||||
libisofs_errno = UNEXPECTED_FILE_TYPE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( access(path, R_OK) ) {
|
||||
libisofs_errno = NO_READ_ACCESS;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
f = calloc(1, sizeof(struct iso_tree_node_file));
|
||||
|
||||
/* fill fields */
|
||||
f->node.refcount = 1;
|
||||
f->node.attrib = st;
|
||||
f->loc.path = strdup(path);
|
||||
f->node.type = LIBISO_NODE_FILE;
|
||||
|
||||
p = strdup(path); /* because basename() might modify its arg */
|
||||
f->node.name = strdup( basename(p) );
|
||||
free(p);
|
||||
|
||||
/* add to parent (this also sets f->node->parent) */
|
||||
iso_tree_add_child(parent, (struct iso_tree_node*) f);
|
||||
|
||||
return (struct iso_tree_node*) f;
|
||||
}
|
||||
|
||||
struct iso_tree_node*
|
||||
iso_tree_add_symlink(struct iso_tree_node_dir *parent,
|
||||
const char *name, const char *dest)
|
||||
{
|
||||
struct iso_tree_node_symlink *link;
|
||||
|
||||
assert( parent && name && dest);
|
||||
|
||||
link = calloc(1, sizeof(struct iso_tree_node_symlink));
|
||||
|
||||
/* fill fields */
|
||||
set_default_stat(&link->node.attrib);
|
||||
link->node.refcount = 1;
|
||||
link->node.attrib.st_mode |= S_IFLNK;
|
||||
link->node.name = strdup(name);
|
||||
link->node.type = LIBISO_NODE_SYMLINK;
|
||||
link->dest = strdup(dest);
|
||||
|
||||
/* add to parent (this also sets link->node->parent) */
|
||||
iso_tree_add_child(parent, (struct iso_tree_node*) link);
|
||||
|
||||
return (struct iso_tree_node*) link;
|
||||
}
|
||||
|
||||
struct iso_tree_node_dir*
|
||||
iso_tree_add_dir(struct iso_tree_node_dir *parent,
|
||||
const char *name)
|
||||
{
|
||||
struct iso_tree_node_dir *dir;
|
||||
|
||||
assert( parent && name );
|
||||
|
||||
dir = calloc(1, sizeof(struct iso_tree_node_dir));
|
||||
|
||||
dir->node.refcount = 1;
|
||||
dir->node.attrib = parent->node.attrib;
|
||||
dir->node.type = LIBISO_NODE_DIR;
|
||||
dir->node.name = strdup(name);
|
||||
|
||||
iso_tree_add_child(parent, (struct iso_tree_node*) dir);
|
||||
return dir;
|
||||
}
|
||||
|
||||
enum iso_tree_node_type
|
||||
iso_tree_node_get_type(struct iso_tree_node *node)
|
||||
{
|
||||
assert(node);
|
||||
return node->type;
|
||||
}
|
||||
|
||||
void
|
||||
iso_tree_node_set_name(struct iso_tree_node *node, const char *name)
|
||||
{
|
||||
free(node->name);
|
||||
node->name = strdup(name);
|
||||
}
|
||||
|
||||
const char *
|
||||
iso_tree_node_get_name(struct iso_tree_node *node)
|
||||
{
|
||||
assert(node);
|
||||
return node->name;
|
||||
}
|
||||
|
||||
void
|
||||
iso_tree_node_set_hidden(struct iso_tree_node *node, int hide_attrs)
|
||||
{
|
||||
assert(node);
|
||||
node->hide_flags = hide_attrs;
|
||||
}
|
||||
|
||||
int
|
||||
iso_tree_node_is_hidden(struct iso_tree_node *node)
|
||||
{
|
||||
assert(node);
|
||||
return node->hide_flags;
|
||||
}
|
||||
|
||||
void
|
||||
iso_tree_node_set_gid(struct iso_tree_node *node, gid_t gid)
|
||||
{
|
||||
assert(node);
|
||||
node->attrib.st_gid = gid;
|
||||
}
|
||||
|
||||
gid_t
|
||||
iso_tree_node_get_gid(struct iso_tree_node *node)
|
||||
{
|
||||
assert(node);
|
||||
return node->attrib.st_gid;
|
||||
}
|
||||
|
||||
void
|
||||
iso_tree_node_set_uid(struct iso_tree_node *node, uid_t uid)
|
||||
{
|
||||
assert(node);
|
||||
node->attrib.st_uid = uid;
|
||||
}
|
||||
|
||||
uid_t
|
||||
iso_tree_node_get_uid(struct iso_tree_node *node)
|
||||
{
|
||||
assert(node);
|
||||
return node->attrib.st_uid;
|
||||
}
|
||||
|
||||
void
|
||||
iso_tree_node_set_permissions(struct iso_tree_node *node, mode_t mode)
|
||||
{
|
||||
assert(node);
|
||||
node->attrib.st_mode = (node->attrib.st_mode & S_IFMT) |
|
||||
(mode & ~S_IFMT);
|
||||
}
|
||||
|
||||
mode_t
|
||||
iso_tree_node_get_permissions(struct iso_tree_node *node)
|
||||
{
|
||||
assert(node);
|
||||
return node->attrib.st_mode & ~S_IFMT;
|
||||
}
|
||||
|
||||
off_t
|
||||
iso_tree_node_get_size(struct iso_tree_node *node)
|
||||
{
|
||||
return node->attrib.st_size;
|
||||
}
|
||||
|
||||
void
|
||||
iso_tree_node_set_mtime(struct iso_tree_node *node, time_t time)
|
||||
{
|
||||
node->attrib.st_mtime = time;
|
||||
}
|
||||
|
||||
time_t
|
||||
iso_tree_node_get_mtime(struct iso_tree_node *node)
|
||||
{
|
||||
return node->attrib.st_mtime;
|
||||
}
|
||||
|
||||
void
|
||||
iso_tree_node_set_atime(struct iso_tree_node *node, time_t time)
|
||||
{
|
||||
node->attrib.st_atime = time;
|
||||
}
|
||||
|
||||
time_t
|
||||
iso_tree_node_get_atime(struct iso_tree_node *node)
|
||||
{
|
||||
return node->attrib.st_atime;
|
||||
}
|
||||
|
||||
void
|
||||
iso_tree_node_set_ctime(struct iso_tree_node *node, time_t time)
|
||||
{
|
||||
node->attrib.st_ctime = time;
|
||||
}
|
||||
|
||||
time_t
|
||||
iso_tree_node_get_ctime(struct iso_tree_node *node)
|
||||
{
|
||||
return node->attrib.st_ctime;
|
||||
}
|
||||
|
||||
void
|
||||
iso_tree_node_set_sort_weight(struct iso_tree_node *node, int w)
|
||||
{
|
||||
assert(node);
|
||||
if ( ISO_ISDIR(node) ) {
|
||||
size_t i;
|
||||
struct iso_tree_node_dir *dir;
|
||||
dir = (struct iso_tree_node_dir *) node;
|
||||
for (i=0; i < dir->nchildren; i++) {
|
||||
iso_tree_node_set_sort_weight(dir->children[i], w);
|
||||
}
|
||||
} else if ( ISO_ISREG(node) ) {
|
||||
struct iso_tree_node_file *file;
|
||||
file = (struct iso_tree_node_file *) node;
|
||||
file->sort_weight = w;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
iso_tree_node_symlink_set_dest(struct iso_tree_node_symlink *node,
|
||||
const char *dest)
|
||||
{
|
||||
assert(node && dest);
|
||||
free(node->dest);
|
||||
node->dest = strdup(dest);
|
||||
}
|
||||
|
||||
const char *
|
||||
iso_tree_node_symlink_get_dest(struct iso_tree_node_symlink *node)
|
||||
{
|
||||
assert(node);
|
||||
return node->dest;
|
||||
}
|
||||
|
||||
struct iso_tree_node*
|
||||
iso_tree_add_node(struct iso_tree_node_dir *parent,
|
||||
const char *path)
|
||||
{
|
||||
struct stat st;
|
||||
struct iso_tree_node *node;
|
||||
|
||||
assert( parent && path);
|
||||
|
||||
if (lstat(path, &st) == -1) {
|
||||
libisofs_errno = NO_FILE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( access(path, R_OK) ) {
|
||||
libisofs_errno = NO_READ_ACCESS;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch (st.st_mode & S_IFMT) {
|
||||
case S_IFREG:
|
||||
/* regular file */
|
||||
node = iso_tree_add_file(parent, path);
|
||||
break;
|
||||
case S_IFLNK:
|
||||
/* symlink */
|
||||
{
|
||||
char dest[PATH_MAX];
|
||||
char *p;
|
||||
int n;
|
||||
|
||||
n = readlink(path, dest, PATH_MAX);
|
||||
if ( n == -1 ) {
|
||||
libisofs_errno = INTERNAL_ERROR;
|
||||
return NULL;
|
||||
}
|
||||
dest[n] = '\0';
|
||||
p = strdup(path); /* because basename() might modify its arg */
|
||||
node = iso_tree_add_symlink(parent, basename(p), dest);
|
||||
free(p);
|
||||
node->attrib = st;
|
||||
}
|
||||
break;
|
||||
case S_IFDIR:
|
||||
/* directory */
|
||||
{
|
||||
char *p;
|
||||
p = strdup(path); /* because basename() might modify its arg */
|
||||
node = (struct iso_tree_node*) iso_tree_add_dir(parent, basename(p));
|
||||
free(p);
|
||||
node->attrib = st;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
libisofs_errno = UNEXPECTED_FILE_TYPE;
|
||||
node = NULL;
|
||||
break;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
struct iso_tree_iter *
|
||||
iso_tree_node_children(struct iso_tree_node_dir *dir)
|
||||
{
|
||||
struct iso_tree_iter *iter;
|
||||
assert(dir);
|
||||
iter = malloc(sizeof(struct iso_tree_iter));
|
||||
iter->dir = dir;
|
||||
iter->index = -1;
|
||||
return iter;
|
||||
}
|
||||
|
||||
struct iso_tree_node *
|
||||
iso_tree_iter_next(struct iso_tree_iter *iter)
|
||||
{
|
||||
assert(iter);
|
||||
if ( ++iter->index < iter->dir->nchildren )
|
||||
return iter->dir->children[iter->index];
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
iso_tree_iter_has_next(struct iso_tree_iter *iter)
|
||||
{
|
||||
assert(iter);
|
||||
return iter->index + 1 < iter->dir->nchildren;
|
||||
}
|
||||
|
||||
void
|
||||
iso_tree_iter_free(struct iso_tree_iter *iter)
|
||||
{
|
||||
free(iter);
|
||||
}
|
||||
|
||||
int
|
||||
iso_tree_node_take(struct iso_tree_node_dir *dir, struct iso_tree_node *node)
|
||||
{
|
||||
int i;
|
||||
assert(dir && node);
|
||||
|
||||
/* search for the node in the dir */
|
||||
for (i = 0; i < dir->nchildren; ++i) {
|
||||
if ( dir->children[i] == node )
|
||||
break;
|
||||
}
|
||||
|
||||
if (i < dir->nchildren) {
|
||||
int j;
|
||||
for (j = i+1; j < dir->nchildren; ++j) {
|
||||
dir->children[j-1] = dir->children[j];
|
||||
}
|
||||
--dir->nchildren;
|
||||
dir->children = realloc(dir->children, dir->nchildren * sizeof(void*));
|
||||
node->parent = NULL;
|
||||
return 0;
|
||||
} else {
|
||||
/* the node doesn't exist on dir */
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
iso_tree_node_remove(struct iso_tree_node_dir *dir, struct iso_tree_node *node)
|
||||
{
|
||||
int res;
|
||||
assert(dir && node);
|
||||
res = iso_tree_node_take(dir, node);
|
||||
if (!res)
|
||||
iso_tree_free(node);
|
||||
return res;
|
||||
}
|
||||
|
||||
int
|
||||
iso_tree_node_take_iter(struct iso_tree_iter *iter)
|
||||
{
|
||||
int j;
|
||||
struct iso_tree_node_dir *dir;
|
||||
struct iso_tree_node *node;
|
||||
|
||||
assert(iter);
|
||||
|
||||
dir = iter->dir;
|
||||
|
||||
if (iter->index < 0)
|
||||
return -1; /* index before beginning */
|
||||
|
||||
if (iter->index >= dir->nchildren)
|
||||
return -2; /* index after end */
|
||||
|
||||
node = dir->children[iter->index];
|
||||
node->parent = NULL;
|
||||
for (j = iter->index+1; j < dir->nchildren; ++j) {
|
||||
dir->children[j-1] = dir->children[j];
|
||||
}
|
||||
--dir->nchildren;
|
||||
dir->children = realloc(dir->children, dir->nchildren * sizeof(void*));
|
||||
|
||||
/* update iter index */
|
||||
--iter->index;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
iso_tree_node_remove_iter(struct iso_tree_iter *iter)
|
||||
{
|
||||
int j;
|
||||
struct iso_tree_node_dir *dir;
|
||||
struct iso_tree_node *node;
|
||||
|
||||
assert(iter);
|
||||
|
||||
dir = iter->dir;
|
||||
|
||||
if (iter->index < 0)
|
||||
return -1; /* index before beginning */
|
||||
|
||||
if (iter->index >= dir->nchildren)
|
||||
return -2; /* index after end */
|
||||
|
||||
node = dir->children[iter->index];
|
||||
for (j = iter->index+1; j < dir->nchildren; ++j) {
|
||||
dir->children[j-1] = dir->children[j];
|
||||
}
|
||||
--dir->nchildren;
|
||||
dir->children = realloc(dir->children, dir->nchildren * sizeof(void*));
|
||||
|
||||
/* update iter index */
|
||||
--iter->index;
|
||||
|
||||
/* and free node */
|
||||
node->parent = NULL;
|
||||
iso_tree_free(node);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct iso_tree_node_dir *
|
||||
iso_tree_node_get_parent(struct iso_tree_node *node)
|
||||
{
|
||||
assert(node);
|
||||
return node->parent;
|
||||
}
|
||||
|
||||
void
|
||||
iso_tree_node_ref(struct iso_tree_node *node)
|
||||
{
|
||||
++node->refcount;
|
||||
}
|
||||
|
||||
void
|
||||
iso_tree_free(struct iso_tree_node *root)
|
||||
{
|
||||
if (!root)
|
||||
return;
|
||||
if (--root->refcount < 1) {
|
||||
if ( ISO_ISDIR(root) ) {
|
||||
size_t i;
|
||||
struct iso_tree_node_dir *dir;
|
||||
dir = (struct iso_tree_node_dir *) root;
|
||||
for (i=0; i < dir->nchildren; i++) {
|
||||
iso_tree_free(dir->children[i]);
|
||||
}
|
||||
free(dir->children);
|
||||
} else if ( ISO_ISLNK(root) ) {
|
||||
struct iso_tree_node_symlink *link;
|
||||
link = (struct iso_tree_node_symlink *) root;
|
||||
free(link->dest);
|
||||
} else if ( ISO_ISREG(root) ) {
|
||||
struct iso_tree_node_file *file;
|
||||
file = (struct iso_tree_node_file *) root;
|
||||
if (root->procedence == LIBISO_NEW)
|
||||
free(file->loc.path);
|
||||
} else if ( ISO_ISBOOT(root) ) {
|
||||
struct iso_tree_node_boot *boot;
|
||||
boot = (struct iso_tree_node_boot *) root;
|
||||
if (root->procedence == LIBISO_NEW && boot->img)
|
||||
free(boot->loc.path);
|
||||
}
|
||||
free(root->name);
|
||||
free(root);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
iso_tree_radd_dir_aux(struct iso_tree_node_dir *parent, const char *path,
|
||||
struct iso_tree_radd_dir_behavior *behavior,
|
||||
struct iso_hash_table *excludes)
|
||||
{
|
||||
struct iso_tree_node *new;
|
||||
DIR *dir;
|
||||
struct dirent *ent;
|
||||
|
||||
dir = opendir(path);
|
||||
if (!dir) {
|
||||
warn("couldn't open directory %s: %s\n", path, strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
while ((ent = readdir(dir))) {
|
||||
char child[strlen(ent->d_name) + strlen(path) + 2];
|
||||
|
||||
if (behavior->stop_on_error & behavior->error)
|
||||
break;
|
||||
|
||||
if (strcmp(ent->d_name, ".") == 0 ||
|
||||
strcmp(ent->d_name, "..") == 0)
|
||||
continue;
|
||||
|
||||
//TODO check if path already finished in '/'
|
||||
sprintf(child, "%s/%s", path, ent->d_name);
|
||||
|
||||
/* see if this child is excluded. */
|
||||
if (iso_exclude_lookup(excludes, child))
|
||||
continue;
|
||||
|
||||
new = iso_tree_add_node(parent, child);
|
||||
if (!new || !ISO_ISDIR(new)) {
|
||||
if (!new)
|
||||
behavior->error = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
iso_tree_radd_dir_aux( (struct iso_tree_node_dir *) new, child,
|
||||
behavior, excludes);
|
||||
|
||||
}
|
||||
closedir(dir);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
iso_tree_radd_dir(struct iso_tree_node_dir *parent, const char *path,
|
||||
struct iso_tree_radd_dir_behavior *behavior)
|
||||
{
|
||||
struct iso_tree_node_dir *dir;
|
||||
struct iso_hash_table table = { {0,}, 0};
|
||||
|
||||
assert ( parent && path );
|
||||
|
||||
behavior->error = 0;
|
||||
|
||||
/* initialize exclude hash_table */
|
||||
if ( behavior->excludes ) {
|
||||
char *exclude;
|
||||
int i = 0;
|
||||
while ( (exclude = behavior->excludes[i++]) ) {
|
||||
iso_exclude_add_path(&table, exclude);
|
||||
}
|
||||
}
|
||||
|
||||
/* recurse into dir */
|
||||
iso_tree_radd_dir_aux(parent, path, behavior, &table);
|
||||
|
||||
/* clear hashtable */
|
||||
iso_exclude_empty(&table);
|
||||
}
|
||||
|
||||
void
|
||||
iso_tree_print(const struct iso_tree_node *root, int spaces)
|
||||
{
|
||||
char sp[spaces+1];
|
||||
|
||||
memset(sp, ' ', spaces);
|
||||
sp[spaces] = '\0';
|
||||
|
||||
printf("%s%s\n", sp, root->name);
|
||||
|
||||
if ( ISO_ISDIR(root) ) {
|
||||
size_t i;
|
||||
struct iso_tree_node_dir *dir;
|
||||
|
||||
dir = (struct iso_tree_node_dir *) root;
|
||||
for (i=0; i < dir->nchildren; i++) {
|
||||
iso_tree_print(dir->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)
|
||||
{
|
||||
|
||||
(ISO_ISDIR(root) ? dir : file)
|
||||
(root, callback_data, spaces);
|
||||
|
||||
if ( ISO_ISDIR(root) ) {
|
||||
size_t i;
|
||||
struct iso_tree_node_dir *dir_node;
|
||||
|
||||
dir_node = (struct iso_tree_node_dir *) root;
|
||||
for (i=0; i < dir_node->nchildren; i++) {
|
||||
iso_tree_print_verbose(dir_node->children[i], dir,
|
||||
file, callback_data, spaces+2);
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user