ref: 89778e7a0ed792d720c05ceb0a4246032a9dc623
parent: b25d2025d901c27b3ce5fe7497cb82d6bd4e5415
author: Roberto E. Vargas Caballero <k0ga@shike2.com>
date: Wed Feb 21 15:38:19 EST 2018
[ar] Full rewrite of ar This new code is much better than the previus code.
--- a/ar/main.c
+++ b/ar/main.c
@@ -16,16 +16,26 @@
#define NOSAVE 0
#define SAVE 1
+enum {
+ BEFORE,
+ INDOT,
+ AFTER,
+};
+
+struct tmp {
+ char *name;
+ FILE *fp;
+} tmps[3];
+
char *argv0;
-static int bflag, vflag, cflag, lflag, uflag, aflag, haslist;
-static char *posname, *tmpafile1, *tmpafile2, *arfile;
+static int bflag, vflag, cflag, lflag, uflag, aflag;
+static char *arfile, *posname;
-struct arop {
+struct member {
FILE *src;
- FILE *dst;
- FILE *tmp;
struct ar_hdr hdr;
+ int cur;
char *fname;
long size;
long mode;
@@ -35,10 +45,12 @@
static void
cleanup(void)
{
- if (tmpafile1)
- remove(tmpafile1);
- if (tmpafile2)
- remove(tmpafile2);
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ if (tmps[i].name)
+ remove(tmps[i].name);
+ }
}
static void
@@ -128,7 +140,7 @@
}
static void
-append(FILE *fp, char *list[])
+append(FILE *fp, char *argv[])
{
char *fname;
@@ -137,8 +149,8 @@
exit(1);
}
- for ( ; fname = *list; ++list) {
- *list = NULL;
+ for ( ; fname = *argv; ++argv) {
+ *argv = NULL;
archive(fname, fp, 'a');
}
@@ -149,32 +161,19 @@
}
static void
-cat(FILE *src1, FILE *src2, FILE *dst)
+copy(struct member *op, struct tmp *tmp)
{
int c;
+ size_t siz = op->size;
+ struct ar_hdr *hdr = &op->hdr;
- while ((c = getc(src1)) != EOF)
- fputc(c, dst);
- while ((c = getc(src2)) != EOF)
- fputc(c, dst);
- if (ferror(src1) || ferror(src2) || fclose(dst) == EOF) {
- perror("ar:moving files in archive");
- exit(1);
- }
-}
-
-static void
-copy(struct ar_hdr *hdr, long siz, FILE *src, FILE *dst)
-{
- int c;
-
- fwrite(hdr, sizeof(*hdr), 1, dst);
+ fwrite(hdr, sizeof(*hdr), 1, tmp->fp);
if ((siz & 1) == 1)
siz++;
while (siz--) {
- if ((c = getc(src)) == EOF)
+ if ((c = getc(op->src)) == EOF)
break;
- fputc(c, dst);
+ fputc(c, tmp->fp);
}
}
@@ -187,7 +186,7 @@
}
static char *
-perms(struct arop *op)
+perms(struct member *op)
{
static char buf[10];
@@ -200,87 +199,59 @@
}
static int
-inlist(char *fname, char *list[])
+inlist(char *fname, int argc, char *argv[])
{
- while (*list && strcmp(*list, fname))
- ++list;
- if (*list == NULL)
- return 0;
- for (; *list; ++list)
- list[0] = list[1];
- return 1;
+ for (; argc-- > 0; ++argv) {
+ if (!strcmp(*argv, fname)) {
+ *argv = NULL;
+ return 1;
+ }
+ }
+ return 0;
}
static void
-split(struct arop *op, char *files[])
+move(struct member *op, int argc, char *argv[])
{
- if (!inlist(op->fname, files)) {
- copy(&op->hdr, op->size, op->src, op->dst);
- return;
+ int where;
+
+ if (inlist(op->fname, argc, argv)) {
+ where = INDOT;
+ } else if (posname && !strcmp(posname, op->fname)) {
+ where = (bflag) ? AFTER : BEFORE;
+ op->cur = AFTER;
} else {
- if (vflag)
- printf("m - %s\n", op->fname);
- copy(&op->hdr, op->size, op->src, op->tmp);
+ where = op->cur;
}
+ copy(op, &tmps[where]);
}
static void
-merge(struct arop *op, char *list[])
+update(struct member *op, int argc, char *argv[])
{
- int c;
+ int where;
+ FILE *fp = tmps[BEFORE].fp;
- if (strcmp(op->fname, posname)) {
- copy(&op->hdr, op->size, op->src, op->dst);
+ if (inlist(op->fname, argc, argv)) {
+ archive(op->fname, tmps[op->cur].fp, 'r');
return;
+ } else if (posname && !strcmp(posname, op->fname)) {
+ where = (bflag) ? AFTER : BEFORE;
+ op->cur = AFTER;
+ } else {
+ where = op->cur;
}
-
- if (aflag)
- copy(&op->hdr, op->size, op->src, op->dst);
-
- while ((c = getc(op->tmp)) != EOF)
- putc(c, op->dst);
-
- if (bflag)
- copy(&op->hdr, op->size, op->src, op->dst);
+ copy(op, &tmps[where]);
}
static void
-insert(struct arop *op, char *list[])
+extract(struct member *op, int argc, char *argv[])
{
- if (!posname || strcmp(op->fname, posname)) {
- copy(&op->hdr, op->size, op->src, op->dst);
- return;
- }
-
- if (aflag)
- copy(&op->hdr, op->size, op->src, op->dst);
-
- for ( ; *list; ++list)
- archive(*list, op->dst, 'a');
-
- if (bflag)
- copy(&op->hdr, op->size, op->src, op->dst);
-}
-
-static void
-update(struct arop *op, char *files[])
-{
- char **l;
-
- if (!inlist(op->fname, files))
- copy(&op->hdr, op->size, op->src, op->dst);
- else
- archive(op->fname, op->dst, 'r');
-}
-
-static void
-extract(struct arop *op, char *files[])
-{
int c;
long siz;
FILE *fp;
- if (haslist && !inlist(op->fname, files))
+ if (argc > 0 && !inlist(op->fname, argc, argv))
return;
if (vflag)
printf("x - %s\n", op->fname);
@@ -291,9 +262,8 @@
while (siz-- > 0 && (c = getc(op->src)) != EOF)
putc(c, fp);
fflush(fp);
- if (ferror(op->src) || ferror(fp))
+ if (fclose(op->src) == EOF || ferror(fp))
goto error_file;
- fclose(fp);
/* TODO: set attributes */
return;
@@ -305,12 +275,12 @@
}
static void
-print(struct arop *op, char *files[])
+print(struct member *op, int argc, char *argv[])
{
long siz;
int c;
- if (haslist && !inlist(op->fname, files))
+ if (argc > 0 && !inlist(op->fname, argc, argv))
return;
if (vflag)
printf("\n<%s>\n\n", op->fname);
@@ -320,13 +290,13 @@
}
static void
-list(struct arop *op, char *files[])
+list(struct member *op, int argc, char *argv[])
{
time_t t;
struct ar_hdr *hdr = &op->hdr;
char mtime[30];
- if (haslist && !inlist(op->fname, files))
+ if (argc > 0 && !inlist(op->fname, argc, argv))
return;
if (!vflag) {
printf("%s\n", op->fname);
@@ -343,14 +313,14 @@
}
static void
-del(struct arop *op, char *files[])
+del(struct member *op, int argc, char *argv[])
{
- if (inlist(op->fname, files)) {
+ if (inlist(op->fname, argc, argv)) {
if (vflag)
printf("d - %s\n", op->fname);
return;
}
- copy(&op->hdr, op->size, op->src, op->dst);
+ copy(op, &tmps[BEFORE]);
}
static char *
@@ -394,7 +364,7 @@
}
static int
-valid(struct arop *op)
+valid(struct member *op)
{
struct ar_hdr *hdr = &op->hdr;
@@ -411,15 +381,12 @@
}
static void
-run(FILE *fp, FILE *tmp1, FILE *tmp2,
- char *files[], void (*fun)(struct arop *, char *files[]))
+run(FILE *fp, int argc, char *argv[],
+ void (*fun)(struct member *, int argc, char *files[]))
{
- struct arop op;
+ struct member op;
- op.src = fp;
- op.dst = tmp1;
- op.tmp = tmp2;
- while (!ferror(fp) && fread(&op.hdr, sizeof(op.hdr), 1, fp) == 1) {
+ while (fread(&op.hdr, sizeof(op.hdr), 1, fp) == 1) {
fpos_t pos;
if (!valid(&op)) {
@@ -430,90 +397,85 @@
}
/* TODO: Implement early break */
fgetpos(fp, &pos);
- (*fun)(&op, files);
+ (*fun)(&op, argc, argv);
fsetpos(fp, &pos);
fseek(fp, op.size+1 & ~1, SEEK_CUR);
}
- if (ferror(fp)) {
+ if (ferror(fp) || fclose(fp) == EOF) {
perror("ar:reading members");
exit(1);
}
- fclose(fp);
- if (tmp1 && fflush(tmp1) == EOF) {
- perror("ar:writing in temporary file");
+}
+
+static void
+merge(void)
+{
+ FILE *fp, *fi;
+ int c, i;
+
+ fseek(tmps[0].fp, 0, SEEK_SET);
+ fseek(tmps[1].fp, 0, SEEK_SET);
+ fseek(tmps[2].fp, 0, SEEK_SET);
+
+ if ((fp = fopen(arfile, "wb")) == NULL) {
+ perror("ar:reopening archive");
exit(1);
}
- if (tmp2 && fflush(tmp2) == EOF) {
- perror("ar:writing in temporary file");
+
+ fwrite(ARFMAG, sizeof(ARFMAG), 1, fp);
+
+ for (i = 0; i < 3; i++) {
+ fi = tmps[i].fp;
+ while ((c = getc(fi)) != EOF)
+ putc(c, fp);
+ if (ferror(fi)) {
+ perror("ar:error in temporary");
+ exit(1);
+ }
+ }
+
+ if (fclose(fp) == EOF) {
+ perror("ar:writing archive file");
exit(1);
}
}
static void
-closetmp(FILE *tmp, char **name, int save)
+closetmp(int which)
{
- int c;
- FILE *fp;
+ struct tmp *tmp = &tmps[which];
- if (lflag) {
- if (save && rename(*name, arfile) < 0) {
- perror("ar:renaming temporary");
- exit(1);
- }
- *name = NULL;
- } else if (save) {
- if ((fp = fopen(arfile, "wb")) == NULL) {
- perror("ar:reopening archive file");
- exit(1);
- }
- rewind(tmp);
- while ((c = getc(tmp)) != EOF)
- fputc(c, fp);
- fflush(fp);
- if (ferror(fp) || ferror(tmp)) {
- perror("ar:copying from temporary");
- exit(1);
- }
- fclose(fp);
+ if (fclose(tmp->fp) == EOF) {
+ perror("ar:closing temporaries");
+ exit(1);
}
- fclose(tmp);
}
-static FILE *
-opentmp(char *fname, char **dst)
+static void
+opentmp(char *fname, int which)
{
- FILE *tmp;
+ struct tmp *tmp = &tmps[which];
if (lflag) {
- *dst = fname;
- tmp = fopen(fname, "w+b");
+ tmp->name = fname;
+ tmp->fp = fopen(fname, "w+b");
} else {
- tmp = tmpfile();
+ tmp->fp = tmpfile();
}
- if (tmp == NULL) {
+
+ if (tmp->fp == NULL) {
perror("ar:creating temporary");
exit(1);
}
- fputs(ARMAG, tmp);
-
- return tmp;
}
static void
-usage(void)
+doit(int key, char *argv[], int argc)
{
- fputs("ar [-drqtpmx][posname] [-vuaibcl] [posname] arfile name ...\n",
- stderr);
- exit(1);
-}
+ FILE *fp;
-static void
-doit(int key, char *flist[])
-{
- FILE *tmp1, *tmp2, *fp;
-
fp = openar();
- if (*flist == NULL &&
+ if (argc == 0 &&
(key == 'r' || key == 'd' || key == 'm' || key == 'q')) {
if (fclose(fp) == EOF) {
perror("ar:early close of archive file");
@@ -521,63 +483,55 @@
}
return;
}
- haslist = *flist != NULL;
+ opentmp("ar.tmp1", BEFORE);
+ opentmp("ar.tmp2", INDOT);
+ opentmp("ar.tmp3", AFTER);
+
switch (key) {
case 'r':
- tmp1 = opentmp("ar.tmp1", &tmpafile1);
- run(fp, tmp1, NULL, flist, update);
-
- if (!posname) {
- append(tmp1, flist);
- break;
- }
-
- fseek(tmp1, SARMAG, SEEK_SET);
- tmp2 = opentmp("ar.tmp2", &tmpafile2);
- run(tmp1, tmp2, NULL, flist, insert);
- closetmp(tmp1, &tmpafile1, NOSAVE);
- closetmp(tmp2, &tmpafile2, SAVE);
+ run(fp, argc, argv, update);
+ merge();
break;
- case 'q':
- append(fp, flist);
+ case 'm':
+ run(fp, argc, argv, move);
+ merge();
break;
case 'd':
- tmp1 = opentmp("ar.tmp", &tmpafile1);
- run(fp, tmp1, NULL, flist, del);
- closetmp(tmp1, &tmpafile1, SAVE);
+ run(fp, argc, argv, del);
+ merge();
break;
case 't':
- run(fp, NULL, NULL, flist, list);
+ run(fp, argc, argv, list);
break;
case 'p':
- run(fp, NULL, NULL, flist, print);
+ run(fp, argc, argv, print);
break;
case 'x':
- run(fp, NULL, NULL, flist, extract);
+ run(fp, argc, argv, extract);
break;
- case 'm':
- tmp1 = opentmp("ar.tmp1", &tmpafile1);
- tmp2 = opentmp("ar.tmp2", &tmpafile2);
- run(fp, tmp1, tmp2, flist, split);
+ case 'q':
+ append(fp, argv);
+ break;
+ }
- fp = openar();
- fseek(tmp1, SARMAG, SEEK_SET);
- fseek(tmp2, SARMAG, SEEK_SET);
- if (!posname) {
- cat(tmp1, tmp2, fp);
- break;
+ closetmp(BEFORE);
+ closetmp(INDOT);
+ closetmp(AFTER);
+
+ for ( ; argc-- > 0; ++argv) {
+ if (*argv) {
+ fprintf(stderr, "ar: No member named '%s\n", *argv);
+ exit(1);
}
- run(tmp1, fp, tmp2, NULL, merge);
- closetmp(tmp1, &tmpafile1, NOSAVE);
- closetmp(tmp2, &tmpafile2, NOSAVE);
- break;
}
- if (*flist == NULL)
- return;
+}
- while (*flist)
- fprintf(stderr, "ar: No member named '%s\n", *flist++);
+static void
+usage(void)
+{
+ fputs("ar [-drqtpmx][posname] [-vuaibcl] [posname] arfile name ...\n",
+ stderr);
exit(1);
}
@@ -651,7 +605,7 @@
signal(SIGTERM, sigfun);
arfile = *argv;
- doit(key, argv+1);
+ doit(key, ++argv, --argc);
if (fflush(stdout) == EOF) {
perror("ar:error writing to stdout");