lib: Consolidate checks for read-only database.
authorCarl Worth <cworth@cworth.org>
Thu, 7 Jan 2010 18:19:44 +0000 (10:19 -0800)
committerCarl Worth <cworth@cworth.org>
Thu, 7 Jan 2010 18:19:44 +0000 (10:19 -0800)
Previously, many checks were deep in the library just before a cast
operation. These have now been replaced with internal errors and new
checks have instead been added at the beginning of all top-levelentry
points requiring a read-write database.

The new checks now also use a single function for checking and
printing the error message. This will give us a convenient location to
extend the check, (such as based on database version as well).

lib/database.cc
lib/directory.cc
lib/message.cc
lib/notmuch-private.h
lib/notmuch.h

index 125b37ebb6b5538d4d4d07cf2d6c3eaef2df7ee2..807e39eda50917b5f46ad800f381641cabc60461 100644 (file)
@@ -475,6 +475,17 @@ notmuch_database_create (const char *path)
     return notmuch;
 }
 
+notmuch_status_t
+_notmuch_database_ensure_writable (notmuch_database_t *notmuch)
+{
+    if (notmuch->mode == NOTMUCH_DATABASE_MODE_READ_ONLY) {
+       fprintf (stderr, "Cannot write to a read-only database.\n");
+       return NOTMUCH_STATUS_READONLY_DATABASE;
+    }
+
+    return NOTMUCH_STATUS_SUCCESS;
+}
+
 notmuch_database_t *
 notmuch_database_open (const char *path,
                       notmuch_database_mode_t mode)
@@ -1034,11 +1045,13 @@ notmuch_database_add_message (notmuch_database_t *notmuch,
     if (message_ret)
        *message_ret = NULL;
 
+    ret = _notmuch_database_ensure_writable (notmuch);
+    if (ret)
+       return ret;
+
     message_file = notmuch_message_file_open (filename);
-    if (message_file == NULL) {
-       ret = NOTMUCH_STATUS_FILE_ERROR;
-       goto DONE;
-    }
+    if (message_file == NULL)
+       return NOTMUCH_STATUS_FILE_ERROR;
 
     notmuch_message_file_restrict_headers (message_file,
                                           "date",
@@ -1173,10 +1186,9 @@ notmuch_database_remove_message (notmuch_database_t *notmuch,
     Xapian::Document document;
     notmuch_status_t status;
 
-    if (notmuch->mode == NOTMUCH_DATABASE_MODE_READ_ONLY) {
-       fprintf (stderr, "Attempted to update a read-only database.\n");
-       return NOTMUCH_STATUS_READONLY_DATABASE;
-    }
+    status = _notmuch_database_ensure_writable (notmuch);
+    if (status)
+       return status;
 
     db = static_cast <Xapian::WritableDatabase *> (notmuch->xapian_db);
 
index d5015e0ac6f351102b894d0e5efe96f437575408..461c0cc367801b72819f429013a214552efc279d 100644 (file)
@@ -182,11 +182,8 @@ _notmuch_directory_create (notmuch_database_t *notmuch,
 
     path = _notmuch_database_relative_path (notmuch, path);
 
-    if (notmuch->mode == NOTMUCH_DATABASE_MODE_READ_ONLY) {
-       fprintf (stderr, "Attempted to update a read-only database.\n");
-       *status_ret = NOTMUCH_STATUS_READONLY_DATABASE;
-       return NULL;
-    }
+    if (notmuch->mode == NOTMUCH_DATABASE_MODE_READ_ONLY)
+       INTERNAL_ERROR ("Failure to ensure database is writable");
 
     db = static_cast <Xapian::WritableDatabase *> (notmuch->xapian_db);
 
@@ -268,11 +265,11 @@ notmuch_directory_set_mtime (notmuch_directory_t *directory,
 {
     notmuch_database_t *notmuch = directory->notmuch;
     Xapian::WritableDatabase *db;
+    notmuch_status_t status;
 
-    if (notmuch->mode == NOTMUCH_DATABASE_MODE_READ_ONLY) {
-       fprintf (stderr, "Attempted to update a read-only database.\n");
-       return NOTMUCH_STATUS_READONLY_DATABASE;
-    }
+    status = _notmuch_database_ensure_writable (notmuch);
+    if (status)
+       return status;
 
     db = static_cast <Xapian::WritableDatabase *> (notmuch->xapian_db);
 
index 0fc54668cb9a362454551d8880bade40b7c6583e..ea9c8bd96afb1b34ccb8ebb329c5f93ebcaa344b 100644 (file)
@@ -174,11 +174,6 @@ _notmuch_message_create_for_message_id (notmuch_database_t *notmuch,
     unsigned int doc_id;
     char *term;
 
-    if (notmuch->mode == NOTMUCH_DATABASE_MODE_READ_ONLY) {
-       *status_ret = NOTMUCH_PRIVATE_STATUS_READONLY_DATABASE;
-       return NULL;
-    }
-
     *status_ret = NOTMUCH_PRIVATE_STATUS_SUCCESS;
 
     message = notmuch_database_find_message (notmuch, message_id);
@@ -192,6 +187,9 @@ _notmuch_message_create_for_message_id (notmuch_database_t *notmuch,
        return NULL;
     }
 
+    if (notmuch->mode == NOTMUCH_DATABASE_MODE_READ_ONLY)
+       INTERNAL_ERROR ("Failure to ensure database is writable.");
+
     db = static_cast<Xapian::WritableDatabase *> (notmuch->xapian_db);
     try {
        doc.add_term (term);
@@ -706,7 +704,12 @@ _notmuch_message_remove_term (notmuch_message_t *message,
 notmuch_status_t
 notmuch_message_add_tag (notmuch_message_t *message, const char *tag)
 {
-    notmuch_private_status_t status;
+    notmuch_private_status_t private_status;
+    notmuch_status_t status;
+
+    status = _notmuch_database_ensure_writable (message->notmuch);
+    if (status)
+       return status;
 
     if (tag == NULL)
        return NOTMUCH_STATUS_NULL_POINTER;
@@ -714,10 +717,10 @@ notmuch_message_add_tag (notmuch_message_t *message, const char *tag)
     if (strlen (tag) > NOTMUCH_TAG_MAX)
        return NOTMUCH_STATUS_TAG_TOO_LONG;
 
-    status = _notmuch_message_add_term (message, "tag", tag);
-    if (status) {
+    private_status = _notmuch_message_add_term (message, "tag", tag);
+    if (private_status) {
        INTERNAL_ERROR ("_notmuch_message_add_term return unexpected value: %d\n",
-                       status);
+                       private_status);
     }
 
     if (! message->frozen)
@@ -729,7 +732,12 @@ notmuch_message_add_tag (notmuch_message_t *message, const char *tag)
 notmuch_status_t
 notmuch_message_remove_tag (notmuch_message_t *message, const char *tag)
 {
-    notmuch_private_status_t status;
+    notmuch_private_status_t private_status;
+    notmuch_status_t status;
+
+    status = _notmuch_database_ensure_writable (message->notmuch);
+    if (status)
+       return status;
 
     if (tag == NULL)
        return NOTMUCH_STATUS_NULL_POINTER;
@@ -737,10 +745,10 @@ notmuch_message_remove_tag (notmuch_message_t *message, const char *tag)
     if (strlen (tag) > NOTMUCH_TAG_MAX)
        return NOTMUCH_STATUS_TAG_TOO_LONG;
 
-    status = _notmuch_message_remove_term (message, "tag", tag);
-    if (status) {
+    private_status = _notmuch_message_remove_term (message, "tag", tag);
+    if (private_status) {
        INTERNAL_ERROR ("_notmuch_message_remove_term return unexpected value: %d\n",
-                       status);
+                       private_status);
     }
 
     if (! message->frozen)
@@ -749,39 +757,60 @@ notmuch_message_remove_tag (notmuch_message_t *message, const char *tag)
     return NOTMUCH_STATUS_SUCCESS;
 }
 
-void
+notmuch_status_t
 notmuch_message_remove_all_tags (notmuch_message_t *message)
 {
-    notmuch_private_status_t status;
+    notmuch_private_status_t private_status;
+    notmuch_status_t status;
     notmuch_tags_t *tags;
     const char *tag;
 
+    status = _notmuch_database_ensure_writable (message->notmuch);
+    if (status)
+       return status;
+
     for (tags = notmuch_message_get_tags (message);
         notmuch_tags_has_more (tags);
         notmuch_tags_advance (tags))
     {
        tag = notmuch_tags_get (tags);
 
-       status = _notmuch_message_remove_term (message, "tag", tag);
-       if (status) {
+       private_status = _notmuch_message_remove_term (message, "tag", tag);
+       if (private_status) {
            INTERNAL_ERROR ("_notmuch_message_remove_term return unexpected value: %d\n",
-                           status);
+                           private_status);
        }
     }
 
     if (! message->frozen)
        _notmuch_message_sync (message);
+
+    return NOTMUCH_STATUS_SUCCESS;
 }
 
-void
+notmuch_status_t
 notmuch_message_freeze (notmuch_message_t *message)
 {
+    notmuch_status_t status;
+
+    status = _notmuch_database_ensure_writable (message->notmuch);
+    if (status)
+       return status;
+
     message->frozen++;
+
+    return NOTMUCH_STATUS_SUCCESS;
 }
 
 notmuch_status_t
 notmuch_message_thaw (notmuch_message_t *message)
 {
+    notmuch_status_t status;
+
+    status = _notmuch_database_ensure_writable (message->notmuch);
+    if (status)
+       return status;
+
     if (message->frozen > 0) {
        message->frozen--;
        if (message->frozen == 0)
index 8b582640aacdf54e6e1518a5d00d8228b1b6b982..4eb82619afa91235daa1c3a00ffad6efe27a7294 100644 (file)
@@ -151,6 +151,9 @@ typedef enum _notmuch_private_status {
 const char *
 _find_prefix (const char *name);
 
+notmuch_status_t
+_notmuch_database_ensure_writable (notmuch_database_t *notmuch);
+
 const char *
 _notmuch_database_relative_path (notmuch_database_t *notmuch,
                                 const char *path);
index f3e1d28661414abaca44088dba4931c853027daa..d03373044a2b800e6ac03d7922cd1355c8ebe75e 100644 (file)
@@ -229,6 +229,9 @@ notmuch_database_get_directory (notmuch_database_t *database,
  *
  * NOTMUCH_STATUS_FILE_NOT_EMAIL: the contents of filename don't look
  *     like an email message. Nothing added to the database.
+ *
+ * NOTMUCH_STATUS_READONLY_DATABASE: Database was opened in read-only
+ *     mode so no message can be added.
  */
 notmuch_status_t
 notmuch_database_add_message (notmuch_database_t *database,
@@ -252,6 +255,9 @@ notmuch_database_add_message (notmuch_database_t *database,
  * NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID: This filename was removed but
  *     the message persists in the database with at least one other
  *     filename.
+ *
+ * NOTMUCH_STATUS_READONLY_DATABASE: Database was opened in read-only
+ *     mode so no message can be removed.
  */
 notmuch_status_t
 notmuch_database_remove_message (notmuch_database_t *database,
@@ -789,6 +795,9 @@ notmuch_message_get_tags (notmuch_message_t *message);
  *
  * NOTMUCH_STATUS_TAG_TOO_LONG: The length of 'tag' is too long
  *     (exceeds NOTMUCH_TAG_MAX)
+ *
+ * NOTMUCH_STATUS_READONLY_DATABASE: Database was opened in read-only
+ *     mode so message cannot be modified.
  */
 notmuch_status_t
 notmuch_message_add_tag (notmuch_message_t *message, const char *tag);
@@ -803,6 +812,9 @@ notmuch_message_add_tag (notmuch_message_t *message, const char *tag);
  *
  * NOTMUCH_STATUS_TAG_TOO_LONG: The length of 'tag' is too long
  *     (exceeds NOTMUCH_TAG_MAX)
+ *
+ * NOTMUCH_STATUS_READONLY_DATABASE: Database was opened in read-only
+ *     mode so message cannot be modified.
  */
 notmuch_status_t
 notmuch_message_remove_tag (notmuch_message_t *message, const char *tag);
@@ -811,8 +823,11 @@ notmuch_message_remove_tag (notmuch_message_t *message, const char *tag);
  *
  * See notmuch_message_freeze for an example showing how to safely
  * replace tag values.
+ *
+ * NOTMUCH_STATUS_READONLY_DATABASE: Database was opened in read-only
+ *     mode so message cannot be modified.
  */
-void
+notmuch_status_t
 notmuch_message_remove_all_tags (notmuch_message_t *message);
 
 /* Freeze the current state of 'message' within the database.
@@ -847,8 +862,15 @@ notmuch_message_remove_all_tags (notmuch_message_t *message);
  * somehow getting interrupted. This could result in the message being
  * left with no tags if the interruption happened after
  * notmuch_message_remove_all_tags but before notmuch_message_add_tag.
+ *
+ * Return value:
+ *
+ * NOTMUCH_STATUS_SUCCESS: Message successfully frozen.
+ *
+ * NOTMUCH_STATUS_READONLY_DATABASE: Database was opened in read-only
+ *     mode so message cannot be modified.
  */
-void
+notmuch_status_t
 notmuch_message_freeze (notmuch_message_t *message);
 
 /* Thaw the current 'message', synchronizing any changes that may have
@@ -957,6 +979,9 @@ notmuch_tags_destroy (notmuch_tags_t *tags);
  *
  * NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception
  *     occurred, mtime not stored.
+ *
+ * NOTMUCH_STATUS_READONLY_DATABASE: Database was opened in read-only
+ *     mode so directory mtime cannot be modified.
  */
 notmuch_status_t
 notmuch_directory_set_mtime (notmuch_directory_t *directory,