X-Git-Url: https://git.notmuchmail.org/git?a=blobdiff_plain;f=lib%2Fdatabase.cc;h=7d09119cecddf54a94e34b8f2a9948ee203fbb85;hb=6ca6c089e9df7affe6bee0392197509a24ab2546;hp=acd06de8b4ff89ea2757b4d21c65bb1262a809eb;hpb=e890b0cf4011fd9fd77ebd87343379e4a778888b;p=notmuch diff --git a/lib/database.cc b/lib/database.cc index acd06de8..7d09119c 100644 --- a/lib/database.cc +++ b/lib/database.cc @@ -63,6 +63,11 @@ typedef struct { * * tag: Any tags associated with this message by the user. * + * direntry: A colon-separated pair of values (INTEGER:STRING), + * where INTEGER is the document ID of a directory + * document, and STRING is the name of a file within + * that directory for this mail message. + * * A mail document also has two values: * * TIMESTAMP: The time_t value corresponding to the message's @@ -75,8 +80,7 @@ typedef struct { * user in searching. But the database doesn't really care itself * about any of these. * - * Finally, the data portion of a mail document contains the path name - * of the mail message (relative to the database path). + * The data portion of a mail document is empty. * * Directory document * ------------------ @@ -87,12 +91,19 @@ typedef struct { * The directory document contains the following terms: * * directory: The directory path (relative to the database path) + * Or the SHA1 sum of the directory path (if the + * path itself is too long to fit in a Xapian + * term). + * * parent: The document ID of the parent directory document. * Top-level directories will have a parent value of 0. * * and has a single value: * * TIMESTAMP: The mtime of the directory (at last scan) + * + * The data portion of a directory document contains the path of the + * directory (relative to the datbase path). */ /* With these prefix values we follow the conventions published here: @@ -115,6 +126,7 @@ prefix_t BOOLEAN_PREFIX_INTERNAL[] = { { "reference", "XREFERENCE" }, { "replyto", "XREPLYTO" }, { "directory", "XDIRECTORY" }, + { "direntry", "XDIRENTRY" }, { "parent", "XPARENT" }, }; @@ -590,18 +602,40 @@ directory_db_path (const char *path) return path; } +/* Given a path, split it into two parts: the directory part is all + * components except for the last, and the basename is that last + * component. Getting the return-value for either part is optional + * (the caller can pass NULL). + * + * The original 'path' can represent either a regular file or a + * directory---the splitting will be carried out in the same way in + * either case. Trailing slashes on 'path' will be ignored, and any + * cases of multiple '/' characters appearing in series will be + * treated as a single '/'. + * + * Allocation (if any) will have 'ctx' as the talloc owner. But + * pointers will be returned within the original path string whenever + * possible. + * + * Note: If 'path' is non-empty and contains no non-trailing slash, + * (that is, consists of a filename with no parent directory), then + * the directory returned will be an empty string. However, if 'path' + * is an empty string, then both directory and basename will be + * returned as NULL. + */ notmuch_status_t -_find_parent_id (notmuch_database_t *notmuch, - const char *path, - Xapian::docid *parent_id) +_notmuch_database_split_path (void *ctx, + const char *path, + const char **directory, + const char **basename) { - const char *slash, *parent_db_path; - char *parent_path; - notmuch_private_status_t private_status; - notmuch_status_t status = NOTMUCH_STATUS_SUCCESS; + const char *slash; if (path == NULL || *path == '\0') { - *parent_id = 0; + if (directory) + *directory = NULL; + if (basename) + *basename = NULL; return NOTMUCH_STATUS_SUCCESS; } @@ -622,6 +656,9 @@ _find_parent_id (notmuch_database_t *notmuch, if (*slash == '/') break; + if (basename) + *basename = slash; + --slash; } @@ -633,33 +670,70 @@ _find_parent_id (notmuch_database_t *notmuch, --slash; } - if (slash == path) - parent_path = talloc_strdup (notmuch, ""); - else - parent_path = talloc_strndup (notmuch, path, slash - path + 1); + if (slash == path) { + if (directory) + *directory = talloc_strdup (ctx, ""); + if (basename) + *basename = path; + } else { + if (directory) + *directory = talloc_strndup (ctx, path, slash - path + 1); + } + + return NOTMUCH_STATUS_SUCCESS; +} + +notmuch_status_t +_notmuch_database_find_directory_id (notmuch_database_t *notmuch, + const char *path, + unsigned int *directory_id) +{ + notmuch_private_status_t private_status; + notmuch_status_t status = NOTMUCH_STATUS_SUCCESS; + const char *db_path; - parent_db_path = directory_db_path (parent_path); + if (path == NULL) { + *directory_id = 0; + return NOTMUCH_STATUS_SUCCESS; + } + + db_path = directory_db_path (path); private_status = find_unique_doc_id (notmuch, "directory", - parent_db_path, parent_id); + db_path, directory_id); if (private_status == NOTMUCH_PRIVATE_STATUS_NO_DOCUMENT_FOUND) { status = notmuch_database_set_directory_mtime (notmuch, - parent_path, 0); + path, 0); if (status) - return status; + goto DONE; + private_status = find_unique_doc_id (notmuch, "directory", - parent_db_path, parent_id); - status = COERCE_STATUS (private_status, "_find_parent_id"); + db_path, directory_id); + status = COERCE_STATUS (private_status, "_find_directory_id"); } - if (parent_db_path != parent_path) - free ((char *) parent_db_path); + DONE: + if (db_path != path) + free ((char *) db_path); - talloc_free (parent_path); + if (status) + *directory_id = -1; return status; } +const char * +_notmuch_database_get_directory_path (void *ctx, + notmuch_database_t *notmuch, + unsigned int doc_id) +{ + Xapian::Document document; + + document = find_document_for_doc_id (notmuch, doc_id); + + return talloc_strdup (ctx, document.get_data ().c_str ()); +} + /* Given a legal 'path' for the database, return the relative path. * * The return value will be a pointer to the originl path contents, @@ -704,8 +778,9 @@ notmuch_database_set_directory_mtime (notmuch_database_t *notmuch, unsigned int doc_id; notmuch_private_status_t status; notmuch_status_t ret = NOTMUCH_STATUS_SUCCESS; - const char *db_path = NULL; - Xapian::docid parent_id; + const char *parent, *db_path = NULL; + unsigned int parent_id; + void *local = talloc_new (notmuch); if (notmuch->mode == NOTMUCH_DATABASE_MODE_READ_ONLY) { fprintf (stderr, "Attempted to update a read-only database.\n"); @@ -724,20 +799,20 @@ notmuch_database_set_directory_mtime (notmuch_database_t *notmuch, Xapian::sortable_serialise (mtime)); if (status == NOTMUCH_PRIVATE_STATUS_NO_DOCUMENT_FOUND) { - char *term = talloc_asprintf (NULL, "%s%s", + char *term = talloc_asprintf (local, "%s%s", _find_prefix ("directory"), db_path); doc.add_term (term); - talloc_free (term); - status = _find_parent_id (notmuch, path, &parent_id); - if (status) - return status; + doc.set_data (path); + + _notmuch_database_split_path (local, path, &parent, NULL); - term = talloc_asprintf (NULL, "%s%u", + _notmuch_database_find_directory_id (notmuch, parent, &parent_id); + + term = talloc_asprintf (local, "%s%u", _find_prefix ("parent"), parent_id); doc.add_term (term); - talloc_free (term); db->add_document (doc); } else { @@ -754,6 +829,8 @@ notmuch_database_set_directory_mtime (notmuch_database_t *notmuch, if (db_path != path) free ((char *) db_path); + talloc_free (local); + return ret; } @@ -766,6 +843,7 @@ notmuch_database_get_directory_mtime (notmuch_database_t *notmuch, notmuch_private_status_t status; const char *db_path = NULL; time_t ret = 0; + void *local = talloc_new (notmuch); db_path = directory_db_path (path);