util/nvmutil: use renameat for atomic write

not rename(). use renameat()

this re-uses the logic added for mkhtemp.

this will later enable more stringent
integrity checks, though we already verify
the integrity of a file after writing it
back, and renameat is always tied to the
descriptor, so it's fine.

Signed-off-by: Leah Rowe <leah@libreboot.org>
This commit is contained in:
Leah Rowe
2026-03-24 19:13:59 +00:00
parent 217ad55bed
commit 3522a23587
3 changed files with 32 additions and 23 deletions

View File

@@ -287,6 +287,11 @@ struct xfile {
unsigned char bufcmp[GBE_BUF_SIZE]; /* compare gbe/tmp/reads */
unsigned char pad[GBE_WORK_SIZE]; /* the file that wouldn't die */
/* we later rename in-place, using old fd. renameat() */
int dirfd;
char *base;
char *tmpbase;
};
/* Command table, MAC address, files

View File

@@ -432,32 +432,12 @@ gbe_mv(void)
saved_errno = errno;
/* TODO: remove this path-based rename,
use fd */
rval = rename(f->tname, f->fname);
if (rval > -1) {
/* rename on same filesystem
*/
rval = fs_rename_at(f->dirfd, f->tmpbase,
f->dirfd, f->base);
if (rval > -1)
tmp_gbe_bin_exists = 0;
/*
if (fsync(dest_fd) < 0) {
f->io_err_gbe_bin = 1;
rval = -1;
}
*/
goto ret_gbe_mv;
}
if (errno != EXDEV)
goto ret_gbe_mv;
err(errno, "BUG: cross-filesystem move (this shouldn't happen)");
ret_gbe_mv:
/* TODO: this whole section is bloat.

View File

@@ -29,6 +29,8 @@ xstart(int argc, char *argv[])
static char *dir = NULL;
static char *base = NULL;
char *realdir = NULL;
char *tmpdir = NULL;
char *tmpbase_local = NULL;
static struct xstate us = {
{
@@ -118,9 +120,27 @@ xstart(int argc, char *argv[])
err_no_cleanup(errno, "xstart: don't know CWD of %s",
us.f.fname);
if ((us.f.base = strdup(base)) == NULL)
err_no_cleanup(errno, "strdup base");
us.f.dirfd = fs_open(dir,
O_RDONLY | O_DIRECTORY);
if (us.f.dirfd < 0)
err_no_cleanup(errno, "%s: open dir", dir);
if (new_tmpfile(&us.f.tmp_fd, &us.f.tname, dir) < 0)
err_no_cleanup(errno, "%s", us.f.tname);
if (fs_dirname_basename(us.f.tname,
&tmpdir, &tmpbase_local, 0) < 0)
err_no_cleanup(errno, "tmp basename");
us.f.tmpbase = strdup(tmpbase_local);
if (us.f.tmpbase == NULL)
err_no_cleanup(errno, "strdup tmpbase");
free_if_null(&tmpdir);
if (us.f.tname == NULL)
err_no_cleanup(errno, "x->f.tname null");
if (*us.f.tname == '\0')
@@ -197,6 +217,10 @@ exit_cleanup(void)
if (f->tname != NULL)
if (unlink(f->tname) == -1)
close_err = 1;
close_no_err(&f->dirfd);
free_if_null(&f->base);
free_if_null(&f->tmpbase);
}
if (saved_errno)