--- lib/package_alternatives.c.orig +++ lib/package_alternatives.c @@ -145,99 +145,84 @@ remove_symlinks(struct xbps_handle *xhp, xbps_array_t a, const char *grname) static int create_symlinks(struct xbps_handle *xhp, xbps_array_t a, const char *grname) { - unsigned int i, cnt; + int rv; + unsigned int i, n; + char *alternative, *tok1, *tok2, *linkpath, *target, *dir, *p; - cnt = xbps_array_count(a); - for (i = 0; i < cnt; i++) { - xbps_string_t str; - char *tgt_dup, *tgt_dir, *lnk_dup, *lnk_dir; - char *l, *lnk, *tgt = NULL; - const char *tgt0; - int rv; + n = xbps_array_count(a); - str = xbps_array_get(a, i); - l = left(xbps_string_cstring_nocopy(str)); - assert(l); - tgt0 = right(xbps_string_cstring_nocopy(str)); - assert(tgt0); - /* always create target dir, for dangling symlinks */ - tgt_dup = strdup(tgt0); - assert(tgt_dup); - tgt_dir = dirname(tgt_dup); - if (strcmp(tgt_dir, ".")) { - tgt = xbps_xasprintf("%s%s", xhp->rootdir, tgt_dir); - if (xbps_mkpath(tgt, 0755) != 0) { - if (errno != EEXIST) { - rv = errno; - xbps_dbg_printf(xhp, "failed to create " - "target dir '%s' for group '%s': %s\n", - tgt, grname, strerror(errno)); - free(tgt_dup); - free(tgt); - free(l); - return rv; - } - } - free(tgt); + for (i = 0; i < n; i++) { + alternative = xbps_string_cstring(xbps_array_get(a, i)); + + if (!(tok1 = strtok(alternative, ":")) || + !(tok2 = strtok(NULL, ":"))) { + free(alternative); + return -1; } - /* always create link dir, for dangling symlinks */ - lnk_dup = strdup(l); - assert(lnk_dup); - lnk_dir = dirname(lnk_dup); - if (strcmp(lnk_dir, ".")) { - lnk = xbps_xasprintf("%s%s", xhp->rootdir, lnk_dir); - if (xbps_mkpath(lnk, 0755) != 0) { - if (errno != EEXIST) { - rv = errno; - xbps_dbg_printf(xhp, "failed to create symlink" - "dir '%s' for group '%s': %s\n", - lnk, grname, strerror(errno)); - free(tgt_dup); - free(lnk_dup); - free(lnk); - free(l); - return rv; - } - } - free(lnk); + target = strdup(tok2); + dir = dirname(tok2); + + /* add target dir to relative links */ + if (tok1[0] != '/') + linkpath = xbps_xasprintf("%s/%s/%s", xhp->rootdir, dir, tok1); + else + linkpath = xbps_xasprintf("%s/%s", xhp->rootdir, tok1); + + /* create target directory, necessary for dangling symlinks */ + dir = xbps_xasprintf("%s/%s", xhp->rootdir, dir); + if (strcmp(dir, ".") && xbps_mkpath(dir, 0755) && errno != EEXIST) { + rv = errno; + xbps_dbg_printf(xhp, + "failed to create target dir '%s' for group '%s': %s\n", + dir, grname, strerror(errno)); + free(dir); + goto err; } - free(lnk_dup); - - if (l[0] != '/') { - lnk = xbps_xasprintf("%s%s/%s", xhp->rootdir, tgt_dir, l); - free(tgt_dup); - tgt_dup = strdup(tgt0); - assert(tgt_dup); - tgt = strdup(basename(tgt_dup)); - free(tgt_dup); - } else { - free(tgt_dup); - tgt = strdup(tgt0); - lnk = xbps_xasprintf("%s%s", xhp->rootdir, l); + free(dir); + + /* create link directory, necessary for dangling symlinks */ + p = strdup(linkpath); + dir = dirname(p); + if (strcmp(dir, ".") && xbps_mkpath(dir, 0755) && errno != EEXIST) { + rv = errno; + xbps_dbg_printf(xhp, + "failed to create symlink dir '%s' for group '%s': %s\n", + dir, grname, strerror(errno)); + free(p); + goto err; } + free(p); + xbps_set_cb_state(xhp, XBPS_STATE_ALTGROUP_LINK_ADDED, 0, NULL, - "Creating '%s' alternatives group symlink: %s -> %s", grname, l, tgt); - unlink(lnk); - if (tgt[0] == '/') { - tgt_dup = relpath(lnk + strlen(xhp->rootdir), tgt); - free(tgt); - tgt = tgt_dup; + "Creating '%s' alternatives group symlink: %s -> %s", + grname, tok1, target); + + if (target[0] == '/') { + p = relpath(linkpath + strlen(xhp->rootdir), target); + free(target); + target = p; } - if ((rv = symlink(tgt, lnk)) != 0) { - xbps_dbg_printf(xhp, "failed to create alt symlink '%s'" - "for group '%s': %s\n", lnk, grname, - strerror(errno)); - free(tgt); - free(lnk); - free(l); - return rv; + + unlink(linkpath); + if ((rv = symlink(target, linkpath)) != 0) { + xbps_dbg_printf(xhp, + "failed to create alt symlink '%s' for group '%s': %s\n", + linkpath, grname, strerror(errno)); + goto err; } - free(tgt); - free(lnk); - free(l); + + free(alternative); + free(target); + free(linkpath); } return 0; + +err: + free(alternative); + free(target); + free(linkpath); + return rv; } int