From a843a1a0b82c01a26d5b7020e6e82cf3fdc59de0 Mon Sep 17 00:00:00 2001 From: Andy Fiddaman Date: Thu, 14 Apr 2022 09:38:38 +0000 Subject: [PATCH] Tunlinkat should handle an open directory fid --- backend/fs.c | 26 ++++++++++++++++++++++++-- request.c | 6 +++--- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/backend/fs.c b/backend/fs.c index a88cd60..ac68acf 100644 --- a/backend/fs.c +++ b/backend/fs.c @@ -1751,8 +1751,19 @@ fs_remove(void *softc, struct l9p_fid *fid) return (error); if (unlinkat(file->ff_dirfd, file->ff_name, - S_ISDIR(cst.st_mode) ? AT_REMOVEDIR : 0) != 0) + S_ISDIR(cst.st_mode) ? AT_REMOVEDIR : 0) != 0) { error = errno; + /* + * POSIX allows unlinkat() with AT_REMOVEDIR on a non-empty + * directory to return either ENOTEMPTY or EEXIST. illumos + * and Solaris return EEXIST, apparently because System V did + * not have ENOTEMPTY. + * Since Tunlinkat is part of 9P2000.L, which uses Linux + * errnos, translate that here. + */ + if (error == EEXIST && S_ISDIR(cst.st_mode)) + error = ENOTEMPTY; + } return (error); } @@ -2931,8 +2942,19 @@ fs_unlinkat(void *softc, struct l9p_request *req) return (error); if (req->lr_req.tunlinkat.flags & L9PL_AT_REMOVEDIR) { - if (unlinkat(dirff->ff_dirfd, newname, AT_REMOVEDIR) != 0) + if (unlinkat(dirff->ff_dirfd, newname, AT_REMOVEDIR) != 0) { error = errno; + /* + * POSIX allows unlinkat() with AT_REMOVEDIR on a + * non-empty directory to return either ENOTEMPTY or + * EEXIST. illumos and Solaris return EEXIST, apparently + * because System V did not have ENOTEMPTY. Since + * Tunlinkat is part of 9P2000.L, which uses Linux + * errnos, translate that here. + */ + if (error == EEXIST) + error = ENOTEMPTY; + } } else { if (unlinkat(dirff->ff_dirfd, newname, 0) != 0) error = errno; diff --git a/request.c b/request.c index 357bd23..f477c9a 100644 --- a/request.c +++ b/request.c @@ -1404,12 +1404,12 @@ l9p_dispatch_trenameat(struct l9p_request *req) int error; error = fid_lookup(conn, req->lr_req.hdr.fid, ENOENT, - F_REQUIRE_DIR | F_FORBID_OPEN, &req->lr_fid); + F_REQUIRE_DIR, &req->lr_fid); if (error) return (error); error = fid_lookup(conn, req->lr_req.trenameat.newdirfid, ENOENT, - F_REQUIRE_DIR | F_FORBID_OPEN, &req->lr_fid2); + F_REQUIRE_DIR, &req->lr_fid2); if (error) return (error); @@ -1428,7 +1428,7 @@ l9p_dispatch_tunlinkat(struct l9p_request *req) int error; error = fid_lookup(conn, req->lr_req.hdr.fid, ENOENT, - F_REQUIRE_DIR | F_FORBID_OPEN, &req->lr_fid); + F_REQUIRE_DIR, &req->lr_fid); if (error) return (error);