diff --git a/src/basic/missing_fcntl.h b/src/basic/missing_fcntl.h index 3c85befda9..1248eb7e4d 100644 --- a/src/basic/missing_fcntl.h +++ b/src/basic/missing_fcntl.h @@ -92,3 +92,7 @@ #define RAW_O_LARGEFILE 00100000 #endif #endif + +#ifndef AT_HANDLE_FID +#define AT_HANDLE_FID AT_REMOVEDIR +#endif diff --git a/src/basic/mountpoint-util.c b/src/basic/mountpoint-util.c index 4aecd109d3..71979d29ad 100644 --- a/src/basic/mountpoint-util.c +++ b/src/basic/mountpoint-util.c @@ -13,6 +13,7 @@ #include "fileio.h" #include "filesystems.h" #include "fs-util.h" +#include "missing_fcntl.h" #include "missing_fs.h" #include "missing_mount.h" #include "missing_stat.h" @@ -62,7 +63,8 @@ int name_to_handle_at_loop( size_t n = ORIGINAL_MAX_HANDLE_SZ; - assert((flags & ~(AT_SYMLINK_FOLLOW|AT_EMPTY_PATH)) == 0); + assert(fd >= 0 || fd == AT_FDCWD); + assert((flags & ~(AT_SYMLINK_FOLLOW|AT_EMPTY_PATH|AT_HANDLE_FID)) == 0); /* We need to invoke name_to_handle_at() in a loop, given that it might return EOVERFLOW when the specified * buffer is too small. Note that in contrast to what the docs might suggest, MAX_HANDLE_SZ is only good as a @@ -119,6 +121,30 @@ int name_to_handle_at_loop( } } +int name_to_handle_at_try_fid( + int fd, + const char *path, + struct file_handle **ret_handle, + int *ret_mnt_id, + int flags) { + + int r; + + assert(fd >= 0 || fd == AT_FDCWD); + + /* First issues name_to_handle_at() with AT_HANDLE_FID. If this fails and this is not a fatal error + * we'll try without the flag, in order to support older kernels that didn't have AT_HANDLE_FID + * (i.e. older than Linux 6.5). */ + + r = name_to_handle_at_loop(fd, path, ret_handle, ret_mnt_id, flags | AT_HANDLE_FID); + if (r >= 0) + return r; + if (is_name_to_handle_at_fatal_error(r)) + return r; + + return name_to_handle_at_loop(fd, path, ret_handle, ret_mnt_id, flags & ~AT_HANDLE_FID); +} + static int fd_fdinfo_mnt_id(int fd, const char *filename, int flags, int *ret_mnt_id) { char path[STRLEN("/proc/self/fdinfo/") + DECIMAL_STR_MAX(int)]; _cleanup_free_ char *fdinfo = NULL; diff --git a/src/basic/mountpoint-util.h b/src/basic/mountpoint-util.h index c9d730e25c..c01f290952 100644 --- a/src/basic/mountpoint-util.h +++ b/src/basic/mountpoint-util.h @@ -39,6 +39,7 @@ bool is_name_to_handle_at_fatal_error(int err); int name_to_handle_at_loop(int fd, const char *path, struct file_handle **ret_handle, int *ret_mnt_id, int flags); +int name_to_handle_at_try_fid(int fd, const char *path, struct file_handle **ret_handle, int *ret_mnt_id, int flags); bool file_handle_equal(const struct file_handle *a, const struct file_handle *b);