Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/optimise dracut-install abs_rel #1851

Merged
merged 4 commits into from
Jun 24, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 46 additions & 50 deletions src/install/dracut-install.c
Original file line number Diff line number Diff line change
Expand Up @@ -162,39 +162,43 @@ static size_t dir_len(char const *file)
static char *convert_abs_rel(const char *from, const char *target)
{
/* we use the 4*MAXPATHLEN, which should not overrun */
char relative_from[MAXPATHLEN * 4];
_cleanup_free_ char *realtarget = NULL;
_cleanup_free_ char *target_dir_p = NULL, *realpath_p = NULL;
const char *realfrom = from;
char buf[MAXPATHLEN * 4];
_cleanup_free_ char *realtarget = NULL, *realfrom = NULL, *from_dir_p = NULL;
_cleanup_free_ char *target_dir_p = NULL;
size_t level = 0, fromlevel = 0, targetlevel = 0;
int l;
size_t i, rl, dirlen;

target_dir_p = strdup(target);
if (!target_dir_p)
return strdup(from);

dirlen = dir_len(target_dir_p);
target_dir_p[dirlen] = '\0';
realpath_p = realpath(target_dir_p, NULL);

if (realpath_p == NULL) {
log_warning("convert_abs_rel(): target '%s' directory has no realpath.", target);
return strdup(from);
dirlen = dir_len(from);
from_dir_p = strndup(from, dirlen);
if (!from_dir_p)
return strdup(from + strlen(destrootdir));
if (realpath(from_dir_p, buf) == NULL) {
log_warning("convert_abs_rel(): from '%s' directory has no realpath: %m", from);
return strdup(from + strlen(destrootdir));
}

/* dir_len() skips double /'s e.g. //lib64, so we can't skip just one
* character - need to skip all leading /'s */
rl = strlen(target);
for (i = dirlen + 1; i < rl; ++i)
if (target_dir_p[i] != '/')
break;
_asprintf(&realtarget, "%s/%s", realpath_p, &target_dir_p[i]);
for (i = dirlen + 1; from[i] == '/'; ++i)
;
_asprintf(&realfrom, "%s/%s", buf, from + i);

dirlen = dir_len(target);
target_dir_p = strndup(target, dirlen);
if (!target_dir_p)
return strdup(from + strlen(destrootdir));
if (realpath(target_dir_p, buf) == NULL) {
log_warning("convert_abs_rel(): target '%s' directory has no realpath: %m", target);
return strdup(from + strlen(destrootdir));
}

for (i = dirlen + 1; target[i] == '/'; ++i)
;
_asprintf(&realtarget, "%s/%s", buf, target + i);

/* now calculate the relative path from <from> to <target> and
store it in <relative_from>
store it in <buf>
*/
relative_from[0] = 0;
rl = 0;

/* count the pathname elements of realtarget */
Expand All @@ -212,13 +216,13 @@ static char *convert_abs_rel(const char *from, const char *target)
if (realtarget[i] == '/')
level++;

/* add "../" to the relative_from path, until the common pathname is
/* add "../" to the buf path, until the common pathname is
reached */
for (i = level; i < targetlevel; i++) {
if (i != level)
relative_from[rl++] = '/';
relative_from[rl++] = '.';
relative_from[rl++] = '.';
buf[rl++] = '/';
buf[rl++] = '.';
buf[rl++] = '.';
}

/* set l to the next uncommon pathname element in realfrom */
Expand All @@ -227,17 +231,17 @@ static char *convert_abs_rel(const char *from, const char *target)
/* skip next '/' */
l++;

/* append the uncommon rest of realfrom to the relative_from path */
/* append the uncommon rest of realfrom to the buf path */
for (i = level; i <= fromlevel; i++) {
if (rl)
relative_from[rl++] = '/';
buf[rl++] = '/';
while (realfrom[l] && realfrom[l] != '/')
relative_from[rl++] = realfrom[l++];
buf[rl++] = realfrom[l++];
l++;
}

relative_from[rl] = 0;
return strdup(relative_from);
buf[rl] = 0;
return strdup(buf);
}

static int ln_r(const char *src, const char *dst)
Expand Down Expand Up @@ -431,19 +435,21 @@ static char *get_real_file(const char *src, bool fullyresolve)
struct stat sb;
ssize_t linksz;
char linktarget[PATH_MAX + 1];
_cleanup_free_ char *fullsrcpath;
_cleanup_free_ char *fullsrcpath_a = NULL;
const char *fullsrcpath;
_cleanup_free_ char *abspath = NULL;

if (sysrootdirlen) {
if (strncmp(src, sysrootdir, sysrootdirlen) == 0) {
fullsrcpath = strdup(src);
fullsrcpath = src;
} else {
_asprintf(&fullsrcpath, "%s/%s",
_asprintf(&fullsrcpath_a, "%s/%s",
(sysrootdirlen ? sysrootdir : ""),
(src[0] == '/' ? src + 1 : src));
fullsrcpath = fullsrcpath_a;
}
} else {
fullsrcpath = strdup(src);
fullsrcpath = src;
}

log_debug("get_real_file('%s')", fullsrcpath);
Expand Down Expand Up @@ -471,15 +477,7 @@ static char *get_real_file(const char *src, bool fullyresolve)
if (linktarget[0] == '/') {
_asprintf(&abspath, "%s%s", (sysrootdirlen ? sysrootdir : ""), linktarget);
} else {
_cleanup_free_ char *fullsrcdir = strdup(fullsrcpath);

if (!fullsrcdir) {
log_error("Out of memory!");
exit(EXIT_FAILURE);
}

fullsrcdir[dir_len(fullsrcdir)] = '\0';
_asprintf(&abspath, "%s/%s", fullsrcdir, linktarget);
_asprintf(&abspath, "%.*s/%s", (int)dir_len(fullsrcpath), fullsrcpath, linktarget);
}

if (fullyresolve) {
Expand Down Expand Up @@ -820,12 +818,11 @@ static int dracut_install(const char *orig_src, const char *orig_dst, bool isdir
} else {

/* check destination directory */
fulldstdir = strdup(fulldstpath);
fulldstdir = strndup(fulldstpath, dir_len(fulldstpath));
if (!fulldstdir) {
log_error("Out of memory!");
return 1;
}
fulldstdir[dir_len(fulldstdir)] = '\0';

ret = stat(fulldstdir, &db);

Expand All @@ -838,11 +835,10 @@ static int dracut_install(const char *orig_src, const char *orig_dst, bool isdir
}
/* create destination directory */
log_debug("dest dir '%s' does not exist", fulldstdir);
dname = strdup(dst);

dname = strndup(dst, dir_len(dst));
if (!dname)
return 1;

dname[dir_len(dname)] = '\0';
ret = dracut_install(dname, dname, true, false, true);

if (ret != 0) {
Expand Down