diff --git a/configure.ac b/configure.ac index aeb9efd..3fe440c 100644 --- a/configure.ac +++ b/configure.ac @@ -58,7 +58,7 @@ AC_SEARCH_LIBS([dlopen], [dl], [], [AC_MSG_ERROR([unable to find dlopen()])]) AC_FUNC_ERROR_AT_LINE AC_FUNC_MALLOC -AC_CHECK_FUNCS([open_by_handle_at error memset strdup copy_file_range]) +AC_CHECK_FUNCS([open_by_handle_at error memset strdup copy_file_range statx]) AC_CONFIG_FILES([Makefile lib/Makefile]) AC_OUTPUT diff --git a/direct.c b/direct.c index bc91ea3..84f40ef 100644 --- a/direct.c +++ b/direct.c @@ -75,15 +75,45 @@ direct_getxattr (struct ovl_layer *l, const char *path, const char *name, char * } static int -direct_fstat (struct ovl_layer *l, int fd, const char *path, struct stat *st) +direct_fstat (struct ovl_layer *l, int fd, const char *path, unsigned int mask, struct stat *st) { +#ifdef HAVE_STATX + int ret; + struct statx stx; + + ret = statx (fd, "", AT_STATX_DONT_SYNC|AT_EMPTY_PATH, mask, &stx); + + if (ret < 0 && errno == ENOSYS) + goto fallback; + if (ret == 0) + statx_to_stat (&stx, st); + + return ret; +#endif + + fallback: return fstat (fd, st); + } static int -direct_statat (struct ovl_layer *l, const char *path, struct stat *st, int flags) +direct_statat (struct ovl_layer *l, const char *path, struct stat *st, int flags, unsigned int mask) { - return TEMP_FAILURE_RETRY (fstatat (l->fd, path, st, flags)); +#ifdef HAVE_STATX + int ret; + struct statx stx; + + ret = statx (l->fd, path, AT_STATX_DONT_SYNC|flags, mask, &stx); + + if (ret < 0 && errno == ENOSYS) + goto fallback; + if (ret == 0) + statx_to_stat (&stx, st); + + return ret; +#endif + fallback: + return fstatat (l->fd, path, st, flags); } static struct dirent * diff --git a/fuse-overlayfs.h b/fuse-overlayfs.h index abc667a..7a3f884 100644 --- a/fuse-overlayfs.h +++ b/fuse-overlayfs.h @@ -17,6 +17,7 @@ */ #ifndef FUSE_OVERLAYFS_H # define FUSE_OVERLAYFS_H +# define _GNU_SOURCE # include # include @@ -121,8 +122,8 @@ struct data_source int (*load_data_source)(struct ovl_layer *l, const char *opaque, const char *path); int (*cleanup)(struct ovl_layer *l); int (*file_exists)(struct ovl_layer *l, const char *pathname); - int (*statat)(struct ovl_layer *l, const char *path, struct stat *st, int flags); - int (*fstat)(struct ovl_layer *l, int fd, const char *path, struct stat *st); + int (*statat)(struct ovl_layer *l, const char *path, struct stat *st, int flags, unsigned int mask); + int (*fstat)(struct ovl_layer *l, int fd, const char *path, unsigned int mask, struct stat *st); void *(*opendir)(struct ovl_layer *l, const char *path); struct dirent *(*readdir)(void *dirp); int (*closedir)(void *dirp); @@ -135,4 +136,21 @@ struct data_source /* passtrough to the file system. */ struct data_source direct_access_ds; +# ifndef HAVE_STATX +# define STATX_TYPE 0x00000001U /* Want/got stx_mode & S_IFMT */ +# define STATX_MODE 0x00000002U /* Want/got stx_mode & ~S_IFMT */ +# define STATX_NLINK 0x00000004U /* Want/got stx_nlink */ +# define STATX_UID 0x00000008U /* Want/got stx_uid */ +# define STATX_GID 0x00000010U /* Want/got stx_gid */ +# define STATX_ATIME 0x00000020U /* Want/got stx_atime */ +# define STATX_MTIME 0x00000040U /* Want/got stx_mtime */ +# define STATX_CTIME 0x00000080U /* Want/got stx_ctime */ +# define STATX_INO 0x00000100U /* Want/got stx_ino */ +# define STATX_SIZE 0x00000200U /* Want/got stx_size */ +# define STATX_BLOCKS 0x00000400U /* Want/got stx_blocks */ +# define STATX_BASIC_STATS 0x000007ffU /* The stuff in the normal stat struct */ +# define STATX_BTIME 0x00000800U /* Want/got stx_btime */ +# define STATX_ALL 0x00000fffU /* All currently supported flags */ +# endif + #endif diff --git a/main.c b/main.c index 55fc2ec..2cddc4b 100644 --- a/main.c +++ b/main.c @@ -598,7 +598,7 @@ delete_whiteout (struct ovl_data *lo, int dirfd, struct ovl_node *parent, const strconcat3 (whiteout_path, PATH_MAX, parent->path, "/", name); - if (get_upper_layer (lo)->ds->statat (get_upper_layer (lo), whiteout_path, &st, AT_SYMLINK_NOFOLLOW) == 0 + if (get_upper_layer (lo)->ds->statat (get_upper_layer (lo), whiteout_path, &st, AT_SYMLINK_NOFOLLOW, STATX_MODE|STATX_TYPE) == 0 && (st.st_mode & S_IFMT) == S_IFCHR && major (st.st_rdev) == 0 && minor (st.st_rdev) == 0) @@ -676,13 +676,13 @@ rpl_stat (fuse_req_t req, struct ovl_node *node, int fd, const char *path, struc if (st_in) memcpy (st, st_in, sizeof (* st)); else if (fd >= 0) - ret = l->ds->fstat (l, fd, path, st); + ret = l->ds->fstat (l, fd, path, STATX_BASIC_STATS, st); else if (path != NULL) ret = stat (path, st); else if (node->hidden) ret = fstatat (node_dirfd (node), node->path, st, AT_SYMLINK_NOFOLLOW); else - ret = l->ds->statat (l, node->path, st, AT_SYMLINK_NOFOLLOW); + ret = l->ds->statat (l, node->path, st, AT_SYMLINK_NOFOLLOW, STATX_BASIC_STATS); if (ret < 0) return ret; @@ -1204,7 +1204,7 @@ make_ovl_node (struct ovl_data *lo, const char *path, struct ovl_layer *layer, c if (fd < 0) { - if (errno != EPERM && it->ds->statat (it, npath, &st, AT_SYMLINK_NOFOLLOW) == 0) + if (errno != EPERM && it->ds->statat (it, npath, &st, AT_SYMLINK_NOFOLLOW, STATX_TYPE|STATX_MODE|STATX_INO) == 0) { ret->tmp_ino = st.st_ino; ret->tmp_dev = st.st_dev; @@ -1215,7 +1215,7 @@ make_ovl_node (struct ovl_data *lo, const char *path, struct ovl_layer *layer, c } /* It is an open FD, stat the file and read the origin xattrs. */ - if (it->ds->fstat (it, fd, npath, &st) == 0) + if (it->ds->fstat (it, fd, npath, STATX_TYPE|STATX_MODE|STATX_INO, &st) == 0) { ret->tmp_ino = st.st_ino; ret->tmp_dev = st.st_dev; @@ -1250,7 +1250,7 @@ make_ovl_node (struct ovl_data *lo, const char *path, struct ovl_layer *layer, c originfd = open_by_handle_at (AT_FDCWD, fh, O_RDONLY); if (originfd >= 0) { - if (it->ds->fstat (it, originfd, npath, &st) == 0) + if (it->ds->fstat (it, originfd, npath, STATX_TYPE|STATX_MODE|STATX_INO, &st) == 0) { ret->tmp_ino = st.st_ino; ret->tmp_dev = st.st_dev; @@ -1444,7 +1444,7 @@ load_dir (struct ovl_data *lo, struct ovl_node *n, struct ovl_layer *layer, char a whiteout file. */ struct stat st; - ret = it->ds->statat (it, node_path, &st, AT_SYMLINK_NOFOLLOW); + ret = it->ds->statat (it, node_path, &st, AT_SYMLINK_NOFOLLOW, STATX_TYPE); if (ret < 0) { it->ds->closedir (dp); @@ -1678,7 +1678,7 @@ do_lookup_file (struct ovl_data *lo, fuse_ino_t parent, const char *name) strconcat3 (path, PATH_MAX, pnode->path, "/", name); - ret = it->ds->statat (it, path, &st, AT_SYMLINK_NOFOLLOW); + ret = it->ds->statat (it, path, &st, AT_SYMLINK_NOFOLLOW, STATX_TYPE|STATX_MODE|STATX_INO); if (ret < 0) { int saved_errno = errno; @@ -2493,7 +2493,7 @@ copyup (struct ovl_data *lo, struct ovl_node *node) sprintf (wd_tmp_file_name, "%lu", get_next_wd_counter ()); - ret = node->layer->ds->statat (node->layer, node->path, &st, AT_SYMLINK_NOFOLLOW); + ret = node->layer->ds->statat (node->layer, node->path, &st, AT_SYMLINK_NOFOLLOW, STATX_BASIC_STATS); if (ret < 0) return ret; @@ -3197,7 +3197,7 @@ ovl_do_open (fuse_req_t req, fuse_ino_t parent, const char *name, int flags, mod if (st == NULL) st = &st_tmp; - if (get_upper_layer (lo)->ds->fstat (get_upper_layer (lo), fd, path, st) < 0) + if (get_upper_layer (lo)->ds->fstat (get_upper_layer (lo), fd, path, STATX_BASIC_STATS, st) < 0) return -1; n = make_ovl_node (lo, path, get_upper_layer (lo), name, st->st_ino, st->st_dev, false, p, lo->fast_ino_check); diff --git a/plugin.h b/plugin.h index 4ae3562..ffe3218 100644 --- a/plugin.h +++ b/plugin.h @@ -20,8 +20,8 @@ # define PLUGIN_H # include -# include # include +# include typedef struct data_source *(*plugin_load_data_source)(struct ovl_layer *layer, const char *opaque, const char *path); typedef int (*plugin_release)(struct ovl_layer *layer); diff --git a/utils.c b/utils.c index 26853e3..3e18a70 100644 --- a/utils.c +++ b/utils.c @@ -17,18 +17,45 @@ */ #include +#include "utils.h" #include #include #include -#include "utils.h" +#include int file_exists_at (int dirfd, const char *pathname) { return faccessat (dirfd, pathname, F_OK, AT_SYMLINK_NOFOLLOW|AT_EACCESS); - } +#ifdef HAVE_STATX +void +copy_statx_to_stat_time (struct statx_timestamp *stx, struct timespec *st) +{ + st->tv_sec = stx->tv_sec; + st->tv_nsec = stx->tv_nsec; +} + +void +statx_to_stat (struct statx *stx, struct stat *st) +{ + st->st_dev = makedev (stx->stx_dev_major, stx->stx_dev_minor); + st->st_ino = stx->stx_ino; + st->st_mode = stx->stx_mode; + st->st_nlink = stx->stx_nlink; + st->st_uid = stx->stx_uid; + st->st_gid = stx->stx_gid; + st->st_rdev = makedev (stx->stx_rdev_major, stx->stx_rdev_minor); + st->st_size = stx->stx_size; + st->st_blksize = stx->stx_blksize; + st->st_blocks = stx->stx_blocks; + copy_statx_to_stat_time (&stx->stx_atime, &st->st_atim); + copy_statx_to_stat_time (&stx->stx_ctime, &st->st_ctim); + copy_statx_to_stat_time (&stx->stx_mtime, &st->st_mtim); +} +#endif + int strconcat3 (char *dest, size_t size, const char *s1, const char *s2, const char *s3) { diff --git a/utils.h b/utils.h index a00daa3..3cdae2e 100644 --- a/utils.h +++ b/utils.h @@ -18,11 +18,17 @@ #ifndef UTILS_H # define UTILS_H +# define _GNU_SOURCE + +# include + # include # include # include # include # include +# include +# include # include "fuse-overlayfs.h" void cleanup_freep (void *p); @@ -43,4 +49,8 @@ int open_fd_or_get_path (struct ovl_layer *l, const char *path, char *out, int * # define LIKELY(x) __builtin_expect((x),1) # define UNLIKELY(x) __builtin_expect((x),0) +# ifdef HAVE_STATX +void statx_to_stat (struct statx *stx, struct stat *st); +# endif + #endif