diff --git a/src/fs/FileSystem.cxx b/src/fs/FileSystem.cxx
index 59571e138..b2d4c69da 100644
--- a/src/fs/FileSystem.cxx
+++ b/src/fs/FileSystem.cxx
@@ -21,8 +21,10 @@
 #include "FileSystem.hxx"
 #include "AllocatedPath.hxx"
 #include "Limits.hxx"
+#include "system/Error.hxx"
 
 #include <errno.h>
+#include <fcntl.h>
 
 AllocatedPath
 ReadLink(Path path)
@@ -44,3 +46,23 @@ ReadLink(Path path)
 	return AllocatedPath::FromFS(buffer);
 #endif
 }
+
+void
+TruncateFile(Path path)
+{
+#ifdef WIN32
+	HANDLE h = CreateFile(path.c_str(), GENERIC_WRITE, 0, nullptr,
+			      TRUNCATE_EXISTING, FILE_ATTRIBUTE_NORMAL,
+			      nullptr);
+	if (h == INVALID_HANDLE_VALUE)
+		throw FormatLastError("Failed to truncate %s", path.c_str());
+
+	CloseHandle(h);
+#else
+	int fd = open_cloexec(path.c_str(), O_WRONLY|O_TRUNC, 0);
+	if (fd < 0)
+		throw FormatErrno("Failed to truncate %s", path.c_str());
+
+	close(fd);
+#endif
+}
diff --git a/src/fs/FileSystem.hxx b/src/fs/FileSystem.hxx
index d76c159fb..b6c4d59e3 100644
--- a/src/fs/FileSystem.hxx
+++ b/src/fs/FileSystem.hxx
@@ -104,6 +104,13 @@ StatFile(Path file, struct stat &buf, bool follow_symlinks = true)
 
 #endif
 
+/**
+ * Truncate a file that exists already.  Throws std::system_error on
+ * error.
+ */
+void
+TruncateFile(Path path);
+
 /**
  * Wrapper for unlink() that uses #Path names.
  */