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