#include #include #include #include #include static void append(const char *path); static void catio(FILE *in, FILE *out, long n); static void fatal(const char *s); static void extract(void); static char *strvstr(char **strv, const char *str); static struct Entry { char path[257]; char size[15]; } ent; int main(int argc, char *argv[]) { int i; if(argc < 2 || strlen(argv[1]) != 1) { usage: fputs("usage: wrap {cdrtx} [files...]\n", stderr); exit(1); } switch(*argv[1]) { case 'd': case 'r': while(fread(&ent, sizeof ent, 1, stdin)) if(!strvstr(argv + 2, ent.path)) { fwrite(&ent, sizeof ent, 1, stdout); catio(stdin, stdout, atol(ent.size)); } else catio(stdin, NULL, atol(ent.size)); if(*argv[1] != 'r') break; case 'c': for(i = 2; i < argc; i++) append(argv[i]); break; case 't': while(fread(&ent, sizeof ent, 1, stdin)) { if(argc == 2 || strvstr(argv + 2, ent.path)) printf("%s\n", ent.path); catio(stdin, NULL, atol(ent.size)); } break; case 'x': while(fread(&ent, sizeof ent, 1, stdin)) if(argc == 2 || strvstr(argv + 2, ent.path)) extract(); break; default: goto usage; } return EXIT_SUCCESS; } void append(const char *path) { struct stat st; FILE *fp; if(stat(path, &st) < 0) fatal(path); if(!(fp = fopen(path, "r"))) fatal(path); memset(&ent, 0, sizeof ent); strncpy(ent.path, path, sizeof ent.path - 1); snprintf(ent.size, sizeof ent.size - 1, "%lu", st.st_size); fwrite(&ent, sizeof ent, 1, stdout); catio(fp, stdout, st.st_size); fclose(fp); } void catio(FILE *in, FILE *out, long n) { char buf[8192]; long m; for(; (m = (n < sizeof buf) ? n : sizeof buf); n -= m) if(!fread(buf, m, 1, in)) fatal("read error"); else if(out && !fwrite(buf, m, 1, out)) fatal("write error"); } void extract(void) { char *p = ent.path; FILE *fp; while((p = strchr(p + 1, '/'))) { *p = '\0'; if(mkdir(ent.path, 0755) < 0 && errno != EEXIST) fatal(ent.path); *p = '/'; } if(!(fp = fopen(ent.path, "w"))) fatal(ent.path); catio(stdin, fp, atol(ent.size)); fclose(fp); } void fatal(const char *s) { fprintf(stderr, "wrap: %s: %s\n", s, strerror(errno)); exit(EXIT_FAILURE); } char * strvstr(char **strv, const char *str) { for(; *strv; strv++) if(!strcmp(*strv, str)) return *strv; return NULL; }