From: Lennart Poettering Date: Thu, 8 Dec 2022 11:45:26 +0000 (+0100) Subject: data-fd-util: add new memfd_clone_fd() helper X-Git-Tag: v253-rc1~332^2~4 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6bea3d8e0f076b27323daba89f46993cd1925f0d;p=thirdparty%2Fsystemd.git data-fd-util: add new memfd_clone_fd() helper This adds a new helper for cloning any file's contents (or block device contents) into a new memfd. --- diff --git a/src/shared/data-fd-util.c b/src/shared/data-fd-util.c index b6eb3d9f418..58ee1845afd 100644 --- a/src/shared/data-fd-util.c +++ b/src/shared/data-fd-util.c @@ -4,6 +4,9 @@ #include #include #include +#if HAVE_LINUX_MEMFD_H +#include +#endif #include "alloc-util.h" #include "copy.h" @@ -12,6 +15,8 @@ #include "fs-util.h" #include "io-util.h" #include "memfd-util.h" +#include "missing_mman.h" +#include "missing_syscall.h" #include "tmpfile-util.h" /* When the data is smaller or equal to 64K, try to place the copy in a memfd/pipe */ @@ -343,3 +348,50 @@ finish: return fd_reopen(tmp_fd, O_RDONLY|O_CLOEXEC); } + +int memfd_clone_fd(int fd, const char *name, int mode) { + _cleanup_close_ int mfd = -EBADF; + bool ro; + int r; + + /* Creates a clone of a regular file in a memfd. Unlike copy_data_fd() this returns strictly a memfd + * (and if it can't it will fail). Thus the resulting fd is seekable, and definitely reports as + * S_ISREG. */ + + assert(fd >= 0); + assert(name); + assert(IN_SET(mode & O_ACCMODE, O_RDONLY, O_RDWR)); + assert((mode & ~(O_RDONLY|O_RDWR|O_CLOEXEC)) == 0); + + ro = (mode & O_ACCMODE) == O_RDONLY; + + mfd = memfd_create(name, + ((FLAGS_SET(mode, O_CLOEXEC) || ro) ? MFD_CLOEXEC : 0) | + (ro ? MFD_ALLOW_SEALING : 0)); + if (mfd < 0) + return -errno; + + r = copy_bytes(fd, mfd, UINT64_MAX, COPY_REFLINK); + if (r < 0) + return r; + + if (ro) { + _cleanup_close_ int rfd = -1; + + r = memfd_set_sealed(mfd); + if (r < 0) + return r; + + rfd = fd_reopen(mfd, mode); + if (rfd < 0) + return rfd; + + return TAKE_FD(rfd); + } + + off_t f = lseek(mfd, 0, SEEK_SET); + if (f < 0) + return -errno; + + return TAKE_FD(mfd); +} diff --git a/src/shared/data-fd-util.h b/src/shared/data-fd-util.h index 827e149662d..f0e7923556f 100644 --- a/src/shared/data-fd-util.h +++ b/src/shared/data-fd-util.h @@ -5,3 +5,4 @@ int acquire_data_fd(const void *data, size_t size, unsigned flags); int copy_data_fd(int fd); +int memfd_clone_fd(int fd, const char *name, int mode);