diff --git a/src/db/update/Walk.cxx b/src/db/update/Walk.cxx
index 1bcf452d3..aa564faad 100644
--- a/src/db/update/Walk.cxx
+++ b/src/db/update/Walk.cxx
@@ -337,7 +337,7 @@ UpdateWalk::UpdateDirectory(Directory &directory,
 	std::unique_ptr<StorageDirectoryReader> reader;
 
 	try {
-		reader.reset(storage.OpenDirectory(directory.GetPath()));
+		reader = storage.OpenDirectory(directory.GetPath());
 	} catch (...) {
 		LogError(std::current_exception());
 		return false;
diff --git a/src/storage/CompositeStorage.cxx b/src/storage/CompositeStorage.cxx
index 545124d4b..133f355dc 100644
--- a/src/storage/CompositeStorage.cxx
+++ b/src/storage/CompositeStorage.cxx
@@ -33,25 +33,20 @@
  * instance and the virtual directory entries.
  */
 class CompositeDirectoryReader final : public StorageDirectoryReader {
-	StorageDirectoryReader *other;
+	std::unique_ptr<StorageDirectoryReader> other;
 
 	std::set<std::string> names;
 	std::set<std::string>::const_iterator current, next;
 
 public:
-	template<typename M>
-	CompositeDirectoryReader(StorageDirectoryReader *_other,
-				 const M &map)
-		:other(_other) {
+	template<typename O, typename M>
+	CompositeDirectoryReader(O &&_other, const M &map)
+		:other(std::forward<O>(_other)) {
 		for (const auto &i : map)
 			names.insert(i.first);
 		next = names.begin();
 	}
 
-	virtual ~CompositeDirectoryReader() {
-		delete other;
-	}
-
 	/* virtual methods from class StorageDirectoryReader */
 	const char *Read() noexcept override;
 	StorageFileInfo GetInfo(bool follow) override;
@@ -67,8 +62,7 @@ CompositeDirectoryReader::Read() noexcept
 			return name;
 		}
 
-		delete other;
-		other = nullptr;
+		other.reset();
 	}
 
 	if (next == names.end())
@@ -271,7 +265,7 @@ CompositeStorage::GetInfo(const char *uri, bool follow)
 		throw std::runtime_error("No such file or directory");
 }
 
-StorageDirectoryReader *
+std::unique_ptr<StorageDirectoryReader>
 CompositeStorage::OpenDirectory(const char *uri)
 {
 	const std::lock_guard<Mutex> protect(mutex);
@@ -287,14 +281,15 @@ CompositeStorage::OpenDirectory(const char *uri)
 		return f.directory->storage->OpenDirectory(f.uri);
 	}
 
-	StorageDirectoryReader *other = nullptr;
+	std::unique_ptr<StorageDirectoryReader> other;
 
 	try {
 		other = f.directory->storage->OpenDirectory(f.uri);
 	} catch (...) {
 	}
 
-	return new CompositeDirectoryReader(other, directory->children);
+	return std::make_unique<CompositeDirectoryReader>(std::move(other),
+							  directory->children);
 }
 
 std::string
diff --git a/src/storage/CompositeStorage.hxx b/src/storage/CompositeStorage.hxx
index 6bc871bab..a586b9c46 100644
--- a/src/storage/CompositeStorage.hxx
+++ b/src/storage/CompositeStorage.hxx
@@ -119,7 +119,7 @@ public:
 	/* virtual methods from class Storage */
 	StorageFileInfo GetInfo(const char *uri, bool follow) override;
 
-	StorageDirectoryReader *OpenDirectory(const char *uri) override;
+	std::unique_ptr<StorageDirectoryReader> OpenDirectory(const char *uri) override;
 
 	std::string MapUTF8(const char *uri) const noexcept override;
 
diff --git a/src/storage/StorageInterface.hxx b/src/storage/StorageInterface.hxx
index 2b356987e..dbad0c041 100644
--- a/src/storage/StorageInterface.hxx
+++ b/src/storage/StorageInterface.hxx
@@ -23,6 +23,7 @@
 #include "check.h"
 #include "Compiler.h"
 
+#include <memory>
 #include <string>
 
 struct StorageFileInfo;
@@ -56,7 +57,7 @@ public:
 	/**
 	 * Throws #std::runtime_error on error.
 	 */
-	virtual StorageDirectoryReader *OpenDirectory(const char *uri_utf8) = 0;
+	virtual std::unique_ptr<StorageDirectoryReader> OpenDirectory(const char *uri_utf8) = 0;
 
 	/**
 	 * Map the given relative URI to an absolute URI.
diff --git a/src/storage/plugins/CurlStorage.cxx b/src/storage/plugins/CurlStorage.cxx
index e2696c1ac..aedbafd11 100644
--- a/src/storage/plugins/CurlStorage.cxx
+++ b/src/storage/plugins/CurlStorage.cxx
@@ -60,7 +60,7 @@ public:
 	/* virtual methods from class Storage */
 	StorageFileInfo GetInfo(const char *uri_utf8, bool follow) override;
 
-	StorageDirectoryReader *OpenDirectory(const char *uri_utf8) override;
+	std::unique_ptr<StorageDirectoryReader> OpenDirectory(const char *uri_utf8) override;
 
 	std::string MapUTF8(const char *uri_utf8) const noexcept override;
 
@@ -474,14 +474,14 @@ public:
 		:PropfindOperation(curl, uri, 1),
 		 base_path(UriPathOrSlash(uri)) {}
 
-	StorageDirectoryReader *Perform() {
+	std::unique_ptr<StorageDirectoryReader> Perform() {
 		Wait();
 		return ToReader();
 	}
 
 private:
-	StorageDirectoryReader *ToReader() {
-		return new MemoryStorageDirectoryReader(std::move(entries));
+	std::unique_ptr<StorageDirectoryReader> ToReader() {
+		return std::make_unique<MemoryStorageDirectoryReader>(std::move(entries));
 	}
 
 	/**
@@ -534,7 +534,7 @@ protected:
 	}
 };
 
-StorageDirectoryReader *
+std::unique_ptr<StorageDirectoryReader>
 CurlStorage::OpenDirectory(const char *uri_utf8)
 {
 	// TODO: escape the given URI
diff --git a/src/storage/plugins/LocalStorage.cxx b/src/storage/plugins/LocalStorage.cxx
index 405c7e659..83b877648 100644
--- a/src/storage/plugins/LocalStorage.cxx
+++ b/src/storage/plugins/LocalStorage.cxx
@@ -59,7 +59,7 @@ public:
 	/* virtual methods from class Storage */
 	StorageFileInfo GetInfo(const char *uri_utf8, bool follow) override;
 
-	StorageDirectoryReader *OpenDirectory(const char *uri_utf8) override;
+	std::unique_ptr<StorageDirectoryReader> OpenDirectory(const char *uri_utf8) override;
 
 	std::string MapUTF8(const char *uri_utf8) const noexcept override;
 
@@ -140,10 +140,10 @@ LocalStorage::GetInfo(const char *uri_utf8, bool follow)
 	return Stat(MapFSOrThrow(uri_utf8), follow);
 }
 
-StorageDirectoryReader *
+std::unique_ptr<StorageDirectoryReader>
 LocalStorage::OpenDirectory(const char *uri_utf8)
 {
-	return new LocalDirectoryReader(MapFSOrThrow(uri_utf8));
+	return std::make_unique<LocalDirectoryReader>(MapFSOrThrow(uri_utf8));
 }
 
 gcc_pure
diff --git a/src/storage/plugins/NfsStorage.cxx b/src/storage/plugins/NfsStorage.cxx
index cf9659150..49a2adca1 100644
--- a/src/storage/plugins/NfsStorage.cxx
+++ b/src/storage/plugins/NfsStorage.cxx
@@ -88,7 +88,7 @@ public:
 	/* virtual methods from class Storage */
 	StorageFileInfo GetInfo(const char *uri_utf8, bool follow) override;
 
-	StorageDirectoryReader *OpenDirectory(const char *uri_utf8) override;
+	std::unique_ptr<StorageDirectoryReader> OpenDirectory(const char *uri_utf8) override;
 
 	std::string MapUTF8(const char *uri_utf8) const noexcept override;
 
@@ -334,8 +334,8 @@ public:
 				  const char *_path)
 		:BlockingNfsOperation(_connection), path(_path) {}
 
-	StorageDirectoryReader *ToReader() {
-		return new MemoryStorageDirectoryReader(std::move(entries));
+	std::unique_ptr<StorageDirectoryReader> ToReader() {
+		return std::make_unique<MemoryStorageDirectoryReader>(std::move(entries));
 	}
 
 protected:
@@ -377,7 +377,7 @@ NfsListDirectoryOperation::CollectEntries(struct nfsdir *dir)
 	}
 }
 
-StorageDirectoryReader *
+std::unique_ptr<StorageDirectoryReader>
 NfsStorage::OpenDirectory(const char *uri_utf8)
 {
 	const std::string path = UriToNfsPath(uri_utf8);
diff --git a/src/storage/plugins/SmbclientStorage.cxx b/src/storage/plugins/SmbclientStorage.cxx
index e7b8d8f13..3f393f3b5 100644
--- a/src/storage/plugins/SmbclientStorage.cxx
+++ b/src/storage/plugins/SmbclientStorage.cxx
@@ -67,7 +67,7 @@ public:
 	/* virtual methods from class Storage */
 	StorageFileInfo GetInfo(const char *uri_utf8, bool follow) override;
 
-	StorageDirectoryReader *OpenDirectory(const char *uri_utf8) override;
+	std::unique_ptr<StorageDirectoryReader> OpenDirectory(const char *uri_utf8) override;
 
 	std::string MapUTF8(const char *uri_utf8) const noexcept override;
 
@@ -124,7 +124,7 @@ SmbclientStorage::GetInfo(const char *uri_utf8, gcc_unused bool follow)
 	return ::GetInfo(mapped.c_str());
 }
 
-StorageDirectoryReader *
+std::unique_ptr<StorageDirectoryReader>
 SmbclientStorage::OpenDirectory(const char *uri_utf8)
 {
 	std::string mapped = MapUTF8(uri_utf8);
@@ -138,7 +138,8 @@ SmbclientStorage::OpenDirectory(const char *uri_utf8)
 			throw MakeErrno("Failed to open directory");
 	}
 
-	return new SmbclientDirectoryReader(std::move(mapped.c_str()), handle);
+	return std::make_unique<SmbclientDirectoryReader>(std::move(mapped.c_str()),
+							  handle);
 }
 
 gcc_pure
diff --git a/test/run_storage.cxx b/test/run_storage.cxx
index 267b98750..3d987f541 100644
--- a/test/run_storage.cxx
+++ b/test/run_storage.cxx
@@ -82,7 +82,6 @@ Ls(Storage &storage, const char *path)
 		       mtime, name);
 	}
 
-	delete dir;
 	return EXIT_SUCCESS;
 }