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 25void append_file (int, int); 26void do_unchop (char *, char *); 27void replace (char *, char *); 28char *temp_file (void); 29void usage (void); 30bool valid_file (char *); 31 32 33// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 34// globals 35 36#define BLOCKSIZE 64 * 1024 // file data is read in BLOCKSIZE blocks 37static char Block[BLOCKSIZE]; // and stored in the global Block array 38 39static int Errors = 0; 40 41 42 43void 44usage() 45{ 46 printf("Usage: unchop file\n"); 47 printf("Concatenates files named file00, file01... into file\n"); 48} 49 50 51int 52main(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 83void 84do_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 117void 118append_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 135bool 136valid_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 153void 154replace(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 170char * 171temp_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