1 /*\
2 |*| Parity Archive - A way to restore missing files in a set.
3 |*|
4 |*| Copyright (C) 2001 Willem Monsuwe (willem@stack.nl)
5 |*|
6 |*| File format by Stefan Wehlus -
7 |*| initial idea by Tobias Rieper, further suggestions by Kilroy Balore
8 |*|
9 |*| In short: Files are XORed with each other and the result is stored.
10 |*| From this, one missing file can be recreated.
11 \*/
12
13 #include <stdio.h>
14 #include <ctype.h>
15 #include <string.h>
16 #include "fileops.h"
17 #include "rwpar.h"
18 #include "backend.h"
19 #include "checkpar.h"
20 #include "makepar.h"
21 #include "interface.h"
22
23 struct cmdline cmd;
24
25 /*\
26 |*| Print usage
27 \*/
28 int
usage(void)29 usage(void)
30 {
31 printf(
32 "Usage:\n"
33 " par c(heck) [options] <par file> : Check parity archive\n"
34 " par r(ecover) [options] <par file> : Restore missing volumes\n"
35 " par a(dd) [options] <par file> [files] : Add files to parity archive\n"
36 " Advanced:\n"
37 " par m(ix) [options] : Try to restore from all parity files at once\n"
38 " par i(nteractive) [<par files>] : Interactive mode (very bare-bones)\n"
39 "\n"
40 "Options: (Can be turned off with '+')\n"
41 " -m : Move existing files out of the way\n"
42 " -f : Fix faulty filenames\n"
43 " -p<n>: Number of files per parity volume\n"
44 " or -n<n>: Number of parity volumes to create\n"
45 " -d : Search for duplicate files\n"
46 " -k : Keep broken files\n"
47 " -s : Be smart if filenames are consistently different.\n"
48 " +i : Do not add following files to parity volumes\n"
49 " +c : Do not create parity volumes\n"
50 " +C : Ignore case in filename comparisons\n"
51 " +H : Do not check control hashes\n"
52 " -v,+v: Increase or decrease verbosity\n"
53 " -h,-?: Display this help\n"
54 " -- : Always treat following arguments as files\n"
55 "\n"
56 );
57 return 0;
58 }
59
60 /*\ Sanity check \*/
61 static int
check_sizes(void)62 check_sizes(void)
63 {
64 int fail = 0;
65 if (sizeof(u8) != 1) {
66 fprintf(stderr, "u8 isn't 8 bits wide.\n");
67 fail++;
68 }
69 if (sizeof(u16) != 2) {
70 fprintf(stderr, "u16 isn't 16 bits wide.\n");
71 fail++;
72 }
73 if (sizeof(u32) != 4) {
74 fprintf(stderr, "u32 isn't 32 bits wide.\n");
75 fail++;
76 }
77 if (sizeof(i64) != 8) {
78 fprintf(stderr, "u64 isn't 64 bits wide.\n");
79 fail++;
80 }
81 return fail;
82 }
83
84 /*\ In ui_text.h \*/
85 void ui_text(void);
86
87 /*\
88 |*| Main loop. Simple stuff.
89 \*/
90 int
main(int argc,char * argv[])91 main(int argc, char *argv[])
92 {
93 par_t *par = 0;
94 int fail = 0;
95 char *p;
96
97 if (check_sizes())
98 return -1;
99
100 /*\ Some defaults \*/
101 memset(&cmd, 0, sizeof(cmd));
102 cmd.volumes = 10;
103 cmd.pervol = 1;
104 cmd.pxx = 1;
105 cmd.ctrl = 1;
106 cmd.add = 1;
107 cmd.usecase = 1;
108
109 if (argc == 1) return usage();
110
111 for (; argc > 1; argc--, argv++) {
112 if (((argv[1][0] == '-') || (argv[1][0] == '+')) &&
113 argv[1][1] && !cmd.dash) {
114 for (p = argv[1]; *p; p++) switch (*p) {
115 case '-':
116 if (p[1] == '-')
117 cmd.dash = 1;
118 else
119 cmd.plus = 1;
120 break;
121 case '+':
122 cmd.plus = 0;
123 break;
124 case 'm':
125 cmd.move = cmd.plus;
126 break;
127 case 'i':
128 cmd.add = cmd.plus;
129 break;
130 case 'f':
131 cmd.fix = cmd.plus;
132 break;
133 case 'c':
134 cmd.pxx = cmd.plus;
135 break;
136 case 'd':
137 cmd.dupl = cmd.plus;
138 break;
139 case 'v':
140 if (cmd.plus)
141 cmd.loglevel++;
142 else
143 cmd.loglevel--;
144 break;
145 case 'p':
146 case 'n':
147 cmd.pervol = (*p == 'p');
148 while (isspace(*++p))
149 ;
150 if (!*p) {
151 argv++;
152 argc--;
153 p = argv[1];
154 }
155 if (!isdigit(*p)) {
156 fprintf(stderr, "Value expected!\n");
157 } else {
158 cmd.volumes = 0;
159 do {
160 cmd.volumes *= 10;
161 cmd.volumes += *p - '0';
162 } while (isdigit(*++p));
163 p--;
164 }
165 break;
166 case 'H':
167 cmd.ctrl = cmd.plus;
168 break;
169 case 'C':
170 cmd.usecase = cmd.plus;
171 break;
172 case 'k':
173 cmd.keep = cmd.plus;
174 break;
175 case 's':
176 cmd.smart = cmd.plus;
177 break;
178 case '?':
179 case 'h':
180 return usage();
181 default:
182 fprintf(stderr,
183 "Unknown switch: '%c'\n", *p);
184 break;
185 }
186 continue;
187 }
188 if (!cmd.action) {
189 switch (argv[1][0]) {
190 case 'c':
191 case 'C':
192 cmd.action = ACTION_CHECK;
193 break;
194 case 'm':
195 case 'M':
196 cmd.action = ACTION_MIX;
197 break;
198 case 'r':
199 case 'R':
200 cmd.action = ACTION_RESTORE;
201 break;
202 case 'a':
203 case 'A':
204 cmd.action = ACTION_ADD;
205 break;
206 case 'i':
207 case 'I':
208 cmd.action = ACTION_TEXT_UI;
209 break;
210 default:
211 fprintf(stderr, "Unknown command: '%s'\n",
212 argv[1]);
213 break;
214 }
215 continue;
216 }
217 switch (cmd.action) {
218 default:
219 cmd.action = ACTION_CHECK;
220 /*\ FALLTHROUGH \*/
221 case ACTION_CHECK:
222 case ACTION_RESTORE:
223 fprintf(stderr, "Checking %s\n", argv[1]);
224 par = read_par_header(unist(argv[1]), 0, 0, 0);
225 if (!par) {
226 fail = 2;
227 continue;
228 }
229 if (check_par(par) < 0) fail = 1;
230 free_par(par);
231 par = 0;
232 break;
233 case ACTION_ADD:
234 fprintf(stderr, "Adding to %s\n", argv[1]);
235 par = read_par_header(unist(argv[1]), 1, 0, 0);
236 if (!par) return 2;
237 cmd.action = ACTION_ADDING;
238 break;
239 case ACTION_ADDING:
240 par_add_file(par, find_file_name(unist(argv[1]), 1));
241 break;
242 case ACTION_MIX:
243 fprintf(stderr, "Unknown argument: '%s'\n", argv[1]);
244 break;
245 case ACTION_TEXT_UI:
246 par_load(unist(argv[1]));
247 break;
248 }
249 }
250 if (cmd.action == ACTION_TEXT_UI) {
251 ui_text();
252 return 0;
253 }
254 if (cmd.action == ACTION_MIX) {
255 par = find_all_par_files();
256 if (par) {
257 fprintf(stderr, "\nChecking:\n");
258 if (check_par(par) < 0)
259 fail = 1;
260 free_par(par);
261 par = 0;
262 } else {
263 fail = 2;
264 }
265 }
266 if (par) {
267 if (cmd.pxx && !par_make_pxx(par))
268 fail |= 1;
269 if (!par->vol_number && !write_par_header(par))
270 fail |= 1;
271 free_par(par);
272 }
273 return fail;
274 }
275