+/* 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
+_notmuch_database_split_path (void *ctx,
+ const char *path,
+ const char **directory,
+ const char **basename)
+{
+ const char *slash;
+
+ if (path == NULL || *path == '\0') {
+ if (directory)
+ *directory = NULL;
+ if (basename)
+ *basename = NULL;
+ 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;
+
+ if (basename)
+ *basename = slash;
+
+ --slash;
+ }
+
+ /* Finally, skip multiple slashes. */
+ while (slash != path) {
+ if (*slash != '/')
+ break;
+
+ --slash;
+ }
+
+ 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_directory_t *directory;
+ notmuch_status_t status;
+
+ if (path == NULL) {
+ *directory_id = 0;
+ return NOTMUCH_STATUS_SUCCESS;
+ }
+
+ directory = _notmuch_directory_create (notmuch, path, &status);
+ if (status) {
+ *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.
+ *
+ * The necessary directory documents will be created in the database
+ * as needed.
+ */
+notmuch_status_t
+_notmuch_database_filename_to_direntry (void *ctx,
+ notmuch_database_t *notmuch,
+ const char *filename,
+ 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,
+ &directory_id);
+ if (status)
+ return status;
+
+ *direntry = talloc_asprintf (ctx, "%u:%s", directory_id, basename);
+
+ return NOTMUCH_STATUS_SUCCESS;
+}
+