From 13838d1b260ecca71856c5bddcc6d8b7060c5f78 Mon Sep 17 00:00:00 2001 From: Peter Hyman Date: Mon, 31 Jul 2023 13:40:26 -0500 Subject: [PATCH] Scrub link and remove fix: Scrub and remove both link and target. This addresses and issue where the -r option removes the link, but not the target. Now, both will be removed. In addition, when -D newdir is used it renames the link but not the target. Now, it will rename the target. When -D and -r are used together, both link and target will be removed. --- src/scrub.c | 32 +++++++++++++++++++++++++++----- src/util.c | 15 +++++++++++++-- src/util.h | 2 +- 3 files changed, 41 insertions(+), 8 deletions(-) diff --git a/src/scrub.c b/src/scrub.c index 39059e6..90b2229 100644 --- a/src/scrub.c +++ b/src/scrub.c @@ -291,7 +291,9 @@ static int scrub_object(char *filename, const struct opt_struct *opt, { bool havesig = false; int errcount = 0; + char *absolute_path; /* store absolute path if symlink */ + absolute_path = is_symlink(filename); /* get absolute path. If NULL not a symlink */ switch (filetype(filename)) { case FILE_NOEXIST: fprintf(stderr, "%s: %s does not exist\n", prog, filename); @@ -320,7 +322,7 @@ static int scrub_object(char *filename, const struct opt_struct *opt, fprintf(stderr, "%s: %s already scrubbed? (-f to force)\n", prog, filename); errcount++; - } else if (is_symlink(filename) && opt->nofollow) { + } else if (absolute_path && opt->nofollow) { fprintf(stderr, "%s: skipping symlink %s because --no-link (-L) option was set\n", prog, filename); errcount++; @@ -334,7 +336,7 @@ static int scrub_object(char *filename, const struct opt_struct *opt, } break; case FILE_REGULAR: - if (is_symlink(filename) && opt->nofollow) { + if (absolute_path && opt->nofollow) { /* symlink, don't remove target */ if (opt->remove && !noexec) { if (dryrun) { printf("%s: (dryrun) unlink %s\n", prog, filename); @@ -381,16 +383,28 @@ static int scrub_object(char *filename, const struct opt_struct *opt, #endif if (opt->dirent) { if (dryrun) { - printf("%s: (dryrun) scrub dirent %s\n", - prog, filename); + if (absolute_path) { + printf("%s: (dryrun) scrub dirent target %s\n", + prog, absolute_path); + } else { + printf("%s: (dryrun) scrub dirent %s\n", + prog, filename); + } } else { - scrub_dirent(filename, opt); + if (absolute_path) { + scrub_dirent(absolute_path, opt); + } else { + scrub_dirent(filename, opt); + } } } if (opt->remove) { char *rmfile = opt->dirent ? opt->dirent : filename; if (dryrun) { printf("%s: (dryrun) unlink %s\n", prog, rmfile); + if (absolute_path) { /* link target */ + printf("%s: (dryrun) unlink target %s\n", prog, absolute_path); + } } else { printf("%s: unlinking %s\n", prog, rmfile); if (unlink(rmfile) != 0) { @@ -398,6 +412,14 @@ static int scrub_object(char *filename, const struct opt_struct *opt, strerror(errno)); exit(1); } + if (absolute_path) { /* link target */ + if (unlink(filename) != 0) { + printf("%s: unlinking target %s\n", prog, absolute_path); + fprintf(stderr, "%s: unlink %s: %s\n", prog, absolute_path, + strerror(errno)); + exit(1); + } + } } } } diff --git a/src/util.c b/src/util.c index 1dc349e..32291ae 100644 --- a/src/util.c +++ b/src/util.c @@ -58,12 +58,23 @@ write_all(int fd, const unsigned char *buf, int count) } /* Indicates whether the file represented by 'path' is a symlink. + * and if so, return a pointer to the realpath. */ -int +char * is_symlink(char *path) { struct stat sb; - return lstat(path, &sb) == 0 && S_ISLNK(sb.st_mode); + int error; + char *resolved_path; + + if ((error = lstat(path, &sb)) != 0) + return NULL; /* not a link */ + if ((resolved_path=realpath(path,NULL)) == NULL) + return NULL; /* some error in determining absolute path */ + if (!S_ISLNK(sb.st_mode)) /* if it's not a link */ + return NULL; + + return resolved_path; } /* Return the type of file represented by 'path'. diff --git a/src/util.h b/src/util.h index 9cd97e8..9480803 100644 --- a/src/util.h +++ b/src/util.h @@ -31,7 +31,7 @@ typedef enum { UP, DOWN } round_t; int read_all(int fd, unsigned char *buf, int count); int write_all(int fd, const unsigned char *buf, int count); -int is_symlink(char *path); +char * is_symlink(char *path); filetype_t filetype(char *path); off_t blkalign(off_t offset, int blocksize, round_t rtype); void * alloc_buffer(int bufsize);