Skip to content

Commit 1d1b425

Browse files
committed
libutil: Implement createAnonymousTempFile
There are a lot of cases where we don't care about having the temporary file linked anywhere at all -- just a descriptor is more than enough.
1 parent 3a32039 commit 1d1b425

File tree

3 files changed

+44
-0
lines changed

3 files changed

+44
-0
lines changed

src/libutil-tests/file-system.cc

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,4 +381,21 @@ TEST(openFileEnsureBeneathNoSymlinks, works)
381381

382382
#endif
383383

384+
/* ----------------------------------------------------------------------------
385+
* createAnonymousTempFile
386+
* --------------------------------------------------------------------------*/
387+
388+
TEST(createAnonymousTempFile, works)
389+
{
390+
auto fd = createAnonymousTempFile();
391+
writeFull(fd.get(), "test");
392+
lseek(fd.get(), 0, SEEK_SET);
393+
FdSource source{fd.get()};
394+
EXPECT_EQ(source.drain(), "test");
395+
lseek(fd.get(), 0, SEEK_END);
396+
writeFull(fd.get(), "test");
397+
lseek(fd.get(), 0, SEEK_SET);
398+
EXPECT_EQ(source.drain(), "testtest");
399+
}
400+
384401
} // namespace nix

src/libutil/file-system.cc

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -713,11 +713,32 @@ std::filesystem::path createTempDir(const std::filesystem::path & tmpRoot, const
713713
}
714714
}
715715

716+
AutoCloseFD createAnonymousTempFile()
717+
{
718+
AutoCloseFD fd;
719+
#ifdef O_TMPFILE
720+
fd = ::open(defaultTempDir().c_str(), O_TMPFILE | O_CLOEXEC | O_RDWR, S_IWUSR | S_IRUSR);
721+
if (!fd)
722+
throw SysError("creating anonymous temporary file");
723+
#else
724+
auto [fd2, path] = createTempFile("nix-anonymous");
725+
if (!fd2)
726+
throw SysError("creating temporary file '%s'", path);
727+
fd = std::move(fd2);
728+
# ifndef _WIN32
729+
unix::closeOnExec(fd.get());
730+
unlink(requireCString(path)); /* We only care about the file descriptor. */
731+
# endif
732+
#endif
733+
return fd;
734+
}
735+
716736
std::pair<AutoCloseFD, Path> createTempFile(const Path & prefix)
717737
{
718738
Path tmpl(defaultTempDir() + "/" + prefix + ".XXXXXX");
719739
// Strictly speaking, this is UB, but who cares...
720740
// FIXME: use O_TMPFILE.
741+
// FIXME: Windows should use FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE
721742
AutoCloseFD fd = toDescriptor(mkstemp((char *) tmpl.c_str()));
722743
if (!fd)
723744
throw SysError("creating temporary file '%s'", tmpl);

src/libutil/include/nix/util/file-system.hh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,12 @@ typedef std::unique_ptr<DIR, DIRDeleter> AutoCloseDir;
337337
std::filesystem::path
338338
createTempDir(const std::filesystem::path & tmpRoot = "", const std::string & prefix = "nix", mode_t mode = 0755);
339339

340+
/**
341+
* Create an anonymous readable/writable temporary file, returning a file handle.
342+
* On UNIX there resulting file isn't linked to any path on the filesystem.
343+
*/
344+
AutoCloseFD createAnonymousTempFile();
345+
340346
/**
341347
* Create a temporary file, returning a file handle and its path.
342348
*/

0 commit comments

Comments
 (0)