diff --git a/src/lib/nfs/Connection.cxx b/src/lib/nfs/Connection.cxx
index 33e75a7c5..012e4daa2 100644
--- a/src/lib/nfs/Connection.cxx
+++ b/src/lib/nfs/Connection.cxx
@@ -49,6 +49,21 @@ NfsConnection::CancellableCallback::Stat(nfs_context *ctx,
 	return true;
 }
 
+inline bool
+NfsConnection::CancellableCallback::OpenDirectory(nfs_context *ctx,
+						  const char *path,
+						  Error &error)
+{
+	int result = nfs_opendir_async(ctx, path, Callback, this);
+	if (result < 0) {
+		error.Format(nfs_domain, "nfs_opendir_async() failed: %s",
+			     nfs_get_error(ctx));
+		return false;
+	}
+
+	return true;
+}
+
 inline bool
 NfsConnection::CancellableCallback::Open(nfs_context *ctx,
 					 const char *path, int flags,
@@ -206,6 +221,34 @@ NfsConnection::Stat(const char *path, NfsCallback &callback, Error &error)
 	return true;
 }
 
+bool
+NfsConnection::OpenDirectory(const char *path, NfsCallback &callback,
+			     Error &error)
+{
+	assert(!callbacks.Contains(callback));
+
+	auto &c = callbacks.Add(callback, *this, true);
+	if (!c.OpenDirectory(context, path, error)) {
+		callbacks.Remove(c);
+		return false;
+	}
+
+	ScheduleSocket();
+	return true;
+}
+
+const struct nfsdirent *
+NfsConnection::ReadDirectory(struct nfsdir *dir)
+{
+	return nfs_readdir(context, dir);
+}
+
+void
+NfsConnection::CloseDirectory(struct nfsdir *dir)
+{
+	return nfs_closedir(context, dir);
+}
+
 bool
 NfsConnection::Open(const char *path, int flags, NfsCallback &callback,
 		    Error &error)
diff --git a/src/lib/nfs/Connection.hxx b/src/lib/nfs/Connection.hxx
index a82921d4e..aebafd4d3 100644
--- a/src/lib/nfs/Connection.hxx
+++ b/src/lib/nfs/Connection.hxx
@@ -33,6 +33,8 @@
 #include <forward_list>
 
 struct nfs_context;
+struct nfsdir;
+struct nfsdirent;
 class NfsCallback;
 
 /**
@@ -66,6 +68,8 @@ class NfsConnection : SocketMonitor, DeferredMonitor {
 
 		bool Stat(nfs_context *context, const char *path,
 			  Error &error);
+		bool OpenDirectory(nfs_context *context, const char *path,
+				   Error &error);
 		bool Open(nfs_context *context, const char *path, int flags,
 			  Error &error);
 		bool Stat(nfs_context *context, struct nfsfh *fh,
@@ -158,6 +162,12 @@ public:
 	void RemoveLease(NfsLease &lease);
 
 	bool Stat(const char *path, NfsCallback &callback, Error &error);
+
+	bool OpenDirectory(const char *path, NfsCallback &callback,
+			   Error &error);
+	const struct nfsdirent *ReadDirectory(struct nfsdir *dir);
+	void CloseDirectory(struct nfsdir *dir);
+
 	bool Open(const char *path, int flags, NfsCallback &callback,
 		  Error &error);
 	bool Stat(struct nfsfh *fh, NfsCallback &callback, Error &error);