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
01874 if (fn[0] == '.' && fn[1] == PATH_SEPARATOR)
01875 fn+=2;
01876
01877 STOPIF_SVNERR( svn_io_open_unique_file2,
01878 (&tmp_f, unique_name, fn, extension,
01879 svn_io_file_del_on_close, pool));
01880 STOPIF( apr_file_close(tmp_f), NULL);
01881
01882 DEBUGP("got unique name for local file: %s", *unique_name);
01883
01884 if (rename(fn, *unique_name) == -1)
01885 {
01886
01887 status=errno;
01888 DEBUGP("renaming %s to %s gives an error %d.",
01889 fn, *unique_name, status);
01890
01891
01892
01893
01894 if (unlink(*unique_name) == -1)
01895
01896 DEBUGP("Cannot unlink %s: %d", *unique_name, errno);
01897
01898 STOPIF(status,
01899 "Cannot rename local file to unique name %s",
01900 *unique_name);
01901 }
01902
01903 ex:
01904 return status;
01905 }
01906
01907
01911 int hlp__get_svn_config(apr_hash_t **config)
01912 {
01913 int status;
01914 svn_error_t *status_svn;
01915 static apr_hash_t *cfg=NULL;
01916
01917
01918 status=0;
01919
01920
01921 if (!cfg)
01922 STOPIF_SVNERR( svn_config_get_config,
01923 (&cfg, opt__get_string(OPT__CONFIG_DIR), global_pool));
01924
01925 *config=cfg;
01926 ex:
01927 return status;
01928 }
01929
01930
01934 int hlp__strnalloc(int len, char **dest, const char const *source)
01935 {
01936 int status;
01937
01938 STOPIF( hlp__alloc( dest, len+1), NULL);
01939
01940 if (source)
01941 memcpy(*dest, source, len);
01942 (*dest)[len]=0;
01943
01944 ex:
01945 return status;
01946 }
01947
01949 int hlp__strmnalloc(int len, char **dest,
01950 const char const *source, ...)
01951 {
01952 int status;
01953 va_list vl;
01954 char *dst;
01955
01956
01957
01958
01959 STOPIF( hlp__alloc( dest, len), NULL);
01960
01961 va_start(vl, source);
01962 dst=*dest;
01963
01964 while (source)
01965 {
01966 while (1)
01967 {
01968 BUG_ON(len<=0);
01969 if (! (*dst=*source) ) break;
01970 source++, dst++, len--;
01971 }
01972
01973 source=va_arg(vl, char*);
01974 }
01975
01976 ex:
01977 return status;
01978 }
01979
01980
01985 int hlp__calloc(void *output, size_t nmemb, size_t count)
01986 {
01987 int status;
01988 void **tgt=output;
01989
01990 status=0;
01991 *tgt=calloc(nmemb, count);
01992 STOPIF_CODE_ERR(!*tgt, ENOMEM,
01993 "calloc(%llu, %llu) failed", (t_ull)nmemb, (t_ull)count);
01994
01995 ex:
01996 return status;
01997 }
01998
01999
02001 int hlp__realloc(void *output, size_t size)
02002 {
02003 int status;
02004 void **tgt;
02005
02006 status=0;
02007 tgt=output;
02008 *tgt=realloc(*tgt, size);
02009
02010 STOPIF_CODE_ERR(!*tgt && size, ENOMEM,
02011 "(re)alloc(%llu) failed", (t_ull)size);
02012
02013 ex:
02014 return status;
02015 }
02016
02017
02019 char* hlp__get_word(char *input, char **word_start)
02020 {
02021 input=hlp__skip_ws(input);
02022 if (word_start)
02023 *word_start=input;
02024
02025 while (*input && !isspace(*input)) input++;
02026 return input;
02027 }
02028
02029
02030
02031 #ifndef HAVE_STRSEP
02032
02036 char * strsep (char **stringp, const char *delim)
02037 {
02038 char *start = *stringp;
02039 char *ptr;
02040
02041 if (start == NULL)
02042 return NULL;
02043
02044
02045 if (delim[0] == '\0')
02046 {
02047 *stringp = NULL;
02048 return start;
02049 }
02050
02051
02052 if (delim[1] == '\0')
02053 ptr = strchr (start, delim[0]);
02054 else
02055
02056 ptr = strpbrk (start, delim);
02057 if (ptr == NULL)
02058 {
02059 *stringp = NULL;
02060 return start;
02061 }
02062
02063 *ptr = '\0';
02064 *stringp = ptr + 1;
02065
02066 return start;
02067 }
02068
02069 #endif
02070
02071
02072 int hlp__compare_string_pointers(const void *a, const void *b)
02073 {
02074 const char * const *c=a;
02075 const char * const *d=b;
02076 return strcoll(*c,*d);
02077 }
02078
02079