The previous guestfs___download_to_tmp function did not handle
multiboot correctly. In particular it used the same cache name
for downloaded files from different roots, which could have caused
things like applications in each root to be confused.
This changes the function so that the cache filename is prefixed
with the root / fs number, eg. $tmpdir/0-Name instead of $tmpdir/Name.
This change also requires the function to return the new name, so
all places in the code which called this function had to be
updated.
This updates and fixes commit
3c1f762abed92f7a358f3bc93e3396d0606b18ad.
(Cherry picked and backported from
commit
5f26270c343bf543a7bf20cf3e6f182f6282f8ea)
extern void guestfs___call_callbacks_array (guestfs_h *g, uint64_t event, const uint64_t *array, size_t array_len);
#if defined(HAVE_PCRE) && defined(HAVE_HIVEX)
extern int guestfs___check_for_filesystem_on (guestfs_h *g, const char *device, int is_block, int is_partnum);
extern void guestfs___call_callbacks_array (guestfs_h *g, uint64_t event, const uint64_t *array, size_t array_len);
#if defined(HAVE_PCRE) && defined(HAVE_HIVEX)
extern int guestfs___check_for_filesystem_on (guestfs_h *g, const char *device, int is_block, int is_partnum);
-extern int guestfs___download_to_tmp (guestfs_h *g, const char *filename, const char *basename, int64_t max_size);
+extern char *guestfs___download_to_tmp (guestfs_h *g, struct inspect_fs *fs, const char *filename, const char *basename, int64_t max_size);
extern char *guestfs___case_sensitive_path_silently (guestfs_h *g, const char *);
extern struct inspect_fs *guestfs___search_for_root (guestfs_h *g, const char *root);
extern int guestfs___parse_unsigned_int (guestfs_h *g, const char *str);
extern char *guestfs___case_sensitive_path_silently (guestfs_h *g, const char *);
extern struct inspect_fs *guestfs___search_for_root (guestfs_h *g, const char *root);
extern int guestfs___parse_unsigned_int (guestfs_h *g, const char *str);
}
/* Download a guest file to a local temporary file. The file is
}
/* Download a guest file to a local temporary file. The file is
- * downloaded into g->tmpdir, unless it already exists in g->tmpdir.
- * The final name will be g->tmpdir + "/" + basename. Refuse to
- * download the guest file if it is larger than max_size. The caller
- * does not need to delete the temporary file after use: it will be
- * deleted when the handle is cleaned up.
+ * cached in the temporary directory, and is not downloaded again.
+ *
+ * The name of the temporary (downloaded) file is returned. The
+ * caller must free the pointer, but does *not* need to delete the
+ * temporary file. It will be deleted when the handle is closed.
+ *
+ * Refuse to download the guest file if it is larger than max_size.
+ * On this and other errors, NULL is returned.
+ *
+ * There is actually one cache per 'struct inspect_fs *' in order
+ * to handle the case of multiple roots.
-int
-guestfs___download_to_tmp (guestfs_h *g, const char *filename,
+char *
+guestfs___download_to_tmp (guestfs_h *g, struct inspect_fs *fs,
+ const char *filename,
const char *basename, int64_t max_size)
{
const char *basename, int64_t max_size)
{
- int tmpdirfd, fd, r = -1;
- char buf[32];
+ char *r;
+ int fd;
+ char devfd[32];
- tmpdirfd = open (g->tmpdir, O_RDONLY);
- if (tmpdirfd == -1) {
- perrorf (g, _("%s: temporary directory not found"), g->tmpdir);
- return -1;
+ /* Make the basename unique by prefixing it with the fs number. */
+ if (asprintf (&r, "%s/%ld-%s", g->tmpdir, fs - g->fses, basename) == -1) {
+ perrorf (g, "asprintf");
+ return NULL;
}
/* If the file has already been downloaded, return. */
}
/* If the file has already been downloaded, return. */
- if (faccessat (tmpdirfd, basename, R_OK, 0) == 0) {
- r = 0;
- goto out;
- }
+ if (access (r, R_OK) == 0)
+ return r;
/* Check size of remote file. */
size = guestfs_filesize (g, filename);
if (size == -1)
/* guestfs_filesize failed and has already set error in handle */
/* Check size of remote file. */
size = guestfs_filesize (g, filename);
if (size == -1)
/* guestfs_filesize failed and has already set error in handle */
if (size > max_size) {
error (g, _("size of %s is unreasonably large (%" PRIi64 " bytes)"),
filename, size);
if (size > max_size) {
error (g, _("size of %s is unreasonably large (%" PRIi64 " bytes)"),
filename, size);
- fd = openat (tmpdirfd, basename, O_WRONLY|O_CREAT|O_TRUNC|O_NOCTTY, 0600);
+ fd = open (r, O_WRONLY|O_CREAT|O_TRUNC|O_NOCTTY, 0600);
- perrorf (g, "openat: %s/%s", g->tmpdir, basename);
- goto out;
+ perrorf (g, "open: %s", r);
+ goto error;
- snprintf (buf, sizeof buf, "/dev/fd/%d", fd);
+ snprintf (devfd, sizeof devfd, "/dev/fd/%d", fd);
- if (guestfs_download (g, filename, buf) == -1) {
- unlinkat (tmpdirfd, basename, 0);
+ if (guestfs_download (g, filename, devfd) == -1) {
+ unlink (r);
}
if (close (fd) == -1) {
}
if (close (fd) == -1) {
- perrorf (g, "close: %s/%s", g->tmpdir, basename);
- unlinkat (tmpdirfd, basename, 0);
- goto out;
+ perrorf (g, "close: %s", r);
+ unlink (r);
+ goto error;
- r = 0;
- out:
- if (tmpdirfd >= 0)
- close (tmpdirfd);
-
+
+ error:
+ free (r);
+ return NULL;
static struct guestfs_application_list *
list_applications_rpm (guestfs_h *g, struct inspect_fs *fs)
{
static struct guestfs_application_list *
list_applications_rpm (guestfs_h *g, struct inspect_fs *fs)
{
- const char *basename = "rpm_Name";
- char tmpdir_basename[strlen (g->tmpdir) + strlen (basename) + 2];
- snprintf (tmpdir_basename, sizeof tmpdir_basename, "%s/%s",
- g->tmpdir, basename);
- if (guestfs___download_to_tmp (g, "/var/lib/rpm/Name", basename,
- MAX_PKG_DB_SIZE) == -1)
+ Name = guestfs___download_to_tmp (g, fs,
+ "/var/lib/rpm/Name", "rpm_Name",
+ MAX_PKG_DB_SIZE);
+ if (Name == NULL)
return NULL;
/* Allocate 'apps' list. */
return NULL;
/* Allocate 'apps' list. */
apps->len = 0;
apps->val = NULL;
apps->len = 0;
apps->val = NULL;
- if (guestfs___read_db_dump (g, tmpdir_basename, apps, read_rpm_name) == -1) {
+ if (guestfs___read_db_dump (g, Name, apps, read_rpm_name) == -1) {
guestfs_free_application_list (apps);
guestfs_free_application_list (apps);
static struct guestfs_application_list *
list_applications_deb (guestfs_h *g, struct inspect_fs *fs)
{
static struct guestfs_application_list *
list_applications_deb (guestfs_h *g, struct inspect_fs *fs)
{
- const char *basename = "deb_status";
- char tmpdir_basename[strlen (g->tmpdir) + strlen (basename) + 2];
- snprintf (tmpdir_basename, sizeof tmpdir_basename, "%s/%s",
- g->tmpdir, basename);
-
- if (guestfs___download_to_tmp (g, "/var/lib/dpkg/status", basename,
- MAX_PKG_DB_SIZE) == -1)
+ char *status = NULL;
+ status = guestfs___download_to_tmp (g, fs, "/var/lib/dpkg/status", "status",
+ MAX_PKG_DB_SIZE);
+ if (status == NULL)
return NULL;
struct guestfs_application_list *apps = NULL, *ret = NULL;
return NULL;
struct guestfs_application_list *apps = NULL, *ret = NULL;
char *name = NULL, *version = NULL, *release = NULL;
int installed_flag = 0;
char *name = NULL, *version = NULL, *release = NULL;
int installed_flag = 0;
- fp = fopen (tmpdir_basename, "r");
+ fp = fopen (status, "r");
- perrorf (g, "fopen: %s", tmpdir_basename);
+ perrorf (g, "fopen: %s", status);
}
if (fclose (fp) == -1) {
}
if (fclose (fp) == -1) {
- perrorf (g, "fclose: %s", tmpdir_basename);
+ perrorf (g, "fclose: %s", status);
free (name);
free (version);
free (release);
free (name);
free (version);
free (release);
static struct guestfs_application_list *
list_applications_windows (guestfs_h *g, struct inspect_fs *fs)
{
static struct guestfs_application_list *
list_applications_windows (guestfs_h *g, struct inspect_fs *fs)
{
- const char *basename = "software";
- char tmpdir_basename[strlen (g->tmpdir) + strlen (basename) + 2];
- snprintf (tmpdir_basename, sizeof tmpdir_basename, "%s/%s",
- g->tmpdir, basename);
-
size_t len = strlen (fs->windows_systemroot) + 64;
char software[len];
snprintf (software, len, "%s/system32/config/software",
size_t len = strlen (fs->windows_systemroot) + 64;
char software[len];
snprintf (software, len, "%s/system32/config/software",
+ char *software_hive = NULL;
struct guestfs_application_list *ret = NULL;
hive_h *h = NULL;
struct guestfs_application_list *ret = NULL;
hive_h *h = NULL;
- if (guestfs___download_to_tmp (g, software_path, basename,
- MAX_REGISTRY_SIZE) == -1)
+ software_hive = guestfs___download_to_tmp (g, fs, software_path, "software",
+ MAX_REGISTRY_SIZE);
+ if (software_hive == NULL)
goto out;
free (software_path);
software_path = NULL;
goto out;
free (software_path);
software_path = NULL;
- h = hivex_open (tmpdir_basename, g->verbose ? HIVEX_OPEN_VERBOSE : 0);
+ h = hivex_open (software_hive, g->verbose ? HIVEX_OPEN_VERBOSE : 0);
if (h == NULL) {
perrorf (g, "hivex_open");
goto out;
if (h == NULL) {
perrorf (g, "hivex_open");
goto out;
out:
if (h) hivex_close (h);
free (software_path);
out:
if (h) hivex_close (h);
free (software_path);
static int
check_windows_software_registry (guestfs_h *g, struct inspect_fs *fs)
{
static int
check_windows_software_registry (guestfs_h *g, struct inspect_fs *fs)
{
- const char *basename = "software";
- char tmpdir_basename[strlen (g->tmpdir) + strlen (basename) + 2];
- snprintf (tmpdir_basename, sizeof tmpdir_basename, "%s/%s",
- g->tmpdir, basename);
-
size_t len = strlen (fs->windows_systemroot) + 64;
char software[len];
snprintf (software, len, "%s/system32/config/software",
size_t len = strlen (fs->windows_systemroot) + 64;
char software[len];
snprintf (software, len, "%s/system32/config/software",
+ char *software_hive = NULL;
int ret = -1;
hive_h *h = NULL;
hive_value_h *values = NULL;
int ret = -1;
hive_h *h = NULL;
hive_value_h *values = NULL;
- if (guestfs___download_to_tmp (g, software_path, basename,
- MAX_REGISTRY_SIZE) == -1)
+ software_hive = guestfs___download_to_tmp (g, fs, software_path, "software",
+ MAX_REGISTRY_SIZE);
+ if (software_hive == NULL)
- h = hivex_open (tmpdir_basename, g->verbose ? HIVEX_OPEN_VERBOSE : 0);
+ h = hivex_open (software_hive, g->verbose ? HIVEX_OPEN_VERBOSE : 0);
if (h == NULL) {
perrorf (g, "hivex_open");
goto out;
if (h == NULL) {
perrorf (g, "hivex_open");
goto out;
if (h) hivex_close (h);
free (values);
free (software_path);
if (h) hivex_close (h);
free (values);
free (software_path);
static int
check_windows_system_registry (guestfs_h *g, struct inspect_fs *fs)
{
static int
check_windows_system_registry (guestfs_h *g, struct inspect_fs *fs)
{
- const char *basename = "system";
- char tmpdir_basename[strlen (g->tmpdir) + strlen (basename) + 2];
- snprintf (tmpdir_basename, sizeof tmpdir_basename, "%s/%s",
- g->tmpdir, basename);
-
size_t len = strlen (fs->windows_systemroot) + 64;
char system[len];
snprintf (system, len, "%s/system32/config/system",
size_t len = strlen (fs->windows_systemroot) + 64;
char system[len];
snprintf (system, len, "%s/system32/config/system",
+ char *system_hive = NULL;
int ret = -1;
hive_h *h = NULL;
hive_node_h root, node;
int ret = -1;
hive_h *h = NULL;
hive_node_h root, node;
int32_t dword;
size_t i, count;
int32_t dword;
size_t i, count;
- if (guestfs___download_to_tmp (g, system_path, basename,
- MAX_REGISTRY_SIZE) == -1)
+ system_hive =
+ guestfs___download_to_tmp (g, fs, system_path, "system",
+ MAX_REGISTRY_SIZE);
+ if (system_hive == NULL)
- h = hivex_open (tmpdir_basename, g->verbose ? HIVEX_OPEN_VERBOSE : 0);
+ h = hivex_open (system_hive, g->verbose ? HIVEX_OPEN_VERBOSE : 0);
if (h == NULL) {
perrorf (g, "hivex_open");
goto out;
if (h == NULL) {
perrorf (g, "hivex_open");
goto out;
if (h) hivex_close (h);
free (values);
free (system_path);
if (h) hivex_close (h);
free (values);
free (system_path);