core: Use at-relative lookups for archive-z2 content

We can't quite do it for bare repositories yet because we need to have
a way to go from struct stat -> GFileInfo, and that's buried in gio's
private GLocalFile class.
This commit is contained in:
Colin Walters 2013-09-07 10:10:21 -04:00
parent d2c6e19278
commit 5a685ff989
1 changed files with 105 additions and 71 deletions

View File

@ -767,6 +767,32 @@ list_loose_objects (OstreeRepo *self,
return ret; return ret;
} }
static gboolean
openat_allow_noent (int dfd,
const char *path,
int *fd,
GCancellable *cancellable,
GError **error)
{
GError *temp_error = NULL;
if (!gs_file_openat_noatime (dfd, path, fd,
cancellable, &temp_error))
{
if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
{
*fd = -1;
g_clear_error (&temp_error);
}
else
{
g_propagate_error (error, temp_error);
return FALSE;
}
}
return TRUE;
}
static gboolean static gboolean
load_metadata_internal (OstreeRepo *self, load_metadata_internal (OstreeRepo *self,
OstreeObjectType objtype, OstreeObjectType objtype,
@ -779,11 +805,8 @@ load_metadata_internal (OstreeRepo *self,
GError **error) GError **error)
{ {
gboolean ret = FALSE; gboolean ret = FALSE;
GError *temp_error = NULL;
char loose_path_buf[_OSTREE_LOOSE_PATH_MAX]; char loose_path_buf[_OSTREE_LOOSE_PATH_MAX];
int fd = -1; int fd = -1;
gboolean have_loose_object = FALSE;
gs_unref_object GFile *object_path = NULL;
gs_unref_object GInputStream *ret_stream = NULL; gs_unref_object GInputStream *ret_stream = NULL;
gs_unref_variant GVariant *ret_variant = NULL; gs_unref_variant GVariant *ret_variant = NULL;
@ -791,24 +814,11 @@ load_metadata_internal (OstreeRepo *self,
_ostree_loose_path (loose_path_buf, sha256, objtype, self->mode); _ostree_loose_path (loose_path_buf, sha256, objtype, self->mode);
if (!gs_file_openat_noatime (self->objects_dir_fd, loose_path_buf, &fd, if (!openat_allow_noent (self->objects_dir_fd, loose_path_buf, &fd,
cancellable, &temp_error)) cancellable, error))
{ goto out;
if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
{
have_loose_object = FALSE;
g_clear_error (&temp_error);
}
else
{
g_propagate_error (error, temp_error);
goto out;
}
}
else
have_loose_object = TRUE;
if (have_loose_object) if (fd != -1)
{ {
if (out_variant) if (out_variant)
{ {
@ -852,7 +862,7 @@ load_metadata_internal (OstreeRepo *self,
} }
else if (error_if_not_found) else if (error_if_not_found)
{ {
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
"No such metadata object %s.%s", "No such metadata object %s.%s",
sha256, ostree_object_type_to_string (objtype)); sha256, ostree_object_type_to_string (objtype));
goto out; goto out;
@ -890,73 +900,97 @@ ostree_repo_load_file (OstreeRepo *self,
GError **error) GError **error)
{ {
gboolean ret = FALSE; gboolean ret = FALSE;
gboolean found = FALSE;
OstreeRepoMode repo_mode; OstreeRepoMode repo_mode;
gs_unref_object GFile *loose_path = NULL;
gs_unref_object GInputStream *ret_input = NULL; gs_unref_object GInputStream *ret_input = NULL;
gs_unref_object GFileInfo *ret_file_info = NULL; gs_unref_object GFileInfo *ret_file_info = NULL;
gs_unref_variant GVariant *ret_xattrs = NULL; gs_unref_variant GVariant *ret_xattrs = NULL;
if (!_ostree_repo_find_object (self, OSTREE_OBJECT_TYPE_FILE, checksum, &loose_path,
cancellable, error))
goto out;
repo_mode = ostree_repo_get_mode (self); repo_mode = ostree_repo_get_mode (self);
if (loose_path) if (repo_mode == OSTREE_REPO_MODE_ARCHIVE_Z2)
{ {
switch (repo_mode) char loose_path_buf[_OSTREE_LOOSE_PATH_MAX];
int fd = -1;
struct stat stbuf;
gs_unref_object GInputStream *tmp_stream = NULL;
_ostree_loose_path (loose_path_buf, checksum, OSTREE_OBJECT_TYPE_FILE, self->mode);
if (!openat_allow_noent (self->objects_dir_fd, loose_path_buf, &fd,
cancellable, error))
goto out;
if (fd != -1)
{ {
case OSTREE_REPO_MODE_ARCHIVE_Z2: tmp_stream = g_unix_input_stream_new (fd, TRUE);
{ fd = -1; /* Transfer ownership */
if (!ostree_content_file_parse (TRUE, loose_path, TRUE,
if (!gs_stream_fstat ((GFileDescriptorBased*) tmp_stream, &stbuf,
cancellable, error))
goto out;
if (!ostree_content_stream_parse (TRUE, tmp_stream, stbuf.st_size, TRUE,
out_input ? &ret_input : NULL, out_input ? &ret_input : NULL,
&ret_file_info, &ret_xattrs, &ret_file_info, &ret_xattrs,
cancellable, error)) cancellable, error))
goto out; goto out;
}
break;
case OSTREE_REPO_MODE_BARE:
{
ret_file_info = g_file_query_info (loose_path, OSTREE_GIO_FAST_QUERYINFO,
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
cancellable, error);
if (!ret_file_info)
goto out;
if (out_xattrs) found = TRUE;
{
if (!ostree_get_xattrs_for_file (loose_path, &ret_xattrs,
cancellable, error))
goto out;
}
if (out_input && g_file_info_get_file_type (ret_file_info) == G_FILE_TYPE_REGULAR)
{
ret_input = (GInputStream*) gs_file_read_noatime (loose_path, cancellable, error);
if (!ret_input)
{
g_prefix_error (error, "Error opening loose file object %s: ", gs_file_get_path_cached (loose_path));
goto out;
}
}
}
break;
} }
} }
else if (self->parent_repo)
{
if (!ostree_repo_load_file (self->parent_repo, checksum,
out_input ? &ret_input : NULL,
out_file_info ? &ret_file_info : NULL,
out_xattrs ? &ret_xattrs : NULL,
cancellable, error))
goto out;
}
else else
{ {
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, gs_unref_object GFile *loose_path = NULL;
"Couldn't find file object '%s'", checksum);
goto out; loose_path = _ostree_repo_get_object_path (self, checksum, OSTREE_OBJECT_TYPE_FILE);
if (!ot_gfile_query_info_allow_noent (loose_path, OSTREE_GIO_FAST_QUERYINFO,
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
&ret_file_info,
cancellable, error))
goto out;
if (ret_file_info)
{
if (out_xattrs)
{
if (!ostree_get_xattrs_for_file (loose_path, &ret_xattrs,
cancellable, error))
goto out;
}
if (out_input && g_file_info_get_file_type (ret_file_info) == G_FILE_TYPE_REGULAR)
{
ret_input = (GInputStream*) gs_file_read_noatime (loose_path, cancellable, error);
if (!ret_input)
{
g_prefix_error (error, "Error opening loose file object %s: ", gs_file_get_path_cached (loose_path));
goto out;
}
}
found = TRUE;
}
}
if (!found)
{
if (self->parent_repo)
{
if (!ostree_repo_load_file (self->parent_repo, checksum,
out_input ? &ret_input : NULL,
out_file_info ? &ret_file_info : NULL,
out_xattrs ? &ret_xattrs : NULL,
cancellable, error))
goto out;
}
else
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
"Couldn't find file object '%s'", checksum);
goto out;
}
} }
ret = TRUE; ret = TRUE;