logo

utils-std

Collection of commonly available Unix tools
commit: b31d16cba79ce9892c36db520c2e8a43df6c8830
parent 31812994d3503b922c6ca74cc7a1fc749736a650
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date:   Fri, 29 Mar 2024 04:50:18 +0100

cmd/rm: Avoid non-portable AT_SYMLINK_NOFOLLOW by skipping symlinks

Diffstat:

Mcmd/rm.c15++++++++++++---
Mtest-cmd/rm.t6+++---
2 files changed, 15 insertions(+), 6 deletions(-)

diff --git a/cmd/rm.c b/cmd/rm.c @@ -196,12 +196,21 @@ do_unlinkat(int fd, char *name, char *acc_path) if(!force) { - // FIXME: Terminal always considered to be present for tests reason - if(faccessat(fd, name, W_OK, AT_SYMLINK_NOFOLLOW) != 0 || opt_i) + if(opt_i) { - errno = 0; if(!consentf("rm: Remove '%s' ? [y/N] ", acc_path)) return 0; } + else + { + // Don't check symbolic links, would need AT_SYMLINK_NOFOLLOW on faccessat which isn't portable + // Can assume symbolic links are 0777 anyway + if(!S_ISLNK(stats.st_mode) && faccessat(fd, name, W_OK, 0) != 0) + { + errno = 0; + + if(!consentf("rm: Remove non-writable '%s' ? [y/N] ", acc_path)) return 0; + } + } } assert(errno == 0); diff --git a/test-cmd/rm.t b/test-cmd/rm.t @@ -82,14 +82,14 @@ Extra check from rm(1), unrelated to the EPERM that unlink gets on a non-writabl $ touch no_write $ chmod -- -w no_write $ echo | rm no_write - rm: Remove 'no_write' ? [y/N] + rm: Remove non-writable 'no_write' ? [y/N] rm: Got empty response, considering it false $ test -f no_write $ echo n | rm no_write - rm: Remove 'no_write' ? [y/N] n + rm: Remove non-writable 'no_write' ? [y/N] n $ test -f no_write $ echo y | rm no_write - rm: Remove 'no_write' ? [y/N] y + rm: Remove non-writable 'no_write' ? [y/N] y $ test ! -f no_write