libostree: Move file creation APIs out of core, into checkout.c
Since this was the only user, let's not have generic code to go from OSTree representation -> filesystem here. It should live in checkout.
This commit is contained in:
parent
79c922a00b
commit
36815f52b5
|
|
@ -40,8 +40,6 @@ ostree_checksum_file
|
|||
ostree_checksum_file_async
|
||||
ostree_checksum_file_async_finish
|
||||
ostree_create_directory_metadata
|
||||
ostree_create_file_from_input
|
||||
ostree_create_temp_file_from_input
|
||||
ostree_create_temp_dir
|
||||
ostree_validate_structureof_objtype
|
||||
ostree_validate_structureof_csum_v
|
||||
|
|
|
|||
|
|
@ -1511,214 +1511,6 @@ zlib_file_header_parse (GVariant *metadata,
|
|||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ostree_create_file_from_input:
|
||||
* @dest_file: Destination; must not exist
|
||||
* @finfo: File information
|
||||
* @xattrs: (allow-none): Optional extended attributes
|
||||
* @input: (allow-none): Optional file content, must be %NULL for symbolic links
|
||||
* @cancellable: Cancellable
|
||||
* @error: Error
|
||||
*
|
||||
* Create a directory, regular file, or symbolic link, based on
|
||||
* @finfo. Append extended attributes from @xattrs if provided. For
|
||||
* %G_FILE_TYPE_REGULAR, set content based on @input.
|
||||
*/
|
||||
gboolean
|
||||
ostree_create_file_from_input (GFile *dest_file,
|
||||
GFileInfo *finfo,
|
||||
GVariant *xattrs,
|
||||
GInputStream *input,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
const char *dest_path;
|
||||
guint32 uid, gid, mode;
|
||||
gs_unref_object GOutputStream *out = NULL;
|
||||
|
||||
if (g_cancellable_set_error_if_cancelled (cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
if (finfo != NULL)
|
||||
{
|
||||
mode = g_file_info_get_attribute_uint32 (finfo, "unix::mode");
|
||||
}
|
||||
else
|
||||
{
|
||||
mode = S_IFREG | 0664;
|
||||
}
|
||||
dest_path = gs_file_get_path_cached (dest_file);
|
||||
|
||||
if (S_ISDIR (mode))
|
||||
{
|
||||
if (mkdir (gs_file_get_path_cached (dest_file), mode) < 0)
|
||||
{
|
||||
ot_util_set_error_from_errno (error, errno);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
else if (S_ISREG (mode))
|
||||
{
|
||||
if (finfo != NULL)
|
||||
{
|
||||
uid = g_file_info_get_attribute_uint32 (finfo, "unix::uid");
|
||||
gid = g_file_info_get_attribute_uint32 (finfo, "unix::gid");
|
||||
|
||||
if (!gs_file_create_with_uidgid (dest_file, mode, uid, gid, &out,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!gs_file_create (dest_file, mode, &out,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (input)
|
||||
{
|
||||
if (g_output_stream_splice ((GOutputStream*)out, input, 0,
|
||||
cancellable, error) < 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!g_output_stream_close ((GOutputStream*)out, NULL, error))
|
||||
goto out;
|
||||
|
||||
/* Work around libguestfs/FUSE bug */
|
||||
if (mode & (S_ISUID|S_ISGID))
|
||||
{
|
||||
if (chmod (dest_path, mode) == -1)
|
||||
{
|
||||
ot_util_set_error_from_errno (error, errno);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (S_ISLNK (mode))
|
||||
{
|
||||
const char *target = g_file_info_get_attribute_byte_string (finfo, "standard::symlink-target");
|
||||
if (symlink (target, dest_path) < 0)
|
||||
{
|
||||
ot_util_set_error_from_errno (error, errno);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Invalid mode %u", mode);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* We only need to chown for directories and symlinks; we already
|
||||
* did a chown for files above via fchown().
|
||||
*/
|
||||
if (finfo != NULL && !S_ISREG (mode))
|
||||
{
|
||||
uid = g_file_info_get_attribute_uint32 (finfo, "unix::uid");
|
||||
gid = g_file_info_get_attribute_uint32 (finfo, "unix::gid");
|
||||
|
||||
if (lchown (dest_path, uid, gid) < 0)
|
||||
{
|
||||
ot_util_set_error_from_errno (error, errno);
|
||||
g_prefix_error (error, "lchown(%u, %u) failed: ", uid, gid);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (xattrs != NULL)
|
||||
{
|
||||
if (!ostree_set_xattrs (dest_file, xattrs, cancellable, error))
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
if (!ret && !S_ISDIR(mode))
|
||||
{
|
||||
(void) unlink (dest_path);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ostree_create_temp_file_from_input:
|
||||
* @dir: Target directory
|
||||
* @prefix: Optional prefix
|
||||
* @suffix: Optional suffix
|
||||
* @finfo: File information
|
||||
* @xattrs: (allow-none): Optional extended attributes
|
||||
* @input: (allow-none): Optional file content, must be %NULL for symbolic links
|
||||
* @out_file: (out): Path for newly created directory, file, or symbolic link
|
||||
* @cancellable: Cancellable
|
||||
* @error: Error
|
||||
*
|
||||
* Like ostree_create_file_from_input(), but securely allocates a
|
||||
* randomly-named target in @dir. This is a unified version of
|
||||
* mkstemp()/mkdtemp() that also supports symbolic links.
|
||||
*/
|
||||
gboolean
|
||||
ostree_create_temp_file_from_input (GFile *dir,
|
||||
const char *prefix,
|
||||
const char *suffix,
|
||||
GFileInfo *finfo,
|
||||
GVariant *xattrs,
|
||||
GInputStream *input,
|
||||
GFile **out_file,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
GError *temp_error = NULL;
|
||||
int i = 0;
|
||||
gs_unref_object GFile *possible_file = NULL;
|
||||
|
||||
/* 128 attempts seems reasonable... */
|
||||
for (i = 0; i < 128; i++)
|
||||
{
|
||||
gs_free char *possible_name = NULL;
|
||||
|
||||
if (g_cancellable_set_error_if_cancelled (cancellable, error))
|
||||
goto out;
|
||||
|
||||
possible_name = gsystem_fileutil_gen_tmp_name (prefix, suffix);
|
||||
g_clear_object (&possible_file);
|
||||
possible_file = g_file_get_child (dir, possible_name);
|
||||
|
||||
if (!ostree_create_file_from_input (possible_file, finfo, xattrs, input,
|
||||
cancellable, &temp_error))
|
||||
{
|
||||
if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_EXISTS))
|
||||
{
|
||||
g_clear_error (&temp_error);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_propagate_error (error, temp_error);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i >= 128)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Exhausted 128 attempts to create a temporary file");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
ot_transfer_out_value(out_file, &possible_file);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ostree_create_temp_dir:
|
||||
* @dir: Use this as temporary base
|
||||
|
|
|
|||
|
|
@ -228,23 +228,6 @@ gboolean ostree_checksum_file_async_finish (GFile *f,
|
|||
GVariant *ostree_create_directory_metadata (GFileInfo *dir_info,
|
||||
GVariant *xattrs);
|
||||
|
||||
gboolean ostree_create_file_from_input (GFile *dest_file,
|
||||
GFileInfo *finfo,
|
||||
GVariant *xattrs,
|
||||
GInputStream *input,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
gboolean ostree_create_temp_file_from_input (GFile *dir,
|
||||
const char *prefix,
|
||||
const char *suffix,
|
||||
GFileInfo *finfo,
|
||||
GVariant *xattrs,
|
||||
GInputStream *input,
|
||||
GFile **out_file,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
gboolean ostree_create_temp_dir (GFile *dir,
|
||||
const char *prefix,
|
||||
const char *suffix,
|
||||
|
|
|
|||
|
|
@ -28,6 +28,214 @@
|
|||
#include "ostree-repo-file.h"
|
||||
#include "ostree-repo-private.h"
|
||||
|
||||
/*
|
||||
* create_file_from_input:
|
||||
* @dest_file: Destination; must not exist
|
||||
* @finfo: File information
|
||||
* @xattrs: (allow-none): Optional extended attributes
|
||||
* @input: (allow-none): Optional file content, must be %NULL for symbolic links
|
||||
* @cancellable: Cancellable
|
||||
* @error: Error
|
||||
*
|
||||
* Create a directory, regular file, or symbolic link, based on
|
||||
* @finfo. Append extended attributes from @xattrs if provided. For
|
||||
* %G_FILE_TYPE_REGULAR, set content based on @input.
|
||||
*/
|
||||
static gboolean
|
||||
create_file_from_input (GFile *dest_file,
|
||||
GFileInfo *finfo,
|
||||
GVariant *xattrs,
|
||||
GInputStream *input,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
const char *dest_path;
|
||||
guint32 uid, gid, mode;
|
||||
gs_unref_object GOutputStream *out = NULL;
|
||||
|
||||
if (g_cancellable_set_error_if_cancelled (cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
if (finfo != NULL)
|
||||
{
|
||||
mode = g_file_info_get_attribute_uint32 (finfo, "unix::mode");
|
||||
}
|
||||
else
|
||||
{
|
||||
mode = S_IFREG | 0664;
|
||||
}
|
||||
dest_path = gs_file_get_path_cached (dest_file);
|
||||
|
||||
if (S_ISDIR (mode))
|
||||
{
|
||||
if (mkdir (gs_file_get_path_cached (dest_file), mode) < 0)
|
||||
{
|
||||
ot_util_set_error_from_errno (error, errno);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
else if (S_ISREG (mode))
|
||||
{
|
||||
if (finfo != NULL)
|
||||
{
|
||||
uid = g_file_info_get_attribute_uint32 (finfo, "unix::uid");
|
||||
gid = g_file_info_get_attribute_uint32 (finfo, "unix::gid");
|
||||
|
||||
if (!gs_file_create_with_uidgid (dest_file, mode, uid, gid, &out,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!gs_file_create (dest_file, mode, &out,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (input)
|
||||
{
|
||||
if (g_output_stream_splice ((GOutputStream*)out, input, 0,
|
||||
cancellable, error) < 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!g_output_stream_close ((GOutputStream*)out, NULL, error))
|
||||
goto out;
|
||||
|
||||
/* Work around libguestfs/FUSE bug */
|
||||
if (mode & (S_ISUID|S_ISGID))
|
||||
{
|
||||
if (chmod (dest_path, mode) == -1)
|
||||
{
|
||||
ot_util_set_error_from_errno (error, errno);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (S_ISLNK (mode))
|
||||
{
|
||||
const char *target = g_file_info_get_attribute_byte_string (finfo, "standard::symlink-target");
|
||||
if (symlink (target, dest_path) < 0)
|
||||
{
|
||||
ot_util_set_error_from_errno (error, errno);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Invalid mode %u", mode);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* We only need to chown for directories and symlinks; we already
|
||||
* did a chown for files above via fchown().
|
||||
*/
|
||||
if (finfo != NULL && !S_ISREG (mode))
|
||||
{
|
||||
uid = g_file_info_get_attribute_uint32 (finfo, "unix::uid");
|
||||
gid = g_file_info_get_attribute_uint32 (finfo, "unix::gid");
|
||||
|
||||
if (lchown (dest_path, uid, gid) < 0)
|
||||
{
|
||||
ot_util_set_error_from_errno (error, errno);
|
||||
g_prefix_error (error, "lchown(%u, %u) failed: ", uid, gid);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (xattrs != NULL)
|
||||
{
|
||||
if (!ostree_set_xattrs (dest_file, xattrs, cancellable, error))
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
if (!ret && !S_ISDIR(mode))
|
||||
{
|
||||
(void) unlink (dest_path);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* create_temp_file_from_input:
|
||||
* @dir: Target directory
|
||||
* @prefix: Optional prefix
|
||||
* @suffix: Optional suffix
|
||||
* @finfo: File information
|
||||
* @xattrs: (allow-none): Optional extended attributes
|
||||
* @input: (allow-none): Optional file content, must be %NULL for symbolic links
|
||||
* @out_file: (out): Path for newly created directory, file, or symbolic link
|
||||
* @cancellable: Cancellable
|
||||
* @error: Error
|
||||
*
|
||||
* Like create_file_from_input(), but securely allocates a
|
||||
* randomly-named target in @dir. This is a unified version of
|
||||
* mkstemp()/mkdtemp() that also supports symbolic links.
|
||||
*/
|
||||
static gboolean
|
||||
create_temp_file_from_input (GFile *dir,
|
||||
const char *prefix,
|
||||
const char *suffix,
|
||||
GFileInfo *finfo,
|
||||
GVariant *xattrs,
|
||||
GInputStream *input,
|
||||
GFile **out_file,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
GError *temp_error = NULL;
|
||||
int i = 0;
|
||||
gs_unref_object GFile *possible_file = NULL;
|
||||
|
||||
/* 128 attempts seems reasonable... */
|
||||
for (i = 0; i < 128; i++)
|
||||
{
|
||||
gs_free char *possible_name = NULL;
|
||||
|
||||
if (g_cancellable_set_error_if_cancelled (cancellable, error))
|
||||
goto out;
|
||||
|
||||
possible_name = gsystem_fileutil_gen_tmp_name (prefix, suffix);
|
||||
g_clear_object (&possible_file);
|
||||
possible_file = g_file_get_child (dir, possible_name);
|
||||
|
||||
if (!create_file_from_input (possible_file, finfo, xattrs, input,
|
||||
cancellable, &temp_error))
|
||||
{
|
||||
if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_EXISTS))
|
||||
{
|
||||
g_clear_error (&temp_error);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_propagate_error (error, temp_error);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i >= 128)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Exhausted 128 attempts to create a temporary file");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
ot_transfer_out_value(out_file, &possible_file);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
checkout_file_from_input (GFile *file,
|
||||
OstreeRepoCheckoutMode mode,
|
||||
|
|
@ -60,7 +268,7 @@ checkout_file_from_input (GFile *file,
|
|||
{
|
||||
if (g_file_info_get_file_type (temp_info) == G_FILE_TYPE_DIRECTORY)
|
||||
{
|
||||
if (!ostree_create_file_from_input (file, temp_info,
|
||||
if (!create_file_from_input (file, temp_info,
|
||||
xattrs, input,
|
||||
cancellable, &temp_error))
|
||||
{
|
||||
|
|
@ -78,7 +286,7 @@ checkout_file_from_input (GFile *file,
|
|||
else
|
||||
{
|
||||
dir = g_file_get_parent (file);
|
||||
if (!ostree_create_temp_file_from_input (dir, NULL, "checkout",
|
||||
if (!create_temp_file_from_input (dir, NULL, "checkout",
|
||||
temp_info, xattrs, input, &temp_file,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
|
|
@ -98,7 +306,7 @@ checkout_file_from_input (GFile *file,
|
|||
}
|
||||
else
|
||||
{
|
||||
if (!ostree_create_file_from_input (file, temp_info,
|
||||
if (!create_file_from_input (file, temp_info,
|
||||
xattrs, input, cancellable, error))
|
||||
goto out;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue