New API call iso_tree_resolve_symlink().

release-1.5.4.branch
Thomas Schmitt 10 years ago
parent 2c88e74798
commit 7a8995f322
  1. 37
      libisofs/libisofs.h
  2. 1
      libisofs/libisofs.ver
  3. 4
      libisofs/messages.c
  4. 81
      libisofs/tree.c

@ -5059,6 +5059,37 @@ int iso_tree_path_to_node(IsoImage *image, const char *path, IsoNode **node);
*/
char *iso_tree_get_node_path(IsoNode *node);
/**
* Get the destination node of a symbolic link within the IsoImage.
*
* @param img
* The image wherein to try resolving the link.
* @param sym
* The symbolic link node which to resolve.
* @param res
* Will return the found destination node, in case of success.
* Call iso_node_ref() / iso_node_unref() if you intend to use the node
* over API calls which might in any event delete it.
* @param depth
* Prevents endless loops. Submit as 0.
* @param flag
* Bitfield for control purposes. Submit 0 for now.
* @return
* 1 on success,
* < 0 on failure, especially ISO_DEEP_SYMLINK and ISO_DEAD_SYMLINK
*
* @since 1.2.4
*/
int iso_tree_resolve_symlink(IsoImage *img, IsoSymlink *sym, IsoNode **res,
int *depth, int flag);
/* Maximum number link resolution steps before ISO_DEEP_SYMLINK gets
* returned by iso_tree_resolve_symlink().
*
* @since 1.2.4
*/
#define LIBISO_MAX_LINK_DEPTH 100
/**
* Increments the reference counting of the given IsoDataSource.
*
@ -7373,6 +7404,12 @@ int iso_image_hfsplus_get_blessed(IsoImage *img, IsoNode ***blessed_nodes,
/** Name collision in HFS+, mangling not possible (FAILURE, HIGH, -393) */
#define ISO_HFSP_NO_MANGLE 0xE830FE77
/** Symbolic link cannot be resolved (FAILURE, HIGH, -394) */
#define ISO_DEAD_SYMLINK 0xE830FE76
/** Too many chained symbolic links (FAILURE, HIGH, -395) */
#define ISO_DEEP_SYMLINK 0xE830FE75
/* Internal developer note:
Place new error codes directly above this comment.

@ -257,6 +257,7 @@ iso_tree_get_node_path;
iso_tree_get_replace_mode;
iso_tree_path_to_node;
iso_tree_remove_exclude;
iso_tree_resolve_symlink;
iso_tree_set_follow_symlinks;
iso_tree_set_ignore_hidden;
iso_tree_set_ignore_special;

@ -496,6 +496,10 @@ const char *iso_error_to_msg(int errcode)
return "APM block size prevents coexistence with GPT";
case ISO_HFSP_NO_MANGLE:
return "Name collision in HFS+, mangling not possible";
case ISO_DEAD_SYMLINK:
return "Symbolic link cannot be resolved";
case ISO_DEEP_SYMLINK:
return "Too many chained symbolic links";
default:
return "Unknown error";
}

@ -1196,3 +1196,84 @@ int iso_tree_clone(IsoNode *node,
return ret;
}
int iso_tree_resolve_symlink(IsoImage *img, IsoSymlink *sym, IsoNode **res,
int *depth, int flag)
{
IsoDir *cur_dir = NULL;
IsoNode *n, *resolved_node;
char *dest, *dest_start, *dest_end;
int ret = 0;
unsigned int comp_len, dest_len;
dest = sym->dest;
dest_len = strlen(dest);
if (dest[0] == '/') {
/* >>> ??? How to resolve absolute links without knowing the
path of the future mount point ?
??? Would it be better to throw error ?
I can only assume that it gets mounted at / during some stage
of booting.
*/;
cur_dir = img->root;
dest_end = dest;
} else {
cur_dir = sym->node.parent;
if (cur_dir == NULL)
cur_dir = img->root;
dest_end = dest - 1;
}
while (dest_end < dest + dest_len) {
dest_start = dest_end + 1;
dest_end = strchr(dest_start, '/');
if (dest_end == NULL)
dest_end = dest_start + strlen(dest_start);
comp_len = dest_end - dest_start;
if (comp_len == 0 || (comp_len == 1 && dest_start[0] == '.'))
continue;
if (comp_len == 2 && dest_start[0] == '.' && dest_start[1] == '.') {
cur_dir = cur_dir->node.parent;
if (cur_dir == NULL) /* link shoots over root */
return ISO_DEAD_SYMLINK;
continue;
}
/* Search node in cur_dir */
for (n = cur_dir->children; n != NULL; n = n->next)
if (strncmp(dest_start, n->name, comp_len) == 0 &&
strlen(n->name) == comp_len)
break;
if (n == NULL)
return ISO_DEAD_SYMLINK;
if (n->type == LIBISO_DIR) {
cur_dir = (IsoDir *) n;
} else if (n->type == LIBISO_SYMLINK) {
if (*depth >= LIBISO_MAX_LINK_DEPTH)
return ISO_DEEP_SYMLINK;
(*depth)++;
ret = iso_tree_resolve_symlink(img, (IsoSymlink *) n,
&resolved_node, depth, 0);
if (ret < 0)
return ret;
if (resolved_node->type != LIBISO_DIR) {
n = resolved_node;
goto leaf_type;
}
cur_dir = (IsoDir *) resolved_node;
} else {
leaf_type:;
if (dest_end < dest + dest_len) /* attempt to dive into file */
return ISO_DEAD_SYMLINK;
*res = n;
return ISO_SUCCESS;
}
}
*res = cur_dir;
return ISO_SUCCESS;
}

Loading…
Cancel
Save