When elftoolchain's objcopy (or strip) is rewriting a file in-place,

make it create the temporary file in the same directory as the source
file by default, instead of always using $TMPDIR or /tmp. If creating
that file fails because the directory is not writable, also fallback to
$TMPDIR or /tmp.

This has also been submitted upstream as:
https://sourceforge.net/p/elftoolchain/tickets/597/

Reported by:	cem
PR:		250872
MFC after:	2 weeks
This commit is contained in:
Dimitry Andric 2020-11-18 18:40:58 +00:00
parent 1e4309ae4e
commit 1e4896b176
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=367809
3 changed files with 48 additions and 35 deletions

View file

@ -68,7 +68,7 @@ process_ar_obj(struct elfcopy *ecp, struct ar_obj *obj)
int fd;
/* Output to a temporary file. */
create_tempfile(&tempfile, &fd);
create_tempfile(NULL, &tempfile, &fd);
if ((ecp->eout = elf_begin(fd, ELF_C_WRITE, NULL)) == NULL)
errx(EXIT_FAILURE, "elf_begin() failed: %s",
elf_errmsg(-1));

View file

@ -298,7 +298,7 @@ void create_scn(struct elfcopy *_ecp);
void create_srec(struct elfcopy *_ecp, int _ifd, int _ofd, const char *_ofn);
void create_symtab(struct elfcopy *_ecp);
void create_symtab_data(struct elfcopy *_ecp);
void create_tempfile(char **_fn, int *_fd);
void create_tempfile(const char *_src, char **_fn, int *_fd);
void finalize_external_symtab(struct elfcopy *_ecp);
void free_elf(struct elfcopy *_ecp);
void free_sec_act(struct elfcopy *_ecp);

View file

@ -512,44 +512,57 @@ free_elf(struct elfcopy *ecp)
/* Create a temporary file. */
void
create_tempfile(char **fn, int *fd)
create_tempfile(const char *src, char **fn, int *fd)
{
static const char _TEMPDIR[] = "/tmp/";
static const char _TEMPFILE[] = "ecp.XXXXXXXX";
const char *tmpdir;
char *cp, *tmpf;
size_t tlen, plen;
#define _TEMPFILE "ecp.XXXXXXXX"
#define _TEMPFILEPATH "/tmp/ecp.XXXXXXXX"
char *tmpf;
size_t tlen, slen, plen;
if (fn == NULL || fd == NULL)
return;
/* Repect TMPDIR environment variable. */
tmpdir = getenv("TMPDIR");
if (tmpdir != NULL && *tmpdir != '\0') {
tlen = strlen(tmpdir);
plen = strlen(_TEMPFILE);
tmpf = malloc(tlen + plen + 2);
for (;;) {
if (src == NULL) {
/* Respect TMPDIR environment variable. */
tmpdir = getenv("TMPDIR");
if (tmpdir == NULL || *tmpdir == '\0')
tmpdir = _TEMPDIR;
tlen = strlen(tmpdir);
slen = tmpdir[tlen - 1] == '/' ? 0 : 1;
} else {
/* Create temporary file relative to source file. */
if ((tmpdir = strrchr(src, '/')) == NULL) {
/* No path, only use a template filename. */
tlen = 0;
} else {
/* Append the template after the slash. */
tlen = ++tmpdir - src;
tmpdir = src;
}
slen = 0;
}
plen = strlen(_TEMPFILE) + 1;
tmpf = malloc(tlen + slen + plen);
if (tmpf == NULL)
err(EXIT_FAILURE, "malloc failed");
strncpy(tmpf, tmpdir, tlen);
cp = &tmpf[tlen - 1];
if (*cp++ != '/')
*cp++ = '/';
strncpy(cp, _TEMPFILE, plen);
cp[plen] = '\0';
} else {
tmpf = strdup(_TEMPFILEPATH);
if (tmpf == NULL)
err(EXIT_FAILURE, "strdup failed");
if (tlen > 0)
memcpy(tmpf, tmpdir, tlen);
if (slen > 0)
tmpf[tlen] = '/';
/* Copy template filename including NUL terminator. */
memcpy(tmpf + tlen + slen, _TEMPFILE, plen);
if ((*fd = mkstemp(tmpf)) != -1)
break;
if (errno != EACCES || src == NULL)
err(EXIT_FAILURE, "mkstemp %s failed", tmpf);
/* Permission denied, try again using TMPDIR or /tmp. */
free(tmpf);
src = NULL;
}
if ((*fd = mkstemp(tmpf)) == -1)
err(EXIT_FAILURE, "mkstemp %s failed", tmpf);
if (fchmod(*fd, 0644) == -1)
err(EXIT_FAILURE, "fchmod %s failed", tmpf);
*fn = tmpf;
#undef _TEMPFILE
#undef _TEMPFILEPATH
}
/*
@ -571,16 +584,16 @@ copy_from_tempfile(const char *src, const char *dst, int infd, int *outfd,
if (rename(src, dst) >= 0) {
*outfd = infd;
return (0);
} else if (errno != EXDEV)
} else if (errno != EXDEV && errno != EACCES)
return (-1);
/*
* If the rename() failed due to 'src' and 'dst' residing in
* two different file systems, invoke a helper function in
* libelftc to do the copy.
*/
if (unlink(dst) < 0)
if (errno != EACCES && unlink(dst) < 0)
return (-1);
}
@ -630,7 +643,7 @@ create_file(struct elfcopy *ecp, const char *src, const char *dst)
err(EXIT_FAILURE, "fstat %s failed", src);
if (dst == NULL)
create_tempfile(&tempfile, &ofd);
create_tempfile(src, &tempfile, &ofd);
else
if ((ofd = open(dst, O_RDWR|O_CREAT, 0755)) == -1)
err(EXIT_FAILURE, "open %s failed", dst);
@ -663,7 +676,7 @@ create_file(struct elfcopy *ecp, const char *src, const char *dst)
if (ecp->oed == ELFDATANONE)
ecp->oed = ELFDATA2LSB;
}
create_tempfile(&elftemp, &efd);
create_tempfile(src, &elftemp, &efd);
if ((ecp->eout = elf_begin(efd, ELF_C_WRITE, NULL)) == NULL)
errx(EXIT_FAILURE, "elf_begin() failed: %s",
elf_errmsg(-1));
@ -723,7 +736,7 @@ create_file(struct elfcopy *ecp, const char *src, const char *dst)
tempfile);
free(tempfile);
}
create_tempfile(&tempfile, &ofd0);
create_tempfile(src, &tempfile, &ofd0);
/*