On 20 May 2011 21:51, Nick <suckless-...@njw.me.uk> wrote:
> One thing which could be considered would be allowing specifying
> file / directory names on argv.

> Another feature which would be nice would be stripping of leading /
> and .. from path names when creating and extracting archives.

Attached!

I also fixed a bug in my patch, and a bug in tip.

cls
diff -r fadca8e2d4d0 sltar.c
--- a/sltar.c	Fri May 20 22:12:58 2011 +0100
+++ b/sltar.c	Fri May 20 23:39:53 2011 +0100
@@ -3,6 +3,7 @@
  *
  * See LICENSE for further informations
  */
+#include <dirent.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <stdio.h>
@@ -14,22 +15,23 @@
 	SUM  = 148, TYPE = 156, LINK = 157, MAJ = 329, MIN  = 337, END   = 512
 };
 
+static int appenddir(const char *dir);
 static int append(const char *file);
 static int cksum(unsigned char *b);
-static int create(void);
-static int xtract(char a);
+static int create(int argc, char *argv[]);
+static int xtract(int argc, char *argv[], char a);
 
 int
 main(int argc, char *argv[]) {
 	char a;
 
-	if(argc == 2 && strlen(argv[1]) == 1)
+	if(argc > 1 && strlen(argv[1]) == 1)
 		switch((a = argv[1][0])) {
 		case 'c':
-			return create();
+			return create(argc-2, &argv[2]);
 		case 'x':
 		case 't':
-			return xtract(a);
+			return xtract(argc-2, &argv[2], a);
 		}
 
 	/* should not reach */
@@ -44,7 +46,7 @@
 	char buf[END];
 	size_t n;
 	struct stat st;
-	FILE *fp;
+	FILE *fp = NULL;
 
 	if(stat(file, &st) == -1) {
 		fprintf(stderr, "%s: cannot stat\n", file);
@@ -78,23 +80,45 @@
 		fprintf(stderr, "%s: unsupported file type\n", file);
 		return EXIT_FAILURE;
 	}
-	if(buf[TYPE] == '3' || buf[TYPE] == '4') {
+	if(S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode)) {
 		snprintf(&buf[MAJ], 8, "%07o", major(st.st_rdev));
 		snprintf(&buf[MIN], 8, "%07o", minor(st.st_rdev));
 	}
 	snprintf(&buf[SUM], 8, "%06o", cksum((unsigned char *)buf));
 	buf[SUM+7] = ' ';
 
-	if(!(fp = fopen(file, "r"))) {
+	if(S_ISREG(st.st_mode) && !(fp = fopen(file, "r"))) {
 		fprintf(stderr, "%s: cannot open\n", file);
 		return EXIT_FAILURE;
 	}
-	for(n = 1; n > 0; n = fread(buf, 1, sizeof buf, fp)) {
+	for(n = 1; n > 0; n = fp ? fread(buf, 1, sizeof buf, fp) : 0) {
 		fwrite(buf, sizeof buf, 1, stdout);
 		memset(buf, 0, sizeof buf);
 	}
-	fclose(fp);
-	return EXIT_SUCCESS;
+	if(fp)
+		fclose(fp);
+	return S_ISDIR(st.st_mode) ? appenddir(file) : EXIT_SUCCESS;
+}
+
+int
+appenddir(const char *dir)
+{
+	char buf[BUFSIZ];
+	int ret = EXIT_SUCCESS;
+	struct dirent *d;
+	DIR *dp;
+
+	if(!(dp = opendir(dir))) {
+		fprintf(stderr, "%s: cannot opendir\n", dir);
+		return EXIT_FAILURE;
+	}
+	while((d = readdir(dp)))
+		if(strcmp(d->d_name, ".") != 0 && strcmp(d->d_name, "..") != 0) {
+			snprintf(buf, sizeof buf, "%s/%s", dir, d->d_name);
+			if(append(buf) == EXIT_FAILURE)
+				ret = EXIT_FAILURE;
+		}
+	return ret;
 }
 
 int
@@ -108,32 +132,47 @@
 }
 
 int
-create(void) {
+create(int argc, char *argv[]) {
 	char buf[BUFSIZ], *p;
-	int ret = EXIT_SUCCESS;
+	int i, ret = EXIT_SUCCESS;
 
-	while(fgets(buf, sizeof buf, stdin)) {
-		if((p = strchr(buf, '\n')))
+	for(i = 0; argc ? i < argc : fgets(buf, sizeof buf, stdin) != NULL; i++) {
+		if(!argc && (p = strchr(buf, '\n')))
 			*p = '\0';
-		if(append(buf) == EXIT_FAILURE)
+		if(append(argc ? argv[i] : buf) == EXIT_FAILURE)
 			ret = EXIT_FAILURE;
 	}
 	return ret;
 }
 
 int
-xtract(char a) {
-	int l;
-	char b[END],fname[101],lname[101];
+xtract(int argc, char *argv[], char a) {
+	int i, l;
+	char b[END], fname[101], lname[101], *p;
 	FILE *f = NULL;
 
 	for(lname[100] = fname[100] = l = 0; fread(b,END,1,stdin); l -= END)
-		 if(l <= 0) {
+		if(l <= 0) {
 			if(*b == '\0')
 				break;
-			memcpy(fname,b,100);
+			for(p = b; *p == '/'; p++);
+			memcpy(fname, p, 100);
+
+			for(i = 0; i < argc; i++)
+				if(!strcmp(argv[i], fname))
+					break;
+
 			memcpy(lname,b + LINK,100);
-			l = strtoull(b + SIZE,0,8) + END;
+
+			if(b[TYPE] == '0')
+				l = strtoull(b + SIZE,0,8) + END;
+			else
+				l = END;
+			if(argc && i == argc) {
+				if(a == 'x' && b[TYPE] == '0' && !(f = fopen("/dev/null", "w")))
+					perror("/dev/null");
+				continue;
+			}
 			if(a == 't') {
 				puts(fname);
 				continue;

Reply via email to