// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ // // Copyright (c) 2001-2003, Haiku // // This software is part of the Haiku distribution and is covered // by the MIT License. // // // File: unchop.c // Author: Daniel Reinhold (danielre@users.sf.net) // Description: recreates a file previously split with chop // // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ #include #include #include #include #include #include #include #include void append_file (int, int); void do_unchop (char *, char *); void replace (char *, char *); char *temp_file (void); void usage (void); bool valid_file (char *); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // globals #define BLOCKSIZE 64 * 1024 // file data is read in BLOCKSIZE blocks static char Block[BLOCKSIZE]; // and stored in the global Block array static int Errors = 0; void usage() { printf("Usage: unchop file\n"); printf("Concatenates files named file00, file01... into file\n"); } int main(int argc, char *argv[]) { if (argc != 2) { usage(); return 0; } else { char *origfile = argv[1]; char *tmpfile = origfile; bool needs_replace = false; if (valid_file(origfile)) { // output file already exists -- write to temp file tmpfile = temp_file(); needs_replace = true; } do_unchop(tmpfile, origfile); if (needs_replace) { if (Errors == 0) replace(origfile, tmpfile); else remove(tmpfile); } } return Errors; } void do_unchop(char *outfile, char *basename) { int fdout = open(outfile, O_WRONLY|O_CREAT|O_APPEND); if (fdout < 0) fprintf(stderr, "can't open '%s': %s\n", outfile, strerror(errno)); else { int i; char fnameN[256]; for (i = 0; i < 999999; ++i) { sprintf(fnameN, "%s%02d", basename, i); if (valid_file(fnameN)) { int fdin = open(fnameN, O_RDONLY); if (fdin < 0) { fprintf(stderr, "can't open '%s': %s\n", fnameN, strerror(errno)); ++Errors; } else { append_file(fdin, fdout); close(fdin); } } else { if (i == 0) printf("No chunk files present (%s)", fnameN); break; } } close(fdout); } } void append_file(int fdin, int fdout) { // appends the entire contents of the input file // to the output file ssize_t got; for (;;) { got = read(fdin, Block, BLOCKSIZE); if (got <= 0) break; write(fdout, Block, got); } } bool valid_file(char *fname) { // for this program, a valid file is one that: // a) exists (that always helps) // b) is a regular file (not a directory, link, etc.) struct stat e; if (stat(fname, &e) == -1) { // no such file return false; } return (S_ISREG(e.st_mode)); } void replace(char *origfile, char *newfile) { // replace the contents of the original file // with the contents of the new file char buf[1000]; // delete the original file remove(origfile); // rename the new file to the original file name sprintf(buf, "mv \"%s\" \"%s\"", newfile, origfile); system(buf); } char * temp_file(void) { // creates a new, temporary file and returns its name char *tmp = tmpnam(NULL); FILE *fp = fopen(tmp, "w"); fclose(fp); return tmp; }