[systemd-devel] [PATCH 6/7] journal: Open JournalFile by dirfd and filename instead of path

Krzesimir Nowak krzesimir at endocode.com
Mon Jun 1 08:29:02 PDT 2015


That way we can have access to a file that is not accessible by path,
for example to a file in overlayfs in different mount namespace (which
is the case for rkt pods).
---
 src/journal-remote/journal-remote-write.c |  12 +-
 src/journal-remote/journal-remote.c       |  34 ++--
 src/journal/journal-file.c                | 108 +++++-----
 src/journal/journal-file.h                |  10 +-
 src/journal/journal-internal.h            |   3 +-
 src/journal/journal-vacuum.c              |  27 +--
 src/journal/journal-vacuum.h              |   3 +-
 src/journal/journal-verify.c              |   4 +-
 src/journal/journalctl.c                  |   8 +-
 src/journal/journald-server.c             | 113 +++++++----
 src/journal/sd-journal.c                  | 324 ++++++++++++++++++++----------
 src/journal/test-journal-flush.c          |  13 +-
 src/journal/test-journal-interleaving.c   |  55 +++--
 src/journal/test-journal-stream.c         |  10 +-
 src/journal/test-journal-verify.c         |  13 +-
 src/journal/test-journal.c                |  21 +-
 src/shared/util.c                         |  20 ++
 src/shared/util.h                         |   1 +
 18 files changed, 515 insertions(+), 264 deletions(-)

diff --git a/src/journal-remote/journal-remote-write.c b/src/journal-remote/journal-remote-write.c
index 99820fa..0fdeb7f 100644
--- a/src/journal-remote/journal-remote-write.c
+++ b/src/journal-remote/journal-remote-write.c
@@ -59,7 +59,7 @@ static int do_rotate(JournalFile **f, bool compress, bool seal) {
         int r = journal_file_rotate(f, compress, seal);
         if (r < 0) {
                 if (*f)
-                        log_error_errno(r, "Failed to rotate %s: %m", (*f)->path);
+                        log_error_errno(r, "Failed to rotate %s/%s: %m", (*f)->directory->path, (*f)->filename);
                 else
                         log_error_errno(r, "Failed to create rotated journal: %m");
         }
@@ -93,7 +93,7 @@ Writer* writer_free(Writer *w) {
                 return NULL;
 
         if (w->journal) {
-                log_debug("Closing journal file %s.", w->journal->path);
+                log_debug("Closing journal file %s/%s.", w->journal->directory->path, w->journal->filename);
                 journal_file_close(w->journal);
         }
 
@@ -136,8 +136,8 @@ int writer_write(Writer *w,
         assert(iovw->count > 0);
 
         if (journal_file_rotate_suggested(w->journal, 0)) {
-                log_info("%s: Journal header limits reached or header out-of-date, rotating",
-                         w->journal->path);
+                log_info("%s/%s: Journal header limits reached or header out-of-date, rotating",
+                         w->journal->directory->path, w->journal->filename);
                 r = do_rotate(&w->journal, compress, seal);
                 if (r < 0)
                         return r;
@@ -151,12 +151,12 @@ int writer_write(Writer *w,
                 return 1;
         }
 
-        log_debug_errno(r, "%s: Write failed, rotating: %m", w->journal->path);
+        log_debug_errno(r, "%s/%s: Write failed, rotating: %m", w->journal->directory->path, w->journal->filename);
         r = do_rotate(&w->journal, compress, seal);
         if (r < 0)
                 return r;
         else
-                log_debug("%s: Successfully rotated journal", w->journal->path);
+                log_debug("%s/%s: Successfully rotated journal", w->journal->directory->path, w->journal->filename);
 
         log_debug("Retrying write.");
         r = journal_file_append_entry(w->journal, ts, iovw->iovec, iovw->count,
diff --git a/src/journal-remote/journal-remote.c b/src/journal-remote/journal-remote.c
index 911e2a1..1a4c337 100644
--- a/src/journal-remote/journal-remote.c
+++ b/src/journal-remote/journal-remote.c
@@ -162,14 +162,20 @@ static int spawn_getter(const char *getter, const char *url) {
 #define filename_escape(s) xescape((s), "/ ")
 
 static int open_output(Writer *w, const char* host) {
-        _cleanup_free_ char *_output = NULL;
-        const char *output;
+        _cleanup_free_ char *directory = NULL;
+        _cleanup_free_ char *filename = NULL;
+        JournalDirectory *dir;
         int r;
 
         switch (arg_split_mode) {
-        case JOURNAL_WRITE_SPLIT_NONE:
+        case JOURNAL_WRITE_SPLIT_NONE: {
+                const char *output;
+
                 output = arg_output ?: REMOTE_JOURNAL_PATH "/remote.journal";
+                directory = dirname_malloc(output);
+                filename = basename_malloc(output);
                 break;
+        }
 
         case JOURNAL_WRITE_SPLIT_HOST: {
                 _cleanup_free_ char *name;
@@ -180,13 +186,10 @@ static int open_output(Writer *w, const char* host) {
                 if (!name)
                         return log_oom();
 
-                r = asprintf(&_output, "%s/remote-%s.journal",
-                             arg_output ?: REMOTE_JOURNAL_PATH,
-                             name);
+                directory = strdup(arg_output ?: REMOTE_JOURNAL_PATH);
+                r = asprintf(&filename, "remote-%s.journal", name);
                 if (r < 0)
                         return log_oom();
-
-                output = _output;
                 break;
         }
 
@@ -194,17 +197,24 @@ static int open_output(Writer *w, const char* host) {
                 assert_not_reached("what?");
         }
 
-        r = journal_file_open_reliably(output,
+        r = journal_directory_open(directory, &dir);
+        if (r < 0) {
+                log_error_errno(r, "Failed to open journal directory %s: %m",
+                                directory);
+                return r;
+        }
+        r = journal_file_open_reliably(dir, filename,
                                        O_RDWR|O_CREAT, 0640,
                                        arg_compress, arg_seal,
                                        &w->metrics,
                                        w->mmap,
                                        NULL, &w->journal);
+        dir = journal_directory_unref(dir);
         if (r < 0)
-                log_error_errno(r, "Failed to open output journal %s: %m",
-                                output);
+                log_error_errno(r, "Failed to open output journal %s/%s: %m",
+                                directory, filename);
         else
-                log_debug("Opened output file %s", w->journal->path);
+                log_debug("Opened output file %s/%s", w->journal->directory->path, w->journal->filename);
         return r;
 }
 
diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c
index be6a552..5acc63c 100644
--- a/src/journal/journal-file.c
+++ b/src/journal/journal-file.c
@@ -154,8 +154,9 @@ void journal_file_close(JournalFile *f) {
                 (void) btrfs_defrag_fd(f->fd);
         }
 
+        free(f->filename);
+        journal_directory_unref(f->directory);
         safe_close(f->fd);
-        free(f->path);
 
         if (f->mmap)
                 mmap_cache_unref(f->mmap);
@@ -258,12 +259,14 @@ static int journal_file_verify_header(JournalFile *f) {
         flags = le32toh(f->header->incompatible_flags);
         if (flags & ~HEADER_INCOMPATIBLE_SUPPORTED) {
                 if (flags & ~HEADER_INCOMPATIBLE_ANY)
-                        log_debug("Journal file %s has unknown incompatible flags %"PRIx32,
-                                  f->path, flags & ~HEADER_INCOMPATIBLE_ANY);
+                        log_debug("Journal file %s/%s has unknown incompatible flags %"PRIx32,
+                                  f->directory->path, f->filename,
+                                  flags & ~HEADER_INCOMPATIBLE_ANY);
                 flags = (flags & HEADER_INCOMPATIBLE_ANY) & ~HEADER_INCOMPATIBLE_SUPPORTED;
                 if (flags)
-                        log_debug("Journal file %s uses incompatible flags %"PRIx32
-                                  " disabled at compilation time.", f->path, flags);
+                        log_debug("Journal file %s/%s uses incompatible flags %"PRIx32
+                                  " disabled at compilation time.", f->directory->path,
+                                  f->filename, flags);
                 return -EPROTONOSUPPORT;
         }
 
@@ -272,12 +275,14 @@ static int journal_file_verify_header(JournalFile *f) {
         flags = le32toh(f->header->compatible_flags);
         if (f->writable && (flags & ~HEADER_COMPATIBLE_SUPPORTED)) {
                 if (flags & ~HEADER_COMPATIBLE_ANY)
-                        log_debug("Journal file %s has unknown compatible flags %"PRIx32,
-                                  f->path, flags & ~HEADER_COMPATIBLE_ANY);
+                        log_debug("Journal file %s/%s has unknown compatible flags %"PRIx32,
+                                  f->directory->path, f->filename,
+                                  flags & ~HEADER_COMPATIBLE_ANY);
                 flags = (flags & HEADER_COMPATIBLE_ANY) & ~HEADER_COMPATIBLE_SUPPORTED;
                 if (flags)
-                        log_debug("Journal file %s uses compatible flags %"PRIx32
-                                  " disabled at compilation time.", f->path, flags);
+                        log_debug("Journal file %s/%s uses compatible flags %"PRIx32
+                                  " disabled at compilation time.", f->directory->path,
+                                  f->filename, flags);
                 return -EPROTONOSUPPORT;
         }
 
@@ -318,12 +323,14 @@ static int journal_file_verify_header(JournalFile *f) {
                 state = f->header->state;
 
                 if (state == STATE_ONLINE) {
-                        log_debug("Journal file %s is already online. Assuming unclean closing.", f->path);
+                        log_debug("Journal file %s/%s is already online. Assuming unclean closing.",
+                                  f->directory->path, f->filename);
                         return -EBUSY;
                 } else if (state == STATE_ARCHIVED)
                         return -ESHUTDOWN;
                 else if (state != STATE_OFFLINE) {
-                        log_debug("Journal file %s has unknown state %i.", f->path, state);
+                        log_debug("Journal file %s/%s has unknown state %i.",
+                                  f->directory->path, f->filename, state);
                         return -EBUSY;
                 }
         }
@@ -2128,8 +2135,8 @@ int journal_file_next_entry(
 
         if (p > 0 &&
             (direction == DIRECTION_DOWN ? ofs <= p : ofs >= p)) {
-                log_debug("%s: entry array corrupted at entry %"PRIu64,
-                          f->path, i);
+                log_debug("%s/%s: entry array corrupted at entry %"PRIu64,
+                          f->directory->path, f->filename, i);
                 return -EBADMSG;
         }
 
@@ -2453,7 +2460,7 @@ void journal_file_print_header(JournalFile *f) {
 
         assert(f);
 
-        printf("File Path: %s\n"
+        printf("File Path: %s/%s\n"
                "File ID: %s\n"
                "Machine ID: %s\n"
                "Boot ID: %s\n"
@@ -2473,7 +2480,7 @@ void journal_file_print_header(JournalFile *f) {
                "Tail Monotonic Timestamp: %s\n"
                "Objects: %"PRIu64"\n"
                "Entry Objects: %"PRIu64"\n",
-               f->path,
+               f->directory->path, f->filename,
                sd_id128_to_string(f->header->file_id, a),
                sd_id128_to_string(f->header->machine_id, b),
                sd_id128_to_string(f->header->boot_id, c),
@@ -2550,15 +2557,16 @@ static int journal_file_warn_btrfs(JournalFile *f) {
                 return 0;
         }
 
-        log_notice("Creating journal file %s on a btrfs file system, and copy-on-write is enabled. "
+        log_notice("Creating journal file %s/%s on a btrfs file system, and copy-on-write is enabled. "
                    "This is likely to slow down journal access substantially, please consider turning "
-                   "off the copy-on-write file attribute on the journal directory, using chattr +C.", f->path);
+                   "off the copy-on-write file attribute on the journal directory, using chattr +C.", f->directory->path, f->filename);
 
         return 1;
 }
 
 int journal_file_open(
-                const char *fname,
+                JournalDirectory *dir,
+                const char *filename,
                 int flags,
                 mode_t mode,
                 bool compress,
@@ -2568,20 +2576,21 @@ int journal_file_open(
                 JournalFile *template,
                 JournalFile **ret) {
 
+
         bool newly_created = false;
         JournalFile *f;
         void *h;
         int r;
 
-        assert(fname);
+        assert(filename);
         assert(ret);
 
         if ((flags & O_ACCMODE) != O_RDONLY &&
             (flags & O_ACCMODE) != O_RDWR)
                 return -EINVAL;
 
-        if (!endswith(fname, ".journal") &&
-            !endswith(fname, ".journal~"))
+        if (!endswith(filename, ".journal") &&
+            !endswith(filename, ".journal~"))
                 return -EINVAL;
 
         f = new0(JournalFile, 1);
@@ -2613,19 +2622,19 @@ int journal_file_open(
                 }
         }
 
-        f->path = strdup(fname);
-        if (!f->path) {
+        f->chain_cache = ordered_hashmap_new(&uint64_hash_ops);
+        if (!f->chain_cache) {
                 r = -ENOMEM;
                 goto fail;
         }
 
-        f->chain_cache = ordered_hashmap_new(&uint64_hash_ops);
-        if (!f->chain_cache) {
+        f->filename = strdup(filename);
+        if (!f->filename) {
                 r = -ENOMEM;
                 goto fail;
         }
-
-        f->fd = open(f->path, f->flags|O_CLOEXEC, f->mode);
+        f->directory = journal_directory_ref(dir);
+        f->fd = openat(f->directory->fd, f->filename, f->flags|O_CLOEXEC, f->mode);
         if (f->fd < 0) {
                 r = -errno;
                 goto fail;
@@ -2770,12 +2779,12 @@ int journal_file_rotate(JournalFile **f, bool compress, bool seal) {
         if (!old_file->writable)
                 return -EINVAL;
 
-        if (!endswith(old_file->path, ".journal"))
+        if (!endswith(old_file->filename, ".journal"))
                 return -EINVAL;
 
-        l = strlen(old_file->path);
+        l = strlen(old_file->filename);
         r = asprintf(&p, "%.*s@" SD_ID128_FORMAT_STR "-%016"PRIx64"-%016"PRIx64".journal",
-                     (int) l - 8, old_file->path,
+                     (int) l - 8, old_file->filename,
                      SD_ID128_FORMAT_VAL(old_file->header->seqnum_id),
                      le64toh((*f)->header->head_entry_seqnum),
                      le64toh((*f)->header->head_entry_realtime));
@@ -2785,7 +2794,8 @@ int journal_file_rotate(JournalFile **f, bool compress, bool seal) {
         /* Try to rename the file to the archived version. If the file
          * already was deleted, we'll get ENOENT, let's ignore that
          * case. */
-        r = rename(old_file->path, p);
+        r = renameat(old_file->directory->fd, old_file->filename,
+                     old_file->directory->fd, p);
         if (r < 0 && errno != ENOENT)
                 return -errno;
 
@@ -2796,7 +2806,7 @@ int journal_file_rotate(JournalFile **f, bool compress, bool seal) {
          * we archive them */
         old_file->defrag_on_close = true;
 
-        r = journal_file_open(old_file->path, old_file->flags, old_file->mode, compress, seal, NULL, old_file->mmap, old_file, &new_file);
+        r = journal_file_open(old_file->directory, old_file->filename, old_file->flags, old_file->mode, compress, seal, NULL, old_file->mmap, old_file, &new_file);
         journal_file_close(old_file);
 
         *f = new_file;
@@ -2804,7 +2814,8 @@ int journal_file_rotate(JournalFile **f, bool compress, bool seal) {
 }
 
 int journal_file_open_reliably(
-                const char *fname,
+                JournalDirectory *dir,
+                const char *filename,
                 int flags,
                 mode_t mode,
                 bool compress,
@@ -2813,12 +2824,11 @@ int journal_file_open_reliably(
                 MMapCache *mmap_cache,
                 JournalFile *template,
                 JournalFile **ret) {
-
         int r;
         size_t l;
         _cleanup_free_ char *p = NULL;
 
-        r = journal_file_open(fname, flags, mode, compress, seal,
+        r = journal_file_open(dir, filename, flags, mode, compress, seal,
                               metrics, mmap_cache, template, ret);
         if (!IN_SET(r,
                     -EBADMSG,           /* corrupted */
@@ -2837,19 +2847,20 @@ int journal_file_open_reliably(
         if (!(flags & O_CREAT))
                 return r;
 
-        if (!endswith(fname, ".journal"))
+        if (!endswith(filename, ".journal"))
                 return r;
 
         /* The file is corrupted. Rotate it away and try it again (but only once) */
 
-        l = strlen(fname);
+        l = strlen(filename);
         if (asprintf(&p, "%.*s@%016"PRIx64 "-%016"PRIx64 ".journal~",
-                     (int) l - 8, fname,
+                     (int) l - 8, filename,
                      now(CLOCK_REALTIME),
                      random_u64()) < 0)
                 return -ENOMEM;
 
-        r = rename(fname, p);
+        r = renameat(dir->fd, filename,
+                     dir->fd, p);
         if (r < 0)
                 return -errno;
 
@@ -2859,10 +2870,10 @@ int journal_file_open_reliably(
         (void) chattr_path(p, false, FS_NOCOW_FL);
         (void) btrfs_defrag(p);
 
-        log_warning("File %s corrupted or uncleanly shut down, renaming and replacing.", fname);
+        log_warning("File %s/%s corrupted or uncleanly shut down, renaming and replacing.", dir->path, filename);
 
-        return journal_file_open(fname, flags, mode, compress, seal,
-                                 metrics, mmap_cache, template, ret);
+        return journal_file_open(dir, filename, flags, mode, compress,
+                                 seal, metrics, mmap_cache, template, ret);
 }
 
 int journal_file_copy_entry(JournalFile *from, JournalFile *to, Object *o, uint64_t p, uint64_t *seqnum, Object **ret, uint64_t *offset) {
@@ -3093,7 +3104,8 @@ bool journal_file_rotate_suggested(JournalFile *f, usec_t max_file_usec) {
         /* If we gained new header fields we gained new features,
          * hence suggest a rotation */
         if (le64toh(f->header->header_size) < sizeof(Header)) {
-                log_debug("%s uses an outdated header, suggesting rotation.", f->path);
+                log_debug("%s/%s uses an outdated header, suggesting rotation.",
+                          f->directory->path, f->filename);
                 return true;
         }
 
@@ -3105,8 +3117,9 @@ bool journal_file_rotate_suggested(JournalFile *f, usec_t max_file_usec) {
 
         if (JOURNAL_HEADER_CONTAINS(f->header, n_data))
                 if (le64toh(f->header->n_data) * 4ULL > (le64toh(f->header->data_hash_table_size) / sizeof(HashItem)) * 3ULL) {
-                        log_debug("Data hash table of %s has a fill level at %.1f (%"PRIu64" of %"PRIu64" items, %llu file size, %"PRIu64" bytes per hash table item), suggesting rotation.",
-                                  f->path,
+                        log_debug("Data hash table of %s/%s has a fill level at %.1f (%"PRIu64" of %"PRIu64" items, %llu file size, %"PRIu64" bytes per hash table item), suggesting rotation.",
+                                  f->directory->path,
+                                  f->filename,
                                   100.0 * (double) le64toh(f->header->n_data) / ((double) (le64toh(f->header->data_hash_table_size) / sizeof(HashItem))),
                                   le64toh(f->header->n_data),
                                   le64toh(f->header->data_hash_table_size) / sizeof(HashItem),
@@ -3117,8 +3130,9 @@ bool journal_file_rotate_suggested(JournalFile *f, usec_t max_file_usec) {
 
         if (JOURNAL_HEADER_CONTAINS(f->header, n_fields))
                 if (le64toh(f->header->n_fields) * 4ULL > (le64toh(f->header->field_hash_table_size) / sizeof(HashItem)) * 3ULL) {
-                        log_debug("Field hash table of %s has a fill level at %.1f (%"PRIu64" of %"PRIu64" items), suggesting rotation.",
-                                  f->path,
+                        log_debug("Field hash table of %s/%s has a fill level at %.1f (%"PRIu64" of %"PRIu64" items), suggesting rotation.",
+                                  f->directory->path,
+                                  f->filename,
                                   100.0 * (double) le64toh(f->header->n_fields) / ((double) (le64toh(f->header->field_hash_table_size) / sizeof(HashItem))),
                                   le64toh(f->header->n_fields),
                                   le64toh(f->header->field_hash_table_size) / sizeof(HashItem));
diff --git a/src/journal/journal-file.h b/src/journal/journal-file.h
index 403c8f7..9a00de6 100644
--- a/src/journal/journal-file.h
+++ b/src/journal/journal-file.h
@@ -34,6 +34,7 @@
 #include "macro.h"
 #include "mmap-cache.h"
 #include "hashmap.h"
+#include "journal-dir.h"
 
 typedef struct JournalMetrics {
         uint64_t max_use;
@@ -81,7 +82,8 @@ typedef struct JournalFile {
         LocationType location_type;
         uint64_t last_n_entries;
 
-        char *path;
+        JournalDirectory *directory;
+        char *filename;
         struct stat last_stat;
         usec_t last_stat_usec;
 
@@ -125,7 +127,8 @@ typedef struct JournalFile {
 } JournalFile;
 
 int journal_file_open(
-                const char *fname,
+                JournalDirectory *dir,
+                const char *filename,
                 int flags,
                 mode_t mode,
                 bool compress,
@@ -139,7 +142,8 @@ int journal_file_set_offline(JournalFile *f);
 void journal_file_close(JournalFile *j);
 
 int journal_file_open_reliably(
-                const char *fname,
+                JournalDirectory *dir,
+                const char *filename,
                 int flags,
                 mode_t mode,
                 bool compress,
diff --git a/src/journal/journal-internal.h b/src/journal/journal-internal.h
index b51ecdb..90a0f3f 100644
--- a/src/journal/journal-internal.h
+++ b/src/journal/journal-internal.h
@@ -33,6 +33,7 @@
 #include "set.h"
 #include "journal-file.h"
 #include "sd-journal.h"
+#include "journal-dir.h"
 
 typedef struct Match Match;
 typedef struct Location Location;
@@ -78,7 +79,7 @@ struct Location {
 };
 
 struct Directory {
-        char *path;
+        JournalDirectory *d;
         int wd;
         bool is_root;
 };
diff --git a/src/journal/journal-vacuum.c b/src/journal/journal-vacuum.c
index 81a577e..f1134bb 100644
--- a/src/journal/journal-vacuum.c
+++ b/src/journal/journal-vacuum.c
@@ -67,7 +67,7 @@ static int vacuum_compare(const void *_a, const void *_b) {
 }
 
 static void patch_realtime(
-                const char *dir,
+                JournalDirectory *dir,
                 const char *fn,
                 const struct stat *st,
                 unsigned long long *realtime) {
@@ -101,14 +101,7 @@ static void patch_realtime(
          * unfortunately there's currently no sane API to query
          * it. Hence let's implement this manually... */
 
-        /* Unfortunately there is is not fgetxattrat(), so we need to
-         * go via path here. :-( */
-
-        path = strjoin(dir, "/", fn, NULL);
-        if (!path)
-                return;
-
-        if (path_getcrtime(path, &crtime) >= 0) {
+        if (fd_getcrtime_at(dir->fd, fn, &crtime, 0) >= 0) {
                 if (crtime < *realtime)
                         *realtime = crtime;
         }
@@ -142,7 +135,7 @@ static int journal_file_empty(int dir_fd, const char *name) {
 }
 
 int journal_directory_vacuum(
-                const char *directory,
+                JournalDirectory *directory,
                 uint64_t max_use,
                 usec_t max_retention_usec,
                 usec_t *oldest_usec,
@@ -170,9 +163,9 @@ int journal_directory_vacuum(
                         max_retention_usec = retention_limit = 0;
         }
 
-        d = opendir(directory);
-        if (!d)
-                return -errno;
+        r = journal_directory_opendir(directory, &d);
+        if (r < 0)
+                return r;
 
         for (;;) {
                 struct dirent *de;
@@ -266,10 +259,10 @@ int journal_directory_vacuum(
                         uint64_t size = 512UL * (uint64_t) st.st_blocks;
 
                         if (unlinkat(dirfd(d), p, 0) >= 0) {
-                                log_full(verbose ? LOG_INFO : LOG_DEBUG, "Deleted empty archived journal %s/%s (%s).", directory, p, format_bytes(sbytes, sizeof(sbytes), size));
+                                log_full(verbose ? LOG_INFO : LOG_DEBUG, "Deleted empty archived journal %s/%s (%s).", directory->path, p, format_bytes(sbytes, sizeof(sbytes), size));
                                 freed += size;
                         } else if (errno != ENOENT)
-                                log_warning_errno(errno, "Failed to delete empty archived journal %s/%s: %m", directory, p);
+                                log_warning_errno(errno, "Failed to delete empty archived journal %s/%s: %m", directory->path, p);
 
                         free(p);
                         continue;
@@ -303,7 +296,7 @@ int journal_directory_vacuum(
                         break;
 
                 if (unlinkat(dirfd(d), list[i].filename, 0) >= 0) {
-                        log_full(verbose ? LOG_INFO : LOG_DEBUG, "Deleted archived journal %s/%s (%s).", directory, list[i].filename, format_bytes(sbytes, sizeof(sbytes), list[i].usage));
+                        log_full(verbose ? LOG_INFO : LOG_DEBUG, "Deleted archived journal %s/%s (%s).", directory->path, list[i].filename, format_bytes(sbytes, sizeof(sbytes), list[i].usage));
                         freed += list[i].usage;
 
                         if (list[i].usage < sum)
@@ -312,7 +305,7 @@ int journal_directory_vacuum(
                                 sum = 0;
 
                 } else if (errno != ENOENT)
-                        log_warning_errno(errno, "Failed to delete archived journal %s/%s: %m", directory, list[i].filename);
+                        log_warning_errno(errno, "Failed to delete archived journal %s/%s: %m", directory->path, list[i].filename);
         }
 
         if (oldest_usec && i < n_list && (*oldest_usec == 0 || list[i].realtime < *oldest_usec))
diff --git a/src/journal/journal-vacuum.h b/src/journal/journal-vacuum.h
index c45cc31..cdcdfcd 100644
--- a/src/journal/journal-vacuum.h
+++ b/src/journal/journal-vacuum.h
@@ -21,5 +21,6 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include "journal-dir.h"
 
-int journal_directory_vacuum(const char *directory, uint64_t max_use, usec_t max_retention_usec, usec_t *oldest_usec, bool vacuum);
+int journal_directory_vacuum(JournalDirectory *directory, uint64_t max_use, usec_t max_retention_usec, usec_t *oldest_usec, bool vacuum);
diff --git a/src/journal/journal-verify.c b/src/journal/journal-verify.c
index ce734d8..347920e 100644
--- a/src/journal/journal-verify.c
+++ b/src/journal/journal-verify.c
@@ -1265,8 +1265,8 @@ fail:
         if (show_progress)
                 flush_progress();
 
-        log_error("File corruption detected at %s:"OFSfmt" (of %llu bytes, %"PRIu64"%%).",
-                  f->path,
+        log_error("File corruption detected at %s/%s:"OFSfmt" (of %llu bytes, %"PRIu64"%%).",
+                  f->directory->path, f->filename,
                   p,
                   (unsigned long long) f->last_stat.st_size,
                   100 * p / f->last_stat.st_size);
diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c
index 76ec082..8a2d4a1 100644
--- a/src/journal/journalctl.c
+++ b/src/journal/journalctl.c
@@ -1576,7 +1576,7 @@ static int verify(sd_journal *j) {
 
 #ifdef HAVE_GCRYPT
                 if (!arg_verify_key && JOURNAL_HEADER_SEALED(f->header))
-                        log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f->path);
+                        log_notice("Journal file %s/%s has sealing enabled but verification key has not been passed using --verify-key=.", f->directory->path, f->filename);
 #endif
 
                 k = journal_file_verify(f, arg_verify_key, &first, &validated, &last, true);
@@ -1584,11 +1584,11 @@ static int verify(sd_journal *j) {
                         /* If the key was invalid give up right-away. */
                         return k;
                 } else if (k < 0) {
-                        log_warning("FAIL: %s (%s)", f->path, strerror(-k));
+                        log_warning("FAIL: %s/%s (%s)", f->directory->path, f->filename, strerror(-k));
                         r = k;
                 } else {
                         char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX], c[FORMAT_TIMESPAN_MAX];
-                        log_info("PASS: %s", f->path);
+                        log_info("PASS: %s/%s", f->directory->path, f->filename);
 
                         if (arg_verify_key && JOURNAL_HEADER_SEALED(f->header)) {
                                 if (validated > 0) {
@@ -1899,7 +1899,7 @@ int main(int argc, char *argv[]) {
                         if (d->is_root)
                                 continue;
 
-                        q = journal_directory_vacuum(d->path, arg_vacuum_size, arg_vacuum_time, NULL, true);
+                        q = journal_directory_vacuum(d->d, arg_vacuum_size, arg_vacuum_time, NULL, true);
                         if (q < 0) {
                                 log_error_errno(q, "Failed to vacuum: %m");
                                 r = q;
diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c
index 3353024..6ec0b8e 100644
--- a/src/journal/journald-server.c
+++ b/src/journal/journald-server.c
@@ -200,7 +200,8 @@ void server_fix_perms(Server *s, JournalFile *f, uid_t uid) {
 
         r = fchmod(f->fd, 0640);
         if (r < 0)
-                log_warning_errno(r, "Failed to fix access mode on %s, ignoring: %m", f->path);
+                log_warning_errno(r, "Failed to fix access mode on %s/%s, ignoring: %m",
+                                  f->directory->path, f->filename);
 
 #ifdef HAVE_ACL
         if (uid <= SYSTEM_UID_MAX)
@@ -208,7 +209,8 @@ void server_fix_perms(Server *s, JournalFile *f, uid_t uid) {
 
         acl = acl_get_fd(f->fd);
         if (!acl) {
-                log_warning_errno(errno, "Failed to read ACL on %s, ignoring: %m", f->path);
+                log_warning_errno(errno, "Failed to read ACL on %s/%s, ignoring: %m",
+                                  f->directory->path, f->filename);
                 return;
         }
 
@@ -218,7 +220,8 @@ void server_fix_perms(Server *s, JournalFile *f, uid_t uid) {
                 if (acl_create_entry(&acl, &entry) < 0 ||
                     acl_set_tag_type(entry, ACL_USER) < 0 ||
                     acl_set_qualifier(entry, &uid) < 0) {
-                        log_warning_errno(errno, "Failed to patch ACL on %s, ignoring: %m", f->path);
+                        log_warning_errno(errno, "Failed to patch ACL on %s/%s, ignoring: %m",
+                                          f->directory->path, f->filename);
                         goto finish;
                 }
         }
@@ -228,12 +231,13 @@ void server_fix_perms(Server *s, JournalFile *f, uid_t uid) {
         if (acl_get_permset(entry, &permset) < 0 ||
             acl_add_perm(permset, ACL_READ) < 0 ||
             calc_acl_mask_if_needed(&acl) < 0) {
-                log_warning_errno(errno, "Failed to patch ACL on %s, ignoring: %m", f->path);
+                log_warning_errno(errno, "Failed to patch ACL on %s/%s, ignoring: %m",
+                                  f->directory->path, f->filename);
                 goto finish;
         }
 
         if (acl_set_fd(f->fd, acl) < 0)
-                log_warning_errno(errno, "Failed to set ACL on %s, ignoring: %m", f->path);
+                log_warning_errno(errno, "Failed to set ACL on %s/%s, ignoring: %m", f->directory->path, f->filename);
 
 finish:
         acl_free(acl);
@@ -241,7 +245,9 @@ finish:
 }
 
 static JournalFile* find_journal(Server *s, uid_t uid) {
-        _cleanup_free_ char *p = NULL;
+        _cleanup_free_ char *directory = NULL;
+        _cleanup_free_ char *filename = NULL;
+        JournalDirectory *dir;
         int r;
         JournalFile *f;
         sd_id128_t machine;
@@ -267,8 +273,15 @@ static JournalFile* find_journal(Server *s, uid_t uid) {
         if (f)
                 return f;
 
-        if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/user-"UID_FMT".journal",
-                     SD_ID128_FORMAT_VAL(machine), uid) < 0)
+        if (asprintf(&directory, "/var/log/journal/" SD_ID128_FORMAT_STR,
+                     SD_ID128_FORMAT_VAL(machine)) < 0)
+                return s->system_journal;
+
+        if (asprintf(&filename, "user-" UID_FMT ".journal", uid) < 0)
+                return s->system_journal;
+
+        r = journal_directory_open(directory, &dir);
+        if (r < 0)
                 return s->system_journal;
 
         while (ordered_hashmap_size(s->user_journals) >= USER_JOURNALS_MAX) {
@@ -278,7 +291,8 @@ static JournalFile* find_journal(Server *s, uid_t uid) {
                 journal_file_close(f);
         }
 
-        r = journal_file_open_reliably(p, O_RDWR|O_CREAT, 0640, s->compress, s->seal, &s->system_metrics, s->mmap, NULL, &f);
+        r = journal_file_open_reliably(dir, filename, O_RDWR|O_CREAT, 0640, s->compress, s->seal, &s->system_metrics, s->mmap, NULL, &f);
+        dir = journal_directory_unref(dir);
         if (r < 0)
                 return s->system_journal;
 
@@ -309,7 +323,8 @@ static int do_rotate(
         r = journal_file_rotate(f, s->compress, seal);
         if (r < 0)
                 if (*f)
-                        log_error_errno(r, "Failed to rotate %s: %m", (*f)->path);
+                        log_error_errno(r, "Failed to rotate %s/%s: %m",
+                                        (*f)->directory->path, (*f)->filename);
                 else
                         log_error_errno(r, "Failed to create new %s journal: %m", name);
         else
@@ -374,13 +389,20 @@ static void do_vacuum(
                 JournalMetrics *metrics) {
 
         const char *p;
+        JournalDirectory *dir;
         int r;
 
         if (!f)
                 return;
 
         p = strjoina(path, id);
-        r = journal_directory_vacuum(p, metrics->max_use, s->max_retention_usec, &s->oldest_file_usec, false);
+        r = journal_directory_open(p, &dir);
+        if (r < 0 && r != -ENOENT) {
+                log_error_errno(r, "Failed to vacuum %s: %m", p);
+                return;
+        }
+        r = journal_directory_vacuum(dir, metrics->max_use, s->max_retention_usec, &s->oldest_file_usec, false);
+        dir = journal_directory_unref(dir);
         if (r < 0 && r != -ENOENT)
                 log_error_errno(r, "Failed to vacuum %s: %m", p);
 }
@@ -467,19 +489,19 @@ static bool shall_try_append_again(JournalFile *f, int r) {
            -EIDRM            Journal file has been deleted */
 
         if (r == -E2BIG || r == -EFBIG || r == -EDQUOT || r == -ENOSPC)
-                log_debug("%s: Allocation limit reached, rotating.", f->path);
+                log_debug("%s/%s: Allocation limit reached, rotating.", f->directory->path, f->filename);
         else if (r == -EHOSTDOWN)
-                log_info("%s: Journal file from other machine, rotating.", f->path);
+                log_info("%s/%s: Journal file from other machine, rotating.", f->directory->path, f->filename);
         else if (r == -EBUSY)
-                log_info("%s: Unclean shutdown, rotating.", f->path);
+                log_info("%s/%s: Unclean shutdown, rotating.", f->directory->path, f->filename);
         else if (r == -EPROTONOSUPPORT)
-                log_info("%s: Unsupported feature, rotating.", f->path);
+                log_info("%s/%s: Unsupported feature, rotating.", f->directory->path, f->filename);
         else if (r == -EBADMSG || r == -ENODATA || r == ESHUTDOWN)
-                log_warning("%s: Journal file corrupted, rotating.", f->path);
+                log_warning("%s/%s: Journal file corrupted, rotating.", f->directory->path, f->filename);
         else if (r == -EIO)
-                log_warning("%s: IO error, rotating.", f->path);
+                log_warning("%s/%s: IO error, rotating.", f->directory->path, f->filename);
         else if (r == -EIDRM)
-                log_warning("%s: Journal file has been deleted, rotating.", f->path);
+                log_warning("%s/%s: Journal file has been deleted, rotating.", f->directory->path, f->filename);
         else
                 return false;
 
@@ -500,7 +522,7 @@ static void write_to_journal(Server *s, uid_t uid, struct iovec *iovec, unsigned
                 return;
 
         if (journal_file_rotate_suggested(f, s->max_file_usec)) {
-                log_debug("%s: Journal header limits reached or header out-of-date, rotating.", f->path);
+                log_debug("%s/%s: Journal header limits reached or header out-of-date, rotating.", f->directory->path, f->filename);
                 server_rotate(s);
                 server_vacuum(s);
                 vacuumed = true;
@@ -936,6 +958,8 @@ static int system_journal_open(Server *s, bool flush_requested) {
             (flush_requested
              || access("/run/systemd/journal/flushed", F_OK) >= 0)) {
 
+                JournalDirectory *dir;
+
                 /* If in auto mode: first try to create the machine
                  * path, but not the prefix.
                  *
@@ -947,54 +971,75 @@ static int system_journal_open(Server *s, bool flush_requested) {
 
                 fn = strjoina("/var/log/journal/", ids);
                 (void) mkdir(fn, 0755);
+                r = journal_directory_open(fn, &dir);
+                if (r < 0) {
+                        log_warning_errno(r, "Failed to open system journal: %m");
+                } else {
 
-                fn = strjoina(fn, "/system.journal");
-                r = journal_file_open_reliably(fn, O_RDWR|O_CREAT, 0640, s->compress, s->seal, &s->system_metrics, s->mmap, NULL, &s->system_journal);
+                        r = journal_file_open_reliably(dir, "system.journal", O_RDWR|O_CREAT, 0640, s->compress, s->seal, &s->system_metrics, s->mmap, NULL, &s->system_journal);
+                        dir = journal_directory_unref(dir);
 
-                if (r >= 0)
-                        server_fix_perms(s, s->system_journal, 0);
-                else if (r < 0) {
-                        if (r != -ENOENT && r != -EROFS)
-                                log_warning_errno(r, "Failed to open system journal: %m");
+                        if (r >= 0)
+                                server_fix_perms(s, s->system_journal, 0);
+                        else if (r < 0) {
+                                if (r != -ENOENT && r != -EROFS)
+                                        log_warning_errno(r, "Failed to open system journal: %m");
 
-                        r = 0;
+                                r = 0;
+                        }
                 }
         }
 
         if (!s->runtime_journal &&
             (s->storage != STORAGE_NONE)) {
 
-                fn = strjoin("/run/log/journal/", ids, "/system.journal", NULL);
+                fn = strjoin("/run/log/journal/", ids, NULL);
                 if (!fn)
                         return -ENOMEM;
 
                 if (s->system_journal) {
 
+                        JournalDirectory *dir;
+
                         /* Try to open the runtime journal, but only
                          * if it already exists, so that we can flush
                          * it into the system journal */
 
-                        r = journal_file_open(fn, O_RDWR, 0640, s->compress, false, &s->runtime_metrics, s->mmap, NULL, &s->runtime_journal);
-                        free(fn);
-
+                        r = journal_directory_open(fn, &dir);
                         if (r < 0) {
                                 if (r != -ENOENT)
                                         log_warning_errno(r, "Failed to open runtime journal: %m");
-
                                 r = 0;
+                        } else {
+                                r = journal_file_open(dir, "system.journal", O_RDWR, 0640, s->compress, false, &s->runtime_metrics, s->mmap, NULL, &s->runtime_journal);
+                                free(fn);
+                                dir = journal_directory_unref(dir);
+
+                                if (r < 0) {
+                                        if (r != -ENOENT)
+                                                log_warning_errno(r, "Failed to open runtime journal: %m");
+
+                                        r = 0;
+                                }
                         }
 
                 } else {
 
+                        JournalDirectory *dir;
+
                         /* OK, we really need the runtime journal, so create
                          * it if necessary. */
 
                         (void) mkdir("/run/log", 0755);
                         (void) mkdir("/run/log/journal", 0755);
-                        (void) mkdir_parents(fn, 0750);
+                        (void) mkdir_p(fn, 0750);
 
-                        r = journal_file_open_reliably(fn, O_RDWR|O_CREAT, 0640, s->compress, false, &s->runtime_metrics, s->mmap, NULL, &s->runtime_journal);
+                        r = journal_directory_open(fn, &dir);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to open runtime journal: %m");
+                        r = journal_file_open_reliably(dir, "system.journal", O_RDWR|O_CREAT, 0640, s->compress, false, &s->runtime_metrics, s->mmap, NULL, &s->runtime_journal);
                         free(fn);
+                        dir = journal_directory_unref(dir);
 
                         if (r < 0)
                                 return log_error_errno(r, "Failed to open runtime journal: %m");
diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c
index 9f0f71a..630cc3a 100644
--- a/src/journal/sd-journal.c
+++ b/src/journal/sd-journal.c
@@ -798,7 +798,8 @@ static int real_journal_next(sd_journal *j, direction_t direction) {
 
                 r = next_beyond_location(j, f, direction);
                 if (r < 0) {
-                        log_debug_errno(r, "Can't iterate through %s, ignoring: %m", f->path);
+                        log_debug_errno(r, "Can't iterate through %s/%s, ignoring: %m",
+                                        f->directory->path, f->filename);
                         remove_file_real(j, f);
                         continue;
                 } else if (r == 0) {
@@ -1194,12 +1195,19 @@ static bool file_type_wanted(int flags, const char *filename) {
         return false;
 }
 
-static int add_any_file(sd_journal *j, const char *path) {
+static int add_any_file(sd_journal *j, JournalDirectory *d, const char *filename) {
+        _cleanup_free_ char *path = NULL;
         JournalFile *f = NULL;
         int r;
+        _cleanup_free_ char *fpath = NULL;
 
         assert(j);
-        assert(path);
+        assert(d);
+        assert(filename);
+
+        path = strjoin(d->path, "/", filename, NULL);
+        if (!path)
+                return -ENOMEM;
 
         if (ordered_hashmap_get(j->files, path))
                 return 0;
@@ -1209,19 +1217,23 @@ static int add_any_file(sd_journal *j, const char *path) {
                 return set_put_error(j, -ETOOMANYREFS);
         }
 
-        r = journal_file_open(path, O_RDONLY, 0, false, false, NULL, j->mmap, NULL, &f);
+        r = journal_file_open(d, filename, O_RDONLY, 0, false, false, NULL, j->mmap, NULL, &f);
         if (r < 0)
                 return r;
 
         /* journal_file_dump(f); */
 
-        r = ordered_hashmap_put(j->files, f->path, f);
+        fpath = strjoin(f->directory->path, "/", f->filename, NULL);
+        if (!fpath)
+                return -ENOMEM;
+        r = ordered_hashmap_put(j->files, fpath, f);
         if (r < 0) {
                 journal_file_close(f);
                 return r;
         }
+        fpath = NULL;
 
-        log_debug("File %s added.", f->path);
+        log_debug("File %s/%s added.", f->directory->path, f->filename);
 
         check_network(j, f->fd);
 
@@ -1230,37 +1242,32 @@ static int add_any_file(sd_journal *j, const char *path) {
         return 0;
 }
 
-static int add_file(sd_journal *j, const char *prefix, const char *filename) {
-        _cleanup_free_ char *path = NULL;
+static int add_file(sd_journal *j, JournalDirectory *d, const char *filename) {
         int r;
 
         assert(j);
-        assert(prefix);
+        assert(d);
         assert(filename);
 
         if (j->no_new_files ||
             !file_type_wanted(j->flags, filename))
                 return 0;
 
-        path = strjoin(prefix, "/", filename, NULL);
-        if (!path)
-                return -ENOMEM;
-
-        r = add_any_file(j, path);
+        r = add_any_file(j, d, filename);
         if (r == -ENOENT)
                 return 0;
         return r;
 }
 
-static int remove_file(sd_journal *j, const char *prefix, const char *filename) {
+static int remove_file(sd_journal *j, JournalDirectory *d, const char *filename) {
         _cleanup_free_ char *path;
         JournalFile *f;
 
         assert(j);
-        assert(prefix);
+        assert(d);
         assert(filename);
 
-        path = strjoin(prefix, "/", filename, NULL);
+        path = strjoin(d->path, "/", filename, NULL);
         if (!path)
                 return -ENOMEM;
 
@@ -1273,12 +1280,21 @@ static int remove_file(sd_journal *j, const char *prefix, const char *filename)
 }
 
 static void remove_file_real(sd_journal *j, JournalFile *f) {
+        char *fpath;
+        _cleanup_free_ char *path = NULL;
+
         assert(j);
         assert(f);
 
-        ordered_hashmap_remove(j->files, f->path);
+        path = strjoin(f->directory->path, "/", f->filename, NULL);
+        if (!path) {
+                log_warning("Failed to remove %s/%s.", f->directory->path, f->filename);
+                return;
+        }
+        ordered_hashmap_remove2(j->files, path, (void**)&fpath);
+        free(fpath);
 
-        log_debug("File %s removed.", f->path);
+        log_debug("File %s removed.", path);
 
         if (j->current_file == f) {
                 j->current_file = NULL;
@@ -1287,7 +1303,7 @@ static void remove_file_real(sd_journal *j, JournalFile *f) {
 
         if (j->unique_file == f) {
                 /* Jump to the next unique_file or NULL if that one was last */
-                j->unique_file = ordered_hashmap_next(j->files, j->unique_file->path);
+                j->unique_file = ordered_hashmap_next(j->files, path);
                 j->unique_offset = 0;
                 if (!j->unique_file)
                         j->unique_file_lost = true;
@@ -1298,7 +1314,39 @@ static void remove_file_real(sd_journal *j, JournalFile *f) {
         j->current_invalidate_counter ++;
 }
 
-static int add_directory(sd_journal *j, const char *prefix, const char *dirname) {
+static int new_directory(const char* path, int fd, bool is_root, Directory **ret) {
+        Directory *m;
+        JournalDirectory *d;
+        int r;
+
+        assert(path);
+        assert(ret);
+
+        r = journal_directory_new(path, fd, &d);
+        if (r < 0)
+                return r;
+
+        m = new0(Directory, 1);
+        if (!m) {
+                d = journal_directory_unref(d);
+                return -ENOMEM;
+        }
+
+        m->is_root = is_root;
+        m->d = d;
+        *ret = m;
+
+        return 0;
+}
+
+static void free_directory(Directory *d) {
+        if (d) {
+                journal_directory_unref(d->d);
+                free(d);
+        }
+}
+
+static int add_directory(sd_journal *j, JournalDirectory *directory, const char *dirname) {
         _cleanup_free_ char *path = NULL;
         int r;
         _cleanup_closedir_ DIR *d = NULL;
@@ -1306,54 +1354,59 @@ static int add_directory(sd_journal *j, const char *prefix, const char *dirname)
         Directory *m;
 
         assert(j);
-        assert(prefix);
+        assert(directory);
         assert(dirname);
 
-        log_debug("Considering %s/%s.", prefix, dirname);
+        log_debug("Considering %s/%s.", directory->path, dirname);
 
         if ((j->flags & SD_JOURNAL_LOCAL_ONLY) &&
             (sd_id128_from_string(dirname, &id) < 0 ||
              sd_id128_get_machine(&mid) < 0 ||
-             !(sd_id128_equal(id, mid) || path_startswith(prefix, "/run"))))
+             !(sd_id128_equal(id, mid) || path_startswith(directory->path, "/run"))))
             return 0;
 
-        path = strjoin(prefix, "/", dirname, NULL);
+        path = strjoin(directory->path, "/", dirname, NULL);
         if (!path)
                 return -ENOMEM;
 
-        d = opendir(path);
-        if (!d) {
-                log_debug_errno(errno, "Failed to open %s: %m", path);
-                if (errno == ENOENT)
-                        return 0;
-                return -errno;
-        }
-
         m = hashmap_get(j->directories_by_path, path);
         if (!m) {
-                m = new0(Directory, 1);
-                if (!m)
-                        return -ENOMEM;
+                _cleanup_close_ int fd = -1;
 
-                m->is_root = false;
-                m->path = path;
+                fd = openat(directory->fd, dirname, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
+                if (fd < 0)
+                        return -errno;
 
-                if (hashmap_put(j->directories_by_path, m->path, m) < 0) {
-                        free(m);
+                r = new_directory(path, fd, false, &m);
+                if (r < 0)
+                        return r;
+
+                if (hashmap_put(j->directories_by_path, m->d->path, m) < 0) {
+                        free_directory(m);
                         return -ENOMEM;
                 }
 
-                path = NULL; /* avoid freeing in cleanup */
                 j->current_invalidate_counter ++;
 
-                log_debug("Directory %s added.", m->path);
+                log_debug("Directory %s added.", m->d->path);
 
         } else if (m->is_root)
                 return 0;
 
+        r = journal_directory_opendir(m->d, &d);
+        if (r < 0) {
+                log_debug_errno(errno, "Failed to open %s: %m", m->d->path);
+                if (r == -ENOENT)
+                        return 0;
+                return r;
+        }
+
+        /* TODO: we can't watch changes happening in overlayfs in
+           other mount namespace, unless we get something like
+           inotify_add_watch_dirfd. */
         if (m->wd <= 0 && j->inotify_fd >= 0) {
 
-                m->wd = inotify_add_watch(j->inotify_fd, m->path,
+                m->wd = inotify_add_watch(j->inotify_fd, m->d->path,
                                           IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB|IN_DELETE|
                                           IN_DELETE_SELF|IN_MOVE_SELF|IN_UNMOUNT|IN_MOVED_FROM|
                                           IN_ONLYDIR);
@@ -1369,7 +1422,7 @@ static int add_directory(sd_journal *j, const char *prefix, const char *dirname)
                 de = readdir(d);
                 if (!de && errno != 0) {
                         r = -errno;
-                        log_debug_errno(errno, "Failed to read directory %s: %m", m->path);
+                        log_debug_errno(errno, "Failed to read directory %s: %m", m->d->path);
                         return r;
                 }
                 if (!de)
@@ -1377,10 +1430,10 @@ static int add_directory(sd_journal *j, const char *prefix, const char *dirname)
 
                 if (dirent_is_file_with_suffix(de, ".journal") ||
                     dirent_is_file_with_suffix(de, ".journal~")) {
-                        r = add_file(j, m->path, de->d_name);
+                        r = add_file(j, m->d, de->d_name);
                         if (r < 0) {
                                 log_debug_errno(r, "Failed to add file %s/%s: %m",
-                                                m->path, de->d_name);
+                                                m->d->path, de->d_name);
                                 r = set_put_error(j, r);
                                 if (r < 0)
                                         return r;
@@ -1393,54 +1446,43 @@ static int add_directory(sd_journal *j, const char *prefix, const char *dirname)
         return 0;
 }
 
-static int add_root_directory(sd_journal *j, const char *p) {
+static int add_root_directory_with_fd(sd_journal *j, const char *p, int fd) {
         _cleanup_closedir_ DIR *d = NULL;
         Directory *m;
         int r;
 
         assert(j);
         assert(p);
-
-        if ((j->flags & SD_JOURNAL_RUNTIME_ONLY) &&
-            !path_startswith(p, "/run"))
-                return -EINVAL;
-
-        if (j->prefix)
-                p = strjoina(j->prefix, p);
-
-        d = opendir(p);
-        if (!d)
-                return -errno;
+        assert(fd >= 0);
 
         m = hashmap_get(j->directories_by_path, p);
         if (!m) {
-                m = new0(Directory, 1);
-                if (!m)
-                        return -ENOMEM;
-
-                m->is_root = true;
-                m->path = strdup(p);
-                if (!m->path) {
-                        free(m);
-                        return -ENOMEM;
-                }
+                r = new_directory(p, fd, true, &m);
+                if (r < 0)
+                        return r;
 
-                if (hashmap_put(j->directories_by_path, m->path, m) < 0) {
-                        free(m->path);
-                        free(m);
+                if (hashmap_put(j->directories_by_path, m->d->path, m) < 0) {
+                        free_directory(m);
                         return -ENOMEM;
                 }
 
                 j->current_invalidate_counter ++;
 
-                log_debug("Root directory %s added.", m->path);
+                log_debug("Root directory %s added.", m->d->path);
 
         } else if (!m->is_root)
                 return 0;
 
+        r = journal_directory_opendir(m->d, &d);
+        if (r < 0)
+                return r;
+
+        /* TODO: we can't watch changes happening in overlayfs in
+           other mount namespace, unless we get something like
+           inotify_add_watch_dirfd. */
         if (m->wd <= 0 && j->inotify_fd >= 0) {
 
-                m->wd = inotify_add_watch(j->inotify_fd, m->path,
+                m->wd = inotify_add_watch(j->inotify_fd, m->d->path,
                                           IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB|IN_DELETE|
                                           IN_ONLYDIR);
 
@@ -1459,7 +1501,7 @@ static int add_root_directory(sd_journal *j, const char *p) {
                 de = readdir(d);
                 if (!de && errno != 0) {
                         r = -errno;
-                        log_debug_errno(errno, "Failed to read directory %s: %m", m->path);
+                        log_debug_errno(errno, "Failed to read directory %s: %m", m->d->path);
                         return r;
                 }
                 if (!de)
@@ -1467,10 +1509,10 @@ static int add_root_directory(sd_journal *j, const char *p) {
 
                 if (dirent_is_file_with_suffix(de, ".journal") ||
                     dirent_is_file_with_suffix(de, ".journal~")) {
-                        r = add_file(j, m->path, de->d_name);
+                        r = add_file(j, m->d, de->d_name);
                         if (r < 0) {
                                 log_debug_errno(r, "Failed to add file %s/%s: %m",
-                                                m->path, de->d_name);
+                                                m->d->path, de->d_name);
                                 r = set_put_error(j, r);
                                 if (r < 0)
                                         return r;
@@ -1478,9 +1520,9 @@ static int add_root_directory(sd_journal *j, const char *p) {
                 } else if ((de->d_type == DT_DIR || de->d_type == DT_LNK || de->d_type == DT_UNKNOWN) &&
                            sd_id128_from_string(de->d_name, &id) >= 0) {
 
-                        r = add_directory(j, m->path, de->d_name);
+                        r = add_directory(j, m->d, de->d_name);
                         if (r < 0)
-                                log_debug_errno(r, "Failed to add directory %s/%s: %m", m->path, de->d_name);
+                                log_debug_errno(r, "Failed to add directory %s/%s: %m", m->d->path, de->d_name);
                 }
         }
 
@@ -1489,6 +1531,26 @@ static int add_root_directory(sd_journal *j, const char *p) {
         return 0;
 }
 
+static int add_root_directory(sd_journal *j, const char *p) {
+        _cleanup_close_ int fd = -1;
+
+        assert(j);
+        assert(p);
+
+        if ((j->flags & SD_JOURNAL_RUNTIME_ONLY) &&
+            !path_startswith(p, "/run"))
+                return -EINVAL;
+
+        if (j->prefix)
+                p = strjoina(j->prefix, p);
+
+        fd = open(p, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
+        if (fd < 0)
+                return -errno;
+
+        return add_root_directory_with_fd(j, p, fd);
+}
+
 static int remove_directory(sd_journal *j, Directory *d) {
         assert(j);
 
@@ -1499,15 +1561,14 @@ static int remove_directory(sd_journal *j, Directory *d) {
                         inotify_rm_watch(j->inotify_fd, d->wd);
         }
 
-        hashmap_remove(j->directories_by_path, d->path);
+        hashmap_remove(j->directories_by_path, d->d->path);
 
         if (d->is_root)
-                log_debug("Root directory %s removed.", d->path);
+                log_debug("Root directory %s removed.", d->d->path);
         else
-                log_debug("Directory %s removed.", d->path);
+                log_debug("Directory %s removed.", d->d->path);
 
-        free(d->path);
-        free(d);
+        free_directory(d);
 
         return 0;
 }
@@ -1539,6 +1600,7 @@ static int add_search_paths(sd_journal *j) {
 static int add_current_paths(sd_journal *j) {
         Iterator i;
         JournalFile *f;
+        const char *p;
 
         assert(j);
         assert(j->no_new_files);
@@ -1547,11 +1609,11 @@ static int add_current_paths(sd_journal *j) {
          * "root" directories. We don't expect errors here, so we
          * treat them as fatal. */
 
-        ORDERED_HASHMAP_FOREACH(f, j->files, i) {
+        ORDERED_HASHMAP_FOREACH_KEY(f, p, j->files, i) {
                 _cleanup_free_ char *dir;
                 int r;
 
-                dir = dirname_malloc(f->path);
+                dir = dirname_malloc(p);
                 if (!dir)
                         return -ENOMEM;
 
@@ -1712,6 +1774,8 @@ _public_ int sd_journal_open_files(sd_journal **ret, const char **paths, int fla
         sd_journal *j;
         const char **path;
         int r;
+        Hashmap *dirs;
+        Directory *dir;
 
         assert_return(ret, -EINVAL);
         assert_return(flags == 0, -EINVAL);
@@ -1719,15 +1783,53 @@ _public_ int sd_journal_open_files(sd_journal **ret, const char **paths, int fla
         j = journal_new(flags, NULL);
         if (!j)
                 return -ENOMEM;
+        dirs = hashmap_new(&string_hash_ops);
+        if (!dirs) {
+                r = -ENOMEM;
+                goto fail;
+        }
 
         STRV_FOREACH(path, paths) {
-                r = add_any_file(j, *path);
+                _cleanup_free_ char *d = NULL;
+                _cleanup_free_ char *b = NULL;
+
+                d = dirname_malloc(*path);
+                b = basename_malloc(*path);
+                if (!d || !b)
+                        goto fail;
+
+                dir = hashmap_get(dirs, d);
+                if (!dir) {
+                        _cleanup_close_ int dirfd = -1;
+
+                        dirfd = open(d, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
+                        if (dirfd < 0) {
+                                r = -errno;
+                                log_error_errno(errno, "Failed to open directory %s: %m", d);
+                                goto fail;
+                        }
+                        r = new_directory(d, dirfd, false, &dir);
+                        if (r < 0)
+                                goto fail;
+
+                        r = hashmap_put(dirs, dir->d->path, dir);
+                        if (r < 0) {
+                                free_directory(dir);
+                                goto fail;
+                        }
+                }
+
+                r = add_any_file(j, dir->d, b);
                 if (r < 0) {
                         log_error_errno(r, "Failed to open %s: %m", *path);
                         goto fail;
                 }
         }
 
+        while ((dir = hashmap_steal_first(dirs)))
+                free_directory(dir);
+        hashmap_free(dirs);
+
         j->no_new_files = true;
 
         *ret = j;
@@ -1736,20 +1838,30 @@ _public_ int sd_journal_open_files(sd_journal **ret, const char **paths, int fla
 fail:
         sd_journal_close(j);
 
+        while ((dir = hashmap_steal_first(dirs)))
+                free_directory(dir);
+        hashmap_free(dirs);
+
         return r;
 }
 
 _public_ void sd_journal_close(sd_journal *j) {
         Directory *d;
-        JournalFile *f;
 
         if (!j)
                 return;
 
         sd_journal_flush_matches(j);
 
-        while ((f = ordered_hashmap_steal_first(j->files)))
+        while (!ordered_hashmap_isempty(j->files)) {
+                char *p;
+                JournalFile *f;
+
+                p = ordered_hashmap_first_key(j->files);
+                f = ordered_hashmap_steal_first(j->files);
+                free(p);
                 journal_file_close(f);
+        }
 
         ordered_hashmap_free(j->files);
 
@@ -2129,18 +2241,18 @@ static void process_inotify_event(sd_journal *j, struct inotify_event *e) {
                         /* Event for a journal file */
 
                         if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB)) {
-                                r = add_file(j, d->path, e->name);
+                                r = add_file(j, d->d, e->name);
                                 if (r < 0) {
                                         log_debug_errno(r, "Failed to add file %s/%s: %m",
-                                                        d->path, e->name);
+                                                        d->d->path, e->name);
                                         set_put_error(j, r);
                                 }
 
                         } else if (e->mask & (IN_DELETE|IN_MOVED_FROM|IN_UNMOUNT)) {
 
-                                r = remove_file(j, d->path, e->name);
+                                r = remove_file(j, d->d, e->name);
                                 if (r < 0)
-                                        log_debug_errno(r, "Failed to remove file %s/%s: %m", d->path, e->name);
+                                        log_debug_errno(r, "Failed to remove file %s/%s: %m", d->d->path, e->name);
                         }
 
                 } else if (!d->is_root && e->len == 0) {
@@ -2150,7 +2262,7 @@ static void process_inotify_event(sd_journal *j, struct inotify_event *e) {
                         if (e->mask & (IN_DELETE_SELF|IN_MOVE_SELF|IN_UNMOUNT)) {
                                 r = remove_directory(j, d);
                                 if (r < 0)
-                                        log_debug_errno(r, "Failed to remove directory %s: %m", d->path);
+                                        log_debug_errno(r, "Failed to remove directory %s: %m", d->d->path);
                         }
 
 
@@ -2159,9 +2271,9 @@ static void process_inotify_event(sd_journal *j, struct inotify_event *e) {
                         /* Event for root directory */
 
                         if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB)) {
-                                r = add_directory(j, d->path, e->name);
+                                r = add_directory(j, d->d, e->name);
                                 if (r < 0)
-                                        log_debug_errno(r, "Failed to add directory %s/%s: %m", d->path, e->name);
+                                        log_debug_errno(r, "Failed to add directory %s/%s: %m", d->d->path, e->name);
                         }
                 }
 
@@ -2447,7 +2559,12 @@ _public_ int sd_journal_enumerate_unique(sd_journal *j, const void **data, size_
 
                 /* We reached the end of the list? Then start again, with the next file */
                 if (j->unique_offset == 0) {
-                        j->unique_file = ordered_hashmap_next(j->files, j->unique_file->path);
+                        char *p = strjoin(j->unique_file->directory->path, "/", j->unique_file->filename, NULL);
+
+                        if (!p)
+                                return -ENOMEM;
+                        j->unique_file = ordered_hashmap_next(j->files, p);
+                        free(p);
                         if (!j->unique_file)
                                 return 0;
 
@@ -2463,8 +2580,9 @@ _public_ int sd_journal_enumerate_unique(sd_journal *j, const void **data, size_
 
                 /* Let's do the type check by hand, since we used 0 context above. */
                 if (o->object.type != OBJECT_DATA) {
-                        log_debug("%s:offset " OFSfmt ": object has type %d, expected %d",
-                                  j->unique_file->path, j->unique_offset,
+                        log_debug("%s/%s:offset " OFSfmt ": object has type %d, expected %d",
+                                  j->unique_file->directory->path, j->unique_file->filename,
+                                  j->unique_offset,
                                   o->object.type, OBJECT_DATA);
                         return -EBADMSG;
                 }
@@ -2475,15 +2593,17 @@ _public_ int sd_journal_enumerate_unique(sd_journal *j, const void **data, size_
 
                 /* Check if we have at least the field name and "=". */
                 if (ol <= k) {
-                        log_debug("%s:offset " OFSfmt ": object has size %zu, expected at least %zu",
-                                  j->unique_file->path, j->unique_offset,
+                        log_debug("%s/%s:offset " OFSfmt ": object has size %zu, expected at least %zu",
+                                  j->unique_file->directory->path, j->unique_file->filename,
+                                  j->unique_offset,
                                   ol, k + 1);
                         return -EBADMSG;
                 }
 
                 if (memcmp(odata, j->unique_field, k) || ((const char*) odata)[k] != '=') {
-                        log_debug("%s:offset " OFSfmt ": object does not start with \"%s=\"",
-                                  j->unique_file->path, j->unique_offset,
+                        log_debug("%s/%s:offset " OFSfmt ": object does not start with \"%s=\"",
+                                  j->unique_file->directory->path, j->unique_file->filename,
+                                  j->unique_offset,
                                   j->unique_field);
                         return -EBADMSG;
                 }
diff --git a/src/journal/test-journal-flush.c b/src/journal/test-journal-flush.c
index 2d4f531..97080fb 100644
--- a/src/journal/test-journal-flush.c
+++ b/src/journal/test-journal-flush.c
@@ -27,17 +27,21 @@
 #include "journal-internal.h"
 
 int main(int argc, char *argv[]) {
-        _cleanup_free_ char *fn = NULL;
+        const char *fn;
         char dn[] = "/var/tmp/test-journal-flush.XXXXXX";
+        JournalDirectory *dir;
         JournalFile *new_journal = NULL;
         sd_journal *j = NULL;
         unsigned n = 0;
         int r;
 
         assert_se(mkdtemp(dn));
-        fn = strappend(dn, "/test.journal");
+        fn = "test.journal";
 
-        r = journal_file_open(fn, O_CREAT|O_RDWR, 0644, false, false, NULL, NULL, NULL, &new_journal);
+        r = journal_directory_open(dn, &dir);
+        assert_se(r >= 0);
+
+        r = journal_file_open(dir, fn, O_CREAT|O_RDWR, 0644, false, false, NULL, NULL, NULL, &new_journal);
         assert_se(r >= 0);
 
         r = sd_journal_open(&j, 0);
@@ -67,7 +71,8 @@ int main(int argc, char *argv[]) {
 
         journal_file_close(new_journal);
 
-        unlink(fn);
+        unlinkat(dir->fd, fn, 0);
+        dir = journal_directory_unref(dir);
         assert_se(rmdir(dn) == 0);
 
         return 0;
diff --git a/src/journal/test-journal-interleaving.c b/src/journal/test-journal-interleaving.c
index c2fc123..1bb965f 100644
--- a/src/journal/test-journal-interleaving.c
+++ b/src/journal/test-journal-interleaving.c
@@ -49,16 +49,27 @@ noreturn static void log_assert_errno(const char *text, int eno, const char *fil
                         log_assert_errno(#expr, -_r_, __FILE__, __LINE__, __PRETTY_FUNCTION__); \
         } while (false)
 
-static JournalFile *test_open(const char *name) {
+static JournalFile *test_open(JournalDirectory *dir, const char *filename) {
         JournalFile *f;
-        assert_ret(journal_file_open(name, O_RDWR|O_CREAT, 0644, true, false, NULL, NULL, NULL, &f));
+        assert_ret(journal_file_open(dir, filename, O_RDWR|O_CREAT, 0644, true, false, NULL, NULL, NULL, &f));
         return f;
 }
 
+static JournalDirectory *test_open_dir(const char *dirname) {
+        JournalDirectory *dir;
+
+        assert_ret(journal_directory_open(dirname, &dir));
+        return dir;
+}
+
 static void test_close(JournalFile *f) {
         journal_file_close (f);
 }
 
+static void test_close_dir(JournalDirectory *dir) {
+        journal_directory_unref(dir);
+}
+
 static void append_number(JournalFile *f, int n, uint64_t *seqnum) {
         char *p;
         dual_timestamp ts;
@@ -115,39 +126,48 @@ static void test_check_numbers_up (sd_journal *j, int count) {
 
 }
 
-static void setup_sequential(void) {
+static JournalDirectory* setup_sequential(void) {
         JournalFile *one, *two;
-        one = test_open("one.journal");
-        two = test_open("two.journal");
+        JournalDirectory *dir;
+
+        dir = test_open_dir(".");
+        one = test_open(dir, "one.journal");
+        two = test_open(dir, "two.journal");
         append_number(one, 1, NULL);
         append_number(one, 2, NULL);
         append_number(two, 3, NULL);
         append_number(two, 4, NULL);
         test_close(one);
         test_close(two);
+        return dir;
 }
 
-static void setup_interleaved(void) {
+static JournalDirectory* setup_interleaved(void) {
         JournalFile *one, *two;
-        one = test_open("one.journal");
-        two = test_open("two.journal");
+        JournalDirectory *dir;
+
+        dir = test_open_dir(".");
+        one = test_open(dir, "one.journal");
+        two = test_open(dir, "two.journal");
         append_number(one, 1, NULL);
         append_number(two, 2, NULL);
         append_number(one, 3, NULL);
         append_number(two, 4, NULL);
         test_close(one);
         test_close(two);
+        return dir;
 }
 
-static void test_skip(void (*setup)(void)) {
+static void test_skip(JournalDirectory* (*setup)(void)) {
         char t[] = "/tmp/journal-skip-XXXXXX";
         sd_journal *j;
         int r;
+        JournalDirectory *dir;
 
         assert_se(mkdtemp(t));
         assert_se(chdir(t) >= 0);
 
-        setup();
+        dir = setup();
 
         /* Seek to head, iterate down.
          */
@@ -188,10 +208,11 @@ static void test_skip(void (*setup)(void)) {
         if (arg_keep)
                 log_info("Not removing %s", t);
         else {
-                journal_directory_vacuum(".", 3000000, 0, NULL, true);
+                journal_directory_vacuum(dir, 3000000, 0, NULL, true);
 
                 assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
         }
+        test_close_dir(dir);
 
         puts("------------------------------------------------------------");
 }
@@ -200,14 +221,15 @@ static void test_sequence_numbers(void) {
 
         char t[] = "/tmp/journal-seq-XXXXXX";
         JournalFile *one, *two;
+        JournalDirectory *dir;
         uint64_t seqnum = 0;
         sd_id128_t seqnum_id;
 
         assert_se(mkdtemp(t));
         assert_se(chdir(t) >= 0);
 
-        assert_se(journal_file_open("one.journal", O_RDWR|O_CREAT, 0644,
-                                    true, false, NULL, NULL, NULL, &one) == 0);
+        dir = test_open_dir(".");
+        one = test_open(dir, "one.journal");
 
         append_number(one, 1, &seqnum);
         printf("seqnum=%"PRIu64"\n", seqnum);
@@ -223,7 +245,7 @@ static void test_sequence_numbers(void) {
 
         memcpy(&seqnum_id, &one->header->seqnum_id, sizeof(sd_id128_t));
 
-        assert_se(journal_file_open("two.journal", O_RDWR|O_CREAT, 0644,
+        assert_se(journal_file_open(dir, "two.journal", O_RDWR|O_CREAT, 0644,
                                     true, false, NULL, NULL, one, &two) == 0);
 
         assert_se(two->header->state == STATE_ONLINE);
@@ -254,7 +276,7 @@ static void test_sequence_numbers(void) {
         /* restart server */
         seqnum = 0;
 
-        assert_se(journal_file_open("two.journal", O_RDWR, 0,
+        assert_se(journal_file_open(dir, "two.journal", O_RDWR, 0,
                                     true, false, NULL, NULL, NULL, &two) == 0);
 
         assert_se(sd_id128_equal(two->header->seqnum_id, seqnum_id));
@@ -273,10 +295,11 @@ static void test_sequence_numbers(void) {
         if (arg_keep)
                 log_info("Not removing %s", t);
         else {
-                journal_directory_vacuum(".", 3000000, 0, NULL, true);
+                journal_directory_vacuum(dir, 3000000, 0, NULL, true);
 
                 assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
         }
+        test_close_dir(dir);
 }
 
 int main(int argc, char *argv[]) {
diff --git a/src/journal/test-journal-stream.c b/src/journal/test-journal-stream.c
index e1146c6..ba5a0a8 100644
--- a/src/journal/test-journal-stream.c
+++ b/src/journal/test-journal-stream.c
@@ -74,6 +74,7 @@ static void verify_contents(sd_journal *j, unsigned skip) {
 
 int main(int argc, char *argv[]) {
         JournalFile *one, *two, *three;
+        JournalDirectory *dir;
         char t[] = "/tmp/journal-stream-XXXXXX";
         unsigned i;
         _cleanup_journal_close_ sd_journal *j = NULL;
@@ -90,9 +91,12 @@ int main(int argc, char *argv[]) {
         assert_se(mkdtemp(t));
         assert_se(chdir(t) >= 0);
 
-        assert_se(journal_file_open("one.journal", O_RDWR|O_CREAT, 0666, true, false, NULL, NULL, NULL, &one) == 0);
-        assert_se(journal_file_open("two.journal", O_RDWR|O_CREAT, 0666, true, false, NULL, NULL, NULL, &two) == 0);
-        assert_se(journal_file_open("three.journal", O_RDWR|O_CREAT, 0666, true, false, NULL, NULL, NULL, &three) == 0);
+        assert_se(journal_directory_open(".", &dir) == 0);
+
+        assert_se(journal_file_open(dir, "one.journal", O_RDWR|O_CREAT, 0666, true, false, NULL, NULL, NULL, &one) == 0);
+        assert_se(journal_file_open(dir, "two.journal", O_RDWR|O_CREAT, 0666, true, false, NULL, NULL, NULL, &two) == 0);
+        assert_se(journal_file_open(dir, "three.journal", O_RDWR|O_CREAT, 0666, true, false, NULL, NULL, NULL, &three) == 0);
+        dir = journal_directory_unref(dir);
 
         for (i = 0; i < N_ENTRIES; i++) {
                 char *p, *q;
diff --git a/src/journal/test-journal-verify.c b/src/journal/test-journal-verify.c
index d24502d..2160b8d 100644
--- a/src/journal/test-journal-verify.c
+++ b/src/journal/test-journal-verify.c
@@ -52,11 +52,11 @@ static void bit_toggle(const char *fn, uint64_t p) {
         safe_close(fd);
 }
 
-static int raw_verify(const char *fn, const char *verification_key) {
+static int raw_verify(JournalDirectory *dir, const char *fn, const char *verification_key) {
         JournalFile *f;
         int r;
 
-        r = journal_file_open(fn, O_RDONLY, 0666, true, !!verification_key, NULL, NULL, NULL, &f);
+        r = journal_file_open(dir, fn, O_RDONLY, 0666, true, !!verification_key, NULL, NULL, NULL, &f);
         if (r < 0)
                 return r;
 
@@ -70,6 +70,7 @@ int main(int argc, char *argv[]) {
         char t[] = "/tmp/journal-XXXXXX";
         unsigned n;
         JournalFile *f;
+        JournalDirectory *dir;
         const char *verification_key = argv[1];
         usec_t from = 0, to = 0, total = 0;
         char a[FORMAT_TIMESTAMP_MAX];
@@ -89,7 +90,8 @@ int main(int argc, char *argv[]) {
 
         log_info("Generating...");
 
-        assert_se(journal_file_open("test.journal", O_RDWR|O_CREAT, 0666, true, !!verification_key, NULL, NULL, NULL, &f) == 0);
+        assert_se(journal_directory_open(".", &dir) == 0);
+        assert_se(journal_file_open(dir, "test.journal", O_RDWR|O_CREAT, 0666, true, !!verification_key, NULL, NULL, NULL, &f) == 0);
 
         for (n = 0; n < N_ENTRIES; n++) {
                 struct iovec iovec;
@@ -112,7 +114,7 @@ int main(int argc, char *argv[]) {
 
         log_info("Verifying...");
 
-        assert_se(journal_file_open("test.journal", O_RDONLY, 0666, true, !!verification_key, NULL, NULL, NULL, &f) == 0);
+        assert_se(journal_file_open(dir, "test.journal", O_RDONLY, 0666, true, !!verification_key, NULL, NULL, NULL, &f) == 0);
         /* journal_file_print_header(f); */
         journal_file_dump(f);
 
@@ -137,7 +139,7 @@ int main(int argc, char *argv[]) {
 
                         log_info("[ %"PRIu64"+%"PRIu64"]", p / 8, p % 8);
 
-                        if (raw_verify("test.journal", verification_key) >= 0)
+                        if (raw_verify(dir, "test.journal", verification_key) >= 0)
                                 log_notice(ANSI_HIGHLIGHT_RED_ON ">>>> %"PRIu64" (bit %"PRIu64") can be toggled without detection." ANSI_HIGHLIGHT_OFF, p / 8, p % 8);
 
                         bit_toggle("test.journal", p);
@@ -145,6 +147,7 @@ int main(int argc, char *argv[]) {
         }
 
         log_info("Exiting...");
+        dir = journal_directory_unref(dir);
 
         assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
 
diff --git a/src/journal/test-journal.c b/src/journal/test-journal.c
index caaab25..8e6d7bb 100644
--- a/src/journal/test-journal.c
+++ b/src/journal/test-journal.c
@@ -33,6 +33,7 @@ static bool arg_keep = false;
 static void test_non_empty(void) {
         dual_timestamp ts;
         JournalFile *f;
+        JournalDirectory *dir;
         struct iovec iovec;
         static const char test[] = "TEST1=1", test2[] = "TEST2=2";
         Object *o;
@@ -44,7 +45,8 @@ static void test_non_empty(void) {
         assert_se(mkdtemp(t));
         assert_se(chdir(t) >= 0);
 
-        assert_se(journal_file_open("test.journal", O_RDWR|O_CREAT, 0666, true, true, NULL, NULL, NULL, &f) == 0);
+        assert_se(journal_directory_open(".", &dir) == 0);
+        assert_se(journal_file_open(dir, "test.journal", O_RDWR|O_CREAT, 0666, true, true, NULL, NULL, NULL, &f) == 0);
 
         dual_timestamp_get(&ts);
 
@@ -116,16 +118,18 @@ static void test_non_empty(void) {
         if (arg_keep)
                 log_info("Not removing %s", t);
         else {
-                journal_directory_vacuum(".", 3000000, 0, NULL, true);
+                journal_directory_vacuum(dir, 3000000, 0, NULL, true);
 
                 assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
         }
 
+        dir = journal_directory_unref(dir);
         puts("------------------------------------------------------------");
 }
 
 static void test_empty(void) {
         JournalFile *f1, *f2, *f3, *f4;
+        JournalDirectory *dir;
         char t[] = "/tmp/journal-XXXXXX";
 
         log_set_max_level(LOG_DEBUG);
@@ -133,13 +137,15 @@ static void test_empty(void) {
         assert_se(mkdtemp(t));
         assert_se(chdir(t) >= 0);
 
-        assert_se(journal_file_open("test.journal", O_RDWR|O_CREAT, 0666, false, false, NULL, NULL, NULL, &f1) == 0);
+        assert_se(journal_directory_open(".", &dir) == 0);
 
-        assert_se(journal_file_open("test-compress.journal", O_RDWR|O_CREAT, 0666, true, false, NULL, NULL, NULL, &f2) == 0);
+        assert_se(journal_file_open(dir, "test.journal", O_RDWR|O_CREAT, 0666, false, false, NULL, NULL, NULL, &f1) == 0);
 
-        assert_se(journal_file_open("test-seal.journal", O_RDWR|O_CREAT, 0666, false, true, NULL, NULL, NULL, &f3) == 0);
+        assert_se(journal_file_open(dir, "test-compress.journal", O_RDWR|O_CREAT, 0666, true, false, NULL, NULL, NULL, &f2) == 0);
 
-        assert_se(journal_file_open("test-seal-compress.journal", O_RDWR|O_CREAT, 0666, true, true, NULL, NULL, NULL, &f4) == 0);
+        assert_se(journal_file_open(dir, "test-seal.journal", O_RDWR|O_CREAT, 0666, false, true, NULL, NULL, NULL, &f3) == 0);
+
+        assert_se(journal_file_open(dir, "test-seal-compress.journal", O_RDWR|O_CREAT, 0666, true, true, NULL, NULL, NULL, &f4) == 0);
 
         journal_file_print_header(f1);
         puts("");
@@ -155,7 +161,7 @@ static void test_empty(void) {
         if (arg_keep)
                 log_info("Not removing %s", t);
         else {
-                journal_directory_vacuum(".", 3000000, 0, NULL, true);
+                journal_directory_vacuum(dir, 3000000, 0, NULL, true);
 
                 assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
         }
@@ -164,6 +170,7 @@ static void test_empty(void) {
         journal_file_close(f2);
         journal_file_close(f3);
         journal_file_close(f4);
+        journal_directory_unref(dir);
 }
 
 int main(int argc, char *argv[]) {
diff --git a/src/shared/util.c b/src/shared/util.c
index 395af7c..e27d14e 100644
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -1791,6 +1791,26 @@ int dir_is_empty(const char *path) {
         }
 }
 
+char* basename_malloc(const char *path) {
+        char *b, *base, *base2;
+
+        assert(path);
+
+        b = strdup(path);
+        if (!b)
+                return NULL;
+        base = basename(b);
+        assert(base);
+
+        if (base != b) {
+                base2 = strdup(base);
+                free(b);
+                return base2;
+        }
+
+        return base;
+}
+
 char* dirname_malloc(const char *path) {
         char *d, *dir, *dir2;
 
diff --git a/src/shared/util.h b/src/shared/util.h
index 1cfb45f..9b5d9af 100644
--- a/src/shared/util.h
+++ b/src/shared/util.h
@@ -339,6 +339,7 @@ int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll);
 bool is_device_path(const char *path);
 
 int dir_is_empty(const char *path);
+char* basename_malloc(const char *path);
 char* dirname_malloc(const char *path);
 
 char* lookup_uid(uid_t uid);
-- 
2.1.0



More information about the systemd-devel mailing list