[hacktree] Ensure we don't get duplicate '.' which leads to corruption
- From: Colin Walters <walters src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [hacktree] Ensure we don't get duplicate '.' which leads to corruption
- Date: Sat, 15 Oct 2011 17:09:35 +0000 (UTC)
commit 36ba6e54269229d227a97c9207235a009a40c1cb
Author: Colin Walters <walters verbum org>
Date: Sat Oct 15 13:04:50 2011 -0400
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).
src/libhacktree/hacktree-repo.c | 165 ++++++++++++++++++++++++++++++++-------
src/libhtutil/ht-unix-utils.c | 8 ++
2 files changed, 145 insertions(+), 28 deletions(-)
---
diff --git a/src/libhacktree/hacktree-repo.c b/src/libhacktree/hacktree-repo.c
index b006557..d80a31d 100644
--- a/src/libhacktree/hacktree-repo.c
+++ b/src/libhacktree/hacktree-repo.c
@@ -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,83 @@ hacktree_repo_commit (HacktreeRepo *self,
if (!add_files_to_tree_and_import (self, base, modified_files, tree, 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))
+ 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;
+ }
+ if (previous_commit)
+ g_variant_unref (previous_commit);
+ parsed_tree_data_free (tree);
+ return ret;
+}
- if (!write_checksum_file (priv->head_ref_path, g_checksum_get_string (ret_commit_checksum), error))
- goto out;
+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_free (priv->current_head);
- priv->current_head = g_strdup (g_checksum_get_string (ret_commit_checksum));
+ 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)
@@ -1267,16 +1379,12 @@ 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);
+ g_clear_object (&datain);
+ g_clear_object (&in);
+ g_free (filename);
parsed_tree_data_free (tree);
- if (commit)
- g_variant_unref (commit);
- if (now)
- g_date_time_unref (now);
return ret;
+
}
static gboolean
@@ -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;
}
diff --git a/src/libhtutil/ht-unix-utils.c b/src/libhtutil/ht-unix-utils.c
index 57aa1f4..375c52a 100644
--- a/src/libhtutil/ht-unix-utils.c
+++ b/src/libhtutil/ht-unix-utils.c
@@ -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;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]