xref: /haiku/src/bin/unchop.c (revision 4c8e85b316c35a9161f5a1c50ad70bc91c83a76f)
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