fetcher: Always open tmpfiles in repo (except on FUSE)

This reverts commit 4e61e6f7d0
and re-instates the fix for ensuring that we download temporary
files into the repository location.

However in order to ensure we don't re-introduce
https://github.com/ostreedev/ostree/issues/2900
we detect the case where we're writing to a FUSE mount
and keep the prior behavior.

I've verified that this works with flatpak.

Note a downside of this is the change needs to be triplicated
across the 3 http backends.

This then again
Closes: https://github.com/ostreedev/ostree/issues/2571
This commit is contained in:
Colin Walters 2023-06-29 02:42:04 -04:00
parent 8999d41127
commit ba9c9dedff
8 changed files with 65 additions and 21 deletions

View File

@ -24,6 +24,7 @@
#include <gio/gfiledescriptorbased.h> #include <gio/gfiledescriptorbased.h>
#include <gio/gunixoutputstream.h> #include <gio/gunixoutputstream.h>
#include <glib-unix.h> #include <glib-unix.h>
#include <stdbool.h>
/* These macros came from 7.43.0, but we want to check /* These macros came from 7.43.0, but we want to check
* for versions a bit earlier than that (to work on CentOS 7), * for versions a bit earlier than that (to work on CentOS 7),
@ -76,6 +77,7 @@ struct OstreeFetcher
char *proxy; char *proxy;
struct curl_slist *extra_headers; struct curl_slist *extra_headers;
int tmpdir_dfd; int tmpdir_dfd;
bool force_anonymous;
char *custom_user_agent; char *custom_user_agent;
GMainContext *mainctx; GMainContext *mainctx;
@ -250,6 +252,12 @@ _ostree_fetcher_new (int tmpdir_dfd, const char *remote_name, OstreeFetcherConfi
return fetcher; return fetcher;
} }
void
_ostree_fetcher_set_force_anonymous_tmpfiles (OstreeFetcher *self)
{
self->force_anonymous = true;
}
static void static void
destroy_and_unref_source (GSource *source) destroy_and_unref_source (GSource *source)
{ {
@ -271,13 +279,12 @@ request_get_uri (FetcherRequest *req, GUri *baseuri)
static gboolean static gboolean
ensure_tmpfile (FetcherRequest *req, GError **error) ensure_tmpfile (FetcherRequest *req, GError **error)
{ {
if (!req->tmpf.initialized) if (req->tmpf.initialized)
{ return TRUE;
if (!_ostree_fetcher_tmpf_from_flags (req->flags, req->fetcher->tmpdir_dfd, &req->tmpf, if (req->fetcher->force_anonymous)
error)) return glnx_open_anonymous_tmpfile (O_RDWR | O_CLOEXEC, &req->tmpf, error);
return FALSE; else
} return _ostree_fetcher_tmpf (req->fetcher->tmpdir_dfd, &req->tmpf, error);
return TRUE;
} }
/* Check for completed transfers, and remove their easy handles */ /* Check for completed transfers, and remove their easy handles */

View File

@ -25,6 +25,7 @@
#include <gio/gfiledescriptorbased.h> #include <gio/gfiledescriptorbased.h>
#include <gio/gio.h> #include <gio/gio.h>
#include <gio/gunixoutputstream.h> #include <gio/gunixoutputstream.h>
#include <stdbool.h>
#define LIBSOUP_USE_UNSTABLE_REQUEST_API #define LIBSOUP_USE_UNSTABLE_REQUEST_API
#include <libsoup/soup-request-http.h> #include <libsoup/soup-request-http.h>
#include <libsoup/soup-requester.h> #include <libsoup/soup-requester.h>
@ -59,6 +60,7 @@ typedef struct
char *remote_name; char *remote_name;
int base_tmpdir_dfd; int base_tmpdir_dfd;
bool force_anonymous;
GVariant *extra_headers; GVariant *extra_headers;
gboolean transfer_gzip; gboolean transfer_gzip;
@ -681,6 +683,12 @@ _ostree_fetcher_new (int tmpdir_dfd, const char *remote_name, OstreeFetcherConfi
return self; return self;
} }
void
_ostree_fetcher_set_force_anonymous_tmpfiles (OstreeFetcher *self)
{
self->thread_closure->force_anonymous = true;
}
int int
_ostree_fetcher_get_dfd (OstreeFetcher *fetcher) _ostree_fetcher_get_dfd (OstreeFetcher *fetcher)
{ {
@ -888,9 +896,13 @@ on_stream_read (GObject *object, GAsyncResult *result, gpointer user_data)
{ {
if (!pending->is_membuf) if (!pending->is_membuf)
{ {
if (!_ostree_fetcher_tmpf_from_flags (pending->flags, if (pending->thread_closure->force_anonymous)
pending->thread_closure->base_tmpdir_dfd, {
&pending->tmpf, &local_error)) if (!glnx_open_anonymous_tmpfile (O_RDWR | O_CLOEXEC, &pending->tmpf, &local_error))
goto out;
}
else if (!_ostree_fetcher_tmpf (pending->thread_closure->base_tmpdir_dfd, &pending->tmpf,
&local_error))
goto out; goto out;
pending->out_stream = g_unix_output_stream_new (pending->tmpf.fd, FALSE); pending->out_stream = g_unix_output_stream_new (pending->tmpf.fd, FALSE);
} }

View File

@ -28,6 +28,7 @@
#include <gio/gio.h> #include <gio/gio.h>
#include <gio/gunixoutputstream.h> #include <gio/gunixoutputstream.h>
#include <libsoup/soup.h> #include <libsoup/soup.h>
#include <stdbool.h>
#include "libglnx.h" #include "libglnx.h"
#include "ostree-enumtypes.h" #include "ostree-enumtypes.h"
@ -72,6 +73,7 @@ struct OstreeFetcher
OstreeFetcherConfigFlags config_flags; OstreeFetcherConfigFlags config_flags;
char *remote_name; char *remote_name;
int tmpdir_dfd; int tmpdir_dfd;
bool force_anonymous;
GHashTable *sessions; /* (element-type GMainContext SoupSession ) */ GHashTable *sessions; /* (element-type GMainContext SoupSession ) */
GProxyResolver *proxy_resolver; GProxyResolver *proxy_resolver;
@ -292,6 +294,12 @@ _ostree_fetcher_new (int tmpdir_dfd, const char *remote_name, OstreeFetcherConfi
return self; return self;
} }
void
_ostree_fetcher_set_force_anonymous_tmpfiles (OstreeFetcher *self)
{
self->force_anonymous = true;
}
int int
_ostree_fetcher_get_dfd (OstreeFetcher *self) _ostree_fetcher_get_dfd (OstreeFetcher *self)
{ {
@ -448,8 +456,16 @@ on_stream_read (GObject *object, GAsyncResult *result, gpointer user_data)
{ {
if (!request->is_membuf) if (!request->is_membuf)
{ {
if (!_ostree_fetcher_tmpf_from_flags (request->flags, request->fetcher->tmpdir_dfd, if (request->fetcher->force_anonymous)
&request->tmpf, &local_error)) {
if (!glnx_open_anonymous_tmpfile (O_RDWR | O_CLOEXEC, &request->tmpf, &local_error))
{
g_task_return_error (task, local_error);
return;
}
}
else if (!_ostree_fetcher_tmpf (request->fetcher->tmpdir_dfd, &request->tmpf,
&local_error))
{ {
g_task_return_error (task, local_error); g_task_return_error (task, local_error);
return; return;

View File

@ -32,17 +32,10 @@ G_BEGIN_DECLS
#define OSTREE_FETCHER_USERAGENT_STRING (PACKAGE_NAME "/" PACKAGE_VERSION) #define OSTREE_FETCHER_USERAGENT_STRING (PACKAGE_NAME "/" PACKAGE_VERSION)
static inline gboolean static inline gboolean
_ostree_fetcher_tmpf_from_flags (OstreeFetcherRequestFlags flags, int dfd, GLnxTmpfile *tmpf, _ostree_fetcher_tmpf (int dfd, GLnxTmpfile *tmpf, GError **error)
GError **error)
{ {
if ((flags & OSTREE_FETCHER_REQUEST_LINKABLE) > 0) if (!glnx_open_tmpfile_linkable_at (dfd, ".", O_RDWR | O_CLOEXEC, tmpf, error))
{
if (!glnx_open_tmpfile_linkable_at (dfd, ".", O_RDWR | O_CLOEXEC, tmpf, error))
return FALSE;
}
else if (!glnx_open_anonymous_tmpfile (O_RDWR | O_CLOEXEC, tmpf, error))
return FALSE; return FALSE;
if (!glnx_fchmod (tmpf->fd, 0644, error)) if (!glnx_fchmod (tmpf->fd, 0644, error))
return FALSE; return FALSE;
return TRUE; return TRUE;

View File

@ -88,6 +88,8 @@ GType _ostree_fetcher_get_type (void) G_GNUC_CONST;
OstreeFetcher *_ostree_fetcher_new (int tmpdir_dfd, const char *remote_name, OstreeFetcher *_ostree_fetcher_new (int tmpdir_dfd, const char *remote_name,
OstreeFetcherConfigFlags flags); OstreeFetcherConfigFlags flags);
void _ostree_fetcher_set_force_anonymous_tmpfiles (OstreeFetcher *fetcher);
int _ostree_fetcher_get_dfd (OstreeFetcher *fetcher); int _ostree_fetcher_get_dfd (OstreeFetcher *fetcher);
void _ostree_fetcher_set_cookie_jar (OstreeFetcher *self, const char *jar_path); void _ostree_fetcher_set_cookie_jar (OstreeFetcher *self, const char *jar_path);

View File

@ -193,6 +193,7 @@ struct OstreeRepo
gboolean inited; gboolean inited;
gboolean writable; gboolean writable;
gboolean is_on_fuse; /* TRUE if the repository is on a FUSE filesystem */
OstreeRepoSysrootKind sysroot_kind; OstreeRepoSysrootKind sysroot_kind;
GError *writable_error; GError *writable_error;
gboolean in_transaction; gboolean in_transaction;

View File

@ -2966,6 +2966,8 @@ _ostree_repo_remote_new_fetcher (OstreeRepo *self, const char *remote_name, gboo
} }
fetcher = _ostree_fetcher_new (self->tmp_dir_fd, remote_name, fetcher_flags); fetcher = _ostree_fetcher_new (self->tmp_dir_fd, remote_name, fetcher_flags);
if (self->is_on_fuse)
_ostree_fetcher_set_force_anonymous_tmpfiles (fetcher);
{ {
g_autofree char *tls_client_cert_path = NULL; g_autofree char *tls_client_cert_path = NULL;

View File

@ -3426,6 +3426,17 @@ ostree_repo_open (OstreeRepo *self, GCancellable *cancellable, GError **error)
/* Note - we don't return this error yet! */ /* Note - we don't return this error yet! */
} }
{
struct statfs fsstbuf;
if (fstatfs (self->repo_dir_fd, &fsstbuf) < 0)
return glnx_throw_errno_prefix (error, "fstatfs");
#ifndef FUSE_SUPER_MAGIC
#define FUSE_SUPER_MAGIC 0x65735546
#endif
self->is_on_fuse = (fsstbuf.f_type == FUSE_SUPER_MAGIC);
g_debug ("using fuse: %d", self->is_on_fuse);
}
if (!glnx_fstat (self->objects_dir_fd, &stbuf, error)) if (!glnx_fstat (self->objects_dir_fd, &stbuf, error))
return FALSE; return FALSE;
self->owner_uid = stbuf.st_uid; self->owner_uid = stbuf.st_uid;