From b89b8ebf5d37a943bb76441ae37b13c7038014ad Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Wed, 4 Jul 2018 16:01:20 +0200 Subject: [PATCH] containerfs: use an xattr to store redirects of a file So we can correctly report the same issue for hard links. Closes: https://github.com/giuseppe/containerfs/issues/1 Signed-off-by: Giuseppe Scrivano --- README.md | 4 +-- main.c | 96 ++++++++++++++++++++++++++++++++++++++----------------- 2 files changed, 68 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 1628797..457b4cb 100644 --- a/README.md +++ b/README.md @@ -3,11 +3,9 @@ containerfs An implementation of overlay+shiftfs in FUSE for rootless containers. -Known issues: +Limitations: ======================================================= -Hard links in some cases show different inode values. - Read-only mode is not supported, so it is always required to specify an upperdir and a workingdir. diff --git a/main.c b/main.c index 47aa356..7a8d30d 100644 --- a/main.c +++ b/main.c @@ -58,6 +58,8 @@ #define ATTR_TIMEOUT 1000000000.0 #define ENTRY_TIMEOUT 1000000000.0 +#define REDIRECT_XATTR "user.containerfs.redirect" + #define NODE_TO_INODE(x) ((fuse_ino_t) x) #if defined(__GNUC__) && (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 6) && !defined __cplusplus @@ -552,11 +554,25 @@ make_lo_node (const char *path, struct lo_layer *layer, const char *name, ino_t { struct stat st; struct lo_layer *it; + char path[PATH_MAX]; + strcpy (path, ret->path); for (it = layer; it; it = it->next) { - if (fstatat (it->fd, ret->path, &st, AT_SYMLINK_NOFOLLOW) == 0) + ssize_t s; + int fd = openat (it->fd, path, O_RDONLY); + if (fd < 0) + continue; + + if (fstat (fd, &st) == 0) ret->ino = st.st_ino; + + /* If a redirect is specified, use it for the next layer lookup. */ + s = fgetxattr (fd, REDIRECT_XATTR, path, sizeof (path) - 1); + if (s > 0) + path[s] = '\0'; + + close (fd); } } @@ -660,14 +676,7 @@ load_dir (struct lo_data *lo, struct lo_node *n, struct lo_layer *layer, char *p child = hash_lookup (n->children, &key); if (child) - { - /* Update the ino with the lowest one found. Ignore if the file - was deleted by intermediate layers, we only need to keep the same - inode after a copyup. */ - child->ino = st.st_ino; - child->present_lowerdir = 1; - continue; - } + continue; wh = get_whiteout_name (dent->d_name, &st); if (wh) @@ -685,7 +694,7 @@ load_dir (struct lo_data *lo, struct lo_node *n, struct lo_layer *layer, char *p bool dirp = st.st_mode & S_IFDIR; sprintf (path, "%s/%s", n->path, dent->d_name); - child = make_lo_node (path, it, dent->d_name, st.st_ino, dirp); + child = make_lo_node (path, it, dent->d_name, 0, dirp); if (child == NULL) { @@ -818,22 +827,17 @@ do_lookup_file (struct lo_data *lo, fuse_ino_t parent, const char *name) return NULL; } - if (node) - node->ino = st.st_ino; - else + node = make_lo_node (path, it, name, 0, st.st_mode & S_IFDIR); + if (node == NULL) { - node = make_lo_node (path, it, name, st.st_ino, st.st_mode & S_IFDIR); - if (node == NULL) - { - errno = ENOMEM; - return NULL; - } - if (insert_node (pnode, node, false) == NULL) - { - node_free (node); - errno = ENOMEM; - return NULL; - } + errno = ENOMEM; + return NULL; + } + if (insert_node (pnode, node, false) == NULL) + { + node_free (node); + errno = ENOMEM; + return NULL; } } } @@ -1069,7 +1073,7 @@ lo_listxattr (fuse_req_t req, fuse_ino_t ino, size_t size) ssize_t len; struct lo_node *node; struct lo_data *lo = lo_data (req); - char buf[1024]; + char *buf = NULL; int fd; if (lo_debug (req)) @@ -1082,14 +1086,25 @@ lo_listxattr (fuse_req_t req, fuse_ino_t ino, size_t size) return; } + if (size > 0) + { + buf = malloc (size); + if (buf == NULL) + { + fuse_reply_err (req, ENOMEM); + return; + } + } + fd = openat (node_dirfd (node), node->path, O_RDONLY); if (fd < 0) { + free (buf); fuse_reply_err (req, errno); return; } - len = flistxattr (fd, buf, sizeof (buf)); + len = flistxattr (fd, buf, size); if (len < 0) fuse_reply_err (req, errno); else if (size == 0) @@ -1097,6 +1112,7 @@ lo_listxattr (fuse_req_t req, fuse_ino_t ino, size_t size) else if (len <= size) fuse_reply_buf (req, buf, len); + free (buf); close (fd); } @@ -1106,7 +1122,7 @@ lo_getxattr (fuse_req_t req, fuse_ino_t ino, const char *name, size_t size) ssize_t len; struct lo_node *node; struct lo_data *lo = lo_data (req); - char buf[1024]; + char *buf = NULL; int fd; if (lo_debug (req)) @@ -1119,14 +1135,25 @@ lo_getxattr (fuse_req_t req, fuse_ino_t ino, const char *name, size_t size) return; } + if (size > 0) + { + buf = malloc (size); + if (buf == NULL) + { + fuse_reply_err (req, ENOMEM); + return; + } + } + fd = openat (node_dirfd (node), node->path, O_RDONLY); if (fd < 0) { + free (buf); fuse_reply_err (req, errno); return; } - len = fgetxattr (fd, name, buf, sizeof (buf)); + len = fgetxattr (fd, name, buf, size); if (len < 0) fuse_reply_err (req, errno); else if (size == 0) @@ -1134,6 +1161,7 @@ lo_getxattr (fuse_req_t req, fuse_ino_t ino, const char *name, size_t size) else if (len <= size) fuse_reply_buf (req, buf, len); + free (buf); close (fd); } @@ -2003,6 +2031,16 @@ lo_link (fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent, const char *newna fuse_reply_err (req, errno); return; } + else + { + int dfd = openat (node_dirfd (newparentnode), path, O_WRONLY); + if (dfd >= 0) + { + fsetxattr (dfd, REDIRECT_XATTR, node->path, strlen (node->path), 0); + close (dfd); + } + + } node = make_lo_node (path, get_upper_layer (lo), newname, node->ino, false); if (node == NULL)