[PATCH v2 13/14] lib: Return an error from operations that require an upgrade

Austin Clements amdragon at MIT.EDU
Tue Jul 29 09:48:11 PDT 2014


Previously, there was no protection against a caller invoking an
operation on an old database version that would effectively corrupt
the database by treating it like a newer version.

According to notmuch.h, any caller that opens the database in
read/write mode is supposed to check if the database needs upgrading
and perform an upgrade if it does.  This would protect against this,
but nobody (even the CLI) actually does this.

However, with features, it's easy to protect against incompatible
operations on a fine-grained basis.  This lightweight change allows
callers to safely operate on old database versions, while preventing
specific operations that would corrupt the database with an
informative error message.
---
 lib/database.cc  |  5 +++++
 lib/directory.cc |  5 +++++
 lib/message.cc   |  8 ++++++++
 lib/notmuch.h    | 16 ++++++++++++++++
 4 files changed, 34 insertions(+)

diff --git a/lib/database.cc b/lib/database.cc
index 987b0a6..b323691 100644
--- a/lib/database.cc
+++ b/lib/database.cc
@@ -310,6 +310,8 @@ notmuch_status_to_string (notmuch_status_t status)
 	return "Unbalanced number of calls to notmuch_database_begin_atomic/end_atomic";
     case NOTMUCH_STATUS_UNSUPPORTED_OPERATION:
 	return "Unsupported operation";
+    case NOTMUCH_STATUS_UPGRADE_REQUIRED:
+	return "Operation requires a database upgrade";
     default:
     case NOTMUCH_STATUS_LAST_STATUS:
 	return "Unknown error status value";
@@ -2217,6 +2219,9 @@ notmuch_database_find_message_by_filename (notmuch_database_t *notmuch,
     if (message_ret == NULL)
 	return NOTMUCH_STATUS_NULL_POINTER;
 
+    if (! (notmuch->features & NOTMUCH_FEATURE_FILE_TERMS))
+	return NOTMUCH_STATUS_UPGRADE_REQUIRED;
+
     /* return NULL on any failure */
     *message_ret = NULL;
 
diff --git a/lib/directory.cc b/lib/directory.cc
index 6a3ffed..8daaec8 100644
--- a/lib/directory.cc
+++ b/lib/directory.cc
@@ -105,6 +105,11 @@ _notmuch_directory_create (notmuch_database_t *notmuch,
     const char *db_path;
     notmuch_bool_t create = (flags & NOTMUCH_FIND_CREATE);
 
+    if (! (notmuch->features & NOTMUCH_FEATURE_DIRECTORY_DOCS)) {
+	*status_ret = NOTMUCH_STATUS_UPGRADE_REQUIRED;
+	return NULL;
+    }
+
     *status_ret = NOTMUCH_STATUS_SUCCESS;
 
     path = _notmuch_database_relative_path (notmuch, path);
diff --git a/lib/message.cc b/lib/message.cc
index 4fc427f..1618e81 100644
--- a/lib/message.cc
+++ b/lib/message.cc
@@ -653,6 +653,10 @@ _notmuch_message_add_filename (notmuch_message_t *message,
     if (filename == NULL)
 	INTERNAL_ERROR ("Message filename cannot be NULL.");
 
+    if (! (message->notmuch->features & NOTMUCH_FEATURE_FILE_TERMS) ||
+	! (message->notmuch->features & NOTMUCH_FEATURE_BOOL_FOLDER))
+	return NOTMUCH_STATUS_UPGRADE_REQUIRED;
+
     relative = _notmuch_database_relative_path (message->notmuch, filename);
 
     status = _notmuch_database_split_path (local, relative, &directory, NULL);
@@ -697,6 +701,10 @@ _notmuch_message_remove_filename (notmuch_message_t *message,
     notmuch_private_status_t private_status;
     notmuch_status_t status;
 
+    if (! (message->notmuch->features & NOTMUCH_FEATURE_FILE_TERMS) ||
+	! (message->notmuch->features & NOTMUCH_FEATURE_BOOL_FOLDER))
+	return NOTMUCH_STATUS_UPGRADE_REQUIRED;
+
     status = _notmuch_database_filename_to_direntry (
 	local, message->notmuch, filename, NOTMUCH_FIND_LOOKUP, &direntry);
     if (status || !direntry)
diff --git a/lib/notmuch.h b/lib/notmuch.h
index 3c5ec98..cbf2ba5 100644
--- a/lib/notmuch.h
+++ b/lib/notmuch.h
@@ -160,6 +160,10 @@ typedef enum _notmuch_status {
      */
     NOTMUCH_STATUS_UNSUPPORTED_OPERATION,
     /**
+     * The operation requires a database upgrade.
+     */
+    NOTMUCH_STATUS_UPGRADE_REQUIRED,
+    /**
      * Not an actual status value. Just a way to find out how many
      * valid status values there are.
      */
@@ -438,6 +442,9 @@ notmuch_database_end_atomic (notmuch_database_t *notmuch);
  *
  * NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception occurred;
  *	directory not retrieved.
+ *
+ * NOTMUCH_STATUS_UPGRADE_REQUIRED: The caller must upgrade the
+ * 	database to use this function.
  */
 notmuch_status_t
 notmuch_database_get_directory (notmuch_database_t *database,
@@ -490,6 +497,9 @@ notmuch_database_get_directory (notmuch_database_t *database,
  *
  * NOTMUCH_STATUS_READ_ONLY_DATABASE: Database was opened in read-only
  *	mode so no message can be added.
+ *
+ * NOTMUCH_STATUS_UPGRADE_REQUIRED: The caller must upgrade the
+ * 	database to use this function.
  */
 notmuch_status_t
 notmuch_database_add_message (notmuch_database_t *database,
@@ -520,6 +530,9 @@ notmuch_database_add_message (notmuch_database_t *database,
  *
  * NOTMUCH_STATUS_READ_ONLY_DATABASE: Database was opened in read-only
  *	mode so no message can be removed.
+ *
+ * NOTMUCH_STATUS_UPGRADE_REQUIRED: The caller must upgrade the
+ * 	database to use this function.
  */
 notmuch_status_t
 notmuch_database_remove_message (notmuch_database_t *database,
@@ -575,6 +588,9 @@ notmuch_database_find_message (notmuch_database_t *database,
  * NOTMUCH_STATUS_OUT_OF_MEMORY: Out of memory, creating the message object
  *
  * NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception occurred
+ *
+ * NOTMUCH_STATUS_UPGRADE_REQUIRED: The caller must upgrade the
+ * 	database to use this function.
  */
 notmuch_status_t
 notmuch_database_find_message_by_filename (notmuch_database_t *notmuch,
-- 
2.0.0



More information about the notmuch mailing list