You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1520 lines
43 KiB

/*
* Copyright (c) 2007 Vreixo Formoso
* Copyright (c) 2011 - 2014 Thomas Schmitt
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2
* or later as published by the Free Software Foundation.
* See COPYING file for details.
*/
/*
* Functions that act on the iso tree.
*/
#ifdef HAVE_CONFIG_H
#include "../config.h"
#endif
#include "libisofs.h"
#include "node.h"
#include "image.h"
#include "fsource.h"
#include "builder.h"
#include "messages.h"
#include "tree.h"
#include "util.h"
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <limits.h>
#include <stdio.h>
#include <fnmatch.h>
/**
* Add a new directory to the iso tree.
*
* @param parent
* the dir where the new directory will be created
* @param name
* name for the new dir. If a node with same name already exists on
* parent, this functions fails with ISO_NODE_NAME_NOT_UNIQUE.
* @param dir
* place where to store a pointer to the newly created dir. No extra
* ref is addded, so you will need to call iso_node_ref() if you really
* need it. You can pass NULL in this parameter if you don't need the
* pointer.
* @return
* number of nodes in dir if succes, < 0 otherwise
* Possible errors:
* ISO_NULL_POINTER, if parent or name are NULL
* ISO_NODE_NAME_NOT_UNIQUE, a node with same name already exists
*/
int iso_tree_add_new_dir(IsoDir *parent, const char *name, IsoDir **dir)
{
int ret;
char *n;
IsoDir *node;
IsoNode **pos;
time_t now;
if (parent == NULL || name == NULL) {
return ISO_NULL_POINTER;
}
if (dir) {
*dir = NULL;
}
/* find place where to insert and check if it exists */
if (iso_dir_exists(parent, name, &pos)) {
/* a node with same name already exists */
return ISO_NODE_NAME_NOT_UNIQUE;
}
n = strdup(name);
ret = iso_node_new_dir(n, &node);
if (ret < 0) {
free(n);
return ret;
}
/* permissions from parent */
iso_node_set_permissions((IsoNode*)node, parent->node.mode);
iso_node_set_uid((IsoNode*)node, parent->node.uid);
iso_node_set_gid((IsoNode*)node, parent->node.gid);
iso_node_set_hidden((IsoNode*)node, parent->node.hidden);
/* current time */
now = time(NULL);
iso_node_set_atime((IsoNode*)node, now);
iso_node_set_ctime((IsoNode*)node, now);
iso_node_set_mtime((IsoNode*)node, now);
if (dir) {
*dir = node;
}
/* add to dir */
return iso_dir_insert(parent, (IsoNode*)node, pos, ISO_REPLACE_NEVER);
}
/**
* Add a new symlink to the directory tree. Permissions are set to 0777,
* owner and hidden atts are taken from parent. You can modify any of them
* later.
*
* @param parent
* the dir where the new symlink will be created
* @param name
* name for the new dir. If a node with same name already exists on
* parent, this functions fails with ISO_NODE_NAME_NOT_UNIQUE.
* @param dest
* destination of the link
* @param link
* place where to store a pointer to the newly created link. No extra
* ref is addded, so you will need to call iso_node_ref() if you really
* need it. You can pass NULL in this parameter if you don't need the
* pointer
* @return
* number of nodes in parent if success, < 0 otherwise
* Possible errors:
* ISO_NULL_POINTER, if parent, name or dest are NULL
* ISO_NODE_NAME_NOT_UNIQUE, a node with same name already exists
* ISO_OUT_OF_MEM
*/
int iso_tree_add_new_symlink(IsoDir *parent, const char *name,
const char *dest, IsoSymlink **link)
{
int ret;
char *n, *d;
IsoSymlink *node;
IsoNode **pos;
time_t now;
if (parent == NULL || name == NULL || dest == NULL) {
return ISO_NULL_POINTER;
}
if (link) {
*link = NULL;
}
/* find place where to insert */
if (iso_dir_exists(parent, name, &pos)) {
/* a node with same name already exists */
return ISO_NODE_NAME_NOT_UNIQUE;
}
n = strdup(name);
d = strdup(dest);
ret = iso_node_new_symlink(n, d, &node);
if (ret < 0) {
free(n);
free(d);
return ret;
}
/* permissions from parent */
iso_node_set_permissions((IsoNode*)node, 0777);
iso_node_set_uid((IsoNode*)node, parent->node.uid);
iso_node_set_gid((IsoNode*)node, parent->node.gid);
iso_node_set_hidden((IsoNode*)node, parent->node.hidden);
/* current time */
now = time(NULL);
iso_node_set_atime((IsoNode*)node, now);
iso_node_set_ctime((IsoNode*)node, now);
iso_node_set_mtime((IsoNode*)node, now);
if (link) {
*link = node;
}
/* add to dir */
return iso_dir_insert(parent, (IsoNode*)node, pos, ISO_REPLACE_NEVER);
}
/**
* Add a new special file to the directory tree. As far as libisofs concerns,
* an special file is a block device, a character device, a FIFO (named pipe)
* or a socket. You can choose the specific kind of file you want to add
* by setting mode propertly (see man 2 stat).
*
* Note that special files are only written to image when Rock Ridge
* extensions are enabled. Moreover, a special file is just a directory entry
* in the image tree, no data is written beyond that.
*
* Owner and hidden atts are taken from parent. You can modify any of them
* later.
*
* @param parent
* the dir where the new special file will be created
* @param name
* name for the new special file. If a node with same name already exists
* on parent, this functions fails with ISO_NODE_NAME_NOT_UNIQUE.
* @param mode
* file type and permissions for the new node. Note that you can't
* specify any kind of file here, only special types are allowed. i.e,
* S_IFSOCK, S_IFBLK, S_IFCHR and S_IFIFO are valid types; S_IFLNK,
* S_IFREG and S_IFDIR aren't.
* @param dev
* device ID, equivalent to the st_rdev field in man 2 stat.
* @param special
* place where to store a pointer to the newly created special file. No
* extra ref is addded, so you will need to call iso_node_ref() if you
* really need it. You can pass NULL in this parameter if you don't need
* the pointer.
* @return
* number of nodes in parent if success, < 0 otherwise
* Possible errors:
* ISO_NULL_POINTER, if parent, name or dest are NULL
* ISO_NODE_NAME_NOT_UNIQUE, a node with same name already exists
* ISO_OUT_OF_MEM
*
*/
int iso_tree_add_new_special(IsoDir *parent, const char *name, mode_t mode,
dev_t dev, IsoSpecial **special)
{
int ret;
char *n;
IsoSpecial *node;
IsoNode **pos;
time_t now;
if (parent == NULL || name == NULL) {
return ISO_NULL_POINTER;
}
if (S_ISLNK(mode) || S_ISREG(mode) || S_ISDIR(mode)) {
return ISO_WRONG_ARG_VALUE;
}
if (special) {
*special = NULL;
}
/* find place where to insert */
if (iso_dir_exists(parent, name, &pos)) {
/* a node with same name already exists */
return ISO_NODE_NAME_NOT_UNIQUE;
}
n = strdup(name);
ret = iso_node_new_special(n, mode, dev, &node);
if (ret < 0) {
free(n);
return ret;
}
/* atts from parent */
iso_node_set_uid((IsoNode*)node, parent->node.uid);
iso_node_set_gid((IsoNode*)node, parent->node.gid);
iso_node_set_hidden((IsoNode*)node, parent->node.hidden);
/* current time */
now = time(NULL);
iso_node_set_atime((IsoNode*)node, now);
iso_node_set_ctime((IsoNode*)node, now);
iso_node_set_mtime((IsoNode*)node, now);
if (special) {
*special = node;
}
/* add to dir */
return iso_dir_insert(parent, (IsoNode*)node, pos, ISO_REPLACE_NEVER);
}
/**
* Add a new regular file to the iso tree. Permissions are set to 0444,
* owner and hidden atts are taken from parent. You can modify any of them
* later.
*
* @param parent
* the dir where the new file will be created
* @param name
* name for the new file. If a node with same name already exists on
* parent, this functions fails with ISO_NODE_NAME_NOT_UNIQUE.
* @param stream
* IsoStream for the contents of the file
* @param file
* place where to store a pointer to the newly created file. No extra
* ref is addded, so you will need to call iso_node_ref() if you really
* need it. You can pass NULL in this parameter if you don't need the
* pointer
* @return
* number of nodes in parent if success, < 0 otherwise
* Possible errors:
* ISO_NULL_POINTER, if parent, name or dest are NULL
* ISO_NODE_NAME_NOT_UNIQUE, a node with same name already exists
* ISO_OUT_OF_MEM
*
* @since 0.6.4
*/
int iso_tree_add_new_file(IsoDir *parent, const char *name, IsoStream *stream,
IsoFile **file)
{
int ret;
char *n;
IsoFile *node;
IsoNode **pos;
time_t now;
if (parent == NULL || name == NULL || stream == NULL) {
return ISO_NULL_POINTER;
}
if (file) {
*file = NULL;
}
/* find place where to insert */
if (iso_dir_exists(parent, name, &pos)) {
/* a node with same name already exists */
return ISO_NODE_NAME_NOT_UNIQUE;
}
n = strdup(name);
ret = iso_node_new_file(n, stream, &node);
if (ret < 0) {
free(n);
return ret;
}
/* permissions from parent */
iso_node_set_permissions((IsoNode*)node, 0444);
iso_node_set_uid((IsoNode*)node, parent->node.uid);
iso_node_set_gid((IsoNode*)node, parent->node.gid);
iso_node_set_hidden((IsoNode*)node, parent->node.hidden);
/* current time */
now = time(NULL);
iso_node_set_atime((IsoNode*)node, now);
iso_node_set_ctime((IsoNode*)node, now);
iso_node_set_mtime((IsoNode*)node, now);
if (file) {
*file = node;
}
/* add to dir */
return iso_dir_insert(parent, (IsoNode*)node, pos, ISO_REPLACE_NEVER);
}
/**
* Set whether to follow or not symbolic links when added a file from a source
* to IsoImage.
*/
void iso_tree_set_follow_symlinks(IsoImage *image, int follow)
{
image->follow_symlinks = follow ? 1 : 0;
}
/**
* Get current setting for follow_symlinks.
*
* @see iso_tree_set_follow_symlinks
*/
int iso_tree_get_follow_symlinks(IsoImage *image)
{
return image->follow_symlinks;
}
/**
* Set whether to skip or not hidden files when adding a directory recursibely.
* Default behavior is to not ignore them, i.e., to add hidden files to image.
*/
void iso_tree_set_ignore_hidden(IsoImage *image, int skip)
{
image->ignore_hidden = skip ? 1 : 0;
}
/**
* Get current setting for ignore_hidden.
*
* @see iso_tree_set_ignore_hidden
*/
int iso_tree_get_ignore_hidden(IsoImage *image)
{
return image->ignore_hidden;
}
void iso_tree_set_replace_mode(IsoImage *image, enum iso_replace_mode mode)
{
image->replace = mode;
}
enum iso_replace_mode iso_tree_get_replace_mode(IsoImage *image)
{
return image->replace;
}
/**
* Set whether to skip or not special files. Default behavior is to not skip
* them. Note that, despite of this setting, special files won't never be added
* to an image unless RR extensions were enabled.
*
* @param skip
* Bitmask to determine what kind of special files will be skipped:
* bit0: ignore FIFOs
* bit1: ignore Sockets
* bit2: ignore char devices
* bit3: ignore block devices
*/
void iso_tree_set_ignore_special(IsoImage *image, int skip)
{
image->ignore_special = skip & 0x0F;
}
/**
* Get current setting for ignore_special.
*
* @see iso_tree_set_ignore_special
*/
int iso_tree_get_ignore_special(IsoImage *image)
{
return image->ignore_special;
}
/**
* Set a callback function that libisofs will call for each file that is
* added to the given image by a recursive addition function. This includes
* image import.
*
* @param report
* pointer to a function that will be called just before a file will be
* added to the image. You can control whether the file will be in fact
* added or ignored.
* This function should return 1 to add the file, 0 to ignore it and
* continue, < 0 to abort the process
* NULL is allowed if you don't want any callback.
*/
void iso_tree_set_report_callback(IsoImage *image,
int (*report)(IsoImage*, IsoFileSource*))
{
image->report = report;
}
/**
* Add a excluded path. These are paths that won't never added to image,
* and will be excluded even when adding recursively its parent directory.
*
* For example, in
*
* iso_tree_add_exclude(image, "/home/user/data/private");
* iso_tree_add_dir_rec(image, root, "/home/user/data");
*
* the directory /home/user/data/private won't be added to image.
*
* @return
* 1 on success, < 0 on error
*/
int iso_tree_add_exclude(IsoImage *image, const char *path)
{
if (image == NULL || path == NULL) {
return ISO_NULL_POINTER;
}
image->excludes = realloc(image->excludes, ++image->nexcludes *
sizeof(void*));
if (image->excludes == NULL) {
return ISO_OUT_OF_MEM;
}
image->excludes[image->nexcludes - 1] = strdup(path);
if (image->excludes[image->nexcludes - 1] == NULL) {
return ISO_OUT_OF_MEM;
}
return ISO_SUCCESS;
}
/**
* Remove a previously added exclude.
*
* @see iso_tree_add_exclude
* @return
* 1 on success, 0 exclude do not exists, < 0 on error
*/
int iso_tree_remove_exclude(IsoImage *image, const char *path)
{
size_t i, j;
if (image == NULL || path == NULL) {
return ISO_NULL_POINTER;
}
for (i = 0; (int) i < image->nexcludes; ++i) {
if (strcmp(image->excludes[i], path) == 0) {
/* exclude found */
free(image->excludes[i]);
--image->nexcludes;
for (j = i; (int) j < image->nexcludes; ++j) {
image->excludes[j] = image->excludes[j+1];
}
image->excludes = realloc(image->excludes, image->nexcludes *
sizeof(void*));
return ISO_SUCCESS;
}
}
return 0;
}
static
int iso_tree_add_node_builder(IsoImage *image, IsoDir *parent,
IsoFileSource *src, IsoNodeBuilder *builder,
IsoNode **node)
{
int result;
IsoNode *new;
IsoNode **pos;
char *name = NULL;
if (parent == NULL || src == NULL || builder == NULL) {
result = ISO_NULL_POINTER; goto ex;
}
if (node) {
*node = NULL;
}
name = iso_file_source_get_name(src);
/* find place where to insert */
result = iso_dir_exists(parent, name, &pos);
if (result) {
/* a node with same name already exists */
result = ISO_NODE_NAME_NOT_UNIQUE; goto ex;
}
result = builder->create_node(builder, image, src, name, &new);
if (result < 0)
goto ex;
if (node) {
*node = new;
}
/* finally, add node to parent */
result = iso_dir_insert(parent, (IsoNode*)new, pos, ISO_REPLACE_NEVER);
ex:
if (name != NULL)
free(name);
return result;
}
int iso_tree_add_node(IsoImage *image, IsoDir *parent, const char *path,
IsoNode **node)
{
int result;
IsoFilesystem *fs;
IsoFileSource *file;
if (image == NULL || parent == NULL || path == NULL) {
return ISO_NULL_POINTER;
}
fs = image->fs;
result = fs->get_by_path(fs, path, &file);
if (result < 0) {
return result;
}
result = iso_tree_add_node_builder(image, parent, file, image->builder,
node);
/* free the file */
iso_file_source_unref(file);
return result;
}
int iso_tree_add_new_node(IsoImage *image, IsoDir *parent, const char *name,
const char *path, IsoNode **node)
{
int result;
IsoFilesystem *fs;
IsoFileSource *file;
IsoNode *new;
IsoNode **pos;
if (image == NULL || parent == NULL || name == NULL || path == NULL) {
return ISO_NULL_POINTER;
}
if (node) {
*node = NULL;
}
/* find place where to insert */
result = iso_dir_exists(parent, name, &pos);
if (result) {
/* a node with same name already exists */
return ISO_NODE_NAME_NOT_UNIQUE;
}
fs = image->fs;
result = fs->get_by_path(fs, path, &file);
if (result < 0) {
return result;
}
result = image->builder->create_node(image->builder, image, file,
(char *) name, &new);
/* free the file */
iso_file_source_unref(file);
if (result < 0) {
return result;
}
if (node) {
*node = new;
}
/* finally, add node to parent */
return iso_dir_insert(parent, new, pos, ISO_REPLACE_NEVER);
}
int iso_tree_add_new_cut_out_node(IsoImage *image, IsoDir *parent,
const char *name, const char *path,
off_t offset, off_t size,
IsoNode **node)
{
int result;
struct stat info;
IsoFilesystem *fs;
IsoFileSource *src;
IsoFile *new;
IsoNode **pos;
IsoStream *stream;
if (image == NULL || parent == NULL || name == NULL || path == NULL) {
return ISO_NULL_POINTER;
}
if (node) {
*node = NULL;
}
/* find place where to insert */
result = iso_dir_exists(parent, name, &pos);
if (result) {
/* a node with same name already exists */
return ISO_NODE_NAME_NOT_UNIQUE;
}
fs = image->fs;
result = fs->get_by_path(fs, path, &src);
if (result < 0) {
return result;
}
result = iso_file_source_stat(src, &info);
if (result < 0) {
iso_file_source_unref(src);
return result;
}
if (!S_ISREG(info.st_mode)) {
return ISO_WRONG_ARG_VALUE;
}
if (offset >= info.st_size) {
return ISO_WRONG_ARG_VALUE;
}
/* force regular file */
result = image->builder->create_file(image->builder, image, src, &new);
/* free the file */
iso_file_source_unref(src);
if (result < 0) {
return result;
}
/* replace file iso stream with a cut-out-stream */
result = iso_cut_out_stream_new(src, offset, size, &stream);
if (result < 0) {
iso_node_unref((IsoNode*)new);
return result;
}
iso_stream_unref(new->stream);
new->stream = stream;
result = iso_node_set_name((IsoNode*)new, name);
if (result < 0) {
iso_node_unref((IsoNode*)new);
return result;
}
if (node) {
*node = (IsoNode*)new;
}
/* finally, add node to parent */
return iso_dir_insert(parent, (IsoNode*)new, pos, ISO_REPLACE_NEVER);
}
static
int check_excludes(IsoImage *image, const char *path)
{
int i;
for (i = 0; i < image->nexcludes; ++i) {
char *exclude = image->excludes[i];
if (exclude[0] == '/') {
/* absolute exclude, must completely match path */
if (!fnmatch(exclude, path, FNM_PERIOD|FNM_PATHNAME)) {
return 1;
}
} else {
/* relative exclude, it is enought if a part of the path matches */
char *pos = (char*)path;
while (pos != NULL) {
pos++;
if (!fnmatch(exclude, pos, FNM_PERIOD|FNM_PATHNAME)) {
return 1;
}
pos = strchr(pos, '/');
}
}
}
return 0;
}
static
int check_hidden(IsoImage *image, const char *name)
{
return (image->ignore_hidden && name[0] == '.');
}
static
int check_special(IsoImage *image, mode_t mode)
{
if (image->ignore_special != 0) {
switch(mode & S_IFMT) {
case S_IFBLK:
return image->ignore_special & 0x08 ? 1 : 0;
case S_IFCHR:
return image->ignore_special & 0x04 ? 1 : 0;
case S_IFSOCK:
return image->ignore_special & 0x02 ? 1 : 0;
case S_IFIFO:
return image->ignore_special & 0x01 ? 1 : 0;
default:
return 0;
}
}
return 0;
}
static
void ascii_increment(char *name, int len, int pos, int rollover_carry)
{
int c;
again:;
if (pos < 0 || pos >= len)
pos = len - 1;
c = name[pos];
if (c >= '0' && c < '9') {
c++;
} else if (c == '9') {
c = 'A';
} else if (c >= 'A' && c < 'Z') {
c++;
} else if (c == 'Z') {
c = '_';
} else if (c == '_') {
c = 'a';
} else if (c >= 'a' && c < 'z') {
c++;
} else if (c == 'z') {
c = '0';
name[pos] = c;
pos--;
if (pos >= 0 || rollover_carry)
goto again;
return;
} else {
if (pos == len - 1 || name[pos + 1] == '.')
c = '_'; /* Make first change less riddling */
else
c = '0'; /* But else use the full range of valid characters */
}
name[pos] = c;
}
static
int insert_underscores(char *name, int *len, int *at_pos, int count,
char **new_name)
{
int ret;
LIBISO_ALLOC_MEM(*new_name, char, count + *len + 1);
if (*at_pos > 0)
memcpy(*new_name, name, *at_pos);
if (count > 0)
memset(*new_name + *at_pos, '_', count);
if (*len > *at_pos)
memcpy(*new_name + *at_pos + count, name + *at_pos, *len - *at_pos);
(*new_name)[count + *len] = 0;
*len += count;
*at_pos += count;
ret= ISO_SUCCESS;
ex:;
return ret;
}
static
int make_incrementable_name(char **name, char **unique_name, int *low_pos,
int *rollover_carry, int *pre_check)
{
char *dpt, *npt;
int first, len, ret;
/* The incrementable part of the file shall have at least 7 characters.
There may be up to pow(2.0,32.0)*2048/33 = 266548273400 files.
The set of increment result characters has 63 elements.
pow(63.0,7.0) is nearly 15 times larger than 266548273400.
*/
static int min_incr = 7;
/* At most two suffixes of total length up to 12, like .tar.bz2,
shall be preserved. The incrementable part will eventually be
padded up.
Incrementing begins before the last suffix in any case. But when this
rolls over on short prefixes, then long last suffixes will get used
as high characters of the incremental part. This is indicated by
*rollover_carry which corresponds to the parameter of ascii_increment()
with the same name.
*/
static int max_suffix = 12;
*rollover_carry = 0;
*pre_check = 0;
len = strlen(*name);
/* Check if the part before the first dot is long enough.
If not, then preserve the last two short suffixes.
*/
dpt = strchr(*name, '.');
if (dpt != NULL)
if ((dpt - *name) < min_incr)
dpt = strrchr(*name, '.');
if (dpt != NULL) {
first= (dpt - *name);
if (dpt > *name && len - first < max_suffix) {
for(npt = dpt - 1; npt >= *name && *npt != '.'; npt--);
if (npt >= *name) {
if (len - (npt - *name) <= max_suffix) {
first= (npt - *name);
dpt = npt;
}
}
}
} else
first= len;
if (first < min_incr && (len - first) <= max_suffix) {
ret = insert_underscores(*name, &len, &first, min_incr - first,
unique_name);
if (ret < 0)
goto ex;
*pre_check = 1; /* It might now already be unique */
} else if (len < 64) {
/* Insert an underscore to preserve the original name at least for the
first few increments
*/
ret = insert_underscores(*name, &len, &first, 1, unique_name);
if (ret < 0)
goto ex;
*pre_check = 1;
} else {
LIBISO_ALLOC_MEM(*unique_name, char, len + 1);
memcpy(*unique_name, *name, len);
if (first < min_incr)
*rollover_carry = 1; /* Do not get caged before the dots */
}
(*unique_name)[len] = 0;
*low_pos = first - 1;
ret = 1;
ex:;
return(ret);
}
static
int make_really_unique_name(IsoDir *parent, char **name, char **unique_name,
IsoNode ***pos, int flag)
{
int ret, rollover_carry = 0, pre_check = 0, ascii_idx = -1, len;
ret = make_incrementable_name(name, unique_name, &ascii_idx,
&rollover_carry, &pre_check);
if (ret < 0)
goto ex;
len = strlen(*unique_name);
while (1) {
if (!pre_check)
ascii_increment(*unique_name, len, ascii_idx, !!rollover_carry);
else
pre_check = 0;
ret = iso_dir_exists(parent, *unique_name, pos);
if (ret < 0)
goto ex;
if (ret == 0)
break;
}
*name = *unique_name;
ret = ISO_SUCCESS;
ex:;
if (ret < 0) {
LIBISO_FREE_MEM(*unique_name);
*unique_name = NULL;
}
return ret;
}
/**
* Recursively add a given directory to the image tree.
*
* @return
* 1 continue, < 0 error (ISO_CANCELED stop)
*/
int iso_add_dir_src_rec(IsoImage *image, IsoDir *parent, IsoFileSource *dir)
{
int ret, dir_is_open = 0;
IsoNodeBuilder *builder;
IsoFileSource *file;
IsoNode **pos;
struct stat info;
char *name, *path, *allocated_name = NULL;
IsoNode *new;
enum iso_replace_mode replace;
ret = iso_file_source_open(dir);
if (ret < 0) {
path = iso_file_source_get_path(dir);
/* instead of the probable error, we throw a sorry event */
if (path != NULL) {
ret = iso_msg_submit(image->id, ISO_FILE_CANT_ADD, ret,
"Can't open dir %s", path);
free(path);
} else {
ret = iso_msg_submit(image->id, ISO_NULL_POINTER, ret,
"Can't open dir. NULL pointer caught as dir name");
}
goto ex;
}
dir_is_open = 1;
builder = image->builder;
/* iterate over all directory children */
while (1) {
int skip = 0;