mirror of
https://github.com/ostreedev/ostree.git
synced 2025-03-19 22:50:35 +03:00
Ensure we don't get duplicate '.' which leads to corruption
In path_split(), we squash '.' entirely, since it's redundant and if we don't, we return an extra component which callers would then have to handle. In repo, ensure we're never explicitly parsing '.' either (yet).
This commit is contained in:
parent
2bd973f645
commit
36ba6e5426
@ -25,6 +25,7 @@
|
||||
#include "htutil.h"
|
||||
|
||||
#include <gio/gunixoutputstream.h>
|
||||
#include <gio/gunixinputstream.h>
|
||||
|
||||
static gboolean
|
||||
link_one_file (HacktreeRepo *self, const char *path,
|
||||
@ -875,6 +876,13 @@ check_path (const char *filename,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (strcmp (filename, ".") == 0)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Self-reference '.' in filename '%s' not allowed (yet)", filename);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ht_util_filename_has_dotdot (filename))
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
@ -1117,6 +1125,8 @@ add_one_path_to_tree_and_import (HacktreeRepo *self,
|
||||
file_sha1 = g_hash_table_lookup (current_tree->files, component);
|
||||
dir = g_hash_table_lookup (current_tree->directories, component);
|
||||
|
||||
g_assert_cmpstr (component, !=, ".");
|
||||
|
||||
if (i < components->len - 1)
|
||||
{
|
||||
if (file_sha1 != NULL)
|
||||
@ -1195,6 +1205,56 @@ add_files_to_tree_and_import (HacktreeRepo *self,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
commit_parsed_tree (HacktreeRepo *self,
|
||||
const char *subject,
|
||||
const char *body,
|
||||
GVariant *metadata,
|
||||
ParsedTreeData *tree,
|
||||
GChecksum **out_commit,
|
||||
GError **error)
|
||||
{
|
||||
HacktreeRepoPrivate *priv = GET_PRIVATE (self);
|
||||
gboolean ret = FALSE;
|
||||
GChecksum *root_checksum = NULL;
|
||||
GChecksum *ret_commit = NULL;
|
||||
GVariant *commit = NULL;
|
||||
GDateTime *now = NULL;
|
||||
|
||||
if (!import_parsed_tree (self, tree, &root_checksum, error))
|
||||
goto out;
|
||||
|
||||
now = g_date_time_new_now_utc ();
|
||||
commit = g_variant_new ("(u@a{sv}sssts)",
|
||||
HACKTREE_COMMIT_VERSION,
|
||||
create_empty_gvariant_dict (),
|
||||
priv->current_head ? priv->current_head : "",
|
||||
subject, body ? body : "",
|
||||
g_date_time_to_unix (now) / G_TIME_SPAN_SECOND,
|
||||
g_checksum_get_string (root_checksum));
|
||||
if (!import_gvariant_object (self, HACKTREE_SERIALIZED_COMMIT_VARIANT,
|
||||
commit, &ret_commit, error))
|
||||
goto out;
|
||||
|
||||
if (!write_checksum_file (priv->head_ref_path, g_checksum_get_string (ret_commit), error))
|
||||
goto out;
|
||||
|
||||
g_free (priv->current_head);
|
||||
priv->current_head = g_strdup (g_checksum_get_string (ret_commit));
|
||||
|
||||
ret = TRUE;
|
||||
*out_commit = ret_commit;
|
||||
out:
|
||||
if (root_checksum)
|
||||
g_checksum_free (root_checksum);
|
||||
if (commit)
|
||||
g_variant_unref (commit);
|
||||
if (now)
|
||||
g_date_time_unref (now);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
gboolean
|
||||
hacktree_repo_commit (HacktreeRepo *self,
|
||||
const char *subject,
|
||||
@ -1210,10 +1270,7 @@ hacktree_repo_commit (HacktreeRepo *self,
|
||||
gboolean ret = FALSE;
|
||||
ParsedTreeData *tree = NULL;
|
||||
GVariant *previous_commit = NULL;
|
||||
GVariant *commit = NULL;
|
||||
GChecksum *root_checksum = NULL;
|
||||
GChecksum *ret_commit_checksum = NULL;
|
||||
GDateTime *now = NULL;
|
||||
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
||||
g_return_val_if_fail (priv->inited, FALSE);
|
||||
@ -1234,28 +1291,10 @@ hacktree_repo_commit (HacktreeRepo *self,
|
||||
|
||||
if (!add_files_to_tree_and_import (self, base, modified_files, tree, error))
|
||||
goto out;
|
||||
|
||||
if (!commit_parsed_tree (self, subject, body, metadata, tree, &ret_commit_checksum, error))
|
||||
goto out;
|
||||
|
||||
if (!import_parsed_tree (self, tree, &root_checksum, error))
|
||||
goto out;
|
||||
|
||||
now = g_date_time_new_now_utc ();
|
||||
commit = g_variant_new ("(u@a{sv}sssts)",
|
||||
HACKTREE_COMMIT_VERSION,
|
||||
create_empty_gvariant_dict (),
|
||||
priv->current_head ? priv->current_head : "",
|
||||
subject, body ? body : "",
|
||||
g_date_time_to_unix (now) / G_TIME_SPAN_SECOND,
|
||||
g_checksum_get_string (root_checksum));
|
||||
if (!import_gvariant_object (self, HACKTREE_SERIALIZED_COMMIT_VARIANT,
|
||||
commit, &ret_commit_checksum, error))
|
||||
goto out;
|
||||
|
||||
if (!write_checksum_file (priv->head_ref_path, g_checksum_get_string (ret_commit_checksum), error))
|
||||
goto out;
|
||||
|
||||
g_free (priv->current_head);
|
||||
priv->current_head = g_strdup (g_checksum_get_string (ret_commit_checksum));
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
if (!ret)
|
||||
@ -1267,18 +1306,87 @@ hacktree_repo_commit (HacktreeRepo *self,
|
||||
{
|
||||
*out_commit = ret_commit_checksum;
|
||||
}
|
||||
if (root_checksum)
|
||||
g_checksum_free (root_checksum);
|
||||
if (previous_commit)
|
||||
g_variant_unref (previous_commit);
|
||||
parsed_tree_data_free (tree);
|
||||
if (commit)
|
||||
g_variant_unref (commit);
|
||||
if (now)
|
||||
g_date_time_unref (now);
|
||||
return ret;
|
||||
}
|
||||
|
||||
gboolean
|
||||
hacktree_repo_commit_from_filelist_fd (HacktreeRepo *self,
|
||||
const char *subject,
|
||||
const char *body,
|
||||
GVariant *metadata,
|
||||
const char *base,
|
||||
int fd,
|
||||
char separator,
|
||||
GChecksum **out_commit,
|
||||
GError **error)
|
||||
{
|
||||
HacktreeRepoPrivate *priv = GET_PRIVATE (self);
|
||||
gboolean ret = FALSE;
|
||||
ParsedTreeData *tree = NULL;
|
||||
GVariant *previous_commit = NULL;
|
||||
GChecksum *ret_commit_checksum = NULL;
|
||||
GUnixInputStream *in = NULL;
|
||||
GDataInputStream *datain = NULL;
|
||||
char *filename = NULL;
|
||||
gsize filename_len;
|
||||
GError *temp_error = NULL;
|
||||
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
||||
g_return_val_if_fail (priv->inited, FALSE);
|
||||
|
||||
/* We're overwriting the tree */
|
||||
tree = parsed_tree_data_new ();
|
||||
|
||||
in = (GUnixInputStream*)g_unix_input_stream_new (fd, FALSE);
|
||||
datain = g_data_input_stream_new ((GInputStream*)in);
|
||||
|
||||
while ((filename = g_data_input_stream_read_upto (datain, &separator, 1,
|
||||
&filename_len, NULL, &temp_error)) != NULL)
|
||||
{
|
||||
if (!g_data_input_stream_read_byte (datain, NULL, &temp_error))
|
||||
{
|
||||
if (temp_error != NULL)
|
||||
{
|
||||
g_propagate_prefixed_error (error, temp_error, "%s", "While reading filelist: ");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
if (!add_one_path_to_tree_and_import (self, base, filename, tree, error))
|
||||
goto out;
|
||||
g_free (filename);
|
||||
filename = NULL;
|
||||
}
|
||||
if (filename == NULL && temp_error != NULL)
|
||||
{
|
||||
g_propagate_prefixed_error (error, temp_error, "%s", "While reading filelist: ");
|
||||
goto out;
|
||||
}
|
||||
if (!commit_parsed_tree (self, subject, body, metadata,
|
||||
tree, &ret_commit_checksum, error))
|
||||
goto out;
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
if (!ret)
|
||||
{
|
||||
if (ret_commit_checksum)
|
||||
g_checksum_free (ret_commit_checksum);
|
||||
}
|
||||
else
|
||||
{
|
||||
*out_commit = ret_commit_checksum;
|
||||
}
|
||||
g_clear_object (&datain);
|
||||
g_clear_object (&in);
|
||||
g_free (filename);
|
||||
parsed_tree_data_free (tree);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
static gboolean
|
||||
iter_object_dir (HacktreeRepo *self,
|
||||
GFile *dir,
|
||||
@ -1491,6 +1599,7 @@ checkout_one_directory (HacktreeRepo *self,
|
||||
if (mkdir (dest_path, (mode_t)mode) < 0)
|
||||
{
|
||||
ht_util_set_error_from_errno (error, errno);
|
||||
g_prefix_error (error, "Failed to create directory '%s': ", dest_path);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
@ -100,6 +100,7 @@ ht_util_path_split (const char *path)
|
||||
GPtrArray *ret = NULL;
|
||||
const char *p;
|
||||
const char *slash;
|
||||
int i;
|
||||
|
||||
g_return_val_if_fail (path[0] != '/', NULL);
|
||||
|
||||
@ -121,6 +122,13 @@ ht_util_path_split (const char *path)
|
||||
}
|
||||
} while (p && *p);
|
||||
|
||||
/* Canonicalize by removing duplicate '.' */
|
||||
for (i = ret->len-1; i >= 0; i--)
|
||||
{
|
||||
if (strcmp (ret->pdata[i], ".") == 0)
|
||||
g_ptr_array_remove_index (ret, i);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user