00001
00002
00003
00004
00005
00006
00007
00008
00009 #include <fcntl.h>
00010 #include <stdio.h>
00011 #include <stdlib.h>
00012 #include <unistd.h>
00013 #include <apr_md5.h>
00014 #include <sys/mman.h>
00015
00016 #include "checksum.h"
00017 #include "helper.h"
00018 #include "global.h"
00019 #include "est_ops.h"
00020 #include "waa.h"
00021
00022
00026 #define MAPSIZE (256*1024*1024)
00027
00028
00029
00032 struct t_manber_parms
00033 {
00034 AC_CV_C_UINT32_T values[256];
00035 };
00036
00039 struct t_manber_data
00040 {
00042 struct estat *sts;
00044 svn_stream_t *input;
00046 off_t last_fpos;
00048 off_t fpos;
00049
00051 apr_md5_ctx_t full_md5_ctx;
00053 md5_digest_t full_md5;
00054
00056 apr_md5_ctx_t block_md5_ctx;
00058 md5_digest_t block_md5;
00059
00061 int manber_fd;
00062
00063
00065 AC_CV_C_UINT32_T state;
00067 AC_CV_C_UINT32_T last_state;
00069 int bktrk_bytes;
00071 int bktrk_last;
00073 unsigned char backtrack[CS__MANBER_BACKTRACK];
00078 int data_bits;
00079 };
00080
00082 struct t_manber_parms manber_parms;
00083
00084
00088 static struct t_manber_data cs___manber;
00089
00090
00092 const char cs___mb_wr_format[]= "%s %08x %10llu %10llu\n";
00094 const char cs___mb_rd_format[]= "%*s%n %x %llu %llu\n";
00095
00104 #define MANBER_LINELEN (APR_MD5_DIGESTSIZE*2+1 + 8+1 + 10+1 +10+1 + 1)
00105
00106
00108 int cs___manber_data_init(struct t_manber_data *mbd,
00109 struct estat *sts);
00111 int cs___end_of_block(const unsigned char *data, int maxlen,
00112 int *eob,
00113 struct t_manber_data *mb_f);
00114
00115
00119 inline static int cs__hex2val(char ch)
00120 {
00121
00122
00123
00124
00125
00126
00127
00128 static const signed char values[256]={
00129
00130 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
00131 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
00132
00133 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
00134
00135 +0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
00136
00137 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
00138 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
00139
00140 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
00141 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
00142
00143
00144 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
00145 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
00146 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
00147 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
00148
00149 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
00150 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
00151 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
00152 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
00153 };
00154
00155
00156 return values[ ch & 0xff ];
00157 }
00158
00159
00163 inline int cs__two_ch2bin(char *stg)
00164 {
00165 return
00166 (cs__hex2val(stg[0]) << 4) |
00167 (cs__hex2val(stg[1]) << 0);
00168 }
00169
00170
00173 int cs__char2md5(const char *input, char **eos, md5_digest_t md5)
00174 {
00175 int i, status, x, y;
00176
00177
00178 status=0;
00179 for(i=0; i<APR_MD5_DIGESTSIZE; i++)
00180 {
00181
00182
00183 x=cs__hex2val(input[0]);
00184 y=cs__hex2val(input[1]);
00185
00186
00187
00188
00189 STOPIF_CODE_ERR( (y|x) == -1, EINVAL,
00190 "Illegal hex characters in %c%c", input[0], input[1]);
00191
00192 input+=2;
00193 md5[i]=(x<<4) | y;
00194 }
00195
00196
00197
00198
00199 if (eos) *eos=(char*)input;
00200
00201 ex:
00202 return status;
00203 }
00204
00205
00207 char* cs__md5tohex(const md5_digest_t md5, char *dest)
00208 {
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218 sprintf(dest,
00219 "%02x" "%02x" "%02x" "%02x"
00220 "%02x" "%02x" "%02x" "%02x"
00221 "%02x" "%02x" "%02x" "%02x"
00222 "%02x" "%02x" "%02x" "%02x"
00223 ,
00224 md5[4*0+0], md5[4*0+1], md5[4*0+2], md5[4*0+3],
00225 md5[4*1+0], md5[4*1+1], md5[4*1+2], md5[4*1+3],
00226 md5[4*2+0], md5[4*2+1], md5[4*2+2], md5[4*2+3],
00227 md5[4*3+0], md5[4*3+1], md5[4*3+2], md5[4*3+3]
00228 );
00229 #if 0
00230 int i;
00231
00232
00233 for (i=0; i<APR_MD5_DIGESTSIZE; i++)
00234 {
00235 sprintf(cur+i*2, "%02x", md5[i]);
00236 }
00237 #endif
00238
00239 return dest;
00240 }
00241
00242
00250 char *cs__md5tohex_buffered(const md5_digest_t md5)
00251 {
00252 static int last=0;
00253 static char stg[4][APR_MD5_DIGESTSIZE*2+1] = { { 0 } };
00254 char *cur;
00255
00256 last++;
00257 if (last >= sizeof(stg)/sizeof(stg[0])) last=0;
00258 cur=stg[last];
00259
00260 return cs__md5tohex(md5, cur);
00261 }
00262
00263
00268 int cs___finish_manber(struct t_manber_data *mb_f)
00269 {
00270 int status;
00271
00272 status=0;
00273 STOPIF( apr_md5_final(mb_f->full_md5, & mb_f->full_md5_ctx),
00274 "apr_md5_final failed");
00275 if (mb_f->sts)
00276 memcpy(mb_f->sts->md5, mb_f->full_md5, sizeof(mb_f->sts->md5));
00277
00278 mb_f->sts=NULL;
00279
00280 ex:
00281 return status;
00282 }
00283
00284
00303 int cs__compare_file(struct estat *sts, char *fullpath, int *result)
00304 {
00305 int i, status, fh;
00306 unsigned length_mapped, map_pos, hash_pos;
00307 off_t current_pos;
00308 struct cs__manber_hashes mbh_data;
00309 unsigned char *filedata;
00310 int do_manber;
00311 char *cp;
00312 struct sstat_t actual;
00313 md5_digest_t old_md5 = { 0 };
00314 static struct t_manber_data mb_dat;
00315
00316
00317
00318 if (result) *result = -1;
00319
00320
00321 if (S_ISDIR(sts->st.mode)) return 0;
00322
00323 fh=-1;
00324
00325 if (sts->change_flag != CF_UNKNOWN)
00326 {
00327 DEBUGP("change flag for %s: %d", fullpath, sts->change_flag);
00328 goto ret_result;
00329 }
00330
00331 status=0;
00332
00333 if (!fullpath)
00334 STOPIF( ops__build_path(&fullpath, sts), NULL);
00335
00336 DEBUGP("checking for modification on %s", fullpath);
00337
00338 DEBUGP("hashing %s",fullpath);
00339 memcpy(old_md5, sts->md5, sizeof(old_md5));
00340
00341
00342
00343
00344 STOPIF( hlp__lstat(fullpath, &actual), NULL);
00345
00346 if (S_ISREG(actual.mode))
00347 {
00348 do_manber=1;
00349
00350
00351
00352
00353
00354 if (actual.size < CS__MIN_FILE_SIZE)
00355 do_manber=0;
00356 else
00357 {
00358 status=cs__read_manber_hashes(sts, &mbh_data);
00359 if (status == ENOENT)
00360 do_manber=0;
00361 else
00362 STOPIF(status, "reading manber-hash data for %s", fullpath);
00363 }
00364
00365 hash_pos=0;
00366 STOPIF( cs___manber_data_init(&mb_dat, sts), NULL );
00367
00368
00369 current_pos=0;
00370
00371 fh=open(fullpath, O_RDONLY);
00372
00373
00374 if (fh<0)
00375 {
00376
00377
00378 status=errno;
00379 DEBUGP("File %s is unreadable: %d", fullpath, status);
00380 if (status == EACCES)
00381 {
00382 status=0;
00383 goto ex;
00384 }
00385
00386
00387 if (!status) status=EBUSY;
00388 STOPIF(status, "open(\"%s\", O_RDONLY) failed", fullpath);
00389 }
00390
00391 status=0;
00392 while (current_pos < actual.size)
00393 {
00394 if (actual.size-current_pos < MAPSIZE)
00395 length_mapped=actual.size-current_pos;
00396 else
00397 length_mapped=MAPSIZE;
00398 DEBUGP("mapping %u bytes from %llu",
00399 length_mapped, (t_ull)current_pos);
00400
00401 filedata=mmap(NULL, length_mapped,
00402 PROT_READ, MAP_SHARED,
00403 fh, current_pos);
00404 if (filedata == MAP_FAILED) break;
00405
00406 map_pos=0;
00407 while (map_pos<length_mapped)
00408 {
00409 STOPIF( cs___end_of_block(filedata+map_pos,
00410 length_mapped-map_pos,
00411 &i, &mb_dat ),
00412 NULL);
00413
00414 if (i==-1) break;
00415
00416 if (do_manber)
00417 {
00418 DEBUGP(" old hash=%08X current hash=%08X",
00419 mbh_data.hash[hash_pos], mb_dat.last_state);
00420 DEBUGP(" old end=%llu current end=%llu",
00421 (t_ull)mbh_data.end[hash_pos],
00422 (t_ull)mb_dat.fpos);
00423 DEBUGP(" old md5=%s current md5=%s",
00424 cs__md5tohex_buffered(mbh_data.md5[hash_pos]),
00425 cs__md5tohex_buffered(mb_dat.block_md5));
00426
00427 if (mb_dat.last_state != mbh_data.hash[hash_pos] ||
00428 mb_dat.fpos != mbh_data.end[hash_pos] ||
00429 memcmp(mb_dat.block_md5,
00430 mbh_data.md5[hash_pos],
00431 APR_MD5_DIGESTSIZE) != 0)
00432 {
00433 DEBUGP("found a different block before %llu:",
00434 (t_ull)(current_pos+i));
00435 changed:
00436 sts->md5[0] ^= 0x1;
00437 i=-2;
00438 break;
00439 }
00440
00441
00442 DEBUGP("block #%u ok...", hash_pos);
00443 hash_pos++;
00444
00445
00446
00447 if (hash_pos > mbh_data.count)
00448 goto changed;
00449 }
00450
00451
00452
00453 STOPIF( cs___end_of_block(NULL, 0, NULL, &mb_dat), NULL );
00454
00455 map_pos+=i;
00456 }
00457 if (i==-2) break;
00458
00459 STOPIF_CODE_ERR( munmap((void*)filedata, length_mapped) == -1,
00460 errno, "unmapping of file failed");
00461 current_pos+=length_mapped;
00462 }
00463
00464 STOPIF( cs___finish_manber( &mb_dat), NULL);
00465 }
00466 else if (S_ISLNK(sts->st.mode))
00467 {
00468 STOPIF( ops__link_to_string(sts, fullpath, &cp), NULL);
00469
00470 apr_md5(sts->md5, cp, strlen(cp));
00471 }
00472 else
00473 {
00474 DEBUGP("nothing to hash for %s", fullpath);
00475 }
00476
00477 sts->change_flag = memcmp(old_md5, sts->md5, sizeof(sts->md5)) == 0 ?
00478 CF_NOTCHANGED : CF_CHANGED;
00479 DEBUGP("change flag for %s set to %d", fullpath, sts->change_flag);
00480
00481
00482 ret_result:
00483 if (result)
00484 *result = sts->change_flag == CF_CHANGED;
00485 DEBUGP("comparing %s=%d: md5 %s",
00486 fullpath, sts->change_flag == CF_CHANGED,
00487 cs__md5tohex_buffered(sts->md5));
00488 status=0;
00489
00490 ex:
00491 if (fh>=0) close(fh);
00492
00493 return status;
00494 }
00495
00496
00500 int cs__set_file_committed(struct estat *sts)
00501 {
00502 int status;
00503
00504 status=0;
00505 if (S_ISDIR(sts->st.mode)) goto ex;
00506
00507
00508 sts->flags &= ~(RF_CHECK | RF_PUSHPROPS);
00509
00510 sts->repos_rev=SET_REVNUM;
00511
00512 ex:
00513 return status;
00514 }
00515
00516
00517
00518
00519
00520
00521
00522 int cs___manber_data_init(struct t_manber_data *mbd,
00523 struct estat *sts)
00524 {
00525 int status;
00526
00527 memset(mbd, 0, sizeof(*mbd));
00528 mbd->manber_fd=-1;
00529
00530 BUG_ON(mbd->sts, "manber structure already in use!");
00531 mbd->sts=sts;
00532 mbd->fpos= mbd->last_fpos= 0;
00533 apr_md5_init(& mbd->full_md5_ctx);
00534 STOPIF( cs___end_of_block(NULL, 0, NULL, mbd), NULL );
00535
00536 ex:
00537 return status;
00538 }
00539
00540
00541 void cs___manber_init(struct t_manber_parms *mb_d)
00542 {
00543 int i;
00544 AC_CV_C_UINT32_T p;
00545
00546 if (mb_d->values[0]) return;
00547
00548
00549
00550 for(p=1,i=0; i<CS__MANBER_BACKTRACK; i++)
00551 p=(p * CS__MANBER_PRIME) & CS__MANBER_MODULUS;
00552
00553
00554 for(i=0x00; i<0xff; i++)
00555 mb_d->values[i]=(i*p) & CS__MANBER_MODULUS;
00556 }
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569 int cs___end_of_block(const unsigned char *data, int maxlen,
00570 int *eob,
00571 struct t_manber_data *mb_f)
00572 {
00573 int status;
00574 int i;
00575
00576
00577 status=0;
00578 if (!data)
00579 {
00580 DEBUGP("manber reinit");
00581 mb_f->state=0;
00582 mb_f->last_state=0;
00583 mb_f->bktrk_bytes=0;
00584 mb_f->bktrk_last=0;
00585 mb_f->data_bits=0;
00586 apr_md5_init(& mb_f->block_md5_ctx);
00587 memset(mb_f->block_md5, 0, sizeof(mb_f->block_md5));
00588 cs___manber_init(&manber_parms);
00589 goto ex;
00590 }
00591
00592
00593 *eob = -1;
00594 i=0;
00595
00596
00597 while (i<maxlen &&
00598 mb_f->bktrk_bytes < CS__MANBER_BACKTRACK)
00599 {
00600
00601
00602
00603 mb_f->data_bits |= data[i];
00604
00605 mb_f->state = (mb_f->state * CS__MANBER_PRIME +
00606 data[i] ) % CS__MANBER_MODULUS;
00607 mb_f->backtrack[ mb_f->bktrk_last ] = data[i];
00608
00609
00610
00611
00612
00613 mb_f->bktrk_last = ( mb_f->bktrk_last + 1 ) &
00614 (CS__MANBER_BACKTRACK - 1);
00615 mb_f->bktrk_bytes++;
00616 i++;
00617 }
00618
00619 if (!mb_f->data_bits)
00620 {
00621
00622
00623
00624 while (i<maxlen && !data[i]) i++;
00625
00626 if (i < maxlen)
00627 {
00628 *eob=i;
00629 DEBUGP("zero block border at %d", i);
00630 }
00631 }
00632 else
00633 {
00634 while(i<maxlen)
00635 {
00636
00637
00638
00639
00640
00641
00642
00643
00644 mb_f->last_state=mb_f->state;
00645 mb_f->state = (mb_f->state*CS__MANBER_PRIME + data[i] -
00646 manber_parms.values[ mb_f->backtrack[ mb_f->bktrk_last ] ] )
00647 % CS__MANBER_MODULUS;
00648 mb_f->backtrack[ mb_f->bktrk_last ] = data[i];
00649 mb_f->bktrk_last = ( mb_f->bktrk_last + 1 ) &
00650 (CS__MANBER_BACKTRACK - 1);
00651
00652 i++;
00653
00654
00655 if ( !(mb_f->state & CS__MANBER_BITMASK) )
00656 {
00657 *eob=i;
00658 apr_md5_update(& mb_f->block_md5_ctx, data, i);
00659 apr_md5_final( mb_f->block_md5, & mb_f->block_md5_ctx);
00660 DEBUGP("manber found a border: %u %08X %08X %s",
00661 i, mb_f->last_state, mb_f->state, cs__md5tohex_buffered(mb_f->block_md5));
00662 break;
00663 }
00664 }
00665
00666
00667 if (*eob == -1)
00668 apr_md5_update(& mb_f->block_md5_ctx, data, i);
00669 }
00670
00671
00672 apr_md5_update(& mb_f->full_md5_ctx, data, i);
00673 mb_f->fpos += (*eob == -1) ? maxlen : *eob;
00674
00675 ex:
00676 DEBUGP("on return at fpos=%llu: %08X (databits=%2x)",
00677 (t_ull)mb_f->fpos, mb_f->state, mb_f->data_bits);
00678 return status;
00679 }
00680
00681
00682 int cs___update_manber(struct t_manber_data *mb_f,
00683 const unsigned char *data, apr_size_t len)
00684 {
00685 int status;
00686 int eob, i;
00687
00688
00689
00690
00691 char buffer[MANBER_LINELEN+10];
00692 char *filename;
00693
00694 status=0;
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714 DEBUGP("got a block with %llu bytes", (t_ull)len);
00715 while (1)
00716 {
00717 #if 0
00718
00719 if (mb_f->fpos == 0 && len<32*1024)
00720 eob=-1;
00721 else
00722 #endif
00723 STOPIF( cs___end_of_block(data, len, &eob, mb_f), NULL );
00724
00725 if (eob == -1)
00726 {
00727 DEBUGP("block continues after %lu.", (unsigned long)mb_f->fpos);
00728 break;
00729 }
00730
00731 data += eob;
00732 len -= eob;
00733 DEBUGP("block ends after %lu; size %lu bytes (border=%u).",
00734 (unsigned long)mb_f->fpos,
00735 (unsigned long)(mb_f->fpos - mb_f->last_fpos),
00736 eob);
00737
00738
00739 i=sprintf(buffer, cs___mb_wr_format,
00740 cs__md5tohex_buffered(mb_f->block_md5),
00741 mb_f->last_state,
00742 (t_ull)mb_f->last_fpos,
00743 (t_ull)(mb_f->fpos - mb_f->last_fpos));
00744 BUG_ON(i > sizeof(buffer)-3, "Buffer too small - stack overrun");
00745
00746 if (mb_f->manber_fd == -1)
00747 {
00748
00749
00750
00751 STOPIF( ops__build_path(&filename, mb_f->sts), NULL);
00752 STOPIF( waa__open_byext(filename, WAA__FILE_MD5s_EXT, WAA__WRITE,
00753 & cs___manber.manber_fd), NULL );
00754 DEBUGP("now doing manber-hashing for %s...", filename);
00755 }
00756
00757 STOPIF_CODE_ERR( write( mb_f->manber_fd, buffer, i) != i,
00758 errno, "writing to manber hash file");
00759
00760
00761 STOPIF( cs___end_of_block(NULL, 0, NULL, mb_f), NULL );
00762 mb_f->last_fpos = mb_f->fpos;
00763 }
00764
00765 ex:
00766 return status;
00767 }
00768
00769
00770 svn_error_t *cs___mnbs_close(void *baton);
00771
00772
00773 svn_error_t *cs___mnbs_read(void *baton,
00774 char *data, apr_size_t *len)
00775 {
00776 int status;
00777 svn_error_t *status_svn;
00778 struct t_manber_data *mb_f=baton;
00779
00780 status=0;
00781
00782 STOPIF_SVNERR( svn_stream_read,
00783 (mb_f->input, data, len) );
00784 if (*len && data)
00785 STOPIF( cs___update_manber(mb_f, (unsigned char*)data, *len), NULL);
00786 else
00787 STOPIF_SVNERR( cs___mnbs_close, (baton));
00788 ex:
00789 RETURN_SVNERR(status);
00790 }
00791
00792
00793 svn_error_t *cs___mnbs_write(void *baton,
00794 const char *data, apr_size_t *len)
00795 {
00796 int status;
00797 svn_error_t *status_svn;
00798 struct t_manber_data *mb_f=baton;
00799
00800 status=0;
00801
00802
00803
00804
00805 STOPIF_SVNERR( svn_stream_write,
00806 (mb_f->input, data, len) );
00807 if (*len && data)
00808 STOPIF( cs___update_manber(mb_f, (unsigned char*)data, *len), NULL);
00809 else
00810 STOPIF_SVNERR( cs___mnbs_close, (baton));
00811 ex:
00812 RETURN_SVNERR(status);
00813 }
00814
00815
00816 svn_error_t *cs___mnbs_close(void *baton)
00817 {
00818 int status;
00819 svn_error_t *status_svn;
00820 struct t_manber_data *mb_f=baton;
00821
00822 status=0;
00823
00824
00825
00826 if (mb_f->manber_fd != -1)
00827 {
00828 STOPIF( waa__close(mb_f->manber_fd,
00829 mb_f->fpos < CS__MIN_FILE_SIZE ? ECANCELED :
00830 status != 0), NULL );
00831 mb_f->manber_fd=-1;
00832 }
00833
00834 if (mb_f->input)
00835 {
00836 STOPIF_SVNERR( svn_stream_close,
00837 (mb_f->input) );
00838 mb_f->input=NULL;
00839 }
00840
00841 STOPIF( cs___finish_manber(mb_f), NULL);
00842
00843 ex:
00844 RETURN_SVNERR(status);
00845 }
00846
00847
00860 int cs__new_manber_filter(struct estat *sts,
00861 svn_stream_t *stream_input,
00862 svn_stream_t **filter_stream,
00863 apr_pool_t *pool)
00864 {
00865 int status;
00866 svn_stream_t *new_str;
00867 char *filename;
00868
00869
00870 status=0;
00871 STOPIF( cs___manber_data_init(&cs___manber, sts),
00872 "manber-data-init failed");
00873
00874 cs___manber.input=stream_input;
00875
00876 new_str=svn_stream_create(&cs___manber, pool);
00877 STOPIF_ENOMEM( !new_str );
00878
00879 svn_stream_set_read(new_str, cs___mnbs_read);
00880 svn_stream_set_write(new_str, cs___mnbs_write);
00881 svn_stream_set_close(new_str, cs___mnbs_close);
00882
00883 STOPIF( ops__build_path(&filename, sts), NULL);
00884 DEBUGP("initiating MD5 streaming for %s", filename);
00885
00886 *filter_stream=new_str;
00887
00888
00889
00890
00891
00892 ex:
00893 return status;
00894 }
00895
00896
00985 int cs__read_manber_hashes(struct estat *sts, struct cs__manber_hashes *data)
00986 {
00987 int status;
00988 char *filename;
00989 int fh, i, spp;
00990 unsigned estimated, count;
00991 t_ull length, start;
00992 char buffer[MANBER_LINELEN+10], *cp;
00993 AC_CV_C_UINT32_T value;
00994
00995
00996 status=0;
00997 memset(data, 0, sizeof(*data));
00998 fh=-1;
00999
01000 STOPIF( ops__build_path(&filename, sts), NULL);
01001
01002 status=waa__open_byext(filename, WAA__FILE_MD5s_EXT, WAA__READ, &fh);
01003 if (status == ENOENT) goto ex;
01004 STOPIF( status, "reading md5s-file for %s", filename);
01005
01006 DEBUGP("reading manber-hashes for %s", filename);
01007
01008
01009
01010
01011
01012
01013 length=lseek(fh, 0, SEEK_END);
01014 STOPIF_CODE_ERR( length==-1, errno,
01015 "Cannot get length of file %s", filename);
01016 STOPIF_CODE_ERR( lseek(fh, 0, SEEK_SET), errno,
01017 "Cannot seek in file %s", filename);
01018
01019 estimated = length*21/(MANBER_LINELEN*20)+4;
01020 DEBUGP("estimated %u manber-hashes from filelen %llu",
01021 estimated, length);
01022
01023
01024 STOPIF( hlp__calloc( &data->hash, estimated, sizeof(*data->hash)), NULL);
01025 STOPIF( hlp__calloc( & data->md5, estimated, sizeof( *data->md5)), NULL);
01026 STOPIF( hlp__calloc( & data->end, estimated, sizeof( *data->end)), NULL);
01027
01028
01029 count=0;
01030 while (1)
01031 {
01032 i=read(fh, buffer, sizeof(buffer)-1);
01033 STOPIF_CODE_ERR( i==-1, errno,
01034 "reading manber-hash data");
01035 if (i==0) break;
01036
01037
01038 buffer[i]=0;
01039 cp=strchr(buffer, '\n');
01040 STOPIF_CODE_ERR(!cp, EINVAL,
01041 "line %u is invalid", count+1 );
01042
01043
01044 STOPIF_CODE_ERR( lseek(fh,
01045 -i
01046 + (cp-buffer)
01047 + 1,
01048 SEEK_CUR) == -1, errno,
01049 "lseek back failed");
01050 *cp=0;
01051
01052 i=sscanf(buffer, cs___mb_rd_format,
01053 &spp, &value, &start, &length);
01054 STOPIF_CODE_ERR( i != 3, EINVAL,
01055 "cannot parse line %u for %s", count+1, filename);
01056
01057 data->hash[count]=value;
01058 data->end[count]=start+length;
01059 buffer[spp]=0;
01060 STOPIF( cs__char2md5(buffer, NULL, data->md5[count]), NULL);
01061 count++;
01062 BUG_ON(count > estimated, "lines should have syntax errors - bug in estimation.");
01063 }
01064
01065 data->count=count;
01066 DEBUGP("read %u entry tuples.", count);
01067
01068 if (estimated-count > 3)
01069 {
01070 DEBUGP("reallocating...");
01071
01072 STOPIF( hlp__realloc( &data->hash, count*sizeof(*data->hash)), NULL);
01073 STOPIF( hlp__realloc( & data->md5, count*sizeof(* data->md5)), NULL);
01074 STOPIF( hlp__realloc( & data->end, count*sizeof(* data->end)), NULL);
01075 }
01076
01077
01078
01079 ex:
01080 if (status)
01081 {
01082 IF_FREE(data->hash);
01083 IF_FREE(data->md5);
01084 IF_FREE(data->end);
01085 }
01086
01087 if (fh != -1)
01088 STOPIF_CODE_ERR( close(fh) == -1, errno,
01089 "Cannot close manber hash file (fd=%d)", fh);
01090 return status;
01091 }
01092