aboutsummaryrefslogtreecommitdiffstats
path: root/example/passthrough_ll.c
diff options
context:
space:
mode:
authorMiklos Szeredi <szmi@users.noreply.github.com>2020-05-14 21:17:50 +0200
committerGitHub <noreply@github.com>2020-05-14 20:17:50 +0100
commitded868455aecc883ecc53b1fac7356dba761b240 (patch)
treeb158fd248750b5778c979f2cad932500f9dbb041 /example/passthrough_ll.c
parentfc25c5002cae23151309fce6059e230545fd4d82 (diff)
downloadlibfuse-ded868455aecc883ecc53b1fac7356dba761b240.tar.gz
passthrough_ll: remove symlink fallbacks (#514)
* passthrough_ll/hp: remove symlink fallbacks Path lookup in the kernel has special rules for looking up magic symlinks under /proc. If a filesystem operation is instructed to follow symlinks (e.g. via AT_SYMLINK_FOLLOW or lack of AT_SYMLINK_NOFOLLOW), and the final component is such a proc symlink, then the target of the magic symlink is used for the operation, even if the target itself is a symlink. I.e. path lookup is always terminated after following a final magic symlink. I was erronously assuming that in the above case the target symlink would also be followed, and so workarounds were added for a couple of operations to handle the symlink case. Since the symlink can be handled simply by following the proc symlink, these workardouds are not needed. Signed-off-by: Miklos Szeredi <mszeredi@redhat.com> Co-authored-by: Miklos Szeredi <mszeredi@redhat.com>
Diffstat (limited to 'example/passthrough_ll.c')
-rw-r--r--example/passthrough_ll.c78
1 files changed, 8 insertions, 70 deletions
diff --git a/example/passthrough_ll.c b/example/passthrough_ll.c
index 5667223..06bb50f 100644
--- a/example/passthrough_ll.c
+++ b/example/passthrough_ll.c
@@ -74,7 +74,6 @@ struct lo_inode {
struct lo_inode *next; /* protected by lo->mutex */
struct lo_inode *prev; /* protected by lo->mutex */
int fd;
- bool is_symlink;
ino_t ino;
dev_t dev;
uint64_t refcount; /* protected by lo->mutex */
@@ -188,26 +187,6 @@ static void lo_getattr(fuse_req_t req, fuse_ino_t ino,
fuse_reply_attr(req, &buf, lo->timeout);
}
-static int utimensat_empty_nofollow(struct lo_inode *inode,
- const struct timespec *tv)
-{
- int res;
- char procname[64];
-
- if (inode->is_symlink) {
- res = utimensat(inode->fd, "", tv,
- AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
- if (res == -1 && errno == EINVAL) {
- /* Sorry, no race free way to set times on symlink. */
- errno = EPERM;
- }
- return res;
- }
- sprintf(procname, "/proc/self/fd/%i", inode->fd);
-
- return utimensat(AT_FDCWD, procname, tv, 0);
-}
-
static void lo_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
int valid, struct fuse_file_info *fi)
{
@@ -268,8 +247,10 @@ static void lo_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
if (fi)
res = futimens(fi->fh, tv);
- else
- res = utimensat_empty_nofollow(inode, tv);
+ else {
+ sprintf(procname, "/proc/self/fd/%i", ifd);
+ res = utimensat(AT_FDCWD, procname, tv, 0);
+ }
if (res == -1)
goto out_err;
}
@@ -332,7 +313,6 @@ static int lo_do_lookup(fuse_req_t req, fuse_ino_t parent, const char *name,
if (!inode)
goto out_err;
- inode->is_symlink = S_ISLNK(e->attr.st_mode);
inode->refcount = 1;
inode->fd = newfd;
inode->ino = e->attr.st_ino;
@@ -426,26 +406,6 @@ static void lo_symlink(fuse_req_t req, const char *link,
lo_mknod_symlink(req, parent, name, S_IFLNK, 0, link);
}
-static int linkat_empty_nofollow(struct lo_inode *inode, int dfd,
- const char *name)
-{
- int res;
- char procname[64];
-
- if (inode->is_symlink) {
- res = linkat(inode->fd, "", dfd, name, AT_EMPTY_PATH);
- if (res == -1 && (errno == ENOENT || errno == EINVAL)) {
- /* Sorry, no race free way to hard-link a symlink. */
- errno = EPERM;
- }
- return res;
- }
-
- sprintf(procname, "/proc/self/fd/%i", inode->fd);
-
- return linkat(AT_FDCWD, procname, dfd, name, AT_SYMLINK_FOLLOW);
-}
-
static void lo_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t parent,
const char *name)
{
@@ -453,13 +413,16 @@ static void lo_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t parent,
struct lo_data *lo = lo_data(req);
struct lo_inode *inode = lo_inode(req, ino);
struct fuse_entry_param e;
+ char procname[64];
int saverr;
memset(&e, 0, sizeof(struct fuse_entry_param));
e.attr_timeout = lo->timeout;
e.entry_timeout = lo->timeout;
- res = linkat_empty_nofollow(inode, lo_fd(req, parent), name);
+ sprintf(procname, "/proc/self/fd/%i", inode->fd);
+ res = linkat(AT_FDCWD, procname, lo_fd(req, parent), name,
+ AT_SYMLINK_FOLLOW);
if (res == -1)
goto out_err;
@@ -976,12 +939,6 @@ static void lo_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
ino, name, size);
}
- if (inode->is_symlink) {
- /* Sorry, no race free way to getxattr on symlink. */
- saverr = EPERM;
- goto out;
- }
-
sprintf(procname, "/proc/self/fd/%i", inode->fd);
if (size) {
@@ -1032,12 +989,6 @@ static void lo_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size)
ino, size);
}
- if (inode->is_symlink) {
- /* Sorry, no race free way to listxattr on symlink. */
- saverr = EPERM;
- goto out;
- }
-
sprintf(procname, "/proc/self/fd/%i", inode->fd);
if (size) {
@@ -1088,12 +1039,6 @@ static void lo_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
ino, name, value, size);
}
- if (inode->is_symlink) {
- /* Sorry, no race free way to setxattr on symlink. */
- saverr = EPERM;
- goto out;
- }
-
sprintf(procname, "/proc/self/fd/%i", inode->fd);
ret = setxattr(procname, name, value, size, flags);
@@ -1119,12 +1064,6 @@ static void lo_removexattr(fuse_req_t req, fuse_ino_t ino, const char *name)
ino, name);
}
- if (inode->is_symlink) {
- /* Sorry, no race free way to setxattr on symlink. */
- saverr = EPERM;
- goto out;
- }
-
sprintf(procname, "/proc/self/fd/%i", inode->fd);
ret = removexattr(procname, name);
@@ -1274,7 +1213,6 @@ int main(int argc, char *argv[])
} else {
lo.source = "/";
}
- lo.root.is_symlink = false;
if (!lo.timeout_set) {
switch (lo.cache) {
case CACHE_NEVER: