block: Refactor get_tmp_filename()

At present there are two callers of get_tmp_filename() and they are
inconsistent.

One does:

    /* TODO: extra byte is a hack to ensure MAX_PATH space on Windows. */
    char *tmp_filename = g_malloc0(PATH_MAX + 1);
    ...
    ret = get_tmp_filename(tmp_filename, PATH_MAX + 1);

while the other does:

    s->qcow_filename = g_malloc(PATH_MAX);
    ret = get_tmp_filename(s->qcow_filename, PATH_MAX);

As we can see different 'size' arguments are passed. There are also
platform specific implementations inside the function, and the use
of snprintf is really undesirable.

The function name is also misleading. It creates a temporary file,
not just a filename.

Refactor this routine by changing its name and signature to:

    char *create_tmp_file(Error **errp)

and use g_get_tmp_dir() / g_mkstemp() for a consistent implementation.

While we are here, add some comments to mention that /var/tmp is
preferred over /tmp on non-win32 hosts.

Signed-off-by: Bin Meng <bin.meng@windriver.com>
Message-Id: <20221010040432.3380478-2-bin.meng@windriver.com>
[kwolf: Fixed incorrect errno negation and iotest 051]
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
Bin Meng 2022-10-10 12:04:31 +08:00 committed by Kevin Wolf
parent 6b6471eee1
commit 69fbfff95e
6 changed files with 38 additions and 34 deletions

56
block.c
View File

@ -861,35 +861,42 @@ int bdrv_probe_geometry(BlockDriverState *bs, HDGeometry *geo)
/*
* Create a uniquely-named empty temporary file.
* Return 0 upon success, otherwise a negative errno value.
* Return the actual file name used upon success, otherwise NULL.
* This string should be freed with g_free() when not needed any longer.
*
* Note: creating a temporary file for the caller to (re)open is
* inherently racy. Use g_file_open_tmp() instead whenever practical.
*/
int get_tmp_filename(char *filename, int size)
char *create_tmp_file(Error **errp)
{
#ifdef _WIN32
char temp_dir[MAX_PATH];
/* GetTempFileName requires that its output buffer (4th param)
have length MAX_PATH or greater. */
assert(size >= MAX_PATH);
return (GetTempPath(MAX_PATH, temp_dir)
&& GetTempFileName(temp_dir, "qem", 0, filename)
? 0 : -GetLastError());
#else
int fd;
const char *tmpdir;
tmpdir = getenv("TMPDIR");
if (!tmpdir) {
g_autofree char *filename = NULL;
tmpdir = g_get_tmp_dir();
#ifndef _WIN32
/*
* See commit 69bef79 ("block: use /var/tmp instead of /tmp for -snapshot")
*
* This function is used to create temporary disk images (like -snapshot),
* so the files can become very large. /tmp is often a tmpfs where as
* /var/tmp is usually on a disk, so more appropriate for disk images.
*/
if (!g_strcmp0(tmpdir, "/tmp")) {
tmpdir = "/var/tmp";
}
if (snprintf(filename, size, "%s/vl.XXXXXX", tmpdir) >= size) {
return -EOVERFLOW;
}
fd = mkstemp(filename);
#endif
filename = g_strdup_printf("%s/vl.XXXXXX", tmpdir);
fd = g_mkstemp(filename);
if (fd < 0) {
return -errno;
error_setg_errno(errp, errno, "Could not open temporary file '%s'",
filename);
return NULL;
}
close(fd);
return 0;
#endif
return g_steal_pointer(&filename);
}
/*
@ -3715,8 +3722,7 @@ static BlockDriverState *bdrv_append_temp_snapshot(BlockDriverState *bs,
QDict *snapshot_options,
Error **errp)
{
/* TODO: extra byte is a hack to ensure MAX_PATH space on Windows. */
char *tmp_filename = g_malloc0(PATH_MAX + 1);
g_autofree char *tmp_filename = NULL;
int64_t total_size;
QemuOpts *opts = NULL;
BlockDriverState *bs_snapshot = NULL;
@ -3735,9 +3741,8 @@ static BlockDriverState *bdrv_append_temp_snapshot(BlockDriverState *bs,
}
/* Create the temporary image */
ret = get_tmp_filename(tmp_filename, PATH_MAX + 1);
if (ret < 0) {
error_setg_errno(errp, -ret, "Could not get temporary filename");
tmp_filename = create_tmp_file(errp);
if (!tmp_filename) {
goto out;
}
@ -3771,7 +3776,6 @@ static BlockDriverState *bdrv_append_temp_snapshot(BlockDriverState *bs,
out:
qobject_unref(snapshot_options);
g_free(tmp_filename);
return bs_snapshot;
}

View File

@ -3146,10 +3146,9 @@ static int enable_write_target(BlockDriverState *bs, Error **errp)
array_init(&(s->commits), sizeof(commit_t));
s->qcow_filename = g_malloc(PATH_MAX);
ret = get_tmp_filename(s->qcow_filename, PATH_MAX);
if (ret < 0) {
error_setg_errno(errp, -ret, "can't create temporary file");
s->qcow_filename = create_tmp_file(errp);
if (!s->qcow_filename) {
ret = -ENOENT;
goto err;
}

View File

@ -1230,7 +1230,7 @@ static inline BlockDriverState *child_bs(BdrvChild *child)
}
int bdrv_check_request(int64_t offset, int64_t bytes, Error **errp);
int get_tmp_filename(char *filename, int size);
char *create_tmp_file(Error **errp);
void bdrv_parse_filename_strip_prefix(const char *filename, const char *prefix,
QDict *options);

View File

@ -375,7 +375,8 @@ if [ "${VALGRIND_QEMU_VM}" == "y" ]; then
_casenotrun "Valgrind needs a valid TMPDIR for itself"
fi
VALGRIND_QEMU_VM= \
TMPDIR=/nonexistent run_qemu -drive driver=null-co,snapshot=on
TMPDIR=/nonexistent run_qemu -drive driver=null-co,snapshot=on |
sed -e "s#'[^']*/vl\.[A-Za-z0-9]\{6\}'#SNAPSHOT_PATH#g"
# Using snapshot=on together with read-only=on
echo "info block" |

View File

@ -459,7 +459,7 @@ wrote 4096/4096 bytes at offset 0
read 4096/4096 bytes at offset 0
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
Testing: -drive driver=null-co,snapshot=on
QEMU_PROG: -drive driver=null-co,snapshot=on: Could not get temporary filename: No such file or directory
QEMU_PROG: -drive driver=null-co,snapshot=on: Could not open temporary file SNAPSHOT_PATH: No such file or directory
Testing: -drive file=TEST_DIR/t.qcow2,snapshot=on,read-only=on,if=none,id=drive0
QEMU X.Y.Z monitor - type 'help' for more information

View File

@ -539,7 +539,7 @@ wrote 4096/4096 bytes at offset 0
read 4096/4096 bytes at offset 0
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
Testing: -drive driver=null-co,snapshot=on
QEMU_PROG: -drive driver=null-co,snapshot=on: Could not get temporary filename: No such file or directory
QEMU_PROG: -drive driver=null-co,snapshot=on: Could not open temporary file SNAPSHOT_PATH: No such file or directory
Testing: -drive file=TEST_DIR/t.qcow2,snapshot=on,read-only=on,if=none,id=drive0
QEMU X.Y.Z monitor - type 'help' for more information