[gnome-keyring/trust-store] [gkm] Add function for creating unique filename in transaction.
- From: Stefan Walter <stefw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-keyring/trust-store] [gkm] Add function for creating unique filename in transaction.
- Date: Sun, 19 Sep 2010 02:34:44 +0000 (UTC)
commit be343963893ffd84aff2d2a833c57a66de57542c
Author: Stef Walter <stef memberwebs com>
Date: Sun Sep 19 02:17:01 2010 +0000
[gkm] Add function for creating unique filename in transaction.
Add gkm_transaction_unique_file() function.
pkcs11/gkm/gkm-transaction.c | 104 +++++++++++++++++++++++++---
pkcs11/gkm/gkm-transaction.h | 6 ++-
pkcs11/gkm/tests/unit-test-transaction.c | 110 ++++++++++++++++++++++++++++--
3 files changed, 202 insertions(+), 18 deletions(-)
---
diff --git a/pkcs11/gkm/gkm-transaction.c b/pkcs11/gkm/gkm-transaction.c
index ef45a98..ddadefc 100644
--- a/pkcs11/gkm/gkm-transaction.c
+++ b/pkcs11/gkm/gkm-transaction.c
@@ -61,6 +61,8 @@ typedef struct _Complete {
G_DEFINE_TYPE (GkmTransaction, gkm_transaction, G_TYPE_OBJECT);
+#define MAX_TRIES 100000
+
/* -----------------------------------------------------------------------------
* INTERNAL
*/
@@ -167,15 +169,20 @@ complete_link_temporary (GkmTransaction *self, GObject *unused, gpointer user_da
}
static gboolean
-begin_link_temporary (GkmTransaction *self, const gchar *filename)
+begin_link_temporary_if_exists (GkmTransaction *self, const gchar *filename, gboolean *exists)
{
gchar *result;
+ guint i = 0;
g_assert (GKM_IS_TRANSACTION (self));
g_assert (!gkm_transaction_get_failed (self));
g_assert (filename);
+ g_assert (exists);
+
+ for (i = 0; i < MAX_TRIES; ++i) {
+
+ *exists = TRUE;
- for (;;) {
/* Try to link to random temporary file names */
result = g_strdup_printf ("%s.temp-%d", filename, g_random_int_range (0, G_MAXINT));
if (link (filename, result) == 0) {
@@ -185,6 +192,13 @@ begin_link_temporary (GkmTransaction *self, const gchar *filename)
g_free (result);
+ /* The original file does not exist */
+ if (errno == ENOENT || errno == ENOTDIR) {
+ *exists = FALSE;
+ return TRUE;
+ }
+
+ /* If exists, try again, otherwise fail */
if (errno != EEXIST) {
g_warning ("couldn't create temporary file for: %s: %s", filename, g_strerror (errno));
gkm_transaction_fail (self, CKR_DEVICE_ERROR);
@@ -451,20 +465,21 @@ gkm_transaction_get_result (GkmTransaction *self)
void
gkm_transaction_write_file (GkmTransaction *self, const gchar *filename,
- const guchar *data, gsize n_data)
+ gconstpointer data, gsize n_data)
{
+ gboolean exists;
+
g_return_if_fail (GKM_IS_TRANSACTION (self));
g_return_if_fail (filename);
g_return_if_fail (data);
g_return_if_fail (!gkm_transaction_get_failed (self));
- /* Prepare file to be reverted */
- if (!g_file_test (filename, G_FILE_TEST_EXISTS)) {
+ if (!begin_link_temporary_if_exists (self, filename, &exists))
+ return;
+
+ if (!exists) {
if (!begin_new_file (self, filename))
return;
- } else {
- if (!begin_link_temporary (self, filename))
- return;
}
/* Put data in the expected place */
@@ -474,18 +489,85 @@ gkm_transaction_write_file (GkmTransaction *self, const gchar *filename,
}
}
+gchar*
+gkm_transaction_unique_file (GkmTransaction *self, const gchar *directory,
+ const gchar *basename)
+{
+ gchar *ext;
+ gchar *filename = NULL;
+ gchar *base = NULL;
+ gchar *result = NULL;
+ gint seed = 1;
+ int fd;
+
+ g_return_val_if_fail (GKM_IS_TRANSACTION (self), NULL);
+ g_return_val_if_fail (directory, NULL);
+ g_return_val_if_fail (basename, NULL);
+ g_return_val_if_fail (!gkm_transaction_get_failed (self), NULL);
+
+ filename = g_build_filename (directory, basename, NULL);
+
+ /* Write a zero byte file */
+ fd = g_open (filename, O_RDONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
+ if (fd != -1) {
+ result = g_strdup (basename);
+
+ /* Try to find a unique filename */
+ } else if (errno == EEXIST) {
+ base = g_strdup (basename);
+ ext = strrchr (base, '.');
+ if (ext != NULL)
+ *(ext++) = '\0';
+
+ do {
+ g_free (result);
+ result = g_strdup_printf ("%s_%d%s%s", base, seed++,
+ ext ? "." : "", ext ? ext : "");
+
+ g_free (filename);
+ filename = g_build_filename (directory, result, NULL);
+ fd = g_open (filename, O_RDONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
+
+ } while (seed < MAX_TRIES && fd == -1 && errno == EEXIST);
+ }
+
+ /* Something failed */
+ if (fd == -1){
+ g_warning ("couldn't open file: %s: %s", filename, g_strerror (errno));
+ gkm_transaction_fail (self, CKR_DEVICE_ERROR);
+
+ /* Success, just leave our zero byte file */
+ } else {
+ gkm_transaction_add (self, NULL, complete_new_file, filename);
+ filename = NULL;
+ close (fd);
+ }
+
+ g_free (filename);
+ g_free (base);
+
+ if (gkm_transaction_get_failed (self)) {
+ g_free (result);
+ result = NULL;
+ }
+
+ return result;
+}
+
void
gkm_transaction_remove_file (GkmTransaction *self, const gchar *filename)
{
+ gboolean exists;
+
g_return_if_fail (GKM_IS_TRANSACTION (self));
g_return_if_fail (filename);
g_return_if_fail (!gkm_transaction_get_failed (self));
- /* Already gone? Job accomplished */
- if (!g_file_test (filename, G_FILE_TEST_EXISTS))
+ if (!begin_link_temporary_if_exists (self, filename, &exists))
return;
- if (!begin_link_temporary (self, filename))
+ /* Already gone? Job accomplished */
+ if (!exists)
return;
/* If failure, temporary will automatically be removed */
diff --git a/pkcs11/gkm/gkm-transaction.h b/pkcs11/gkm/gkm-transaction.h
index 9a39bd1..edbdf24 100644
--- a/pkcs11/gkm/gkm-transaction.h
+++ b/pkcs11/gkm/gkm-transaction.h
@@ -69,9 +69,13 @@ CK_RV gkm_transaction_get_result (GkmTransacti
gboolean gkm_transaction_get_completed (GkmTransaction *self);
+gchar* gkm_transaction_unique_file (GkmTransaction *self,
+ const gchar *directory,
+ const gchar *basename);
+
void gkm_transaction_write_file (GkmTransaction *self,
const gchar *filename,
- const guchar *data,
+ gconstpointer data,
gsize n_data);
void gkm_transaction_remove_file (GkmTransaction *self,
diff --git a/pkcs11/gkm/tests/unit-test-transaction.c b/pkcs11/gkm/tests/unit-test-transaction.c
index cc69535..7fc03d2 100644
--- a/pkcs11/gkm/tests/unit-test-transaction.c
+++ b/pkcs11/gkm/tests/unit-test-transaction.c
@@ -25,6 +25,31 @@
#include "gkm/gkm-transaction.h"
+DEFINE_SETUP (transaction_setup)
+{
+ GDir *dir;
+ const gchar *directory;
+ const gchar *basename;
+ gchar *filename;
+
+ directory = testing_scratch_directory ();
+ dir = g_dir_open (directory, 0, NULL);
+ g_assert (dir);
+
+ for (;;) {
+ basename = g_dir_read_name (dir);
+ if (basename == NULL)
+ break;
+ if (g_str_has_prefix (basename, "transaction-")) {
+ filename = g_build_filename (directory, basename, NULL);
+ g_unlink (filename);
+ g_free (filename);
+ }
+ }
+
+ g_dir_close (dir);
+}
+
DEFINE_TEST(transaction_empty)
{
GkmTransaction *transaction;
@@ -190,7 +215,7 @@ DEFINE_TEST(transaction_dispose_completes)
DEFINE_TEST(remove_file_success)
{
GkmTransaction *transaction = gkm_transaction_new ();
- gchar *filename = testing_scratch_filename ("remove-file");
+ gchar *filename = testing_scratch_filename ("transaction-remove");
g_assert (g_file_set_contents (filename, "xxx", 3, NULL));
g_assert (g_file_test (filename, G_FILE_TEST_IS_REGULAR));
@@ -210,7 +235,7 @@ DEFINE_TEST(remove_file_success)
DEFINE_TEST(remove_file_abort)
{
GkmTransaction *transaction = gkm_transaction_new ();
- gchar *filename = testing_scratch_filename ("remove-file");
+ gchar *filename = testing_scratch_filename ("transaction-remove");
gchar *data;
gsize n_data;
@@ -242,7 +267,7 @@ DEFINE_TEST(remove_file_abort)
DEFINE_TEST(remove_file_non_exist)
{
GkmTransaction *transaction = gkm_transaction_new ();
- gchar *filename = testing_scratch_filename ("remove-non-existant");
+ gchar *filename = testing_scratch_filename ("transaction-non-existant");
g_unlink (filename);
@@ -258,7 +283,7 @@ DEFINE_TEST(remove_file_non_exist)
DEFINE_TEST(write_file)
{
GkmTransaction *transaction = gkm_transaction_new ();
- gchar *filename = testing_scratch_filename ("write-test");
+ gchar *filename = testing_scratch_filename ("transaction-test");
gchar *data;
gsize n_data;
@@ -284,7 +309,7 @@ DEFINE_TEST(write_file)
DEFINE_TEST(write_file_abort_gone)
{
GkmTransaction *transaction = gkm_transaction_new ();
- gchar *filename = testing_scratch_filename ("write-test");
+ gchar *filename = testing_scratch_filename ("transaction-test");
gchar *data;
gsize n_data;
@@ -310,7 +335,7 @@ DEFINE_TEST(write_file_abort_gone)
DEFINE_TEST(write_file_abort_revert)
{
GkmTransaction *transaction = gkm_transaction_new ();
- gchar *filename = testing_scratch_filename ("write-test");
+ gchar *filename = testing_scratch_filename ("transaction-test");
gchar *data;
g_assert (g_file_set_contents (filename, "my original", -1, NULL));
@@ -332,3 +357,76 @@ DEFINE_TEST(write_file_abort_revert)
g_object_unref (transaction);
g_free (filename);
}
+
+DEFINE_TEST (unique_file_conflict)
+{
+ GkmTransaction *transaction = gkm_transaction_new ();
+ gchar *filename = testing_scratch_filename ("transaction-test");
+ gchar *dirname;
+ gchar *basename;
+ gchar *result;
+
+ dirname = g_path_get_dirname (filename);
+ basename = g_path_get_basename (filename);
+
+ g_assert (g_file_set_contents (filename, "data", -1, NULL));
+
+ result = gkm_transaction_unique_file (transaction, dirname, basename);
+ g_assert (!gkm_transaction_get_failed (transaction));
+
+ g_assert (result);
+ g_assert_cmpstr (result, !=, basename);
+ g_assert_cmpstr (result, ==, "transaction-test_1");
+
+ g_free (dirname);
+ g_free (basename);
+ g_free (result);
+
+ g_object_unref (transaction);
+ g_free (filename);
+}
+
+DEFINE_TEST (unique_file_conflict_with_ext)
+{
+ GkmTransaction *transaction = gkm_transaction_new ();
+ gchar *filename = testing_scratch_filename ("transaction-test.ext");
+ gchar *dirname;
+ gchar *basename;
+ gchar *result;
+
+ dirname = g_path_get_dirname (filename);
+ basename = g_path_get_basename (filename);
+
+ g_assert (g_file_set_contents (filename, "data", -1, NULL));
+
+ result = gkm_transaction_unique_file (transaction, dirname, basename);
+ g_assert (!gkm_transaction_get_failed (transaction));
+
+ g_assert (result);
+ g_assert_cmpstr (result, !=, basename);
+ g_assert_cmpstr (result, ==, "transaction-test_1.ext");
+
+ g_free (dirname);
+ g_free (basename);
+ g_free (result);
+
+ g_object_unref (transaction);
+ g_free (filename);
+}
+
+DEFINE_TEST (unique_file_no_conflict)
+{
+ GkmTransaction *transaction = gkm_transaction_new ();
+ const gchar *dirname = testing_scratch_directory ();
+ gchar *result;
+
+ result = gkm_transaction_unique_file (transaction, dirname, "transaction-another");
+ g_assert (!gkm_transaction_get_failed (transaction));
+
+ g_assert (result);
+ g_assert_cmpstr (result, ==, "transaction-another");
+
+ g_free (result);
+
+ g_object_unref (transaction);
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]