1 // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ 2 // 3 // Copyright (c) 2001-2003, Haiku 4 // 5 // This software is part of the Haiku distribution and is covered 6 // by the MIT License. 7 // 8 // 9 // File: unchop.c 10 // Author: Daniel Reinhold (danielre@users.sf.net) 11 // Description: recreates a file previously split with chop 12 // 13 // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ 14 15 #include <OS.h> 16 #include <stdio.h> 17 #include <stdlib.h> 18 #include <string.h> 19 #include <errno.h> 20 #include <fcntl.h> 21 #include <unistd.h> 22 #include <sys/stat.h> 23 24 25 void append_file (int, int); 26 void do_unchop (char *, char *); 27 void replace (char *, char *); 28 char *temp_file (void); 29 void usage (void); 30 bool valid_file (char *); 31 32 33 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 34 // globals 35 36 #define BLOCKSIZE 64 * 1024 // file data is read in BLOCKSIZE blocks 37 static char Block[BLOCKSIZE]; // and stored in the global Block array 38 39 static int Errors = 0; 40 41 42 43 void 44 usage() 45 { 46 printf("Usage: unchop file\n"); 47 printf("Concatenates files named file00, file01... into file\n"); 48 } 49 50 51 int 52 main(int argc, char *argv[]) 53 { 54 if (argc != 2) { 55 usage(); 56 return 0; 57 } 58 else { 59 char *origfile = argv[1]; 60 char *tmpfile = origfile; 61 bool needs_replace = false; 62 63 if (valid_file(origfile)) { 64 // output file already exists -- write to temp file 65 tmpfile = temp_file(); 66 needs_replace = true; 67 } 68 69 do_unchop(tmpfile, origfile); 70 71 if (needs_replace) { 72 if (Errors == 0) 73 replace(origfile, tmpfile); 74 else 75 remove(tmpfile); 76 } 77 } 78 79 return Errors; 80 } 81 82 83 void 84 do_unchop(char *outfile, char *basename) 85 { 86 int fdout = open(outfile, O_WRONLY|O_CREAT|O_APPEND); 87 if (fdout < 0) 88 fprintf(stderr, "can't open '%s': %s\n", outfile, strerror(errno)); 89 90 else { 91 int i; 92 char fnameN[256]; 93 94 for (i = 0; i < 999999; ++i) { 95 sprintf(fnameN, "%s%02d", basename, i); 96 97 if (valid_file(fnameN)) { 98 int fdin = open(fnameN, O_RDONLY); 99 if (fdin < 0) { 100 fprintf(stderr, "can't open '%s': %s\n", fnameN, strerror(errno)); 101 ++Errors; 102 } else { 103 append_file(fdin, fdout); 104 close(fdin); 105 } 106 } else { 107 if (i == 0) 108 printf("No chunk files present (%s)", fnameN); 109 break; 110 } 111 } 112 close(fdout); 113 } 114 } 115 116 117 void 118 append_file(int fdin, int fdout) 119 { 120 // appends the entire contents of the input file 121 // to the output file 122 123 ssize_t got; 124 125 for (;;) { 126 got = read(fdin, Block, BLOCKSIZE); 127 if (got <= 0) 128 break; 129 130 write(fdout, Block, got); 131 } 132 } 133 134 135 bool 136 valid_file(char *fname) 137 { 138 // for this program, a valid file is one that: 139 // a) exists (that always helps) 140 // b) is a regular file (not a directory, link, etc.) 141 142 struct stat e; 143 144 if (stat(fname, &e) == -1) { 145 // no such file 146 return false; 147 } 148 149 return (S_ISREG(e.st_mode)); 150 } 151 152 153 void 154 replace(char *origfile, char *newfile) 155 { 156 // replace the contents of the original file 157 // with the contents of the new file 158 159 char buf[1000]; 160 161 // delete the original file 162 remove(origfile); 163 164 // rename the new file to the original file name 165 sprintf(buf, "mv \"%s\" \"%s\"", newfile, origfile); 166 system(buf); 167 } 168 169 170 char * 171 temp_file(void) 172 { 173 // creates a new, temporary file and returns its name 174 175 char *tmp = tmpnam(NULL); 176 177 FILE *fp = fopen(tmp, "w"); 178 fclose(fp); 179 180 return tmp; 181 } 182