acst

Tracks changes and corruption in files using xattr-based checksums.
git clone https://noxz.tech/git/acst.git
Log | Files | Tags | LICENSE

commit: 519394ae92f2bf6ac129eb8d2f90a0e087fb2dc6
parent: 6d55b4afe079a1c29ba66871f6fcbf742de7a17a
author: Chris Noxz <chris@noxz.tech>
date:   Thu, 9 Mar 2023 12:25:13 +0100
Remove unnecessary feature to process directories
MMakefile2+-
Macst.127++++--------
Macst.c46++------------------
Macst.h20++-------
Mtest35+--------------
5 files changed, 20 insertions(+), 110 deletions(-)
diff --git a/Makefile b/Makefile
@@ -8,7 +8,7 @@ OBJ = ${SRC:.c=.o}
 all: options acst
 
 options:
-	@echo st build options:
+	@echo build options:
 	@echo "CFLAGS  = ${CFLAGS}"
 	@echo "CC      = ${CC}"
 
diff --git a/acst.1 b/acst.1
@@ -4,7 +4,7 @@ acst \- Actual C-implementation of a Simple shaTag
 .
 .SH SYNOPSIS
 .B acst
-.RB [ \-dhmnqrvx ]
+.RB [ \-dhmnqvx ]
 .IR "" < FILE ...>
 .
 .SH DESCRIPTION
@@ -85,9 +85,6 @@ and
 .BR malformed
 files and errors are being reported.
 .TP
-.BR -r
-Process directories and their contents recursively, not just files.
-.TP
 .BR -x
 Remove acts's extended attributes (xattrs) from
 .IR FILE .
@@ -159,33 +156,27 @@ Duplicate of checksum among files checked.
 .
 .SH EXAMPLES
 .TP
-.BR "find /strg/shr/media -xdev -type f | acst - > /root/acst.log"
+.BR "find /mnt/memorystick -xdev -type f | acst - > /root/acst.log"
 will use
 .B find
 to recursively traverse through files in
 /mnt/memorystick within the same file system and log the result to
-/root/acst.log. Using
-.B acst
-this way is many times faster than using the recursive argument and can also
-replace all examples below using the recursive argument. It should be treated
-as the preferred method of using
-.BR acst .
+/root/acst.log.
 .TP
-.BR "acst -r /home/user01 /mnt/memorystick > /root/acst.log"
+.BR "find /home/user01 /strg/shr/media -type f | acst - > /root/acst.log"
 will recursively process files in both /home/user01 and /mnt/memorystick even
-if they belong to different file systems, as they are both specified using the
-.IR FILE
-argument, and then log the result to /root/acst.log.
+if they belong to different file systems, and then log the result to
+/root/acst.log.
 .TP
-.BR "acst -rm /home/user01 /mnt/memorystick > /root/acst.log"
+.BR "find /home/user01 /strg/shr/media -type f | acst -m - > /root/acst.log"
 will perform the same operation as above with the addition of also summarizing
 the result of the execution to the log.
 .TP
-.BR "acst -rx /mnt/memorystick > /root/acst.log"
+.BR "find /mnt/memorystick -xdev -type f | acst -x - > /root/acst.log"
 will recursively process and remove extended attributes from files in
 /mnt/memorystick and log the result to /root/acst.log.
 .TP
-.BR "acst -rd /mnt/memorystick"
+.BR "find /mnt/memorystick -xdev -type f | acst -d -
 will recursively check for duplicates among files in /mnt/memorystick based on
 checksums stored as extended attributes.
 .
diff --git a/acst.c b/acst.c
@@ -16,9 +16,9 @@
  * this program. If not, see <https://www.gnu.org/licenses/>.
  */
 
-#include <dirent.h>            // for dirent, closedir, opendir, readdir, DIR
 #include <errno.h>             // for errno, ENODATA
 #include <fcntl.h>             // for open, O_NOFOLLOW, O_RDONLY
+#include <limits.h>            // for PATH_MAX
 #include <stdarg.h>            // for va_end, va_list, va_start
 #include <stdbool.h>           // for true, false, bool
 #include <stdio.h>             // for fprintf, stdout, snprintf, sprintf
@@ -27,7 +27,7 @@
 #include <time.h>              // for timespec
 #include <unistd.h>            // for close, read
 #include <bits/getopt_core.h>  // for getopt, optind
-#include <sys/stat.h>          // for stat, fstat, lstat, S_ISDIR, S_ISREG
+#include <sys/stat.h>          // for stat, fstat, lstat, S_ISREG
 #include <sys/xattr.h>         // for fgetxattr, fremovexattr, fsetxattr
 
 #include "sha256.h"            // for SHA256_final, SHA256_init, SHA256_update
@@ -260,49 +260,12 @@ process_argument(const char *fn)
 		error(ER_OPENING, STR_ERR_OPNF, fn);
 	else if (S_ISREG(st.st_mode))
 		process_file(fn);
-	else if (S_ISDIR(st.st_mode))
-		process_directory(fn);
-	/* make sure to only process regular files or directory walking */
+	/* make sure to only process regular files */
 	else
 		error(ER_NOT_REGULAR, STR_ERR_REGF, fn);
 }
 
 
-static void
-process_directory(const char *fn)
-{
-	DIR            *d;                      // directory pointer
-	struct dirent  *dp;                     // directory entry pointer
-	struct stat     dst,                    // stat holder for directory
-	                st;                     // stat holder for children
-	char           *rp;                     // relative path holder
-
-	if (!arg.recursive)
-		return error(ER_NOT_REGULAR, STR_ERR_RECU, fn);
-
-	/* open directory and get stats */
-	if (!((d = opendir(fn)) && lstat(fn, &dst) == 0))
-		return error(ER_OPENING, STR_ERR_OPND, fn);
-
-	/* loop through directory (including hidden files), making sure to process
-	 * the relative path of each file */
-	while ((dp = readdir(d)) != NULL) {
-		if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0)
-			continue;
-		if (!(rp = (char*)malloc(strlen(fn) + strlen(dp->d_name) + 2)))
-			error(ER_FATAL, STR_ERR_OOM);
-		sprintf(rp, "%s/%s", fn, dp->d_name);
-		/* make sure not to descend directories on other filesystems */
-		if (!(lstat(rp, &st) == 0 && dst.st_dev == st.st_dev))
-			error(ER_OPENING, STR_ERR_DDEV, rp, fn);
-		else
-			process_argument(rp);
-		free(rp);
-	}
-	closedir(d);
-}
-
-
 static void
 process_file(const char *fn)
 {
@@ -500,14 +463,13 @@ main(int argc, char *argv[])
 	gl.dup_head     = NULL;
 	gl.prg          = argv[0];
 
-	while ((opt = getopt(argc, argv, "dhmnqrvx")) != -1)
+	while ((opt = getopt(argc, argv, "dhmnqvx")) != -1)
 		switch (opt) {
 		case 'd':                           arg.duplicates = true; break;
 		case 'h':                           USAGE(EXIT_SUCCESS); break;
 		case 'm':                           arg.summarize = true; break;
 		case 'n':                           arg.dryrun = true; break;
 		case 'q':                           arg.quiet++; break;
-		case 'r':                           arg.recursive = true; break;
 		case 'v':                           VER(); break;
 		case 'x':                           arg.remove = true; break;
 		default:                            USAGE(EXIT_FAILURE);
diff --git a/acst.h b/acst.h
@@ -19,6 +19,7 @@
 #ifndef ACST_H
 #define ACST_H
 
+#include <limits.h>         // for PATH_MAX
 #include <stdbool.h>        // for bool
 #include <stdio.h>          // for printf
 #include <stdlib.h>         // for exit, EXIT_SUCCESS, size_t
@@ -41,13 +42,10 @@
 #define STR_ERR_PMAX        "Error: PATH_MAX reached before end\n"
 #define STR_ERR_ABNO        "Error: abnormal changes detected \"%s\"\n"
 #define STR_ERR_OPNF        "Error: could not open file \"%s\"\n"
-#define STR_ERR_OPND        "Error: could not open directory \"%s\"\n"
-#define STR_ERR_DDEV        "Error: \"%s\" belong to a different devices than \"%s\"\n"
 #define STR_ERR_REGF        "Error: not a regular file \"%s\"\n"
 #define STR_ERR_HASH        "Error: could not compute hash \"%s\"\n"
 #define STR_ERR_XARM        "Error: could not remove extended attributes from file \"%s\": %s\n"
 #define STR_ERR_XAWR        "Error: could not write extended attributes to file \"\%s\"\n"
-#define STR_ERR_RECU        "Error: path is a directory, did you mean to use the -r option? \"%s\"\n"
 #define STR_OUT_STAT        "<%s> %s\n"
 #define STR_OUT_NEW         "new"
 #define STR_OUT_OK          "ok"
@@ -76,7 +74,6 @@
     "  -m                    summarize information at end of execution\n"   \
     "  -n                    don't create or update any file attributes\n"  \
     "  -q                    quiet mode, lowers verbosity\n"                \
-    "  -r                    process files and directories recursively\n"   \
     "  -V                    output version information and exit\n"         \
     "  -x                    remove extended attributes from file(s)\n"     \
     "\n"                                                                    \
@@ -136,7 +133,7 @@ static const char zSHA256[] = "0000000000000000"    /* zeroed out SHA256 */
 
 enum Error {
 	ER_NOT_REGULAR,         /* not a regular file error */
-	ER_OPENING,             /* error opening file or directory */
+	ER_OPENING,             /* error opening file */
 	ER_XATTR_OPERATION,     /* error when performing xattr operations */
 	ER_GENERIC,             /* generic error */
 	ER_FATAL                /* fatal error, should result in program ending */
@@ -175,7 +172,6 @@ typedef struct ExtendedAttribute {
 struct Arguments {
 	bool                    dryrun;             /* make a dry run */
 	int                     quiet;              /* level of quietness */
-	bool                    recursive;          /* indicate to open and walk directories */
 	bool                    remove;             /* remove xattrs */
 	bool                    summarize;          /* show summery at end of program */
 	bool                    duplicates;         /* use xattrs to find duplicates */
@@ -185,7 +181,7 @@ struct Arguments {
 struct Counters {
 	int                     errs;               /* all errors */
 	int                     errNotRegular;      /* not a regular file errors  */
-	int                     errOpening;         /* errors opening file or directory */
+	int                     errOpening;         /* errors opening file */
 	int                     errWritingXattr;    /* errors when performing xattr operations */
 	int                     errGeneric;         /* generic errors */
 
@@ -318,21 +314,13 @@ static void error(enum Error er, const char *fmt, ...);
 static enum FileState file_state(int fd, xa_t *xa_s, xa_t *xa_a);
 
 /**
- * Processes arguments (file names) either from command line or from directory
+ * Processes arguments (file names) from command line
  * output.
  *
  * @param fn                Name of the file
  */
 static void process_argument(const char *fn);
 
-/**
- * Processes directories if stated to do so (see arg.recursive) by looping
- * through their content (children).
- *
- * @param fn                Name of the directory
- */
-static void process_directory(const char *fn);
-
 /**
  * Processes files and returns either error messages or other output if stated
  * to do so (see arg.quiet) based on their file state (see enum FileState
diff --git a/test b/test
@@ -249,37 +249,6 @@ TMPFILE="$(mktemp -d XXXXXXXXXX)" && {
 	diff -u expected output
 	rm -f symlink
 
-	#########################################################################
-	header 'recursion'
-	rm -f object
-	mkdir -p object/level-1/level-2/level-3
-	TZ=CET touch -t 202206220001 object/level-1/file-1
-	TZ=CET touch -t 202206220002 object/level-1/level-2/file-2
-	TZ=CET touch -t 202206220003 object/level-1/level-2/level-3/file-3
-	set +e
-	echo "Error: path is a directory, did you mean to use the -r option? \"object\"" > expected
-	../"${PRG}" object > output 2>&1
-	if [ $? -ne 3 ]; then
-		echo "should have returned error code 3, but returned 0"
-		exit 1
-	fi
-	set -e
-	diff -u expected output
-	sort > expected <<- EOF
-	<new> object/level-1/file-1
-	 stored: 0000000000000000000000000000000000000000000000000000000000000000 0000000000.000000000
-	 actual: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 1655848860.000000000
-	<new> object/level-1/level-2/file-2
-	 stored: 0000000000000000000000000000000000000000000000000000000000000000 0000000000.000000000
-	 actual: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 1655848920.000000000
-	<new> object/level-1/level-2/level-3/file-3
-	 stored: 0000000000000000000000000000000000000000000000000000000000000000 0000000000.000000000
-	 actual: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 1655848980.000000000
-	EOF
-	../"${PRG}" -r object | sort > output
-	diff -u expected output
-	rm -rf object
-
 	#########################################################################
 	header 'multiple files, using command line'
 	sort > expected <<- EOF
@@ -379,8 +348,8 @@ TMPFILE="$(mktemp -d XXXXXXXXXX)" && {
 	echo "3" | tee object/level-1/file-3 object/level-1/level-2/file-3 >\
 	           object/level-1/level-2/level-3/file-3
 	echo "4" > object/level-1/file-4
-	../"${PRG}" -r object > /dev/null 2>&1
-	../"${PRG}" -rd object 2>&1 | sort > output
+	find object -xdev -type f | ../"${PRG}" - > /dev/null 2>&1
+	find object -xdev -type f | ../"${PRG}" -d - 2>&1 | sort > output
 	diff -u expected output
 
 	#########################################################################