00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 #include <stdio.h>
00010 #include <fcntl.h>
00011 #include <unistd.h>
00012 #include <ctype.h>
00013 #include <dlfcn.h>
00014 #include <netdb.h>
00015 #include <time.h>
00016 #include <sys/types.h>
00017 #include <grp.h>
00018 #include <poll.h>
00019 #include <pwd.h>
00020 #include <apr_file_io.h>
00021 #include <apr_md5.h>
00022 #include <subversion-1/svn_config.h>
00023 
00024 #include "global.h"
00025 #include "waa.h"
00026 #include "est_ops.h"
00027 #include "options.h"
00028 #include "interface.h"
00029 #include "checksum.h"
00030 #include "helper.h"
00031 #include "cache.h"
00032 
00033 
00037 
00038 #ifdef HAVE_LOCALES
00039 #include <iconv.h>
00040 #endif
00041 
00042 
00043 #ifdef HAVE_LOCALES
00044 
00048 int hlp___get_conv_handle(const char* from_charset, 
00049         const char* to_charset,
00050         iconv_t* cd)
00051 {
00052     int status;
00053 
00054     status=0;
00055     *cd = iconv_open(to_charset, from_charset);
00056     STOPIF_CODE_ERR( *cd == (iconv_t)-1, errno,
00057             "Conversion from %s to %s is not supported",
00058             from_charset, to_charset);
00059 
00060 ex:
00061     return status;
00062 }
00063 
00064 
00087 inline int hlp___do_convert(iconv_t cd, 
00088         const char* from, char** to, 
00089         int len)
00090 {
00091     static struct cache_t *cache;
00092     int status;
00093     char* to_buf;
00094     const char* from_buf;
00095     size_t srclen_rem, dstlen_rem;
00096     int iconv_ret, i, done;
00097     struct cache_entry_t *ent;
00098 
00099 
00100     STOPIF( cch__new_cache(&cache, 8), NULL);
00101 
00102     
00103     if (!from)
00104     {
00105         *to = NULL;
00106         goto ex;
00107     }
00108 
00109 
00110     srclen_rem = len == -1 ? strlen(from)+1 : len;
00111     from_buf=from;
00112 
00113     STOPIF( cch__add(cache, 0, NULL, srclen_rem, &to_buf), NULL);
00114     ent=cache->entries[cache->lru];
00115 
00116     
00117     while(srclen_rem)
00118     {
00119         done=to_buf - ent->data;
00120 
00121         
00122         if (ent->len - done < srclen_rem)
00123         {
00124             
00125             i=ent->len + 2*srclen_rem + 16;
00126 
00127             
00128 
00129 
00130             i = i < 256 ? 256 : i;
00131 
00132             STOPIF( cch__entry_set(cache->entries + cache->lru,
00133                         0, NULL, i, 1, &to_buf), NULL);
00134             ent=cache->entries[cache->lru];
00135 
00136             
00137 
00138 
00139             to_buf=ent->data+done;
00140         }
00141 
00142         
00143         dstlen_rem=ent->len - done;
00144 
00145         
00146 
00147         DEBUGP("before iconv from=%-*.*s", 
00148                 (int)srclen_rem, (int)srclen_rem, from_buf);
00149         
00150         iconv_ret = iconv(cd,
00151                 (char**)&from_buf, &srclen_rem,
00152                 &to_buf, &dstlen_rem);
00153         DEBUGP("after iconv to=%s ret=%d", 
00154                 ent->data,
00155                 iconv_ret);
00156 
00157         
00158         if (iconv_ret == -1)
00159         {
00160             
00161 
00162 
00163 
00164 
00165             STOPIF_CODE_ERR( errno != E2BIG, errno,
00166                     "Conversion of string failed. "
00167                     "Next bytes are \\x%02X\\x%02X\\x%02X\\x%02X",
00168                     srclen_rem>=1 ? from_buf[0] : 0,
00169                     srclen_rem>=2 ? from_buf[1] : 0,
00170                     srclen_rem>=3 ? from_buf[2] : 0,
00171                     srclen_rem>=4 ? from_buf[3] : 0
00172                     );
00173 
00174             
00175 
00176         }
00177     }
00178 
00179 
00180     
00181     *to_buf=0;
00182 
00183     
00184     *to=ent->data;
00185     DEBUGP("converted %*.*s to %s", len, len, from, *to);
00186 
00187 ex:
00188     
00189     iconv(cd, NULL, NULL, NULL, NULL);
00190 
00191     return status;
00192 }
00193 
00194 
00200 int hlp___dummy_convert(const char *input, char**output, int len)
00201 {
00202     int status;
00203     static struct cache_t *cache;
00204 
00205 
00206     status=0;
00207     if (!input) 
00208         *output=NULL;
00209     else
00210     {
00211         if (len == -1)
00212             len=strlen(input)+1;
00213 
00214         STOPIF( cch__new_cache(&cache, 8), NULL);
00215         STOPIF( cch__add(cache, 0, input, len+1, output), NULL);
00216         (*output)[len]=0;
00217     }
00218 
00219 ex:
00220     return status;
00221 }
00222 
00223 
00227 int hlp__local2utf8(const char *local_string, char** utf8_string, int len)
00228 {
00229     static iconv_t iconv_cd = NULL;
00230     int status;
00231 
00232     status=0;
00233     if (!local_codeset)
00234         STOPIF( hlp___dummy_convert(local_string, utf8_string, len), NULL);
00235     else
00236     {
00237         if (!iconv_cd)
00238         {
00239             STOPIF( hlp___get_conv_handle( local_codeset, "UTF-8", &iconv_cd),
00240                     NULL);
00241         }
00242 
00243         STOPIF( hlp___do_convert(iconv_cd, local_string, utf8_string, len), 
00244                 NULL);
00245     }
00246 
00247 ex:
00248     return status;
00249 }
00250 
00251 
00255 int hlp__utf82local(const char *utf8_string, char** local_string, int len)
00256 {
00257     static iconv_t iconv_cd = NULL;
00258     int status;
00259 
00260     status=0;
00261     if (!local_codeset)
00262         STOPIF( hlp___dummy_convert(utf8_string, local_string, len), NULL);
00263     else
00264     {
00265         
00266         if (!iconv_cd)
00267         {
00268             STOPIF( hlp___get_conv_handle( "UTF-8", local_codeset, &iconv_cd),
00269                     NULL);
00270         }
00271 
00272         STOPIF( hlp___do_convert(iconv_cd, utf8_string, local_string, len),
00273                 NULL);
00274     }
00275 
00276 ex:
00277     return status;
00278 }
00279 #else
00280 
00281 int hlp__local2utf8(const char *local_string, char** utf8_string, int len)
00282 {
00283     static cache_entry_t *c=NULL;
00284 
00285     return cch__entry_set( &c, 0, local_string, len, 0, utf8_string);
00286 }
00287 
00288 int hlp__utf82local(const char *utf8_string, char** local_string, int len)
00289 {
00290     return hlp__local2utf8(utf8_string, local_string, len);
00291 }
00292 #endif
00293 
00294 
00297     inline void __attribute__((always_inline)) 
00298 hlp__copy_stats(struct stat *src, struct sstat_t *dest) 
00299 {
00300     if (S_ISCHR(src->st_mode) || S_ISBLK(src->st_mode)) 
00301         dest->rdev=src->st_rdev;
00302     else
00303         dest->size=src->st_size;
00304 
00305     dest->mode=src->st_mode;
00306 
00307     dest->dev=src->st_dev;
00308     dest->ino=src->st_ino;
00309 
00310     dest->uid=src->st_uid;
00311     dest->gid=src->st_gid;
00312 
00313 #ifdef HAVE_STRUCT_STAT_ST_MTIM
00314     dest->mtim=src->st_mtim;
00315     dest->ctim=src->st_ctim;
00316 #else
00317     dest->mtim.tv_sec=src->st_mtime;
00318     dest->mtim.tv_nsec=0;
00319     dest->ctim.tv_sec=src->st_ctime;
00320     dest->ctim.tv_nsec=0;
00321 #endif
00322 }
00323 
00324 
00341 int hlp__lstat(const char *fn, struct sstat_t *st)
00342 {
00343     int status;
00344     struct stat st64;
00345 
00346     status=lstat(fn, &st64);
00347     if (status == 0) 
00348     {
00349         DEBUGP("%s: uid=%llu gid=%llu mode=0%llo dev=0x%llx "
00350                 "ino=%llu rdev=0x%llx size=%llu",
00351                 fn,
00352                 (t_ull)st64.st_uid, (t_ull)st64.st_gid, (t_ull)st64.st_mode, 
00353                 (t_ull)st64.st_dev, (t_ull)st64.st_ino, 
00354                 (t_ull)st64.st_rdev, (t_ull)st64.st_size);
00355 
00356         
00357 
00358         
00359 
00360 
00361         if (S_ISFIFO(st64.st_mode) || S_ISSOCK(st64.st_mode))
00362         {
00363             st64.st_mode = (st64.st_mode & ~S_IFMT) | S_IFGARBAGE;
00364             status=-ENOENT;
00365         }
00366 
00367         if (st)
00368             hlp__copy_stats(&st64, st);
00369     }
00370     else
00371     {
00372         status=errno;
00373         DEBUGP("stat %s: errno=%d", fn, errno);
00374     }
00375 
00376     return status;
00377 }
00378 
00379 
00381 int hlp__fstat(int fd, struct sstat_t *st)
00382 {
00383     int status;
00384     struct stat st64;
00385 
00386     status=fstat(fd, &st64);
00387     if (status == 0) 
00388     {
00389         hlp__copy_stats(&st64, st);
00390         DEBUGP("fd %d: uid=%d gid=%d mode=%o dev=%llx ino=%llu rdev=%llx size=%llu",
00391                 fd,
00392                 st->uid, st->gid, st->mode, 
00393                 (t_ull)st->dev, (t_ull)st->ino, 
00394                 (t_ull)st->rdev, (t_ull)st->size);
00395     }
00396     else
00397     {
00398         status=errno;
00399         DEBUGP("stat #%d: errno=%d", fd, errno);
00400     }
00401 
00402     return status;
00403 }
00434 
00435 
00436 
00437 
00438 char *hlp__pathcopy(char *dst, int *len, ...)
00439 {
00440     static const char ps[]={ PATH_SEPARATOR, 0 };
00441     int had_path;
00442     char *dest;
00443     const char *src;
00444     const char *src_1, *src_2, *src_3;
00445     int status, eop;
00446     va_list va;
00447     static const char null=0;
00448 
00449 
00450     status=0;
00451     had_path=0;
00452     eop=0;
00453     va_start(va, len);
00454     
00455     dest=dst;
00456     src_1=src_2=src_3=&null;
00457 
00458 
00459     void Increment()
00460     {
00461         src  =src_1;
00462         src_1=src_2;
00463         src_2=src_3;
00464 
00465         
00466         if (*src_3) src_3++;
00467 
00468         
00469 
00470 
00471         if (!eop)
00472             while (!*src_3)
00473             {
00474                 src_3=va_arg(va, char*);
00475                 if (src_3) 
00476                     DEBUGP("adding %s", src_3);
00477                 else
00478                 { 
00479                     
00480 
00481                     eop=1;
00482                     src_3=&null;
00483                     break;
00484                 }
00485             }
00486     }
00487 
00488 
00489     
00490     Increment();
00491     if (*src_3 != PATH_SEPARATOR)
00492     {
00493         strcpy(dest, start_path);
00494         dest+=start_path_len;
00495 
00496         
00497 
00498         while (start_path_len>0 && dest[-1]==PATH_SEPARATOR) dest--;
00499 
00500         
00501 
00502         src_2=ps;
00503     }
00504     else
00505     {
00506         Increment();
00507     }
00508     Increment();
00509     Increment();
00510 
00511 
00512     while (*src)
00513     {
00514         if (*src == PATH_SEPARATOR)
00515         {
00516             if (!had_path)
00517                 *(dest++)=*src;
00518             Increment();
00519 
00520 
00521             had_path=1;
00522             
00523             if (*src == '.' && *src_1 == PATH_SEPARATOR)
00524             {
00525                 
00526 
00527                 Increment();
00528             }
00529             else if (*src == '.' && *src_1 == 0)
00530             {
00531                 
00532 
00533                 *(--dest)=0;
00534                 Increment();
00535             }
00536             else
00537             {
00538                 if (*src   == '.' && 
00539                         *src_1 == '.' && 
00540                         (*src_2 == PATH_SEPARATOR || *src_2 == 0) )
00541                 {
00542                     Increment();
00543                     Increment();
00544 
00545                     
00546 
00547                     dest[-1]=0;
00548                     dest=strrchr(dst, PATH_SEPARATOR);
00549                     
00550                     if (!dest) dest=dst;
00551                     
00552 
00553                     had_path=0;
00554                 }
00555             }
00556         }
00557         else
00558         {
00559             *(dest++)=*src;
00560             Increment();
00561             had_path=0;
00562         }
00563 
00564 #if 0
00565         
00566         dest[0]=0;
00567         DEBUGP("solution: %s", dst);
00568         DEBUGP("next: %s", src);
00569 #endif
00570     }
00571 
00572     
00573     *dest=0;
00574 
00575     if (len) *len=dest-dst;
00576 
00577     DEBUGP("finished path is %s", dst);
00578 
00579     return dst;
00580 }
00581 
00582 
00591 int hlp__parse_rev(char *stg, char **eos, svn_revnum_t *rev)
00592 {
00593     static const char head[]="HEAD";
00594     int status;
00595     int inval;
00596     char *end;
00597 
00598     status=0;
00599     if (strncasecmp(stg, head, strlen(head)) == 0)
00600     {
00601         *rev=SVN_INVALID_REVNUM;
00602         end=stg+strlen(head);
00603     }
00604     else
00605         *rev=strtoull(stg, &end, 10);
00606 
00607     inval = opt_target_revision == 0;
00608     if (eos) 
00609         *eos=end;
00610     else 
00611         inval |= (stg == end) || (*end != 0);
00612 
00613     STOPIF_CODE_ERR( inval, EINVAL,
00614             "The given revision argument '%s' is invalid",
00615             stg);
00616 
00617 ex:
00618     return status;
00619 }
00620 
00621 
00631 const char *hlp__get_grname(gid_t gid, char *not_found)
00632 {
00633     struct group *gr;
00634     static struct cache_t cache = { .max=CACHE_DEFAULT };
00635     char *str;
00636 
00637 
00638     if (cch__find(&cache, gid, NULL, &str, NULL) == 0)
00639         return *str ? str : not_found;
00640 
00641     gr=getgrgid(gid);
00642 
00643     cch__add(&cache, gid, gr ? gr->gr_name : "", -1, &str);
00644     return *str ? str : not_found;
00645 }
00646 
00647 
00655 const char *hlp__get_uname(uid_t uid, char *not_found)
00656 {
00657     struct passwd *pw;
00658     static struct cache_t cache = { .max=CACHE_DEFAULT };
00659     char *str;
00660 
00661     if (cch__find(&cache, uid, NULL, &str, NULL) == 0)
00662         return *str ? str : not_found;
00663 
00664     pw=getpwuid(uid);
00665 
00666     cch__add(&cache, uid, pw ? pw->pw_name : "", -1, &str);
00667     return *str ? str : not_found;
00668 }
00669 
00670 
00673 int hlp__get_uid(char *user, uid_t *uid, apr_pool_t *pool)
00674 {
00675     static struct cache_t *cache=NULL;
00676     int status;
00677     apr_gid_t a_gid;
00678     
00679     cache_value_t cv;
00680 
00681 
00682     STOPIF( cch__new_cache(&cache, 64), NULL);
00683 
00684     if (cch__hash_find(cache, user, &cv) == ENOENT)
00685     {
00686         status=apr_uid_get(uid, &a_gid, user, pool);
00687         if (status)
00688             status=ENOENT;
00689         else
00690         {
00691             cv=*uid;
00692             STOPIF( cch__hash_add(cache, user, cv), NULL);
00693         }
00694     }
00695     else
00696         *uid=(uid_t)cv;
00697 
00698 ex:
00699     return status;
00700 }
00701 
00702 
00705 int hlp__get_gid(char *group, gid_t *gid, apr_pool_t *pool)
00706 {
00707     static struct cache_t *cache=NULL;
00708     int status;
00709     
00710     cache_value_t cv;
00711 
00712 
00713     STOPIF( cch__new_cache(&cache, 64), NULL);
00714     if (cch__hash_find(cache, group, &cv) == ENOENT)
00715     {
00716         status=apr_gid_get(gid, group, pool);
00717         if (status)
00718             status=ENOENT;
00719         else
00720         {
00721             cv=*gid;
00722             STOPIF( cch__hash_add(cache, group, cv), NULL);
00723         }
00724     }
00725     else
00726         *gid=(gid_t)cv;
00727 
00728 ex:
00729     return status;
00730 }
00731 
00732 
00733 #define STRING_LENGTH (4096)
00734 
00746 int hlp__string_from_filep(FILE *input, 
00747         char **string, char **eos, int flags)
00748 {
00749     int status;
00750     static char *buffer=NULL;
00751     static unsigned linenum;
00752     char *start;
00753     int i;
00754 
00755 
00756     status=0;
00757 
00758     if (flags & SFF_RESET_LINENUM)
00759         linenum=0;
00760     if (flags & SFF_GET_LINENUM)
00761         return linenum;
00762     if (!input) goto ex;
00763 
00764     
00765     if (!buffer)
00766         STOPIF( hlp__alloc( &buffer, STRING_LENGTH), NULL);
00767 
00768     while (1)
00769     {
00770         start=NULL;
00771         linenum++;
00772         if (!fgets(buffer, STRING_LENGTH, input))
00773         {
00774             
00775 
00776             if (feof(input)) 
00777             {
00778                 status=EOF;
00779                 goto ex;
00780             }
00781 
00782             status=errno;
00783             goto ex;
00784         }
00785 
00786         start=buffer;
00787         if (flags & SFF_WHITESPACE)
00788             start=hlp__skip_ws(start);
00789 
00790         if ((flags & SFF_COMMENT) && *start == '#') 
00791             continue;
00792 
00793 
00794         i=strlen(start)-1;
00795 
00796         
00797 
00798         if (i > 0 && start[i] == '\n')
00799             i--;
00800         if (i > 0 && start[i] == '\r')
00801             i--;
00802 
00803         
00804 
00805         start[i+1]=0;
00806 
00807         while (i>=0 && isspace(start[i])) i--;
00808         if (flags & SFF_WHITESPACE)
00809             
00810             start[i+1]=0;
00811         if (eos) *eos=start+i+1;
00812 
00813         if (*start) break;
00814     }
00815 
00816     if (start)
00817         DEBUGP("read string %s", start);
00818 
00819     *string = start;
00820 
00821 ex:
00822     return status;
00823 }
00824 
00825 
00829 int hlp__safe_print(FILE *output, char *string, int maxlen)
00830 {
00831     static const char to_encode[32]= {
00832         '0',   0,   0,   0,   0,   0,   0,   0,
00833         'b', 't', 'n',   0,   0, 'r',   0,   0,
00834         'f',   0,   0,   0,   0,   0,   0,   0,
00835         0,   0,   0,   0,   0,   0,   0,   0,
00836     };
00837     int cur;
00838     int status;
00839 
00840     status=0;
00841     
00842 
00843     while (status>=0 && maxlen>0)
00844     {
00845         
00846 
00847 
00848         cur=(*string) & 0xff;
00849         string++;
00850         maxlen--;
00851 
00852         if (cur == 0x7f)
00853         {
00854             STOPIF_CODE_EPIPE( fputs("\\x7f", output), NULL);
00855             continue;
00856         }
00857 
00858         
00859  
00860         if (cur<sizeof(to_encode) || !isprint(cur))
00861         {
00862             STOPIF_CODE_EPIPE( 
00863                     to_encode[cur] ? 
00864                     fprintf(output, "\\%c", to_encode[cur]) :
00865                     fprintf(output, "\\x%02x", cur), NULL);
00866             continue;
00867         }
00868 
00869         
00870         STOPIF_CODE_EPIPE( fputc(cur, output), NULL);
00871     }
00872 
00873     status=0;
00874 
00875 ex:
00876     return status;
00877 }
00878 
00879 
00886 int hlp___encoder_waiter(struct encoder_t *encoder)
00887 {
00888     int status;
00889     
00890 
00891     struct pollfd poll_data;
00892 
00893     if (encoder->is_writer)
00894     {
00895         poll_data.events=POLLOUT;
00896         poll_data.fd=encoder->pipe_in;
00897     }
00898     else
00899     {
00900         poll_data.events=POLLIN;
00901         poll_data.fd=encoder->pipe_out;
00902     }
00903 
00904     status=0;
00905     
00906 
00907     STOPIF_CODE_ERR( poll(&poll_data, 1, 100) == -1, errno,
00908             "Error polling for data");
00909 
00910 ex:
00911     return status;
00912 }
00913 
00914 
00919 svn_error_t *hlp___encode_write(void *baton,
00920         const char *data, apr_size_t *len)
00921 {
00922     int status;
00923     svn_error_t *status_svn;
00924     int write_pos, bytes_left;
00925     struct encoder_t *encoder=baton;
00926     apr_size_t wlen;
00927 
00928 
00929     status=0;
00930     write_pos=0;
00931     bytes_left= len ? *len : 0;
00932     
00933     while (data ? (bytes_left || encoder->bytes_left) : !encoder->eof)
00934     {
00935         
00936         if (bytes_left)
00937         {
00938             status=send(encoder->pipe_in, data+write_pos, 
00939                     bytes_left,
00940                     MSG_DONTWAIT);
00941 
00942             DEBUGP("sending %d bytes to child %d from %d: %d; %d", 
00943                     bytes_left, encoder->child, write_pos, status, errno);
00944 
00945             if (status == -1)
00946             {
00947                 status=errno;
00948                 if (status == EAGAIN)
00949                 {
00950                     
00951                 }
00952                 else
00953                     STOPIF(status, "Error writing to child");
00954             }
00955             else
00956             {
00957                 
00958                 write_pos+=status;
00959                 bytes_left-=status;
00960                 status=0;
00961                 DEBUGP("%d bytes left", bytes_left);
00962             }
00963         }
00964 
00965         
00966 
00967         if (encoder->pipe_out != -1)
00968         {
00969             
00970             status = recv(encoder->pipe_out, encoder->buffer,
00971                     sizeof(encoder->buffer), MSG_DONTWAIT);
00972             DEBUGP("receiving bytes from child %d: %d; %d", 
00973                     encoder->child, status, errno);
00974             if (status==0)
00975             {
00976                 STOPIF_CODE_ERR( close(encoder->pipe_out) == -1, errno,
00977                         "Cannot close connection to child");
00978                 DEBUGP("child %d finished", encoder->child);
00979                 encoder->pipe_out=EOF;
00980                 encoder->eof=1;
00981             }
00982             else
00983             {
00984                 if (status == -1)
00985                 {
00986                     status=errno;
00987                     if (status == EAGAIN)
00988                     {
00989                         
00990                         status=0;
00991                     }
00992                     else
00993                         STOPIF(status, "Error reading from child");
00994                 }
00995                 else
00996                 {
00997                     apr_md5_update(&encoder->md5_ctx, encoder->buffer, status);
00998                     encoder->bytes_left=status;
00999                     encoder->data_pos=0;
01000                     
01001                     status=0;
01002                 }
01003             }
01004         }
01005 
01006         if (encoder->bytes_left)
01007         {
01008             wlen=encoder->bytes_left;
01009             STOPIF_SVNERR( svn_stream_write,
01010                     (encoder->orig, encoder->buffer + encoder->data_pos, &wlen));
01011 
01012             encoder->data_pos+=wlen;
01013             encoder->bytes_left-=wlen;
01014         }
01015 
01016         STOPIF( hlp___encoder_waiter(encoder), NULL);
01017     }
01018 
01019     
01020 
01021 ex:
01022     RETURN_SVNERR(status);
01023 }
01024 
01025 
01030 svn_error_t *hlp___encode_read(void *baton,
01031         char *data, apr_size_t *len)
01032 {
01033     int status;
01034     svn_error_t *status_svn;
01035     int read_pos, bytes_left;
01036     struct encoder_t *encoder=baton;
01037     int ign_count;
01038 
01039 
01040     status=0;
01041     ign_count=1;
01042     read_pos=0;
01043     bytes_left=*len;
01044     while (bytes_left && !encoder->eof)
01045     {
01046         
01047         if (!encoder->bytes_left && encoder->orig)
01048         {
01049             encoder->data_pos=0;
01050             encoder->bytes_left=sizeof(encoder->buffer);
01051 
01052             STOPIF_SVNERR( svn_stream_read, 
01053                     (encoder->orig, encoder->buffer, &(encoder->bytes_left)) );
01054 
01055             DEBUGP("read %llu bytes from stream", (t_ull)encoder->bytes_left);
01056             if (encoder->bytes_left < sizeof(encoder->buffer))
01057             {
01058                 STOPIF_SVNERR( svn_stream_close, (encoder->orig) );
01059                 encoder->orig=NULL;
01060             }
01061         }
01062 
01063         
01064         if (encoder->bytes_left)
01065         {
01066             status=send(encoder->pipe_in, encoder->buffer+encoder->data_pos,
01067                     encoder->bytes_left,
01068                     MSG_DONTWAIT);
01069 
01070             DEBUGP("sending %llu bytes to child %d from %d: %d; %d", 
01071                     (t_ull)encoder->bytes_left, 
01072                     encoder->child, encoder->data_pos, status, errno);
01073 
01074             if (status == -1)
01075             {
01076                 status=errno;
01077                 if (status == EAGAIN)
01078                 {
01079                     
01080                 }
01081                 else
01082                     STOPIF(status, "Error writing to child");
01083             }
01084             else
01085             {
01086                 
01087                 apr_md5_update(&encoder->md5_ctx, 
01088                         encoder->buffer+encoder->data_pos, 
01089                         status);
01090                 encoder->data_pos+=status;
01091                 encoder->bytes_left-=status;
01092                 status=0;
01093                 DEBUGP("%llu bytes left", (t_ull)encoder->bytes_left);
01094             }
01095         }
01096 
01097         if (encoder->bytes_left == 0 && !encoder->orig && 
01098                 encoder->pipe_in != -1)
01099         {
01100             DEBUGP("closing connection");
01101             STOPIF_CODE_ERR( close(encoder->pipe_in) == -1, errno,
01102                     "Cannot close connection to child");
01103             encoder->pipe_in=-1;
01104         }
01105 
01106         
01107 
01108         
01109         status = recv(encoder->pipe_out, data+read_pos,
01110                 bytes_left, MSG_DONTWAIT);
01111         if (status==-1 && errno==EAGAIN && ign_count>0)
01112             ign_count--;
01113         else
01114             DEBUGP("receiving %d bytes from child %d: errno=%d", 
01115                     status, encoder->child, errno);
01116         if (status==0)
01117         {
01118             encoder->eof=1;
01119             STOPIF_CODE_ERR( close(encoder->pipe_out) == -1, errno,
01120                     "Cannot close connection to child");
01121         }
01122         else
01123         {
01124             if (status == -1)
01125             {
01126                 status=errno;
01127                 if (status == EAGAIN)
01128                 {
01129                     if (ign_count == 0) ign_count=20;
01130                     
01131                 }
01132                 else
01133                     STOPIF(status, "Error reading from child");
01134             }
01135             else
01136             {
01137                 
01138                 read_pos+=status;
01139                 bytes_left-=status;
01140                 status=0;
01141             }
01142         }
01143 
01144         STOPIF( hlp___encoder_waiter(encoder), NULL);
01145     }
01146 
01147     *len=read_pos;
01148 
01149 ex:
01150     RETURN_SVNERR(status);
01151 }
01152 
01153 
01154 svn_error_t *hlp___encode_close(void *baton)
01155 {
01156     int status;
01157     svn_error_t *status_svn;
01158     int retval;
01159     struct encoder_t *encoder=baton;
01160     md5_digest_t md5;
01161 
01162 
01163     DEBUGP("closing connections for %d", encoder->child);
01164 
01165     if (encoder->is_writer && encoder->pipe_in!=EOF)
01166     {
01167         
01168 
01169         STOPIF_CODE_ERR( close(encoder->pipe_in) == -1, errno,
01170                 "Cannot close connection to child");
01171         encoder->pipe_in=EOF;
01172 
01173         STOPIF_SVNERR( hlp___encode_write, (baton, NULL, NULL));
01174         STOPIF_SVNERR( svn_stream_close, (encoder->orig) );
01175     }
01176 
01177     status=waitpid(encoder->child, &retval, 0);
01178     DEBUGP("child %d gave %d - %X", encoder->child, status, retval);
01179     STOPIF_CODE_ERR(status == -1, errno,
01180             "Waiting for child process failed");
01181     
01182     status=0;
01183 
01184     apr_md5_final(md5, &encoder->md5_ctx);
01185     if (encoder->output_md5)
01186         memcpy(encoder->output_md5, md5, sizeof(*encoder->output_md5));
01187     DEBUGP("encode end gives MD5 of %s", cs__md5tohex_buffered(md5));
01188 
01189     STOPIF_CODE_ERR(retval != 0, ECHILD, 
01190             "Child process returned 0x%X", retval);
01191 
01192 ex:
01193     IF_FREE(encoder);
01194 
01195     RETURN_SVNERR(status);
01196 }
01197 
01198 
01201 void hlp___encode_filter_child(int pipe_in[2], int pipe_out[2],
01202      const char *path, const char *command)
01203 {
01204     int status, i;
01205 
01206     
01207 
01208     STOPIF_CODE_ERR( dup2(pipe_in[1], STDIN_FILENO) == -1 ||
01209             dup2(pipe_out[1], STDOUT_FILENO) == -1,
01210             errno, "Cannot dup2() the childhandles");
01211 
01212     
01213 
01214 
01215     
01216     STOPIF_CODE_ERR( ( close(pipe_in[0]) |
01217                 close(pipe_out[0]) | 
01218                 close(pipe_in[1]) | 
01219                 close(pipe_out[1]) ) == -1, 
01220             errno, "Cannot close the pipes");
01221 
01222 
01223     
01224 
01225 
01226 
01227     
01228 
01229     
01230     for(i=3; i<FD_SETSIZE; i++)
01231         
01232         close(i);
01233 
01234 
01235     
01236 
01237 
01238 
01239 
01240 
01241 
01242     
01243 
01244 
01245     if (path[0] == '.' && path[1] == PATH_SEPARATOR) 
01246         path+=2;
01247     setenv(FSVS_EXP_CURR_ENTRY, path, 1);
01248 
01249     
01250 
01251 
01252     
01253 
01254 
01255     
01256 
01257     i=system(command);
01258 
01259     STOPIF_CODE_ERR(i == -1, errno, 
01260             "Count not execute the command '%s'", command);
01261     STOPIF_CODE_ERR(WIFSIGNALED(i), ECANCELED,
01262             "The command '%s' got killed by signal %d",
01263             command, WTERMSIG(i));
01264     STOPIF_CODE_ERR(WEXITSTATUS(i), ECANCELED,
01265             "The command '%s' returned an errorcode %u",
01266             command, WEXITSTATUS(i));
01267     STOPIF_CODE_ERR(!WIFEXITED(i), ECANCELED,
01268             "The command '%s' didn't exit normally", command);
01269 
01270     
01271     _exit(0);
01272 ex:
01273     _exit(1);
01274 }
01275 
01276 
01293 int hlp__encode_filter(svn_stream_t *s_stream, const char *command, 
01294         int is_writer,
01295         char *path,
01296         svn_stream_t **output, 
01297         struct encoder_t **encoder_out,
01298         apr_pool_t *pool) 
01299 {
01300     int status;
01301     svn_stream_t *new_str;
01302     struct encoder_t *encoder;
01303     int pipe_in[2];
01304     int pipe_out[2];
01305 
01306 
01307     DEBUGP("encode filter: %s", command);
01308     status=0;
01309 
01310     STOPIF( hlp__alloc( &encoder, sizeof(*encoder)), NULL);
01311 
01312     new_str=svn_stream_create(encoder, pool);
01313     STOPIF_ENOMEM( !new_str);
01314 
01315     svn_stream_set_read(new_str, hlp___encode_read);
01316     svn_stream_set_write(new_str, hlp___encode_write);
01317     svn_stream_set_close(new_str, hlp___encode_close);
01318 
01319 
01320     
01321 
01322 
01323     STOPIF_CODE_ERR( 
01324             socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_in) == -1 ||
01325             socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_out) == -1, 
01326             errno, "Cannot create a socket pair");
01327 
01328     
01329     fflush(NULL);
01330 
01331     encoder->child=fork();
01332     if (encoder->child == 0)
01333         hlp___encode_filter_child(pipe_in, pipe_out, path, command);
01334 
01335 
01336     
01337     STOPIF_CODE_ERR(encoder->child == -1, errno, "Cannot fork()");
01338 
01339     STOPIF_CODE_ERR( ( close(pipe_in[1]) | close(pipe_out[1]) ) == -1, 
01340             errno, "Cannot close the pipes");
01341 
01342     encoder->pipe_in=pipe_in[0];
01343     encoder->pipe_out=pipe_out[0];
01344 
01345     encoder->orig=s_stream;
01346     encoder->bytes_left=0;
01347     encoder->eof=0;
01348     encoder->is_writer=is_writer;
01349     encoder->output_md5=NULL;
01350     apr_md5_init(& encoder->md5_ctx);
01351 
01352     *encoder_out = encoder;
01353 
01354     *output=new_str;
01355 ex:
01356     return status;
01357 }
01358 
01359 
01363 int hlp__chrooter(void)
01364 {
01365     int status;
01366     char *libs, *root, *cwd;
01367     int fd, len;
01368     static const char delim[]=" \r\n\t\f";
01369     static const char so_pre[]="lib";
01370     static const char so_post[]=".so";
01371     void *hdl;
01372     char filename[128];
01373 
01374 
01375     libs=getenv(CHROOTER_LIBS_ENV);
01376     DEBUGP("Libraries to load: %s", libs);
01377 
01378     root=getenv(CHROOTER_ROOT_ENV);
01379     DEBUGP("fd of old root: %s", root);
01380 
01381     cwd=getenv(CHROOTER_CWD_ENV);
01382     DEBUGP("fd of old cwd: %s", cwd);
01383 
01384     
01385     status = (libs ? 1 : 0) | (root ? 2 : 0) | (cwd ? 4 : 0);
01386     if (status == 0) 
01387     {
01388         DEBUGP("All are empty, just return.");
01389         goto ex;
01390     }
01391 
01392     
01393     STOPIF_CODE_ERR(status != 7, EINVAL,
01394             "All of %s, %s and %s must be set!", 
01395             CHROOTER_LIBS_ENV, 
01396             CHROOTER_CWD_ENV, 
01397             CHROOTER_ROOT_ENV);
01398     status=0;
01399 
01400     strcpy(filename, so_pre);
01401 
01402     
01403     libs=strtok(libs, delim);
01404     while (libs && *libs)
01405     {
01406         DEBUGP("Trying library %s", libs);
01407 
01408         hdl=dlopen(libs, RTLD_NOW | RTLD_GLOBAL);
01409         if (hdl == NULL)
01410         {
01411             len=strlen(libs);
01412             if (sizeof(filename) < 
01413                     (len + strlen(so_pre) + strlen(so_post) +2))
01414                 DEBUGP("Library name %s too long for expansion", libs);
01415             else
01416             {
01417                 strcpy(filename+strlen(so_pre), libs);
01418                 strcpy(filename+strlen(so_pre)+len, so_post);
01419                 
01420                 hdl=dlopen(filename, RTLD_NOW | RTLD_GLOBAL);
01421             }
01422             
01423         }
01424         STOPIF_CODE_ERR( hdl == NULL, errno, 
01425                 "Cannot load library %s", libs);
01426 
01427         libs=strtok(NULL, delim);
01428     }
01429 
01430     
01431     strerror(EINVAL);
01432 
01433     
01434     iconv_open("437","850");
01435 
01436     
01437     gethostbyname("localhost");
01438     
01439 
01440 
01441     
01442     fd=atoi(root);
01443     STOPIF_CODE_ERR( fchdir(fd) == -1, errno,
01444             "Cannot fchdir() on handle %d", fd);
01445     
01446     close(fd);
01447 
01448     STOPIF_CODE_ERR( chroot(".") == -1, errno,
01449             "Cannot chroot() back");
01450 
01451     
01452     fd=atoi(cwd);
01453     STOPIF_CODE_ERR( fchdir(fd) == -1, errno,
01454             "Cannot fchdir() on handle %d", fd);
01455     close(fd);
01456 
01457 ex:
01458     return status;
01459 }
01460 
01461 
01474 inline int hlp___is_valid_env(char *env, 
01475         char *path2cmp, int p2c_len,
01476         char **value, int *value_len)
01477 {
01478     char *cp;
01479     int x;
01480 
01481 
01482     *value=NULL;
01483     cp=strchr(env, '=');
01484     if (!cp) return 0;
01485 
01486     
01487     cp++;
01488     *value=cp;
01489 
01490     x=strlen(cp);
01491     
01492     while (x>0 && cp[x-1]==PATH_SEPARATOR) x--;
01493 
01494     if (value_len) *value_len=x;
01495     if (p2c_len == -1) p2c_len=x;
01496 
01497     
01498     return env[0]=='W' && env[1] == 'C' &&
01499         
01500         strncmp(cp, path2cmp, p2c_len) == 0;
01501 }
01502 
01503 
01508 int hlp__match_path_envs(struct estat *root)
01509 {
01510     int status;
01511     char **env;
01512     char *cp;
01513     struct estat *sts;
01514     int len;
01515 
01516 
01517     status=0;
01518     for(env=environ; *env; env++)
01519     {
01520         DEBUGP("test env %s", *env);
01521         
01522 
01523         if (hlp___is_valid_env(*env, wc_path, wc_path_len, &cp, &len))
01524         {
01525             
01526 
01527             if (len == wc_path_len)
01528                 sts=root;
01529             else
01530             {
01531                 
01532                 status=ops__traverse(root, cp+wc_path_len+1, 0, 0, &sts);
01533                 if (status)
01534                 {
01535                     DEBUGP("no match: %s", *env);
01536                     continue;
01537                 }
01538             }
01539 
01540             
01541             len=(cp-*env)-1;
01542 
01543             
01544 
01545 
01546 
01547             STOPIF( hlp__alloc( &sts->arg, 1+len+1+3), NULL);
01548 
01549             
01550             sts->arg[0]=ENVIRONMENT_START;
01551             memcpy(sts->arg+1, *env, len);
01552             sts->arg[1+len]=0;
01553 
01554             DEBUGP("match: %s gets %s", sts->name, sts->arg);
01555         }
01556     }
01557 
01558     
01559     status=0;
01560 ex:
01561     return status;
01562 }
01563 
01564 
01569 int hlp__format_path(struct estat *sts, char *wc_relative_path,
01570         char **output)
01571 {
01572     int status;
01573     static struct cache_entry_t *cache=NULL;
01574     char *path, **env, *cp, *match;
01575     struct estat *parent_with_arg;
01576     static const char ps[2]= { PATH_SEPARATOR, 0};
01577     int len, sts_rel_len, max_len;
01578 
01579 
01580     status=0;
01581     switch (opt__get_int(OPT__PATH))
01582     {
01583         case PATH_WCRELATIVE:
01584             path=wc_relative_path;
01585             break;
01586 
01587         case PATH_CACHEDENVIRON:
01588         case PATH_PARMRELATIVE:
01589             parent_with_arg=sts;
01590             while (parent_with_arg->parent && !parent_with_arg->arg) 
01591             {
01592                 
01593                 parent_with_arg=parent_with_arg->parent;
01594             }
01595 
01596             
01597 
01598 
01601             if (!parent_with_arg->arg) parent_with_arg->arg=wc_path;
01602 
01603 
01604             len=strlen(parent_with_arg->arg);
01605             sts_rel_len=sts->path_len - parent_with_arg->path_len;
01606 
01607             
01608 
01609 
01610 
01611 
01612             if (len == 0 && sts_rel_len == 0) 
01613             {
01614                 path=".";
01615                 break;
01616             }
01617 
01618 
01619             DEBUGP("parent=%s, has %s; len=%d, rel_len=%d", 
01620                     parent_with_arg->name, parent_with_arg->arg, len, sts_rel_len);
01621             
01622             STOPIF( cch__entry_set(&cache, 0, NULL, 
01623                         len + 1 + sts_rel_len + 3,
01624                         0, &path), NULL);
01625 
01626             
01627 
01628 
01629 
01630             memcpy(path, parent_with_arg->arg, len);
01631 
01632             
01633 
01634 
01635 
01636 
01637             if (len>0 && 
01638                     path[len-1] != PATH_SEPARATOR &&
01639                     parent_with_arg != sts) 
01640                 path[len++]=PATH_SEPARATOR;
01641 
01642             memcpy(path+len, 
01643                     wc_relative_path+parent_with_arg->path_len+1, 
01644                     sts_rel_len);
01645             path[len+sts_rel_len]=0;
01646             break;
01647 
01648         case PATH_ABSOLUTE:
01649         case PATH_FULLENVIRON:
01650             STOPIF( cch__entry_set(&cache, 0, NULL, 
01651                         wc_path_len + 1 + sts->path_len + 1, 0, &path), NULL);
01652             hlp__pathcopy(path, NULL, wc_path, ps, wc_relative_path, NULL);
01653 
01654             if (opt__get_int(OPT__PATH) == PATH_ABSOLUTE) break;
01655 
01656             
01657 
01658 
01659 
01660 
01661 
01662 
01663 
01664 
01665 
01666 
01667 
01668 
01669 
01670 
01671 
01672 
01673 
01674 
01675 
01676             match=NULL;
01677             
01678             max_len=1;
01679             for(env=environ; *env; env++)
01680             {
01681                 if (!hlp___is_valid_env(*env, path, -1, &cp, &len)) 
01682                     continue;
01683 
01684                 if (len > max_len && 
01685                         path[len]==PATH_SEPARATOR)
01686                 {
01687                     match=*env;
01688                     max_len=len;
01689                 }
01690             }
01691 
01692             if (match)
01693             {
01694                 DEBUGP("matched %s", match);
01695                 cp=strchr(match, '=');
01696                 
01697 
01698                 if (max_len > cp-match+1)
01699                 {
01700                     
01701                     len=cp-match;
01702 
01703                     
01704                     *path=ENVIRONMENT_START;
01705                     memcpy(path+1, match, len);
01706                     path[1+ len]=PATH_SEPARATOR;
01707 
01708                     
01709                     path[1+ len+1]=0;
01710                     DEBUGP("path=%s, rest=%s; have %d, sts has %d", 
01711                             path, path+max_len+1,
01712                             max_len, sts->path_len);
01713 
01714                     memmove(path+1+len, 
01715                             path+max_len,
01716                             wc_path_len+sts->path_len - max_len);
01717                 }
01718             }
01719 
01720             break;
01721 
01722         default:
01723             BUG_ON(1);
01724     }
01725 
01726     *output=path;
01727 ex:
01728     return status;
01729 }
01730 
01731 
01735 char *hlp__rev_to_string(svn_revnum_t rev)
01736 {
01737     static int last=0;
01738     
01739     static char buffers[2][(int)(sizeof(rev)*3.32)+3];
01740 
01741     last++;
01742     if (last>= sizeof(buffers)/sizeof(buffers[0])) last=0;
01743 
01744     if (rev == SVN_INVALID_REVNUM)
01745         strcpy(buffers[last], "HEAD");
01746     else 
01747     {
01748         BUG_ON(rev < 0);
01749         sprintf(buffers[last], "%llu", (t_ull)rev);
01750     }
01751 
01752     return buffers[last];
01753 }
01754 
01755 
01762 int hlp__strncmp_uline_eq_dash(char *always_ul, char *other, int max)
01763 {
01764     while (max)
01765     {
01766         
01767         if (*always_ul == *other || 
01768                 (*always_ul == '_' && *other == '-')) 
01769             ;
01770         else
01771             
01772             return 1;
01773 
01774         
01775 
01776 
01777         if (max<0 && *always_ul==0) break;
01778 
01779         if (max > 0) max--;
01780         always_ul++;
01781         other++;
01782     }
01783 
01784     return 0;
01785 }
01786 
01787 
01790 int hlp__is_special_property_name(const char *name)
01791 {
01792     static const char prop_pre_toignore[]="svn:entry";
01793     static const char prop_pre_toignore2[]="svn:wc:";
01794 
01795     if (strncmp(name, prop_pre_toignore, strlen(prop_pre_toignore)) == 0 ||
01796             strncmp(name, prop_pre_toignore2, strlen(prop_pre_toignore2)) == 0)
01797         return 1;
01798     return 0;
01799 }
01800 
01801 
01805 int hlp__stream_md5(svn_stream_t *stream, unsigned char md5[APR_MD5_DIGESTSIZE])
01806 {
01807     int status;
01808     svn_error_t *status_svn;
01809     const int buffer_size=16384;
01810     char *buffer;
01811     apr_size_t len;
01812     apr_md5_ctx_t md5_ctx;
01813 
01814 
01815     status=0;
01816     STOPIF( hlp__alloc( &buffer, buffer_size), NULL);
01817 
01818     if (md5)
01819         apr_md5_init(&md5_ctx);
01820     DEBUGP("doing stream md5");
01821 
01822     len=buffer_size;
01823     while (len == buffer_size)
01824     {
01825         STOPIF_SVNERR( svn_stream_read, (stream, buffer, &len));
01826         if (md5)
01827             apr_md5_update(&md5_ctx, buffer, len);
01828     }
01829 
01830     if (md5)
01831         apr_md5_final(md5, &md5_ctx);
01832 
01833 ex:
01834     return status;
01835 }
01836 
01837 
01841 int hlp__delay(time_t start, enum opt__delay_e which)
01842 {
01843     if (opt__get_int(OPT__DELAY) & which)
01844     {
01845         DEBUGP("waiting ...");
01846         if (!start) start=time(NULL);
01847 
01848         
01849         while (time(NULL) <= start)
01850             usleep(25000);
01851     }
01852 
01853     return 0;
01854 }
01855 
01856 
01864 int hlp__rename_to_unique(char *fn, char *extension, 
01865         const char **unique_name, 
01866         apr_pool_t *pool)
01867 {
01868     int status;
01869     svn_error_t *status_svn;
01870     apr_file_t *tmp_f;
01871 
01872 
01873     STOPIF_SVNERR( svn_io_open_unique_file2,
01874             (&tmp_f, unique_name, fn, extension, 
01875              svn_io_file_del_on_close, pool));
01876     STOPIF( apr_file_close(tmp_f), NULL);
01877 
01878     DEBUGP("got unique name for local file: %s", *unique_name);
01879 
01880     if (rename(fn, *unique_name) == -1)
01881     {
01882         
01883         status=errno;
01884         DEBUGP("renaming %s to %s gives an error %d.", 
01885                 fn, *unique_name, status);
01886 
01887         
01888 
01889 
01890         if (unlink(*unique_name) == -1)
01891             
01892             DEBUGP("Cannot unlink %s: %d", *unique_name, errno);
01893 
01894         STOPIF(status, 
01895                 "Cannot rename local file to unique name %s", 
01896                 *unique_name);
01897     }
01898 
01899 ex:
01900     return status;
01901 }
01902 
01903 
01907 int hlp__get_svn_config(apr_hash_t **config)
01908 {
01909     int status;
01910     svn_error_t *status_svn;
01911     static apr_hash_t *cfg=NULL;
01912 
01913 
01914     status=0;
01915     
01916 
01917     if (!cfg)
01918         STOPIF_SVNERR( svn_config_get_config,
01919                 (&cfg, opt__get_string(OPT__CONFIG_DIR), global_pool));
01920 
01921     *config=cfg;
01922 ex:
01923     return status;
01924 }
01925 
01926 
01930 int hlp__strnalloc(int len, char **dest, const char const *source)
01931 {
01932     int status;
01933 
01934     STOPIF( hlp__alloc( dest, len+1), NULL);
01935 
01936     if (source)
01937         memcpy(*dest, source, len);
01938     (*dest)[len]=0;
01939 
01940 ex:
01941     return status;
01942 }
01943 
01945 int hlp__strmnalloc(int len, char **dest, 
01946         const char const *source, ...)
01947 {
01948     int status;
01949     va_list vl;
01950     char *dst;
01951 
01952 
01953     
01954 
01955     STOPIF( hlp__alloc( dest, len), NULL);
01956 
01957     va_start(vl, source);
01958     dst=*dest;
01959 
01960     while (source)
01961     {
01962         while (1)
01963         {
01964             BUG_ON(len<=0);
01965             if (! (*dst=*source) ) break;
01966             source++, dst++, len--;
01967         }
01968 
01969         source=va_arg(vl, char*);
01970     }
01971 
01972 ex:
01973     return status;
01974 }
01975 
01976 
01981 int hlp__calloc(void *output, size_t nmemb, size_t count)
01982 {
01983     int status;
01984     void **tgt=output;
01985 
01986     status=0;
01987     *tgt=calloc(nmemb, count);
01988     STOPIF_CODE_ERR(!*tgt, ENOMEM,
01989             "calloc(%llu, %llu) failed", (t_ull)nmemb, (t_ull)count);
01990 
01991 ex:
01992     return status;
01993 }
01994 
01995 
01997 int hlp__realloc(void *output, size_t size)
01998 {
01999     int status;
02000     void **tgt;
02001 
02002     status=0;
02003     tgt=output;
02004     *tgt=realloc(*tgt, size);
02005     
02006     STOPIF_CODE_ERR(!*tgt && size, ENOMEM,
02007             "(re)alloc(%llu) failed", (t_ull)size);
02008 
02009 ex:
02010     return status;
02011 }
02012 
02013 
02015 char* hlp__get_word(char *input, char **word_start)
02016 {
02017     input=hlp__skip_ws(input);
02018     if (word_start)
02019         *word_start=input;
02020 
02021     while (*input && !isspace(*input)) input++;
02022     return input;
02023 }
02024 
02025 
02026 
02027 #ifndef HAVE_STRSEP
02028 
02032 char * strsep (char **stringp, const char *delim)
02033 {
02034     char *start = *stringp;
02035     char *ptr;
02036 
02037     if (start == NULL)
02038         return NULL;
02039 
02040     
02041     if (delim[0] == '\0')
02042     {
02043         *stringp = NULL;
02044         return start;
02045     }
02046 
02047     
02048     if (delim[1] == '\0')
02049         ptr = strchr (start, delim[0]);
02050     else
02051         
02052         ptr = strpbrk (start, delim);
02053     if (ptr == NULL)
02054     {
02055         *stringp = NULL;
02056         return start;
02057     }
02058 
02059     *ptr = '\0';
02060     *stringp = ptr + 1;
02061 
02062     return start;
02063 }
02064 
02065 #endif
02066 
02067 
02068 int hlp__compare_string_pointers(const void *a, const void *b)
02069 {
02070     const char * const *c=a;
02071     const char * const *d=b;
02072     return strcoll(*c,*d);
02073 }
02074 
02075