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