+notmuch_status_t
+_notmuch_database_find_directory_id (notmuch_database_t *notmuch,
+ const char *path,
+ notmuch_find_flags_t flags,
+ unsigned int *directory_id)
+{
+ notmuch_directory_t *directory;
+ notmuch_status_t status;
+
+ if (path == NULL) {
+ *directory_id = 0;
+ return NOTMUCH_STATUS_SUCCESS;
+ }
+
+ directory = _notmuch_directory_create (notmuch, path, flags, &status);
+ if (status || !directory) {
+ *directory_id = -1;
+ return status;
+ }
+
+ *directory_id = _notmuch_directory_get_document_id (directory);
+
+ notmuch_directory_destroy (directory);
+
+ return NOTMUCH_STATUS_SUCCESS;
+}
+
+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 'filename' for the database, (either relative to
+ * database path or absolute with initial components identical to
+ * database path), return a new string (with 'ctx' as the talloc
+ * owner) suitable for use as a direntry term value.
+ *
+ * If (flags & NOTMUCH_FIND_CREATE), the necessary directory documents
+ * will be created in the database as needed. Otherwise, if the
+ * necessary directory documents do not exist, this sets
+ * *direntry to NULL and returns NOTMUCH_STATUS_SUCCESS.
+ */
+notmuch_status_t
+_notmuch_database_filename_to_direntry (void *ctx,
+ notmuch_database_t *notmuch,
+ const char *filename,
+ notmuch_find_flags_t flags,
+ char **direntry)
+{
+ const char *relative, *directory, *basename;
+ Xapian::docid directory_id;
+ notmuch_status_t status;
+
+ relative = _notmuch_database_relative_path (notmuch, filename);
+
+ status = _notmuch_database_split_path (ctx, relative,
+ &directory, &basename);
+ if (status)
+ return status;
+
+ status = _notmuch_database_find_directory_id (notmuch, directory, flags,
+ &directory_id);
+ if (status || directory_id == (unsigned int)-1) {
+ *direntry = NULL;
+ return status;
+ }
+
+ *direntry = talloc_asprintf (ctx, "%u:%s", directory_id, basename);
+
+ return NOTMUCH_STATUS_SUCCESS;
+}
+
+/* Given a legal 'path' for the database, return the relative path.
+ *
+ * The return value will be a pointer to the original path contents,
+ * and will be either the original string (if 'path' was relative) or
+ * a portion of the string (if path was absolute and begins with the
+ * database path).
+ */
+const char *
+_notmuch_database_relative_path (notmuch_database_t *notmuch,
+ const char *path)
+{
+ const char *db_path, *relative;
+ unsigned int db_path_len;
+
+ db_path = notmuch_database_get_path (notmuch);
+ db_path_len = strlen (db_path);
+
+ relative = path;
+
+ if (*relative == '/') {
+ while (*relative == '/' && *(relative+1) == '/')
+ relative++;
+
+ if (strncmp (relative, db_path, db_path_len) == 0)
+ {
+ relative += db_path_len;
+ while (*relative == '/')
+ relative++;
+ }
+ }
+
+ return relative;
+}
+
+notmuch_status_t
+notmuch_database_get_directory (notmuch_database_t *notmuch,
+ const char *path,
+ notmuch_directory_t **directory)
+{
+ notmuch_status_t status;
+
+ if (directory == NULL)
+ return NOTMUCH_STATUS_NULL_POINTER;
+ *directory = NULL;
+
+ try {
+ *directory = _notmuch_directory_create (notmuch, path,
+ NOTMUCH_FIND_LOOKUP, &status);
+ } catch (const Xapian::Error &error) {
+ _notmuch_database_log (notmuch, "A Xapian exception occurred getting directory: %s.\n",
+ error.get_msg().c_str());
+ notmuch->exception_reported = TRUE;
+ status = NOTMUCH_STATUS_XAPIAN_EXCEPTION;
+ }
+ return status;
+}
+
+/* Allocate a document ID that satisfies the following criteria:
+ *
+ * 1. The ID does not exist for any document in the Xapian database
+ *
+ * 2. The ID was not previously returned from this function
+ *
+ * 3. The ID is the smallest integer satisfying (1) and (2)
+ *
+ * This function will trigger an internal error if these constraints
+ * cannot all be satisfied, (that is, the pool of available document
+ * IDs has been exhausted).
+ */
+unsigned int
+_notmuch_database_generate_doc_id (notmuch_database_t *notmuch)
+{
+ assert (notmuch->last_doc_id >= notmuch->xapian_db->get_lastdocid ());
+
+ notmuch->last_doc_id++;
+
+ if (notmuch->last_doc_id == 0)
+ INTERNAL_ERROR ("Xapian document IDs are exhausted.\n");
+
+ return notmuch->last_doc_id;
+}
+