core: Further unify API to create files

We now have just one place which writes to the filesystem.  Wrap a
temporary file allocation API on top of that.
This commit is contained in:
Colin Walters 2011-12-02 11:22:32 -05:00
parent c7235182a4
commit d1950da1a0
5 changed files with 224 additions and 166 deletions

View File

@ -881,6 +881,7 @@ ostree_create_file_from_input (GFile *dest_file,
GFileInfo *finfo,
GVariant *xattrs,
GInputStream *input,
OstreeObjectType objtype,
GChecksum **out_checksum,
GCancellable *cancellable,
GError **error)
@ -891,14 +892,22 @@ ostree_create_file_from_input (GFile *dest_file,
guint32 uid, gid, mode;
GChecksum *ret_checksum = NULL;
uid = g_file_info_get_attribute_uint32 (finfo, "unix::uid");
gid = g_file_info_get_attribute_uint32 (finfo, "unix::gid");
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 | 0666;
}
dest_path = ot_gfile_get_path_cached (dest_file);
if (S_ISREG (mode))
{
out = g_file_replace (dest_file, NULL, FALSE, 0, NULL, error);
out = g_file_create (dest_file, 0, cancellable, error);
if (!out)
goto out;
@ -913,6 +922,7 @@ ostree_create_file_from_input (GFile *dest_file,
else if (S_ISLNK (mode))
{
const char *target = g_file_info_get_attribute_byte_string (finfo, "standard::symlink-target");
g_assert (objtype == OSTREE_OBJECT_TYPE_FILE);
if (ret_checksum)
g_checksum_update (ret_checksum, (guint8*)target, strlen (target));
if (symlink (target, dest_path) < 0)
@ -924,6 +934,7 @@ ostree_create_file_from_input (GFile *dest_file,
else if (S_ISCHR (mode) || S_ISBLK (mode))
{
guint32 dev = g_file_info_get_attribute_uint32 (finfo, "unix::rdev");
g_assert (objtype == OSTREE_OBJECT_TYPE_FILE);
if (ret_checksum)
g_checksum_update (ret_checksum, (guint8*)&dev, 4);
if (mknod (dest_path, mode, dev) < 0)
@ -934,6 +945,7 @@ ostree_create_file_from_input (GFile *dest_file,
}
else if (S_ISFIFO (mode))
{
g_assert (objtype == OSTREE_OBJECT_TYPE_FILE);
if (mkfifo (dest_path, mode) < 0)
{
ot_util_set_error_from_errno (error, errno);
@ -947,11 +959,22 @@ ostree_create_file_from_input (GFile *dest_file,
goto out;
}
if (finfo != NULL)
{
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);
goto out;
}
}
else
{
uid = geteuid ();
gid = getegid ();
}
if (!S_ISLNK (mode))
{
@ -962,12 +985,17 @@ ostree_create_file_from_input (GFile *dest_file,
}
}
if (xattrs != NULL)
{
g_assert (objtype == OSTREE_OBJECT_TYPE_FILE);
if (!ostree_set_xattrs (dest_file, xattrs, cancellable, error))
goto out;
}
if (ret_checksum)
if (ret_checksum && objtype == OSTREE_OBJECT_TYPE_FILE)
{
ostree_checksum_update_stat (ret_checksum, uid, gid, mode);
if (xattrs)
g_checksum_update (ret_checksum, (guint8*)g_variant_get_data (xattrs), g_variant_get_size (xattrs));
}
@ -985,6 +1013,165 @@ ostree_create_file_from_input (GFile *dest_file,
return ret;
}
static GString *
create_tmp_string (const char *dirpath,
const char *prefix,
const char *suffix)
{
GString *tmp_name = NULL;
if (!prefix)
prefix = "tmp-";
if (!suffix)
suffix = ".tmp";
tmp_name = g_string_new (dirpath);
g_string_append_c (tmp_name, '/');
g_string_append (tmp_name, prefix);
g_string_append (tmp_name, "XXXXXX");
g_string_append (tmp_name, suffix);
return tmp_name;
}
static char *
subst_xxxxxx (GRand *rand,
const char *string)
{
static const char table[] = "ABCEDEFGHIJKLMNOPQRSTUVWXYZabcedefghijklmnopqrstuvwxyz0123456789";
char *ret = g_strdup (string);
guint8 *xxxxxx = (guint8*)strstr (ret, "XXXXXX");
g_assert (xxxxxx != NULL);
while (*xxxxxx == 'X')
{
int offset = g_random_int_range (0, sizeof (table));
*xxxxxx = (guint8)table[offset];
xxxxxx++;
}
return ret;
}
gboolean
ostree_create_temp_file_from_input (GFile *dir,
const char *prefix,
const char *suffix,
GFileInfo *finfo,
GVariant *xattrs,
GInputStream *input,
OstreeObjectType objtype,
GFile **out_file,
GChecksum **out_checksum,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
GChecksum *ret_checksum = NULL;
GRand *rand = NULL;
GString *tmp_name = NULL;
char *possible_name = NULL;
GFile *possible_file = NULL;
GError *temp_error = NULL;
int i = 0;
rand = g_rand_new ();
tmp_name = create_tmp_string (ot_gfile_get_path_cached (dir),
prefix, suffix);
/* 128 attempts seems reasonable... */
for (i = 0; i < 128; i++)
{
g_free (possible_name);
possible_name = subst_xxxxxx (rand, tmp_name->str);
g_clear_object (&possible_file);
possible_file = ot_gfile_new_for_path (possible_name);
if (!ostree_create_file_from_input (possible_file, finfo, xattrs, input,
objtype,
out_checksum ? &ret_checksum : NULL,
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;
if (out_checksum)
{
*out_checksum = ret_checksum;
ret_checksum = NULL;
}
if (out_file)
{
*out_file = possible_file;
possible_file = NULL;
}
out:
if (rand)
g_rand_free (rand);
if (tmp_name)
g_string_free (tmp_name, TRUE);
g_free (possible_name);
g_clear_object (&possible_file);
ot_clear_checksum (&ret_checksum);
return ret;
}
gboolean
ostree_create_temp_regular_file (GFile *dir,
const char *prefix,
const char *suffix,
GFile **out_file,
GOutputStream **out_stream,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
GFile *ret_file = NULL;
GOutputStream *ret_stream = NULL;
if (!ostree_create_temp_file_from_input (dir, prefix, suffix, NULL, NULL, NULL,
OSTREE_OBJECT_TYPE_FILE, &ret_file,
NULL, cancellable, error))
goto out;
ret_stream = (GOutputStream*)g_file_append_to (ret_file, 0, cancellable, error);
if (ret_stream == NULL)
goto out;
ret = TRUE;
*out_file = ret_file;
ret_file = NULL;
*out_stream = ret_stream;
ret_stream = NULL;
out:
g_clear_object (&ret_file);
g_clear_object (&ret_stream);
return ret;
}
static gboolean
unpack_file (GFile *file,
GFile *dest_file,
@ -1003,6 +1190,7 @@ unpack_file (GFile *file,
goto out;
if (!ostree_create_file_from_input (dest_file, finfo, xattrs, in,
OSTREE_OBJECT_TYPE_FILE,
out_checksum ? &ret_checksum : NULL,
cancellable, error))
goto out;

View File

@ -166,10 +166,31 @@ gboolean ostree_create_file_from_input (GFile *file,
GFileInfo *finfo,
GVariant *xattrs,
GInputStream *input,
OstreeObjectType objtype,
GChecksum **out_checksum,
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,
OstreeObjectType objtype,
GFile **out_file,
GChecksum **out_checksum,
GCancellable *cancellable,
GError **error);
gboolean ostree_create_temp_regular_file (GFile *dir,
const char *prefix,
const char *suffix,
GFile **out_file,
GOutputStream **out_stream,
GCancellable *cancellable,
GError **error);
gboolean ostree_parse_packed_file (GFile *file,
GFileInfo **out_file_info,
GVariant **out_xattrs,

View File

@ -592,14 +592,10 @@ stage_and_checksum (OstreeRepo *self,
break;
}
if (!ot_gfile_create_tmp (priv->tmp_dir, prefix, NULL, 0666,
&tmp_f, &stream, cancellable, error))
goto out;
if (!ot_gio_splice_and_checksum (stream, input, &ret_checksum, cancellable, error))
goto out;
if (!g_output_stream_close ((GOutputStream*)stream, NULL, error))
if (!ostree_create_temp_file_from_input (priv->tmp_dir, prefix, NULL, NULL,
NULL, input, OSTREE_OBJECT_TYPE_META,
&tmp_f, &ret_checksum,
cancellable, error))
goto out;
ret_tmpname = g_file_get_child (priv->tmp_dir, g_checksum_get_string (ret_checksum));

View File

@ -196,135 +196,6 @@ ot_gio_splice_and_checksum (GOutputStream *out,
return ret;
}
static GString *
create_tmp_string (const char *dirpath,
const char *prefix,
const char *suffix)
{
GString *tmp_name = NULL;
if (!prefix)
prefix = "tmp-";
if (!suffix)
suffix = ".tmp";
tmp_name = g_string_new (dirpath);
g_string_append_c (tmp_name, '/');
g_string_append (tmp_name, prefix);
g_string_append (tmp_name, "XXXXXX");
g_string_append (tmp_name, suffix);
return tmp_name;
}
gboolean
ot_gfile_create_tmp (GFile *dir,
const char *prefix,
const char *suffix,
int mode,
GFile **out_file,
GOutputStream **out_stream,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
GString *tmp_name = NULL;
int tmpfd = -1;
GFile *ret_file = NULL;
GOutputStream *ret_stream = NULL;
if (g_cancellable_set_error_if_cancelled (cancellable, error))
return FALSE;
tmp_name = create_tmp_string (ot_gfile_get_path_cached (dir), prefix, suffix);
tmpfd = g_mkstemp_full (tmp_name->str, O_WRONLY | O_BINARY, mode);
if (tmpfd == -1)
{
ot_util_set_error_from_errno (error, errno);
goto out;
}
ret_file = ot_gfile_new_for_path (tmp_name->str);
ret_stream = g_unix_output_stream_new (tmpfd, TRUE);
ret = TRUE;
if (out_file)
{
*out_file = ret_file;
ret_file = NULL;
}
if (out_stream)
{
*out_stream = ret_stream;
ret_stream = NULL;
}
out:
g_clear_object (&ret_file);
g_clear_object (&ret_stream);
g_string_free (tmp_name, TRUE);
return ret;
}
static char *
subst_xxxxxx (GRand *rand,
const char *string)
{
char *ret = g_strdup (string);
guint8 *xxxxxx = (guint8*)strstr (ret, "XXXXXX");
g_assert (xxxxxx != NULL);
while (*xxxxxx == 'X')
{
*xxxxxx = (guint8)g_random_int_range (0, 255);
xxxxxx++;
}
return ret;
}
gboolean
ot_gfile_create_tmp_symlink (const char *target,
GFile *dir,
const char *prefix,
const char *suffix,
GFile **out_file,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
GRand *rand = NULL;
GString *tmp_name = NULL;
char *possible_name = NULL;
rand = g_rand_new ();
tmp_name = create_tmp_string (ot_gfile_get_path_cached (dir),
prefix, suffix);
while (TRUE)
{
g_free (possible_name);
possible_name = subst_xxxxxx (rand, tmp_name->str);
if (symlink (target, possible_name) < 0)
{
if (errno == EEXIST)
continue;
ot_util_set_error_from_errno (error, errno);
goto out;
}
}
*out_file = ot_gfile_new_for_path (possible_name);
out:
g_string_free (tmp_name, TRUE);
g_free (possible_name);
if (rand)
g_rand_free (rand);
return ret;
}
gboolean
ot_gfile_merge_dirs (GFile *destination,
GFile *src,

View File

@ -51,24 +51,6 @@ gboolean ot_gio_splice_and_checksum (GOutputStream *out,
GCancellable *cancellable,
GError **error);
gboolean ot_gfile_create_tmp (GFile *dir,
const char *prefix,
const char *suffix,
int mode,
GFile **out_file,
GOutputStream **out_stream,
GCancellable *cancellable,
GError **error);
gboolean ot_gfile_create_tmp_symlink (const char *target,
GFile *dir,
const char *prefix,
const char *suffix,
GFile **out_file,
GCancellable *cancellable,
GError **error);
gboolean ot_gfile_merge_dirs (GFile *destination,
GFile *src,
GCancellable *cancellable,