X-Git-Url: https://git.notmuchmail.org/git?p=notmuch;a=blobdiff_plain;f=lib%2Fdatabase.cc;h=bf56f5206d0f950290ec31637e6fc68516acfe25;hp=0ef59ea9e40564a15dee60636cfa82af9a78131e;hb=406ec4b15d65f1104c7ff3ee654a5e9cd5b39f29;hpb=154bf7ac677c41168c5c6a982fee3f22350adfef diff --git a/lib/database.cc b/lib/database.cc index 0ef59ea9..bf56f520 100644 --- a/lib/database.cc +++ b/lib/database.cc @@ -84,9 +84,11 @@ typedef struct { * maintain data necessary to allow for efficient polling of mail * directories. * - * The directory document is indexed with a single prefixed term: + * The directory document contains the following terms: * * directory: The directory path (relative to the database path) + * parent: The document ID of the parent directory document. + * Top-level directories will have a parent value of 0. * * and has a single value: * @@ -112,8 +114,8 @@ prefix_t BOOLEAN_PREFIX_INTERNAL[] = { { "type", "T" }, { "reference", "XREFERENCE" }, { "replyto", "XREPLYTO" }, - /* XXX: Need a flag day to rename XTIMESTAMP. */ - { "directory", "XTIMESTAMP" }, + { "directory", "XDIRECTORY" }, + { "parent", "XPARENT" }, }; prefix_t BOOLEAN_PREFIX_EXTERNAL[] = { @@ -588,6 +590,101 @@ directory_db_path (const char *path) return path; } +/* Given a 'path' (relative to the database path) return the document + * ID of the directory document corresponding to the parent directory + * of 'path' in 'parent_id'. + * + * The original 'path' can represent either a regular file or a + * directory, (in either case, the document ID of the parent will be + * returned). Trailing slashes on 'path' will be ignored, and any + * cases of multiple '/' characters appearing in series will be + * treated as a single '/'. + * + * If no directory document exists in the database for the parent, (or + * for any of its parents up to the top-level database path), then + * directory documents will be created for these (each with an mtime + * of 0). + * + * Return value: + * + * NOTMUCH_STATUS_SUCCESS: Valid value available in parent_id. + * + * NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception + * occurred and parent_id will be set to (unsigned) -1. + */ +notmuch_status_t +_notmuch_database_find_parent_id (notmuch_database_t *notmuch, + const char *path, + unsigned int *parent_id) +{ + const char *slash, *parent_db_path; + char *parent_path; + notmuch_private_status_t private_status; + notmuch_status_t status = NOTMUCH_STATUS_SUCCESS; + + if (path == NULL || *path == '\0') { + *parent_id = 0; + return NOTMUCH_STATUS_SUCCESS; + } + + /* Find the last slash (not counting a trailing slash), if any. */ + + slash = path + strlen (path) - 1; + + /* First, skip trailing slashes. */ + while (slash != path) { + if (*slash != '/') + break; + + --slash; + } + + /* Then, find a slash. */ + while (slash != path) { + if (*slash == '/') + break; + + --slash; + } + + /* Finally, skip multiple slashes. */ + while (slash != path) { + if (*slash != '/') + break; + + --slash; + } + + if (slash == path) + parent_path = talloc_strdup (notmuch, ""); + else + parent_path = talloc_strndup (notmuch, path, slash - path + 1); + + parent_db_path = directory_db_path (parent_path); + + private_status = find_unique_doc_id (notmuch, "directory", + parent_db_path, parent_id); + if (private_status == NOTMUCH_PRIVATE_STATUS_NO_DOCUMENT_FOUND) { + status = notmuch_database_set_directory_mtime (notmuch, + parent_path, 0); + if (status) + return status; + private_status = find_unique_doc_id (notmuch, "directory", + parent_db_path, parent_id); + status = COERCE_STATUS (private_status, "_find_parent_id"); + } + + if (parent_db_path != parent_path) + free ((char *) parent_db_path); + + talloc_free (parent_path); + + if (status) + *parent_id = -1; + + return status; +} + /* Given a legal 'path' for the database, return the relative path. * * The return value will be a pointer to the originl path contents, @@ -633,6 +730,7 @@ notmuch_database_set_directory_mtime (notmuch_database_t *notmuch, notmuch_private_status_t status; notmuch_status_t ret = NOTMUCH_STATUS_SUCCESS; const char *db_path = NULL; + unsigned int parent_id; if (notmuch->mode == NOTMUCH_DATABASE_MODE_READ_ONLY) { fprintf (stderr, "Attempted to update a read-only database.\n"); @@ -656,6 +754,17 @@ notmuch_database_set_directory_mtime (notmuch_database_t *notmuch, doc.add_term (term); talloc_free (term); + ret = _notmuch_database_find_parent_id (notmuch, path, + &parent_id); + if (ret) + return ret; + + term = talloc_asprintf (NULL, "%s%u", + _find_prefix ("parent"), + parent_id); + doc.add_term (term); + talloc_free (term); + db->add_document (doc); } else { db->replace_document (doc_id, doc);