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