1 /*************************************************************************
2
3 $Id: bsdsfv.c,v 1.18 2003/10/05 01:07:45 webbie Exp $
4
5 Copyright (c) 2000-2003, webbie@ipfw.org
6 All rights reserved.
7
8 Redistribution and use in source and binary forms, with or without
9 modification, are permitted provided that the following conditions are
10 met:
11
12 Redistributions of source code must retain the above copyright notice,
13 this list of conditions and the following disclaimer.
14
15 Redistributions in binary form must reproduce the above copyright notice,
16 this list of conditions and the following disclaimer in the documentation
17 and/or other materials provided with the distribution.
18
19 Neither name of the Webbie nor the names of its contributors may be
20 used to endorse or promote products derived from this software without
21 specific prior written permission.
22
23 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
26 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
27 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
29 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34
35 *************************************************************************/
36
37
38 #define FNAMELEN 250
39 #define MAXSFVFILE 1024
40 #define BSDSFV_VERSION "BSDSFV for UNiX, $Revision: 1.18 $"
41 #define MISSINGTAG ".missing"
42 #define BADTAG ".bad"
43
44 typedef struct sfvtable {
45 char filename[FNAMELEN];
46 int crc;
47 int found;
48 } SFVTABLE;
49
50
51 #include <stdlib.h>
52 #include <stdio.h>
53 #include <string.h>
54 #include <time.h>
55 #include <unistd.h>
56 #include <ctype.h>
57 #include <sys/param.h>
58 #include <sys/types.h>
59 #include <sys/stat.h>
60 #include <sys/mman.h>
61 #include <dirent.h>
62
63
64 long
UpdateCRC(unsigned long CRC,const char * buffer,long count)65 UpdateCRC(unsigned long CRC, const char *buffer, long count)
66 {
67 /*
68 * Note: if you want to know how CRC32-checking works, I
69 * recommend grabbing any old (mid 90's) Z-Modem source.
70 * There is not much you can change in this function, so
71 * if you need a CRC32-check yourself, feel free to rip.
72 */
73 unsigned long CRCTABLE[] = {
74 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
75 0x706af48f,
76 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e,
77 0x97d2d988,
78 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064,
79 0x6ab020f2,
80 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551,
81 0x83d385c7,
82 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f,
83 0x63066cd9,
84 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
85 0xa2677172,
86 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa,
87 0x42b2986c,
88 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf,
89 0xabd13d59,
90 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5,
91 0x56b3c423,
92 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2,
93 0xb10be924,
94 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
95 0x01db7106,
96 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5,
97 0xe8b8d433,
98 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb,
99 0x086d3d2d,
100 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8,
101 0xf262004e,
102 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6,
103 0x12b7e950,
104 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
105 0xfbd44c65,
106 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541,
107 0x3dd895d7,
108 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846,
109 0xda60b8d0,
110 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c,
111 0x270241aa,
112 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409,
113 0xce61e49f,
114 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
115 0x2eb40d81,
116 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c,
117 0x74b1d29a,
118 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12,
119 0x94643b84,
120 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27,
121 0x7d079eb1,
122 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d,
123 0x806567cb,
124 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
125 0x67dd4acc,
126 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8,
127 0xa1d1937e,
128 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd,
129 0x48b2364b,
130 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3,
131 0xa867df55,
132 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0,
133 0x5268e236,
134 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
135 0xb2bd0b28,
136 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b,
137 0x5bdeae1d,
138 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9,
139 0xeb0e363f,
140 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae,
141 0x0cb61b38,
142 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4,
143 0xf1d4e242,
144 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
145 0x18b74777,
146 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff,
147 0xf862ae69,
148 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354,
149 0x3903b3c2,
150 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a,
151 0xd9d65adc,
152 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f,
153 0x30b5ffe9,
154 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
155 0xcdd70693,
156 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02,
157 0x2a6f2b94,
158 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
159 };
160
161 if (buffer && count) {
162 do {
163 CRC =
164 ((CRC >> 8) & 0xFFFFFF) ^
165 CRCTABLE[(unsigned char)((CRC & 0xff) ^
166 *buffer++)];
167 }
168 while (--count);
169
170 }
171 return CRC;
172 }
173
174 /* ^ UpdateCRC ^ */
175
176
177
178 long
GetFileCRC(char * filename)179 GetFileCRC(char *filename)
180 {
181 unsigned long crc = 0xffffffff;
182 FILE *f;
183 long totalread = 0;
184 long localread;
185
186 /*
187 * Note: different buffer sizes may result in noticable
188 * different performance depending on system, so feel
189 * free to modify.
190 */
191 #define BUFFERSIZE 65536*16
192 char buffer[BUFFERSIZE];
193
194 if ((f = fopen(filename, "rb")) != NULL) {
195 do {
196 if ((localread = fread(buffer, 1, BUFFERSIZE, f))) {
197 crc = UpdateCRC(crc, buffer, localread);
198 totalread = totalread + localread;
199 }
200 }
201 while (localread > 0);
202 fclose(f);
203
204 crc = crc ^ 0xffffffff;
205 } else { /* error opening file */
206
207 fprintf(stderr, "\nFatal error: cannot read file: %s\n",
208 filename);
209 }
210
211 return crc;
212 }
213
214 int
FileExists(char * name)215 FileExists(char *name)
216 {
217 FILE *testfile;
218
219 testfile = fopen(name, "rb");
220 if (testfile != NULL) {
221 fclose(testfile);
222 return 1;
223 }
224 return 0;
225 }
226
227
228 int
CheckFileExists(char * name,SFVTABLE sfvTable[],int n)229 CheckFileExists(char *name, SFVTABLE sfvTable[], int n)
230 {
231 while (n > 0) {
232 if (!strncasecmp(sfvTable[--n].filename, name, FNAMELEN))
233 return n;
234 }
235 return (-1);
236 }
237
238
239 void
usage(char * prog)240 usage(char *prog)
241 {
242 printf("\nUsage: %s mode [option] sfv-filename [filename...]\n\n",
243 prog);
244 printf
245 ("Possible modes: -c : create SFV file (only read .rar file as default, see -a)\n");
246 printf
247 (" -t : test single file(s) (multiple filenames possible)\n");
248 printf(" -T : test whole SFV file\n");
249 printf(" -m : count missing files\n");
250 printf
251 ("Options: -l <filename> : use <filename> as banner file (create mode)\n");
252 printf
253 (" -w : Win-SFV emulation mode (create mode)\n");
254 printf
255 (" -a : add all files to .sfv (even .nfo etc.) (create mode)\n");
256 printf
257 (" -d : add files' dates & times to SFV file (create mode)\n");
258 printf
259 (" -g : glftpd mode (counting and test whole mode)\n\n");
260 printf("Examples:\n");
261 printf
262 ("(1) Create test.sfv and add test.* to it : %s -c test.sfv test.*\n",
263 prog);
264 printf
265 ("(2) Check file test.r02 against CRC in test.sfv: %s -t test.sfv test.r02\n",
266 prog);
267 printf
268 ("(3) Check all files listed in test.sfv : %s -T test.sfv\n",
269 prog);
270 printf
271 ("(4) Count number of files missing of test.sfv : %s -m test.sfv\n",
272 prog);
273 printf
274 ("(5) Create myrls.sfv with myrls.* in it, use Win-SFV compatibility mode and file\n");
275 printf
276 ("/tmp/mylogo.nfo as banner: %s -c -w -l /tmp/mylogo.nfo myrls.sfv myrls.*\n",
277 prog);
278 printf("\n");
279 printf
280 ("Read documentation files for more help and check for updates regularily!\n\n");
281 return;
282 }
283
284
285 int
main(int argc,char * argv[])286 main(int argc, char *argv[])
287 {
288 int compatmode = 0; // Win-SFV compatibility mode
289 int haslogo = 0; // add banner to created SFVs
290 int glftpdmode = 0; // glftpd mode
291 int doallfiles = 0; // include even crappy files to SFV
292 int addfinfo = 0; // add files' dates & times to SFV
293 char logoname[FNAMELEN]; // filename of bannerfile
294 char sfvname[FNAMELEN]; // name of .sfv file to use
295 char sfvline[FNAMELEN]; // current line in SFV file
296 int mode = 0; // mode of operation
297 int paramcnt = 0; // command line parameter offset
298
299 SFVTABLE sfvTable[MAXSFVFILE];
300 char COMPLETETAG[] = "[000\%]-[-all.files.CRC.ok-]";
301 char OLDTAG[FNAMELEN];
302 char NEWTAG[FNAMELEN];
303
304 FILE *sfvfile;
305 FILE *logofile;
306 FILE *missingfile;
307 DIR *dirp;
308 struct dirent *dp;
309 long mycrc;
310 int cnt;
311 int dothisone;
312 char cfname[FNAMELEN];
313 char crap[FNAMELEN];
314 char precent[5];
315 int numfiles = 0;
316 int badfiles = 0;
317 int msgfiles = 0;
318 int missingfiles = 0;
319 int paramsave;
320 struct stat fileinfo;
321 time_t curtime;
322 struct tm zeit;
323 char mytime[80];
324 char ch;
325
326 // output program name & version number
327 printf("%s\n", BSDSFV_VERSION);
328
329 // parse command line
330 cnt = 0;
331 while ((ch = getopt(argc, argv, "acdgmtTvwl:")) != -1) {
332 switch (ch) {
333 case 'c': // prepare for create mode
334 mode = 1;
335 cnt++;
336 break;
337
338 case 't': // prepare single file test mode
339 mode = 2;
340 cnt++;
341 break;
342
343 case 'T': // prepare sfv file test mode
344 mode = 3;
345 cnt++;
346 break;
347
348 case 'm': // prepare missing file test mode
349 mode = 4;
350 cnt++;
351 break;
352
353 case 'v': // print version and exit
354 exit(0);
355 break;
356
357 case 'l': // set banner file name
358 haslogo = 1;
359 sprintf(logoname, "%s", optarg);
360 break;
361
362 case 'a': // set lame allfiles-add-mode
363 doallfiles = 1;
364 break;
365
366 case 'w': // set win-sfv compatibility mode
367 compatmode = 1;
368 break;
369
370 case 'd': // add files' dates & times to SFV
371 addfinfo = 1;
372 break;
373
374 case 'g': // set glftpd mode
375 glftpdmode = 1;
376 break;
377
378 case '?':
379 default:
380 usage(argv[0]);
381 return 1;
382 break;
383 }
384 }
385
386 if (argc == optind || cnt != 1) {
387 usage(argv[0]);
388 return 1;
389 }
390 argc -= optind;
391 argv += optind;
392
393 strncpy(sfvname, argv[0], FNAMELEN);
394 argc--;
395 argv++;
396
397 if (mode == 1) {
398 printf("\nCreating new checksum file: %s\n", sfvname);
399
400 if (haslogo)
401 printf("Adding banner file : %s\n", logoname);
402
403 if (compatmode)
404 printf("Using compatibility mode : Win-SFV\n");
405
406 if (doallfiles)
407 printf("Add-all-files mode active\n");
408
409 if (addfinfo)
410 printf("Adding files' times & dates to SFV file\n");
411
412 printf("\n");
413
414 sfvfile = fopen(sfvname, "wt");
415 if (sfvfile == NULL) {
416 fprintf
417 (stderr,
418 "Oh mama! We can\'t write to %s (check permissions!), aborting ...\n",
419 sfvname);
420 return 1;
421 }
422
423 time(&curtime);
424 zeit = *localtime(&curtime);
425 strftime(mytime, 50, "%Y-%m-%d at %H:%M.%S", &zeit);
426
427 if (compatmode)
428 fprintf(sfvfile,
429 "; Generated by WIN-SFV32 v1.1a on %s\r\n;\r\n",
430 mytime);
431 else
432 fprintf(sfvfile, "; Generated by %s on %s\r\n;\r\n",
433 BSDSFV_VERSION, mytime);
434
435 if (haslogo) {
436 logofile = fopen(logoname, "rt");
437 if (logofile == NULL) {
438 fprintf
439 (stderr,
440 "Oh mama! I couldn\'t find logo file %s ... omitting!\n",
441 logoname);
442 } else {
443 while (fgets(sfvline, FNAMELEN,
444 logofile) != NULL) {
445 for (cnt = 0; cnt < strlen(sfvline);
446 cnt++)
447 if (sfvline[cnt] == '\n')
448 sfvline[cnt] = '\0';
449 fprintf(sfvfile, "; %s\r\n", sfvline);
450 }
451 fclose(logofile);
452 }
453 } // add logo
454
455 if (addfinfo) {
456 paramsave = paramcnt;
457 while (paramsave < argc) {
458 stat(argv[paramsave], &fileinfo);
459
460 zeit = *localtime(&fileinfo.st_mtime);
461 strftime(mytime, 50, "%H:%M.%S %Y-%m-%d",
462 &zeit);
463
464 fprintf(sfvfile, "; %12d %s %s\r\n",
465 (int)fileinfo.st_size, mytime,
466 argv[paramsave]);
467
468 paramsave++;
469 }
470 fprintf(sfvfile, ";\r\n");
471 }
472
473
474 while (paramcnt < argc) {
475 sprintf(cfname, "%s", argv[paramcnt]);
476
477 // check if we should process this file
478 dothisone = 1;
479 if (!doallfiles) {
480 if (strstr(cfname, ".r") == NULL &&
481 strstr(cfname, ".R") == NULL &&
482 strstr(cfname, ".0") == NULL)
483 dothisone = 0;
484 }
485
486 if (dothisone) {
487 printf("Adding file: %s ... ", cfname);
488 fflush(stdout);
489 mycrc = GetFileCRC(cfname);
490 printf("CRC = 0x%08lX\n", mycrc);
491 sprintf(sfvline, "%s %08lX", cfname, mycrc);
492
493 // uncomment next 2 lines to
494 // convert filename to upper case, for whatever reason
495 // for (cnt = 0; sfvline[cnt] != '\0'; cnt++)
496 // sfvline[cnt] = toupper (sfvline[cnt]);
497
498 fprintf(sfvfile, "%s\r\n", sfvline);
499 numfiles++;
500 }
501 paramcnt++;
502 }
503
504 fclose(sfvfile);
505
506 printf
507 ("\nSFV file successfully created (%d files processed) ...\n\n",
508 numfiles);
509
510 } // create SFV file mode
511
512
513 if (mode == 2) {
514 while (paramcnt < argc) {
515 sprintf(cfname, "%s", argv[paramcnt]);
516 printf("Testing %s ... ", cfname);
517 fflush(stdout);
518 mycrc = GetFileCRC(cfname);
519 printf("local = 0x%08lX, listed = ", mycrc);
520 fflush(stdout);
521
522 sfvfile = fopen(sfvname, "rt");
523 if (sfvfile == NULL) {
524 fprintf(stderr,
525 "Oh mama! I can\'t open %s ... :-(\n",
526 sfvname);
527 return 1;
528 }
529
530 dothisone = 0;
531
532 if (mycrc != 0xffffffff) {
533 while (fgets(sfvline, FNAMELEN,
534 sfvfile) != NULL) {
535 // Skip comments, blank lines, other crap
536 if (sfvline[0] != ';'
537 && sfvline[0] != '#'
538 && sfvline[0] != ' '
539 && strlen(sfvline) > 8) {
540 for (cnt = strlen(sfvline); cnt >= 0 && sfvline[cnt] != ' '; cnt--) ;
541 if (cnt > 0 ) {
542 strncpy(sfvTable[0].filename, sfvline, cnt);
543 sscanf(sfvline+cnt+1, "%X", &sfvTable[0].crc);
544 }
545
546 if (strncasecmp(cfname,
547 sfvTable[0].filename,
548 strlen(cfname)) == 0) {
549 dothisone = 1;
550 sfvTable[0].found = 1;
551 break;
552 }
553 }
554 }
555 }
556
557 if (dothisone) {
558 printf("0x%08X - ", sfvTable[0].crc);
559
560 if (sfvTable[0].crc == mycrc) {
561 printf("OK\n");
562 if (glftpdmode) {
563 sprintf(crap, "%s%s",
564 sfvTable[0].filename,
565 MISSINGTAG);
566 unlink(crap);
567 sprintf(crap, "%s%s",
568 sfvTable[0].filename,
569 BADTAG);
570 unlink(crap);
571 }
572 } else {
573 printf("BAD\n");
574 badfiles++;
575 if (glftpdmode) {
576 sprintf(crap, "%s%s",
577 sfvTable[0].filename,
578 MISSINGTAG);
579 unlink(crap);
580 sprintf(crap, "%s%s",
581 sfvTable[0].filename,
582 BADTAG);
583 rename(cfname, crap);
584 }
585 }
586 } else {
587 printf("MISSING\n");
588 missingfiles++;
589 }
590 numfiles++;
591 paramcnt++;
592 fclose(sfvfile);
593 }
594
595 printf
596 ("\n%d file(s) tested - %d OK - %d bad - %d missing...\n",
597 numfiles, numfiles - badfiles - missingfiles, badfiles,
598 missingfiles);
599 fflush(stdout);
600
601
602 if (badfiles || missingfiles)
603 return 1;
604 return 0;
605 } // test single file(s) mode
606
607
608 if (mode == 3) {
609 printf("\nProcessing complete check of %s ...\n", sfvname);
610
611 if (glftpdmode)
612 printf("Using glftpd mode\n");
613
614 /*
615 * Read the whole sfv file into memory
616 */
617 sfvfile = fopen(sfvname, "rt");
618 if (sfvfile == NULL) {
619 fprintf(stderr, "Oh mama! I can\'t open %s ... :-(\n",
620 sfvname);
621 return 1;
622 }
623 numfiles = 0;
624 while (fgets(sfvline, FNAMELEN, sfvfile) != NULL) {
625 // Skip comments, blank lines, other crap
626 if (sfvline[0] != ';' && sfvline[0] != '#'
627 && sfvline[0] != ' ' && strlen(sfvline) > 8) {
628 sfvTable[cnt].found = 0;
629
630 for (cnt = strlen(sfvline); cnt >= 0 && sfvline[cnt] != ' '; cnt--) ;
631 if (cnt > 0 ) {
632 strncpy(sfvTable[numfiles].filename, sfvline, cnt);
633 sscanf(sfvline+cnt+1, "%X", &sfvTable[numfiles].crc);
634 }
635
636 numfiles++;
637 if (numfiles >= MAXSFVFILE) {
638 printf
639 ("bsdsfv cannot handle more than %d files\n",
640 MAXSFVFILE);
641 return 1;
642 }
643 }
644 };
645 fclose(sfvfile);
646
647 /*
648 * Read current directory file by file
649 */
650 missingfiles = 0;
651 badfiles = 0;
652 OLDTAG[0] = '\0';
653 dirp = opendir(".");
654 while ((dp = readdir(dirp)) != NULL) {
655 if (glftpdmode &&
656 (dp->d_type == DT_DIR || dp->d_type == DT_UNKNOWN)
657 && (strlen(dp->d_name) == strlen(COMPLETETAG))
658 && (dp->d_name[0] == '[')
659 && !strncmp(dp->d_name + 5, COMPLETETAG + 5,
660 strlen(COMPLETETAG) - 5)) {
661 strcpy(OLDTAG, dp->d_name);
662 }
663 if (dp->d_type == DT_REG || dp->d_type == DT_UNKNOWN) {
664 cnt =
665 CheckFileExists(dp->d_name, sfvTable,
666 numfiles);
667 if (cnt >= 0) {
668 sfvTable[cnt].found = 1;
669
670 printf
671 ("Testing %s ... listed = 0x%08X ... ",
672 dp->d_name, sfvTable[cnt].crc);
673
674 fflush(stdout);
675
676 mycrc = GetFileCRC(dp->d_name);
677
678 printf("local = 0x%08lX ... ", mycrc);
679
680 if (mycrc == sfvTable[cnt].crc) {
681 printf("OK\n");
682 } else {
683 if (mycrc == 0xffffffff) {
684 printf("MISSING\n");
685 missingfiles++;
686 } else {
687 printf("BAD\n");
688 badfiles++;
689 }
690 }
691 fflush(stdout);
692 }
693 }
694 }
695 (void)closedir(dirp);
696
697 for (cnt = 0; cnt < numfiles; cnt++) {
698 if (sfvTable[cnt].found) {
699 if (glftpdmode) {
700 sprintf(crap, "%s%s",
701 sfvTable[cnt].filename,
702 MISSINGTAG);
703 unlink(crap);
704 }
705 } else {
706 printf
707 ("Testing %s ... listed = 0x%08X ... Local = MISSING\n",
708 sfvTable[cnt].filename, sfvTable[cnt].crc);
709 missingfiles++;
710 if (glftpdmode) {
711 sprintf(crap, "%s%s",
712 sfvTable[cnt].filename,
713 MISSINGTAG);
714 missingfile = fopen(crap, "w+");
715 if (missingfile != NULL) {
716 fclose(missingfile);
717 }
718 }
719 }
720 }
721
722 if (glftpdmode) {
723 if (numfiles > 0) {
724 cnt =
725 ((numfiles -
726 missingfiles) * 100) / numfiles;
727 if (cnt > 100)
728 cnt = 100;
729 } else {
730 cnt = 0;
731 }
732
733 sprintf(precent, "%.3d", cnt);
734 strcpy(NEWTAG, COMPLETETAG);
735 NEWTAG[1] = precent[0];
736 NEWTAG[2] = precent[1];
737 NEWTAG[3] = precent[2];
738
739 #ifdef DEBUG
740 printf("cnt %d OLD %s NEW %s\n", cnt, OLDTAG, NEWTAG);
741 #endif
742
743 if (strcmp(OLDTAG, NEWTAG)) {
744 rmdir(OLDTAG);
745 if (mkdir(NEWTAG,
746 S_IRWXU | S_IRWXG | S_IRWXO) == 0)
747 chmod(NEWTAG,
748 S_IRWXU | S_IRWXG | S_IRWXO);
749 }
750 printf("Completion Status: %s\n", NEWTAG);
751 }
752
753 printf
754 ("\n%d file(s) tested - %d OK - %d bad - %d missing ...\n\n",
755 numfiles, numfiles - (badfiles + missingfiles), badfiles,
756 missingfiles);
757
758 if (missingfiles)
759 return 2;
760
761 if (badfiles)
762 return 1;
763
764 return 0;
765 }
766
767 /*
768 * test whole SFV file mode
769 */
770 if (mode == 4) {
771 printf("\nPerforming completion check...\n");
772
773 if (glftpdmode)
774 printf("Using glftpd mode\n");
775
776 /*
777 * Read the whole sfv file into memory
778 */
779 sfvfile = fopen(sfvname, "rt");
780 if (sfvfile == NULL) {
781 fprintf(stderr, "Oh mama! I can\'t open %s ... :-(\n",
782 sfvname);
783 return 1;
784 }
785 numfiles = 0;
786 while (fgets(sfvline, FNAMELEN, sfvfile) != NULL) {
787 // Skip comments, blank lines, other crap
788 if (sfvline[0] != ';' && sfvline[0] != '#'
789 && sfvline[0] != ' ' && strlen(sfvline) > 8) {
790 sfvTable[cnt].found = 0;
791 sscanf(sfvline, "%s %X",
792 sfvTable[numfiles].filename,
793 &sfvTable[numfiles].crc);
794 numfiles++;
795 if (numfiles >= MAXSFVFILE) {
796 printf
797 ("bsdsfv cannot handle more than %d files\n",
798 MAXSFVFILE);
799 return 1;
800 }
801 }
802 };
803 fclose(sfvfile);
804
805 /*
806 * Read current directory file by file
807 */
808 OLDTAG[0] = '\0';
809 dirp = opendir(".");
810 while ((dp = readdir(dirp)) != NULL) {
811 if (glftpdmode &&
812 (dp->d_type == DT_DIR || dp->d_type == DT_UNKNOWN)
813 && (strlen(dp->d_name) == strlen(COMPLETETAG))
814 && (dp->d_name[0] == '[')
815 && !strncmp(dp->d_name + 5, COMPLETETAG + 5,
816 strlen(COMPLETETAG) - 5)) {
817 strcpy(OLDTAG, dp->d_name);
818 }
819 if (dp->d_type == DT_REG || dp->d_type == DT_UNKNOWN) {
820 cnt =
821 CheckFileExists(dp->d_name, sfvTable,
822 numfiles);
823 if (cnt >= 0) {
824 sfvTable[cnt].found = 1;
825 }
826 }
827 }
828 (void)closedir(dirp);
829
830 /*
831 * Read the sfv array and create/delete missing tag file as required
832 */
833 for (cnt = 0; cnt < numfiles; cnt++) {
834 if (sfvTable[cnt].found) {
835 msgfiles++;
836 if (glftpdmode) {
837 sprintf(crap, "%s%s",
838 sfvTable[cnt].filename,
839 MISSINGTAG);
840 unlink(crap);
841 }
842 } else {
843 if (glftpdmode) {
844 sprintf(crap, "%s%s",
845 sfvTable[cnt].filename,
846 MISSINGTAG);
847 missingfile = fopen(crap, "w+");
848 if (missingfile != NULL) {
849 fclose(missingfile);
850 }
851 }
852 }
853 }
854
855 /*
856 Make progress directory
857 */
858 if (glftpdmode) {
859 if (numfiles > 0) {
860 cnt = (msgfiles * 100) / numfiles;
861 if (cnt > 100)
862 cnt = 100;
863 } else
864 cnt = 0;
865
866 sprintf(precent, "%.3d", cnt);
867 strcpy(NEWTAG, COMPLETETAG);
868 NEWTAG[1] = precent[0];
869 NEWTAG[2] = precent[1];
870 NEWTAG[3] = precent[2];
871
872 #ifdef DEBUG
873 printf("cnt %d OLD %s NEW %s\n", cnt, OLDTAG, NEWTAG);
874 #endif
875
876 if (strcmp(OLDTAG, NEWTAG)) {
877 rmdir(OLDTAG);
878 if (mkdir(NEWTAG,
879 S_IRWXU | S_IRWXG | S_IRWXO) == 0)
880 chmod(NEWTAG,
881 S_IRWXU | S_IRWXG | S_IRWXO);
882 }
883 printf("Completion Status: %s\n", NEWTAG);
884 } else {
885 printf
886 ("[total files listed] [local files] [missing files]\n%-4d %-4d %-4d\n",
887 numfiles, msgfiles, numfiles - msgfiles);
888 }
889 return 0;
890 } /* count files mode */
891 return 0;
892 }
893