00001
00002
00003
00004
00005
00006
00007
00008
00009 #include <fcntl.h>
00010 #include <sys/stat.h>
00011 #include <sys/types.h>
00012 #include <errno.h>
00013 #include <apr_pools.h>
00014 #include <apr_md5.h>
00015 #include <subversion-1/svn_md5.h>
00016 #include <ctype.h>
00017 #include <unistd.h>
00018 #include <strings.h>
00019 #include <time.h>
00020 #include <sys/mman.h>
00021
00022
00023 #include "waa.h"
00024 #include "interface.h"
00025 #include "direnum.h"
00026 #include "options.h"
00027 #include "add_unvers.h"
00028 #include "cache.h"
00029 #include "checksum.h"
00030 #include "helper.h"
00031 #include "global.h"
00032 #include "status.h"
00033 #include "est_ops.h"
00034 #include "ignore.h"
00035 #include "actions.h"
00036
00037
00054 static const char ext_tmp[]=".tmp";
00055
00056
00063 char *waa_tmp_path, *waa_tmp_fn,
00064 *conf_tmp_path, *conf_tmp_fn;
00068 static struct sstat_t waa_stat;
00069
00072 static unsigned max_path_len;
00073
00076 struct url_t **urllist=NULL;
00078 int urllist_count=0;
00081 unsigned approx_entry_count;
00082
00083
00084 struct waa___temp_names_t {
00085 char *temp_name;
00086 char *dest_name;
00087 };
00091 static struct waa___temp_names_t *target_name_array=NULL;
00093 static int target_name_array_len=0;
00094
00096 int waa_tmp_path_len;
00097
00099 struct waa__entry_blocks_t waa__entry_block;
00100
00101
00104 char *wc_path;
00106 int wc_path_len;
00107
00108
00109 const char
00120 waa__header_line[]="%u %lu %u %u %u %u";
00121
00122
00124 inline void waa___init_path(enum opt__settings_e which,
00125 char *dest, char **eos)
00126 {
00127 int l;
00128
00129
00130 l=0;
00131 if (strncmp(opt__get_string(OPT__SOFTROOT),
00132 opt__get_string(which),
00133 opt__get_int(OPT__SOFTROOT)) != 0 )
00134 {
00135 strcpy(dest, opt__get_string(OPT__SOFTROOT));
00136 l=opt__get_int(OPT__SOFTROOT);
00137
00138
00139 dest[l++]=PATH_SEPARATOR;
00140 }
00141
00142 l+= strlen( strcpy(dest+l, opt__get_string(which) ) );
00143
00144
00145 if (dest[l-1] != PATH_SEPARATOR)
00146 {
00147 dest[l++]=PATH_SEPARATOR;
00148 dest[l]='\0';
00149 }
00150
00151 *eos=dest + l;
00152 opt__set_int(which, PRIO_MUSTHAVE, l);
00153 }
00154
00155
00159 int waa__init(void)
00160 {
00161 int status;
00162 char *cp;
00163 int len;
00164
00165
00166 status=0;
00167
00168
00169
00170
00171
00172
00176 if (opt__get_int(OPT__CONF_PATH)==0)
00177 {
00178 opt__set_string(OPT__CONF_PATH, PRIO_MUSTHAVE, DEFAULT_CONF_PATH);
00179 opt__set_int(OPT__CONF_PATH, PRIO_MUSTHAVE, strlen(DEFAULT_CONF_PATH));
00180 }
00181
00182
00183
00184 STOPIF_CODE_ERR( opt__get_int(OPT__CONF_PATH)<3, EINVAL,
00185 "The CONF path is invalid; a (non-root) path is expected.");
00186
00187
00188 if (action->is_import_export)
00189 {
00190
00191
00192 opt__set_string(OPT__WAA_PATH, PRIO_MUSTHAVE, NULL);
00193 opt__set_int(OPT__WAA_PATH, PRIO_MUSTHAVE, 0);
00194 }
00195 else
00196 {
00197 if (opt__get_int(OPT__WAA_PATH)==0)
00198 {
00199 opt__set_string(OPT__WAA_PATH, PRIO_MUSTHAVE, DEFAULT_WAA_PATH);
00200 opt__set_int(OPT__WAA_PATH, PRIO_MUSTHAVE, strlen(DEFAULT_WAA_PATH));
00201 }
00202
00203 STOPIF_CODE_ERR( opt__get_int(OPT__WAA_PATH)<3, EINVAL,
00204 "The WAA path should be set to a directory below \"/\".");
00205 }
00206
00207
00208
00209
00210
00211 waa_tmp_path_len=
00212 opt__get_int(OPT__SOFTROOT) + 1 +
00213 ( max(opt__get_int(OPT__WAA_PATH),
00214 opt__get_int(OPT__CONF_PATH)) ) + 1 +
00215 WAA_WC_MD5_CHARS + 1 +
00216 APR_MD5_DIGESTSIZE*2 + 3 +
00217 WAA__MAX_EXT_LENGTH + strlen(ext_tmp) + 1 +4;
00218 DEBUGP("using %d bytes for temporary WAA+conf paths", waa_tmp_path_len);
00219
00220
00221
00222
00223 STOPIF( hlp__alloc( &conf_tmp_path, waa_tmp_path_len), NULL);
00224 waa___init_path(OPT__CONF_PATH, conf_tmp_path, &conf_tmp_fn);
00225
00226 if (!action->is_import_export)
00227 {
00228 STOPIF( hlp__alloc( &waa_tmp_path, waa_tmp_path_len), NULL);
00229
00230 waa___init_path(OPT__WAA_PATH, waa_tmp_path, &waa_tmp_fn);
00231
00232
00233 STOPIF( hlp__lstat(waa_tmp_path, &waa_stat),
00234 "!stat() of waa-path \"%s\" failed. "
00235 "Does your local WAA storage area exist? ",
00236 waa_tmp_path);
00237 DEBUGP("got the WAA as inode %llu", (t_ull)waa_stat.ino);
00238
00239
00240 STOPIF_CODE_ERR( access(conf_tmp_path,
00241 action->is_readonly ? R_OK : W_OK)==-1, errno,
00242 "!Cannot %s to the FSVS_CONF path \"%s\".",
00243 action->is_readonly ? "read" : "write",
00244 conf_tmp_path);
00245 }
00246
00247
00248
00249 opt__set_int( OPT__SOFTROOT, PRIO_MUSTHAVE,
00250 opt__get_int(OPT__SOFTROOT));
00251 cp=opt__variable_from_option(OPT__SOFTROOT);
00252
00253 if (opt__get_string(OPT__SOFTROOT))
00254 setenv(cp, opt__get_string(OPT__SOFTROOT), 1);
00255 else
00256 unsetenv(cp);
00257
00258
00259
00260
00261 len = opt__get_int(OPT__CONFIG_DIR)==0 ?
00262 opt__get_int(OPT__CONF_PATH)+strlen(DEFAULT_CONFIGDIR_SUB)+1 :
00263 opt__get_int(OPT__CONFIG_DIR);
00264 STOPIF( hlp__alloc( &cp, len), NULL);
00265
00266 if (opt__get_int(OPT__CONFIG_DIR)==0)
00267 hlp__pathcopy(cp, &len,
00268 opt__get_string(OPT__CONF_PATH), DEFAULT_CONFIGDIR_SUB, NULL);
00269 else
00270 hlp__pathcopy(cp, &len,
00271 opt__get_string(OPT__CONFIG_DIR), NULL);
00272
00273 opt__set_string(OPT__CONFIG_DIR, PRIO_MUSTHAVE, cp);
00274 opt__set_int(OPT__CONFIG_DIR, PRIO_MUSTHAVE, len);
00275
00276 ex:
00277 return status;
00278 }
00279
00280
00294 int waa__save_cwd(char **where, int *ret_len,
00295 int additional)
00296 {
00297 int status;
00298
00299
00300 static int len=256;
00301 char *path;
00302
00303
00304 path=NULL;
00305 status=0;
00306 while (1)
00307 {
00308 STOPIF( hlp__realloc( &path, len + additional + 4), NULL);
00309
00310
00311
00312 if (getcwd(path, len-1)) break;
00313
00314 STOPIF_CODE_ERR(errno != ERANGE, errno == ENOENT ? ENOTDIR : errno,
00315 "Cannot get the current directory.");
00316
00317 len += 512;
00318 STOPIF_CODE_ERR(len > 1<<13, ERANGE,
00319 "You have mighty long paths. Too long. More than %d bytes? Sorry.",
00320 len);
00321 }
00322
00323 if (ret_len) *ret_len=strlen(path);
00324 *where=path;
00325
00326 ex:
00327 return status;
00328 }
00329
00330
00334 int waa__mkdir(char *dir, int including_last)
00335 {
00336 int status;
00337 STOPIF( waa__mkdir_mask(dir, including_last, 0777), NULL);
00338 ex:
00339 return status;
00340 }
00341
00342
00354 int waa__mkdir_mask(char *dir, int including_last, int mask)
00355 {
00356 int status;
00357 char *last_ps;
00358 struct stat buf;
00359
00360
00361 status=0;
00362
00363 if (lstat(dir, &buf) == -1)
00364 {
00365 if (errno == ENOENT)
00366 {
00367
00368
00369 last_ps=strrchr(dir, PATH_SEPARATOR);
00370 BUG_ON(!last_ps);
00371
00372
00373 *last_ps=0;
00374 status=waa__mkdir(dir, 1);
00375 *last_ps=PATH_SEPARATOR;
00376 STOPIF( status, NULL);
00377
00378 DEBUGP("%s: last is %d", dir, including_last);
00379
00380 if (including_last)
00381 STOPIF_CODE_ERR( mkdir(dir, mask & 07777) == -1, errno,
00382 "cannot mkdir(%s)", dir);
00383 }
00384 else
00385 STOPIF(status, "cannot lstat(%s)", dir);
00386 }
00387 else
00388 {
00389 STOPIF_CODE_ERR( including_last && !S_ISDIR(buf.st_mode), ENOTDIR,
00390 "\"%s\" is not a directory", dir);
00391 }
00392
00393 ex:
00394 return status;
00395 }
00396
00397
00399 int waa___get_path_md5(const char const *path,
00400 unsigned char digest[APR_MD5_DIGESTSIZE])
00401 {
00402 int status;
00403 int plen, wdlen;
00404 char *cp;
00405 static const char root[]= { PATH_SEPARATOR, 0};
00406
00407
00408 status=0;
00409 cp=NULL;
00410 plen=strlen(path);
00411 DEBUGP("path is %s", path);
00412
00413
00414
00415 if (path[0] != PATH_SEPARATOR)
00416 {
00417
00418
00419
00420 STOPIF( waa__save_cwd(&cp, &wdlen, 1 + plen + 1 + 3), NULL);
00421
00422 path= hlp__pathcopy(cp, NULL, cp, "/", path, NULL);
00423
00424
00425 plen=strlen(path);
00426 }
00427
00428 while (plen>1 && path[plen-1] == PATH_SEPARATOR)
00429 plen--;
00430
00431 if (opt__get_string(OPT__SOFTROOT))
00432 {
00433 DEBUGP("have softroot %s for %s, compare %d bytes",
00434 opt__get_string(OPT__SOFTROOT), path, opt__get_int(OPT__SOFTROOT));
00435 if (strncmp(opt__get_string(OPT__SOFTROOT),
00436 path, opt__get_int(OPT__SOFTROOT)) == 0 )
00437 path+=opt__get_int(OPT__SOFTROOT);
00438
00439
00440
00441
00442
00443
00444 if (!*path)
00445 path=(char*)root;
00446
00447 plen=strlen(path);
00448 }
00449
00450 DEBUGP("md5 of %s", path);
00451 apr_md5(digest, path, plen);
00452 IF_FREE(cp);
00453
00454 ex:
00455 return status;
00456 }
00457
00458
00473 int waa__get_waa_directory(char *path,
00474 char **erg, char **eos, char **start_of_spec,
00475 int flags)
00476 {
00477 static int waa_init_for_wc = 0;
00478 int status, len;
00479 char *cp;
00480 unsigned char digest[APR_MD5_DIGESTSIZE], *p2dig;
00481
00482 status=0;
00483 cp=NULL;
00484
00485
00486 if ((flags & GWD_WAA) && !waa_init_for_wc)
00487 {
00488 waa_init_for_wc=1;
00489
00490
00491 if (WAA_WC_MD5_CHARS)
00492 {
00493 BUG_ON(!wc_path);
00494
00495 STOPIF( waa___get_path_md5(wc_path, digest), NULL);
00496
00497
00498
00499
00500
00501 cs__md5tohex(digest, waa_tmp_fn);
00502 waa_tmp_fn += WAA_WC_MD5_CHARS;
00503 *waa_tmp_fn = PATH_SEPARATOR;
00504 waa_tmp_fn++;
00505 }
00506
00507 *waa_tmp_fn = 0;
00508
00509 DEBUGP("init wc base:%s %s", wc_path+opt__get_int(OPT__SOFTROOT), waa_tmp_path);
00510 }
00511
00512
00513 STOPIF( waa___get_path_md5(path, digest), NULL);
00514
00515 p2dig=digest;
00516 len=APR_MD5_DIGESTSIZE;
00517
00518 if (flags & GWD_WAA)
00519 {
00520 *erg = waa_tmp_path;
00521 cp = waa_tmp_fn;
00522 if (start_of_spec) *start_of_spec=cp;
00523
00524
00525 Mbin2hex(p2dig, cp, 1);
00526 len--;
00527
00528 *(cp++) = PATH_SEPARATOR;
00529
00530 Mbin2hex(p2dig, cp, 1);
00531 len--;
00532
00533 *(cp++) = PATH_SEPARATOR;
00534 }
00535 else if (flags & GWD_CONF)
00536 {
00537 *erg = conf_tmp_path;
00538 cp = conf_tmp_fn;
00539 if (start_of_spec) *start_of_spec=cp;
00540 }
00541 else
00542 {
00543 BUG(".:8:.");
00544 }
00545
00546 Mbin2hex(p2dig, cp, len);
00547 if (flags & GWD_MKDIR)
00548 STOPIF( waa__mkdir(*erg, 1), NULL);
00549
00550 *(cp++) = PATH_SEPARATOR;
00551 *cp = '\0';
00552
00553 if (eos) *eos=cp;
00554
00555 DEBUGP("returning %s", *erg);
00556
00557 ex:
00558 return status;
00559 }
00560
00561
00586 int waa__open(char *path,
00587 const char *extension,
00588 int flags,
00589 int *filehandle)
00590 {
00591 char *cp, *orig, *eos, *dest, *start_spec;
00592 int fh, status;
00593 int use_temp_file;
00594 int old_len;
00595
00596
00597 fh=-1;
00598 orig=NULL;
00599
00600
00601
00602
00603
00604 use_temp_file=(flags & O_APPEND) ? 0 :
00605 (flags & (O_WRONLY | O_RDWR | O_CREAT));
00606
00607 STOPIF( waa__get_waa_directory(path, &dest, &eos, &start_spec,
00608 waa__get_gwd_flag(extension) ), NULL);
00609
00610 if (!extension)
00611 {
00612
00613 BUG_ON(eos == dest);
00614 eos[-1]=0;
00615 return hlp__lstat(dest, NULL);
00616 }
00617
00618 strcpy(eos, extension);
00619 BUG_ON( action->is_readonly &&
00620 (flags & (O_WRONLY | O_RDWR | O_APPEND | O_CREAT)),
00621 "Action marked read-only, got flags 0x%x for %s", flags, eos);
00622
00623 if (use_temp_file)
00624 {
00625 STOPIF( hlp__strdup( &orig, dest), NULL);
00626
00627
00628 strcat(eos, ext_tmp);
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639 cp=strchr(start_spec, PATH_SEPARATOR);
00640 while (cp)
00641 {
00642 *cp='_';
00643 cp=strchr(cp+1, PATH_SEPARATOR);
00644 }
00645
00646
00647 STOPIF( hlp__strdup( &dest, dest), NULL);
00648 DEBUGP("tmp for target %s is %s", orig, dest);
00649 }
00650 else
00651 DEBUGP("reading target %s", dest);
00652
00653
00654 if (flags & O_APPEND)
00655 STOPIF( waa__mkdir(dest, 0), NULL);
00656
00657
00658
00659 fh=open(dest, flags, 0777);
00660 if (fh<0)
00661 {
00662 status=errno;
00663 if (status == ENOENT) goto ex;
00664 STOPIF(status, "open %s with flags 0x%X",
00665 dest, flags);
00666 }
00667
00668 DEBUGP("got fh %d", fh);
00669
00670
00671
00672
00673 if (use_temp_file)
00674 {
00675 if (fh >= target_name_array_len)
00676 {
00677
00678 old_len=target_name_array_len;
00679
00680
00681 target_name_array_len=fh+8;
00682 DEBUGP("reallocate target name array to %d", target_name_array_len);
00683 STOPIF( hlp__realloc( &target_name_array,
00684 sizeof(*target_name_array) * target_name_array_len), NULL);
00685
00686
00687 memset(target_name_array + old_len, 0,
00688 sizeof(*target_name_array) * (target_name_array_len-old_len));
00689 }
00690
00691
00692 target_name_array[fh].dest_name=orig;
00693 target_name_array[fh].temp_name=dest;
00694 }
00695
00696 *filehandle=fh;
00697 status=0;
00698
00699 ex:
00700 if (status && fh>-1) close(fh);
00701 return status;
00702 }
00703
00704
00713 int waa__close(int filehandle, int has_failed)
00714 {
00715 int status, do_unlink;
00716 struct waa___temp_names_t *target;
00717
00718
00719
00720
00721 do_unlink=1;
00722 status=0;
00723
00724 target= target_name_array ? target_name_array+filehandle : NULL;
00725
00726 if (target)
00727 DEBUGP("filehandle %d should be %s", filehandle, target->dest_name);
00728 else
00729 DEBUGP("filehandle %d wasn't opened via waa__open()!", filehandle);
00730
00731 status=close(filehandle);
00732 if (!has_failed)
00733 {
00734 STOPIF_CODE_ERR(status == -1, errno, "closing tmp file");
00735
00736 if (target)
00737 {
00738
00739
00740 STOPIF( waa__mkdir(target->dest_name, 0), NULL);
00741
00742
00743 STOPIF_CODE_ERR(
00744 rename(target->temp_name, target->dest_name) == -1,
00745 errno, "renaming tmp file from %s to %s",
00746 target->temp_name, target->dest_name);
00747 }
00748
00749 do_unlink=0;
00750 }
00751
00752 status=0;
00753
00754 ex:
00755
00756
00757 if (do_unlink && target)
00758 {
00759 do_unlink=0;
00760 STOPIF_CODE_ERR( unlink(target->temp_name) == -1, errno,
00761 "Cannot remove temporary file %s", target->temp_name);
00762 }
00763
00764 if (target)
00765 {
00766 IF_FREE(target->temp_name);
00767 IF_FREE(target->dest_name);
00768 }
00769
00770 return status;
00771 }
00772
00773
00780 int waa__make_info_link(char *directory, char *name, char *dest)
00781 {
00782 int status;
00783 char *path, *eos;
00784
00785
00786 STOPIF( waa__get_waa_directory(directory, &path, &eos, NULL,
00787 GWD_CONF | GWD_MKDIR), NULL);
00788
00789 strcpy(eos, name);
00790
00791 if (access(path, F_OK) != 0)
00792 STOPIF_CODE_ERR( symlink(dest, path) == -1,
00793 errno, "cannot create informational symlink '%s' -> '%s'",
00794 path, dest);
00795
00796 ex:
00797 return status;
00798 }
00799
00800
00809 int waa__given_or_current_wd(char *name, char **erg)
00810 {
00811 int status;
00812
00813
00814 status=0;
00815 if (name)
00816 STOPIF( hlp__strdup( erg, name), NULL);
00817 else
00818 STOPIF( waa__save_cwd( erg, NULL, 0), NULL);
00819
00820 ex:
00821 return status;
00822 }
00823
00824
00837 int waa__delete_byext(char *path,
00838 char *extension,
00839 int ignore_not_exist)
00840 {
00841 int status;
00842 char *cp, *eos;
00843 int i;
00844
00845
00846 status=0;
00847 if (extension)
00848 {
00849 STOPIF( waa__get_waa_directory(path, &cp, &eos, NULL,
00850 waa__get_gwd_flag(extension)), NULL);
00851 strcpy(eos, extension);
00852
00853
00854 eos--;
00855 BUG_ON(*eos != PATH_SEPARATOR);
00856 }
00857 else
00858 {
00859 cp=path;
00860 eos=strrchr(cp, PATH_SEPARATOR);
00861 BUG_ON(!eos);
00862 }
00863
00864 DEBUGP("unlink %s", cp);
00865 if (unlink(cp) == -1)
00866 {
00867 status=errno;
00868 if (status == ENOENT && ignore_not_exist) status=0;
00869
00870 STOPIF(status, "Cannot remove spool entry %s", cp);
00871 }
00872
00873
00874
00875
00876
00877
00878 for(i=0; i<3; i++)
00879 {
00880 *eos=0;
00881
00882 if (rmdir(cp) == -1) break;
00883
00884 eos=strrchr(cp, PATH_SEPARATOR);
00885
00886 BUG_ON(!eos, "Got invalid path to remove");
00887 }
00888
00889 DEBUGP("last removed was %s", cp);
00890
00891 ex:
00892 return status;
00893 }
00894
00895
00904 int waa__open_byext(char *entry_name,
00905 char *extension,
00906 int mode,
00907 int *fh)
00908 {
00909 int status;
00910 char *entry;
00911
00912
00913 status=0;
00914 entry=NULL;
00915 STOPIF( waa__given_or_current_wd(entry_name, &entry), NULL );
00916
00917 status=waa__open(entry, extension, mode, fh);
00918 if (status == ENOENT) goto ex;
00919 STOPIF(status, NULL);
00920
00921 ex:
00922 IF_FREE(entry);
00923 return status;
00924 }
00925
00926
00929 int waa__open_dir(char *wc_base,
00930 int write,
00931 int *fh)
00932 {
00933 return waa__open_byext(wc_base, WAA__DIR_EXT, write, fh);
00934 }
00935
00936
00940 int waa__build_tree(struct estat *dir)
00941 {
00942 int status;
00943 struct estat *sts;
00944 int i, ignore, have_ignored, have_found;
00945
00946 status=0;
00947
00948 STOPIF( waa__dir_enum( dir, 0, 0), NULL);
00949
00950
00951 DEBUGP("found %d entries ...", dir->entry_count);
00952 have_ignored=0;
00953 have_found=0;
00954 for(i=0; i<dir->entry_count; i++)
00955 {
00956 sts=dir->by_inode[i];
00957
00958 STOPIF( ign__is_ignore(sts, &ignore), NULL);
00959 if (ignore>0)
00960 {
00961 DEBUGP("ignoring entry %s", sts->name);
00962
00963 sts->to_be_ignored=1;
00964 have_ignored=1;
00965 continue;
00966 }
00967
00968
00969 sts->entry_status=FS_NEW;
00970 ops__set_todo_bits(sts);
00971 approx_entry_count++;
00972 have_found++;
00973
00974 if (S_ISDIR(sts->st.mode))
00975 {
00976 if (ops__are_children_interesting(sts))
00977 {
00978 STOPIF_CODE_ERR( chdir(sts->name) == -1, errno,
00979 "chdir(%s)", sts->name);
00980
00981 STOPIF( waa__build_tree(sts), NULL );
00982
00983
00984 STOPIF_CODE_ERR( chdir("..") == -1, errno,
00985 "parent has gone");
00986 }
00987 }
00988
00989 STOPIF( ac__dispatch(sts), NULL);
00990 }
00991
00992 if (have_ignored)
00993
00994 STOPIF( ops__free_marked(dir, 0), NULL);
00995
00996 if (have_found)
00997 ops__mark_changed_parentcc(dir, entry_status);
00998
00999 ex:
01000 return status;
01001 }
01002
01003
01006 int waa___find_position(struct estat **new,
01007 struct estat ***array, int count)
01008 {
01009 int smaller, middle, bigger_eq;
01010 int status;
01011
01012
01013
01014 if (count == 0)
01015 return 0;
01016
01017
01018
01019
01020
01021
01022
01023
01024
01025
01026
01027 if (dir___f_sort_by_inode(new, array[0]) < 0)
01028 {
01029 DEBUGP("short path taken for 0<1");
01030 return 0;
01031 }
01032
01033 if (count == 1) return 1;
01034
01035
01036 if (dir___f_sort_by_inode(new, array[count-1]) >= 0)
01037 {
01038 DEBUGP("short path taken for >count");
01039 return count;
01040 }
01041 smaller=1;
01042
01043
01044
01045
01046 bigger_eq=count-1;
01047
01048 #if 0
01049 if (1)
01050 {
01051 char tmp[count*(18+1)+10];
01052 int i, n;
01053 for (i=n=0; i<count; i++)
01054 {
01055 n += sprintf(tmp+n,"%llu ", (t_ull)(*array[i])->st.ino);
01056 }
01057 DEBUGP("having %d [ %s]", count, tmp);
01058 DEBUGP("looking for %llu", (t_ull)(*new)->st.ino);
01059 }
01060 #endif
01061
01062 while (1)
01063 {
01064 middle=(bigger_eq+smaller)/2;
01065 DEBUGP("at %d=%llu - %d=%llu - %d=%llu",
01066 smaller, (t_ull)(*array[smaller])->st.ino,
01067 middle, (t_ull)(*array[middle])->st.ino,
01068 bigger_eq, (t_ull)(*array[bigger_eq])->st.ino);
01069
01070 status=dir___f_sort_by_inode(new, array[middle]);
01071 if (status > 0)
01072 smaller=middle+1;
01073 else if (status < 0)
01074 bigger_eq=middle;
01075 else
01076 {
01077
01078
01079
01080 DEBUGP("Jackpot, hardlink!");
01081 bigger_eq=middle;
01082 break;
01083 }
01084 if (bigger_eq<=smaller) break;
01085 }
01086
01087 DEBUGP("believing in %d %llu",
01088 bigger_eq, (t_ull)(*array[bigger_eq])->st.ino);
01089
01090
01091 #if DEBUG
01092 BUG_ON((bigger_eq < count-1 && dir___f_sort_by_inode(new, array[bigger_eq])>0) ||
01093 (bigger_eq >0 && dir___f_sort_by_inode(new, array[bigger_eq-1])<0));
01094 #endif
01095
01096 return bigger_eq;
01097 }
01098
01099
01212 int waa__output_tree(struct estat *root)
01213 {
01214 struct estat ***directory, *sts, **sts_pp;
01215 int max_dir, i, alloc_dir;
01216 unsigned this_len;
01217 int status, waa_info_hdl;
01218 unsigned complete_count, string_space;
01219 char header[HEADER_LEN] = "UNFINISHED";
01220
01221
01222 waa_info_hdl=-1;
01223 directory=NULL;
01224 STOPIF( waa__open_dir(NULL, WAA__WRITE, &waa_info_hdl), NULL);
01225
01226
01227 status=strlen(header);
01228 memset(header + status, '\n', sizeof(header)-status);
01229 i=write(waa_info_hdl, header, sizeof(header));
01230 STOPIF_CODE_ERR( i != sizeof(header), errno,
01231 "header was not written");
01232
01233
01234
01235
01236 alloc_dir=1024;
01237 STOPIF( hlp__calloc( &directory, alloc_dir+1, sizeof(*directory)), NULL);
01238
01239
01240
01241 root->url=NULL;
01242
01243 STOPIF( ops__save_1entry(root, 0, waa_info_hdl), NULL);
01244 root->file_index=complete_count=1;
01245
01246
01247 root->path_len=string_space=strlen(root->name);
01248 max_path_len=root->path_len;
01249
01250
01251
01252
01253 if (!root->entry_count) goto save_header;
01254
01255
01256
01257 if (root->to_be_sorted)
01258 {
01259 DEBUGP("re-sorting root");
01260 STOPIF( dir__sortbyinode(root), NULL);
01261 }
01262
01263
01264
01265 directory[0]=root->by_inode;
01266 max_dir=1;
01267
01268
01269 while (max_dir)
01270 {
01271
01272 sts=( *directory[0] );
01273
01274
01275
01276 directory[0]++;
01277
01278
01279 if (*directory[0] == NULL)
01280 {
01281
01282 max_dir--;
01283 DEBUGP("finished subdir");
01284 memmove(directory, directory+1, sizeof(*directory)*max_dir);
01285 }
01286 else if (max_dir>1)
01287 {
01288
01289
01290 i=waa___find_position(directory[0], directory+1, max_dir-1);
01291 if (i)
01292 {
01293
01294
01295
01296
01297
01298
01299
01300
01301 sts_pp=directory[0];
01302 memmove(directory, directory+1, sizeof(*directory)*i);
01303 directory[i]=sts_pp;
01304 DEBUGP("old current moves to #%u: %llu < %llu",
01305 i,
01306 (t_ull)(*directory[i-1])->st.ino,
01307 (t_ull)(*directory[i ])->st.ino);
01308 }
01309 }
01310
01311
01312
01313 if (!ops__should_entry_be_written_in_list(sts))
01314 continue;
01315
01316
01317
01318 STOPIF( ops__save_1entry(sts, sts->parent->file_index, waa_info_hdl),
01319 NULL);
01320
01321 complete_count++;
01322
01323 sts->file_index=complete_count;
01324
01325 this_len=strlen(sts->name)+1;
01326 string_space += this_len;
01327
01328 if (!sts->path_len)
01329 ops__calc_path_len(sts);
01330 if (sts->path_len > max_path_len)
01331 max_path_len = sts->path_len;
01332
01333
01334 if (ops__has_children(sts))
01335 {
01336
01337
01338
01339
01340
01341
01342
01343
01344
01345
01346 if (max_dir >= alloc_dir)
01347 {
01348 alloc_dir *= 2;
01349 STOPIF( hlp__realloc( &directory, (alloc_dir+1) * sizeof(*directory)), NULL);
01350 DEBUGP("reallocated directory pointers to %u entries", alloc_dir);
01351 }
01352
01353
01354
01355 if (sts->to_be_sorted)
01356 STOPIF( dir__sortbyinode(sts), NULL);
01357
01358
01359
01360 i=waa___find_position(sts->by_inode, directory, max_dir);
01361
01362
01363
01364
01365
01366
01367
01368 memmove(directory+i+1, directory+i,
01369 sizeof(*directory)*(max_dir-i));
01370
01371 directory[i]=sts->by_inode;
01372 DEBUGP("new subdir %llu #%u", (t_ull)(*directory[i])->st.ino, i);
01373 max_dir++;
01374 }
01375
01376 #ifdef DEBUG
01377 for(i=1; i<max_dir; i++)
01378 BUG_ON(
01379 dir___f_sort_by_inode( directory[i-1], directory[i] ) >0);
01380 #endif
01381 }
01382
01383
01384 save_header:
01385
01386
01387 status=snprintf(header, sizeof(header), waa__header_line,
01388 WAA_VERSION, (t_ul)sizeof(header),
01389 complete_count, alloc_dir, string_space+4,
01390 max_path_len+4);
01391 BUG_ON(status >= sizeof(header)-1, "header space not large enough");
01392
01393
01394 memset(header + status, ' ', sizeof(header)-1 -status);
01395 header[sizeof(header)-2]='$';
01396 STOPIF_CODE_ERR( lseek(waa_info_hdl, 0, SEEK_SET) == -1, errno,
01397 "seeking to start of file");
01398 status=write(waa_info_hdl, header, sizeof(header));
01399 STOPIF_CODE_ERR( status != sizeof(header), errno,
01400 "re-writing header failed");
01401
01402 status=0;
01403
01404 ex:
01405 if (waa_info_hdl != -1)
01406 {
01407 i=waa__close(waa_info_hdl, status);
01408 waa_info_hdl=-1;
01409 STOPIF( i, "closing tree handle");
01410 }
01411
01412 if (directory) IF_FREE(directory);
01413
01414 return status;
01415 }
01416
01417
01430 int waa__update_dir(struct estat *old)
01431 {
01432 int dir_hdl, status;
01433 struct estat current;
01434 int nr_new, i;
01435 char *path;
01436
01437
01438 status=nr_new=0;
01439 dir_hdl=-1;
01440
01441 current=*old;
01442 current.by_inode=current.by_name=NULL;
01443 current.entry_count=0;
01444
01445 STOPIF( ops__build_path(&path, old), NULL);
01446
01447
01448
01449 dir_hdl=open(".", O_RDONLY | O_DIRECTORY);
01450 STOPIF_CODE_ERR( dir_hdl==-1, errno,
01451 "saving current directory with open(.)");
01452
01453 DEBUGP("update_dir: chdir(%s)", path);
01454 if (chdir(path) == -1)
01455 {
01456 if (errno == EACCES) goto ex;
01457 STOPIF( errno, "chdir(%s)", path);
01458 }
01459
01460
01461 STOPIF( waa__dir_enum( ¤t, 0, 1), NULL);
01462 DEBUGP("update_dir: direnum found %d; old has %d (%d)",
01463 current.entry_count, old->entry_count,
01464 status);
01465
01466 if (current.entry_count == 0) goto after_compare;
01467
01468
01469
01470
01471
01472
01473
01474
01475
01476
01477
01478
01479
01480
01481
01482
01483
01484
01485
01486
01487
01488
01489
01490 int new_entry(struct estat *sts, struct estat **sts_p)
01491 {
01492 int status;
01493 int ignore;
01494
01495 STOPIF( ign__is_ignore(sts, &ignore), NULL);
01496 if (ignore>0)
01497 DEBUGP("ignoring entry %s", sts->name);
01498 else
01499 {
01500 sts->parent=old;
01501
01502 *sts_p=NULL;
01503 current.by_inode[nr_new]=sts;
01504 nr_new++;
01505
01506 DEBUGP("found a new one!");
01507 sts->entry_status=FS_NEW;
01508 sts->flags |= RF_ISNEW;
01509
01510
01511
01512 ops__set_todo_bits(sts);
01513 STOPIF( ac__dispatch(sts), NULL);
01514
01515 ops__mark_parent_cc(sts, entry_status);
01516 approx_entry_count++;
01517
01518
01519
01520 if (S_ISDIR(sts->st.mode) &&
01521 ops__are_children_interesting(sts) &&
01522 (opt__get_int(OPT__FILTER) & FS_NEW))
01523 {
01524 STOPIF_CODE_ERR( chdir(sts->name) == -1, errno,
01525 "chdir(%s)", sts->name);
01526
01527 STOPIF( waa__build_tree(sts), NULL);
01528
01529 STOPIF_CODE_ERR( chdir("..") == -1, errno,
01530 "parent went away");
01531 }
01532
01533 }
01534
01535 ex:
01536 return status;
01537 }
01538
01539 nr_new=0;
01540 STOPIF( ops__correlate_dirs( old, ¤t,
01541 NULL, NULL, new_entry, NULL), NULL);
01542
01543
01544 DEBUGP("%d new entries", nr_new);
01545
01546 status=0;
01547 if (nr_new)
01548 {
01549 STOPIF( ops__new_entries(old, nr_new, current.by_inode),
01550 "adding %d new entries", nr_new);
01551 }
01552
01553
01554
01555 for(i=0; i < current.entry_count; i++)
01556 if (current.by_name[i] )
01557 STOPIF( ops__free_entry( current.by_name+i ), NULL);
01558
01559
01560 IF_FREE(current.by_inode);
01561 IF_FREE(current.by_name);
01562
01563
01564
01565
01566 after_compare:
01567
01568
01569
01570 old->entry_status &= ~FS_LIKELY;
01571
01572
01573
01574
01575 if (nr_new)
01576 ops__mark_changed_parentcc(old, entry_status);
01577
01578 ex:
01579 if (dir_hdl!=-1)
01580 {
01581 i=fchdir(dir_hdl);
01582 STOPIF_CODE_ERR(i == -1 && !status, errno,
01583 "cannot fchdir() back");
01584 i=close(dir_hdl);
01585 STOPIF_CODE_ERR(i == -1 && !status, errno,
01586 "cannot close dirhandle");
01587 }
01588 DEBUGP("update_dir reports %d new found, status %d", nr_new, status);
01589 return status;
01590 }
01591
01592
01594 #define TREE_DAMAGED(condition, ...) \
01595 STOPIF_CODE_ERR( condition, EINVAL, \
01596 "!The entries file seems to be damaged -- \n" \
01597 " %s.\n" \
01598 "\n" \
01599 "Please read the users@ mailing list.\n" \
01600 " If you know what you're doing you could " \
01601 "try using 'sync-repos'\n" \
01602 " (but please _read_the_documentation_!)\n" \
01603 " 'We apologize for the inconvenience.'", \
01604 __VA_ARGS__);
01605
01606
01613 int waa__input_tree(struct estat *root,
01614 struct waa__entry_blocks_t **blocks,
01615 action_t *callback)
01616 {
01617 int status, waa_info_hdl=-1;
01618 int i, cur, first;
01619 unsigned count, subdirs, string_space;
01620
01621
01622
01623 ino_t parent;
01624 char header[HEADER_LEN];
01625 char *filename;
01626 struct estat *sts, *stat_mem;
01627 char *strings;
01628 int sts_free;
01629 char *dir_mmap, *dir_end, *dir_curr;
01630 off_t length;
01631 t_ul header_len;
01632 struct waa__entry_blocks_t *cur_block;
01633 struct estat *sts_tmp;
01634
01635
01636 waa__entry_block.first=root;
01637 waa__entry_block.count=1;
01638 waa__entry_block.next=waa__entry_block.prev=NULL;
01639 cur_block=&waa__entry_block;
01640
01641 length=0;
01642 dir_mmap=NULL;
01643 status=waa__open_dir(NULL, WAA__READ, &waa_info_hdl);
01644 if (status == ENOENT)
01645 {
01646 status=-ENOENT;
01647 goto ex;
01648 }
01649 STOPIF(status, "cannot open .dir file");
01650
01651 length=lseek(waa_info_hdl, 0, SEEK_END);
01652 STOPIF_CODE_ERR( length == (off_t)-1, errno,
01653 "Cannot get length of .dir file");
01654
01655 DEBUGP("mmap()ping %llu bytes", (t_ull)length);
01656 dir_mmap=mmap(NULL, length,
01657 PROT_READ, MAP_SHARED,
01658 waa_info_hdl, 0);
01659
01660
01661 status=errno;
01662 i=close(waa_info_hdl);
01663 STOPIF_CODE_ERR( !dir_mmap, status, "mmap failed");
01664 STOPIF_CODE_ERR( i, errno, "close() failed");
01665
01666 dir_end=dir_mmap+length;
01667
01668 TREE_DAMAGED( length < (HEADER_LEN+5) ||
01669 dir_mmap[HEADER_LEN-1] != '\n' ||
01670 dir_mmap[HEADER_LEN-2] != '$',
01671 "the header is not correctly terminated");
01672
01673
01674
01675 memcpy(header, dir_mmap, HEADER_LEN-2);
01676 header[HEADER_LEN-2]=0;
01677 status=sscanf(header, waa__header_line,
01678 &i, &header_len,
01679 &count, &subdirs, &string_space,
01680 &max_path_len);
01681 DEBUGP("got %d header fields", status);
01682 TREE_DAMAGED( status != 6,
01683 "not all needed header fields could be parsed");
01684 dir_curr=dir_mmap+HEADER_LEN;
01685
01686 TREE_DAMAGED( i != WAA_VERSION || header_len != HEADER_LEN,
01687 "the header has a wrong version");
01688
01689
01690 approx_entry_count=count;
01691
01692
01693
01694
01695
01696 max_path_len+=1024;
01697
01698 DEBUGP("reading %d subdirs, %d entries, %d bytes string-space",
01699 subdirs, count, string_space);
01700
01701
01702
01703
01704
01705
01706
01707
01708 TREE_DAMAGED( dir_mmap[length-2] != '\0' || dir_mmap[length-1] != '\n',
01709 "the file is not correctly terminated");
01710
01711 DEBUGP("ok, found \\0 or \\0\\n at end");
01712
01713 STOPIF( hlp__alloc( &strings, string_space), NULL);
01714 root->strings=strings;
01715
01716
01717 cur=0;
01718 sts_free=1;
01719 first=1;
01720
01721 while ( count > 0)
01722 {
01723 DEBUGP("curr=%p, end=%p, count=%d",
01724 dir_curr, dir_end, count);
01725 TREE_DAMAGED( dir_curr>=dir_end,
01726 "An entry line has a wrong number of entries");
01727
01728 if (sts_free == 0)
01729 {
01730
01731
01732
01733 STOPIF( ops__allocate(count, &stat_mem, &sts_free), NULL );
01734
01735 STOPIF( waa__insert_entry_block(stat_mem, sts_free), NULL);
01736
01737 cur_block=waa__entry_block.next;
01738 }
01739
01740 sts_free--;
01741 count--;
01742
01743 sts=first ? root : stat_mem+cur;
01744
01745 DEBUGP("about to parse %p = '%-.40s...'", dir_curr, dir_curr);
01746 STOPIF( ops__load_1entry(&dir_curr, sts, &filename, &parent), NULL);
01747
01748
01749
01750 TREE_DAMAGED( (parent && first) ||
01751 (!parent && !first) ||
01752 (parent && parent-1>cur),
01753 "the parent pointers are invalid");
01754
01755 if (first) first=0;
01756 else cur++;
01757
01758
01759 strcpy(strings, filename);
01760 sts->name=strings;
01761 strings += strlen(filename)+1;
01762 BUG_ON(strings - root->strings > string_space);
01763
01764 if (parent)
01765 {
01766 if (parent == 1) sts->parent=root;
01767 else
01768 {
01769 i=parent-2;
01770 BUG_ON(i >= cur);
01771 sts->parent=stat_mem+i;
01772 }
01773
01774
01775 sts->parent->by_inode[ sts->parent->child_index++ ] = sts;
01776 BUG_ON(sts->parent->child_index > sts->parent->entry_count,
01777 "too many children for parent");
01778
01779
01780 if (sts->repos_rev != sts->parent->repos_rev)
01781 {
01782 sts_tmp=sts->parent;
01783 while (sts_tmp && !sts_tmp->other_revs)
01784 {
01785 sts_tmp->other_revs = 1;
01786 sts_tmp=sts_tmp->parent;
01787 }
01788 }
01789 }
01790
01791
01792 if (S_ISDIR(sts->st.mode))
01793 {
01794
01795 if (sts->entry_count)
01796 {
01797 STOPIF( hlp__alloc( &sts->by_inode,
01798 sizeof(*sts->by_inode) * (sts->entry_count+1)), NULL);
01799 sts->by_inode[sts->entry_count]=NULL;
01800 sts->child_index=0;
01801 }
01802 }
01803
01804 if (callback)
01805 STOPIF( callback(sts), NULL);
01806 }
01807
01808
01809 ex:
01810
01811 if (blocks)
01812 *blocks=&waa__entry_block;
01813
01814 if (dir_mmap)
01815 {
01816 i=munmap(dir_mmap, length);
01817 if (!status)
01818 STOPIF_CODE_ERR(i, errno, "munmap() failed");
01819 }
01820
01821 return status;
01822 }
01823
01824
01836 inline int waa___check_dir_for_update(struct estat *sts)
01837 {
01838 int status;
01839
01840
01841 status=0;
01842
01843 if (!sts->do_this_entry) goto ex;
01844
01845
01846
01847
01848
01849
01850
01851
01852 if ((sts->entry_status ||
01853 (opt__get_int(OPT__CHANGECHECK) & CHCHECK_DIRS) ||
01854 (sts->flags & RF_ADD) ||
01855 (sts->flags & RF_CHECK) ) &&
01856 ops__are_children_interesting(sts) &&
01857 action->do_update_dir)
01858 {
01859
01860 DEBUGP("dir_to_print | CHECK for %s", sts->name);
01861 STOPIF( waa__update_dir(sts), NULL);
01862
01863
01864
01865 ops__calc_filter_bit(sts);
01866 }
01867
01868
01869
01870 if (ops__allowed_by_filter(sts))
01871 STOPIF( ac__dispatch(sts), NULL);
01872
01873 ex:
01874 return status;
01875 }
01876
01877
01882 int waa___finish_directory(struct estat *sts)
01883 {
01884 int status;
01885 struct estat *walker;
01886
01887
01888 status=0;
01889
01890 walker=sts;
01891 while (1)
01892 {
01893 DEBUGP("checking directory %s: %u unfini, %d of %d (%s)",
01894 walker->name,
01895 walker->unfinished,
01896 walker->child_index, walker->entry_count,
01897 st__status_string(walker));
01898
01899 if (walker->unfinished > 0) break;
01900
01901
01902
01903
01904 if (walker->entry_count == 0)
01905 BUG_ON(walker != sts);
01906 else if (walker->child_index < walker->entry_count)
01907 break;
01908
01909 DEBUGP("walker=%s; status=%s",
01910 walker->name,
01911 st__status_string_fromint(walker->entry_status));
01912
01913 if (!TEST_PACKED(S_ISDIR, walker->local_mode_packed) ||
01914 (walker->entry_status & FS_REPLACED) == FS_REMOVED)
01915 {
01916
01917
01918
01919
01920 }
01921 else if (!(opt__get_int(OPT__FILTER) & FS_NEW))
01922 {
01923
01924
01925 if (ops__allowed_by_filter(walker))
01926 STOPIF( ac__dispatch(walker), NULL);
01927 }
01928 else
01929 {
01930
01931
01932 STOPIF( waa___check_dir_for_update(walker), NULL);
01933
01934
01935 walker->unfinished+=0x1000;
01936 }
01937
01938
01939
01940 walker=walker->parent;
01941 if (!walker) break;
01942
01943
01944 DEBUGP("%s has a finished child, now %d unfinished",
01945 walker->name, walker->unfinished);
01946
01947
01948 if (walker->unfinished)
01949 walker->unfinished--;
01950 }
01951
01952 if (walker == sts->parent && walker)
01953 DEBUGP("deferring parent %s/%s (%d unfinished)",
01954 walker->name, sts->name, walker->unfinished);
01955
01956 ex:
01957 return status;
01958 }
01959
01960
02023 int waa__update_tree(struct estat *root,
02024 struct waa__entry_blocks_t *cur_block)
02025 {
02026 int status;
02027 struct estat *sts;
02028
02029
02030 if (! (root->do_userselected || root->do_child_wanted) )
02031 {
02032
02033
02034 root->do_userselected =
02035 root->do_this_entry =
02036 root->do_filter_allows_done =
02037 root->do_filter_allows = 1;
02038 DEBUGP("Full tree update");
02039 }
02040
02041
02042 action->keep_children=1;
02043
02044 status=0;
02045 while (cur_block)
02046 {
02047
02048 sts=cur_block->first;
02049 DEBUGP("doing update for %s ... %d left in %p",
02050 sts->name, cur_block->count, cur_block);
02051
02052
02053
02054 if (S_ISDIR(sts->st.mode))
02055 sts->child_index = sts->unfinished = 0;
02056
02057
02058
02059 if (!(sts->flags & RF_ISNEW))
02060 STOPIF( ops__update_filter_set_bits(sts), NULL);
02061
02062 if (!(sts->do_this_entry || sts->do_child_wanted))
02063 goto next;
02064
02065
02066
02067 if (sts->entry_status)
02068 ops__mark_parent_cc(sts, entry_status);
02069
02070 if (sts->parent)
02071 {
02072 if (TEST_PACKED(S_ISDIR, sts->old_rev_mode_packed))
02073 sts->parent->unfinished++;
02074
02075 if (sts->parent->entry_status & FS_REMOVED)
02076 goto next;
02077 }
02078
02079 if (sts->entry_status & FS_REMOVED)
02080 {
02081 if (sts->parent)
02082 {
02083
02084 sts->parent->entry_status &= (~FS_LIKELY);
02085 sts->parent->entry_status |= FS_CHANGED;
02086
02087 }
02088
02089
02090
02091 if (TEST_PACKED(S_ISDIR, sts->old_rev_mode_packed) &&
02092 !action->keep_children)
02093 sts->entry_count=0;
02094
02095
02096
02097 if (TEST_PACKED(S_ISDIR, sts->old_rev_mode_packed))
02098
02099
02100 sts->parent->unfinished--;
02101 }
02102
02103
02104 if (S_ISDIR(PACKED_to_MODE_T(sts->local_mode_packed)) &&
02105 (sts->entry_status & FS_REPLACED) == FS_REPLACED)
02106 {
02107
02108
02109
02110
02111
02112
02113
02114
02115 DEBUGP("new directory %s", sts->name);
02116 sts->entry_count=0;
02117 sts->unfinished=0;
02118 sts->by_inode=sts->by_name=NULL;
02119 sts->strings=NULL;
02120
02121
02122 }
02123
02124
02125 next:
02126
02127
02128 if (TEST_PACKED(S_ISDIR, sts->local_mode_packed) &&
02129 sts->entry_count==0)
02130 {
02131 DEBUGP("doing empty directory %s %d", sts->name, sts->do_this_entry);
02132
02133
02134 STOPIF( waa___finish_directory(sts), NULL);
02135 }
02136
02137
02138
02139
02140
02141 if (!TEST_PACKED(S_ISDIR, sts->local_mode_packed) &&
02142 sts->do_this_entry)
02143 STOPIF( ac__dispatch(sts), NULL);
02144
02145
02146
02147
02148
02149
02150 if (sts->parent && action->keep_children )
02151 {
02152 sts->parent->child_index++;
02153
02154
02155 if (sts->parent->child_index >= sts->parent->entry_count
02156 && sts->parent->do_this_entry)
02157 {
02158 DEBUGP("checking parent %s/%s", sts->parent->name, sts->name);
02159
02160
02161
02162
02163 STOPIF( waa___finish_directory(sts->parent), NULL);
02164 }
02165 else
02166 DEBUGP("deferring parent %s/%s%s: %d of %d, %d unfini",
02167 sts->parent->name, sts->name,
02168 sts->parent->do_this_entry ? "" : " (no do_this_entry)",
02169 sts->parent->child_index, sts->parent->entry_count,
02170 sts->parent->unfinished);
02171 }
02172
02173
02174
02175
02176 cur_block->first++;
02177 cur_block->count--;
02178 if (cur_block->count <= 0)
02179 {
02180
02181
02182 cur_block=cur_block->next;
02183 }
02184 }
02185
02186
02187 ex:
02188 return status;
02189 }
02190
02191
02203 int waa__read_or_build_tree(struct estat *root,
02204 int argc, char *normalized[], char *orig[],
02205 action_t *callback,
02206 int return_ENOENT)
02207 {
02208 int status;
02209 struct waa__entry_blocks_t *blocks;
02210
02211
02212 status=0;
02213 status=waa__input_tree(root, &blocks, callback);
02214 DEBUGP("read tree = %d", status);
02215
02216 if (status == -ENOENT)
02217 {
02218
02219 if (return_ENOENT)
02220 return -ENOENT;
02221 }
02222 else
02223 STOPIF( status, NULL);
02224
02225 if (opt__get_int(OPT__PATH) == PATH_CACHEDENVIRON)
02226 STOPIF( hlp__match_path_envs(root), NULL);
02227
02228
02229 STOPIF( waa__partial_update(root, argc, normalized,
02230 orig, blocks), NULL);
02231
02232
02233
02234 if (action->local_uninit)
02235 STOPIF( action->local_uninit(), NULL);
02236
02237 ex:
02238 return status;
02239 }
02240
02241
02291 int waa__find_common_base2(int argc, char *args[],
02292 char ***normalized,
02293 int flags)
02294 {
02295 int status, i, j;
02296 int len;
02297 char *cp, *confname;
02298 char *paths[argc], *base_copy;
02299 char **norm;
02300 char *nullp[2];
02301 char *last_ps;
02302 const char *path2copy, *basepath2copy;
02303
02304
02305 char canon[PATH_MAX];
02306 static const char ps[]={PATH_SEPARATOR, 0};
02307 int fnlen;
02308
02309
02310 status=0;
02311 norm=NULL;
02312
02313
02314 if (argc == 0)
02315 {
02316 argc=1;
02317 nullp[0]=start_path;
02318 nullp[1]=NULL;
02319 args=nullp;
02320 DEBUGP("faked a single parameter to %s", *args);
02321 }
02322
02323
02324
02325
02326
02327
02328
02329 len = argc * sizeof(char*) + sizeof(NULL);
02330 STOPIF( hlp__alloc( &norm, len), NULL);
02331
02332
02333
02334
02335 len=0;
02336 status=0;
02337 for(i=0; i<argc; i++)
02338 {
02339 last_ps=strrchr(args[i], PATH_SEPARATOR);
02340
02341 if (!last_ps)
02342 {
02343 only_rel_path:
02344
02345
02346
02347 fnlen=start_path_len+1+strlen(args[i])+1;
02348 path2copy=args[i];
02349 basepath2copy=start_path;
02350 }
02351 else if (flags & FCB__NO_REALPATH)
02352 {
02353
02354 if (args[i][0] != PATH_SEPARATOR) goto only_rel_path;
02355
02356 fnlen=strlen(args[i])+1;
02357 basepath2copy=ps;
02358 path2copy=args[i];
02359 }
02360 else if (last_ps == args[i])
02361 {
02362
02363 fnlen=strlen(args[i])+1;
02364 basepath2copy=ps;
02365 path2copy=args[i];
02366 }
02367 else if (last_ps)
02368 {
02369
02370 *last_ps=0;
02371 status=realpath(args[i], canon) ? 0 : errno;
02372
02373 STOPIF( status, "realpath(%s)", args[i]);
02374 *last_ps=PATH_SEPARATOR;
02375
02376 fnlen=strlen(canon)+1+strlen(last_ps+1)+1;
02377 BUG_ON(fnlen >= PATH_MAX, "path longer than PATH_MAX");
02378
02379 path2copy=last_ps;
02380 basepath2copy=canon;
02381 }
02382 else
02383 BUG_ON(1);
02384
02385
02386 STOPIF( hlp__alloc( paths+i, fnlen+1), NULL);
02387 paths[i]++;
02388 hlp__pathcopy(paths[i], &j, basepath2copy, ps, path2copy, NULL);
02389
02390 if (len<j) len=j;
02391 while (len > 1 && paths[i][len-1] == PATH_SEPARATOR)
02392 paths[i][--len]=0;
02393 DEBUGP("got argument #%d as %s[%d]", i, paths[i], len);
02394 }
02395
02396
02397
02398
02399 len=strlen(paths[0]);
02400 for(i=1; i<argc; i++)
02401 {
02402 DEBUGP("len before #%d is %d", i, len);
02403 for(j=0; j<len; j++)
02404
02405 if (paths[i][j] != paths[0][j])
02406 len=j;
02407 }
02408 DEBUGP("len after is %d", len);
02409
02410
02411
02412
02413
02414
02415
02416
02417
02418
02419
02420
02421
02422
02423
02424
02425
02426
02427
02428
02429
02430
02431
02432
02433
02434
02435
02436
02437
02438
02439 if (paths[0][len] == PATH_SEPARATOR ||
02440 paths[0][len] == 0)
02441 {
02442 DEBUGP("Is a directory, possible a wc root.");
02443 }
02444 else
02445 {
02446 DEBUGP("Reverting to next %c", PATH_SEPARATOR);
02447
02448 len--;
02449
02450 while (paths[0][len] != PATH_SEPARATOR && len >0)
02451 len--;
02452 }
02453
02454 BUG_ON(len < 0, "Paths not even equal in separator - "
02455 "they have nothing in common!");
02456
02457
02458 if (len == 0)
02459 {
02460
02461 len=1;
02462 DEBUGP("we're at root.");
02463 }
02464
02465 STOPIF( hlp__strnalloc(len, &base_copy, paths[0]), NULL);
02466 DEBUGP("starting search at %s", base_copy);
02467
02468
02469
02470
02471
02472 while (1)
02473 {
02474
02475
02476
02477 DEBUGP("looking for %s", base_copy);
02478 status=waa__open(base_copy, NULL, 0, 0);
02479
02480
02481 if (!status) break;
02482
02483 if (len <= 1) break;
02484
02485 base_copy[len]=0;
02486 cp=rindex(base_copy, PATH_SEPARATOR);
02487 if (cp)
02488 {
02489
02490 if (cp == base_copy)
02491 cp++;
02492
02493 *cp=0;
02494 len=cp - base_copy;
02495 }
02496 }
02497
02498 DEBUGP("after loop is len=%d, base=%s, and status=%d",
02499 len, base_copy, status);
02500
02501
02502
02503
02504
02505 STOPIF( status, "!Couldn't find a working copy with matching base.");
02506
02507
02508 wc_path=base_copy;
02509 wc_path_len=len;
02510
02511 DEBUGP("found working copy base at %s", wc_path);
02512 STOPIF_CODE_ERR( chdir(wc_path) == -1, errno, "chdir(%s)", wc_path);
02513
02514 setenv(FSVS_EXP_WC_ROOT, wc_path, 1);
02515
02516
02517
02518
02519 for(i=0; i<argc; i++)
02520 {
02521 DEBUGP("path is %s", paths[i]);
02522
02523
02524 if (paths[i][len] == 0)
02525 norm[i] = ".";
02526 else
02527 {
02528 if (len == 1)
02529
02530 norm[i]=paths[i]+1;
02531 else
02532 norm[i]=paths[i]+len+1;
02533
02534
02535
02536 if (flags & FCB__PUT_DOTSLASH)
02537 {
02538 norm[i]-=2;
02539 *norm[i] = '.';
02540 }
02541 }
02542 DEBUGP("we set norm[%d]=%s from %s", i, norm[i], paths[i]);
02543 }
02544 norm[argc]=NULL;
02545
02546
02547
02548
02549
02550
02551
02552 STOPIF( waa__get_waa_directory( wc_path, &confname, &cp, NULL, GWD_CONF),
02553 NULL);
02554 setenv( FSVS_EXP_WC_CONF, confname, 1);
02555 STOPIF( opt__load_settings(confname, "config", PRIO_ETC_WC ), NULL);
02556
02557
02558
02559
02560
02561
02562
02563
02564
02565
02566
02567 if (!action->only_opt_filter ||
02568 opt__get_int(OPT__FILTER) == 0)
02569 opt__set_int(OPT__FILTER, PRIO_MUSTHAVE, FILTER__ALL);
02570
02571 DEBUGP("filter has mask 0x%X (%s)",
02572 opt__get_int(OPT__FILTER),
02573 st__status_string_fromint(opt__get_int(OPT__FILTER)));
02574
02575
02576 ex:
02577 if (status && status!=ENOENT)
02578 {
02579
02580 IF_FREE(norm);
02581 }
02582 else
02583 {
02584
02585 if (normalized)
02586 *normalized=norm;
02587 }
02588
02589 return status;
02590 }
02591
02592
02599 int waa__partial_update(struct estat *root,
02600 int argc, char *normalized[], char *orig[],
02601 struct waa__entry_blocks_t *blocks)
02602 {
02603 int status;
02604 struct estat *sts;
02605 int i, flags;
02606 int faked_arg0;
02607
02608
02609 status=0;
02610
02611
02612
02613
02614 faked_arg0=(argc == 0 && *normalized);
02615
02616 if (faked_arg0) argc=1;
02617
02618 for(i=0; i<argc; i++)
02619 {
02620 DEBUGP("update %d=%s", i, normalized[i]);
02621
02622
02623
02624
02625
02626
02627 status=hlp__lstat(normalized[i], NULL);
02628
02629 if (abs(status) == ENOENT)
02630 flags=OPS__ON_UPD_LIST | OPS__FAIL_NOT_LIST;
02631 else
02632 {
02633 STOPIF( status, "Cannot query entry %s", normalized[i]);
02634 flags = OPS__ON_UPD_LIST | OPS__CREATE;
02635 }
02636
02637 status=ops__traverse(root, normalized[i], flags, RF_ADD, &sts);
02638 if (status == ENOENT)
02639 {
02640 STOPIF_CODE_ERR( !(flags & OPS__CREATE), ENOENT,
02641 "!Entry '%s' is not known.", normalized[i]);
02642 BUG_ON(1);
02643 }
02644 else
02645 STOPIF(status, NULL);
02646
02647
02648 if (opt__get_int(OPT__PATH) == PATH_PARMRELATIVE && !sts->arg)
02649 sts->arg= faked_arg0 ? "" : orig[i];
02650
02651
02652 sts->do_userselected = sts->do_this_entry = 1;
02653 while ( 1 )
02654 {
02655
02656
02657
02658
02659
02660
02661
02662 if (sts->flags & RF_ISNEW)
02663 {
02664 STOPIF( ops__update_single_entry(sts, &sts->st), NULL);
02665 sts->entry_status=FS_NEW;
02666 ops__calc_filter_bit(sts);
02667 }
02668
02669 sts = sts->parent;
02670 if (!sts) break;
02671
02672 sts->do_child_wanted = 1;
02673 }
02674 }
02675
02676 STOPIF( waa__update_tree(root, blocks), NULL);
02677
02678 ex:
02679 return status;
02680 }
02681
02682
02684 int waa__new_entry_block(struct estat *entry, int count,
02685 struct waa__entry_blocks_t *previous)
02686 {
02687 int status;
02688 struct waa__entry_blocks_t *eblock;
02689
02690
02691 status=0;
02692 STOPIF( hlp__alloc( &eblock, sizeof(*eblock)), NULL);
02693 eblock->first=entry;
02694 eblock->count=count;
02695
02696
02697
02698
02699 eblock->next=previous->next;
02700 eblock->prev=previous;
02701 previous->next=eblock;
02702 if (eblock->next)
02703 eblock->next->prev=eblock;
02704
02705 ex:
02706 return status;
02707 }
02708
02709
02712 int waa__find_base(struct estat *root, int *argc, char ***args)
02713 {
02714 int status;
02715 char **normalized;
02716
02717 status=0;
02718
02719
02720 root->arg="";
02721
02722 STOPIF( waa__find_common_base( *argc, *args, &normalized), NULL);
02723 if (*argc > 0 && strcmp(normalized[0], ".") == 0)
02724 {
02725
02726 root->arg = **args;
02727
02728 (*args) ++;
02729 (*argc) --;
02730 }
02731
02732 STOPIF_CODE_ERR( *argc, EINVAL,
02733 "!Only a working copy root is a valid path.");
02734
02735
02736 **args = normalized[0];
02737
02738 ex:
02739 return status;
02740 }
02741
02742
02744 inline int waa___recurse_tree(struct estat **list, action_t handler,
02745 int (*me)(struct estat *, action_t ))
02746 {
02747 struct estat *sts;
02748 int status;
02749
02750 status=0;
02751 while ( (sts=*list) )
02752 {
02753 if (sts->do_this_entry && ops__allowed_by_filter(sts))
02754 STOPIF( handler(sts), NULL);
02755
02756
02757
02758
02759
02760
02761 if ((sts->do_child_wanted || sts->do_userselected) &&
02762 sts->entry_count &&
02763 (sts->local_mode_packed ?
02764 TEST_PACKED(S_ISDIR, sts->local_mode_packed) :
02765 ((sts->entry_status & FS_REMOVED) &&
02766 S_ISDIR(sts->st.mode) &&
02767 opt__get_int(OPT__ALL_REMOVED)==OPT__YES)) )
02768
02769
02770
02771
02772
02773 STOPIF( me(sts, handler), NULL);
02774 list++;
02775 }
02776
02777 ex:
02778 return status;
02779 }
02780
02781
02784 int waa__do_sorted_tree(struct estat *root, action_t handler)
02785 {
02786 int status;
02787
02788 status=0;
02789
02790
02791 if (!root->parent && root->do_this_entry)
02792 STOPIF( handler(root), NULL);
02793
02794 if ( !root->by_name)
02795 STOPIF( dir__sortbyname(root), NULL);
02796
02797 STOPIF( waa___recurse_tree(root->by_name, handler,
02798 waa__do_sorted_tree), NULL);
02799
02800 ex:
02801 IF_FREE(root->by_name);
02802
02803 return status;
02804 }
02805
02806
02814 int waa__dir_enum(struct estat *this,
02815 int est_count,
02816 int by_name)
02817 {
02818 int status;
02819 struct sstat_t cwd_stat;
02820
02821
02822 status=0;
02823 STOPIF( hlp__lstat(".", &cwd_stat), NULL);
02824
02825 DEBUGP("checking: %llu to %llu",
02826 (t_ull)cwd_stat.ino,
02827 (t_ull)waa_stat.ino);
02828
02829 if (cwd_stat.dev == waa_stat.dev &&
02830 cwd_stat.ino == waa_stat.ino)
02831 goto ex;
02832
02833
02834 STOPIF( dir__enumerator(this, est_count, by_name), NULL);
02835
02836 ex:
02837 return status;
02838 }
02839
02840
02850 int waa__copy_entries(struct estat *src, struct estat *dest)
02851 {
02852 int status;
02853 struct estat *newdata, **to_append, **tmp;
02854 int append_count, left, space;
02855
02856
02857 to_append=NULL;
02858 status=0;
02859
02860 ops__copy_single_entry(src, dest);
02861 if (!S_ISDIR(src->st.mode))
02862 goto ex;
02863
02864
02865 append_count=0;
02866 STOPIF( hlp__calloc( &to_append,
02867 src->entry_count+1, sizeof(src->by_name[0])), NULL);
02868
02869 int remember_to_copy(struct estat *sts, struct estat **sts_p)
02870 {
02871 to_append[append_count]=sts;
02872 append_count++;
02873 return 0;
02874 }
02875
02876 STOPIF( ops__correlate_dirs( src, dest,
02877 remember_to_copy,
02878 waa__copy_entries,
02879 NULL, NULL), NULL);
02880
02881
02882
02883
02884
02885
02886
02887
02888 space=0;
02889 for( tmp=to_append, left=append_count; left>0; left--, tmp++, space--)
02890 {
02891 if (space)
02892 newdata++;
02893 else
02894 STOPIF( ops__allocate( left, &newdata, &space), NULL);
02895
02896 newdata->parent=dest;
02897 newdata->name=(*tmp)->name;
02898
02899 STOPIF( waa__copy_entries(*tmp, newdata), NULL);
02900
02901
02902
02903 (*tmp) = newdata;
02904 }
02905
02906 STOPIF( ops__new_entries(dest, append_count, to_append), NULL);
02907
02908
02909 ex:
02910 IF_FREE(to_append);
02911 return status;
02912 }
02913
02914
02923 int waa__get_tmp_name(const char *base_dir,
02924 char **output, apr_file_t **handle,
02925 apr_pool_t *pool)
02926 {
02927 int status;
02928 static struct cache_t *cache;
02929 static struct cache_entry_t *tmp_cache=NULL;
02930 static const char to_append[]=".XXXXXX";
02931 static const char to_prepend[]="fsvs";
02932 char *filename;
02933 int len;
02934
02935
02936 STOPIF( cch__new_cache(&cache, 12), NULL);
02937
02938 len= base_dir ? strlen(base_dir) : 0;
02939 if (!len)
02940 {
02941 if (!tmp_cache)
02942 {
02943
02944
02945
02946 STOPIF( apr_temp_dir_get(&base_dir, pool),
02947 "Getting a temporary directory path");
02948
02949 len=strlen(base_dir);
02950
02951 STOPIF( cch__entry_set( &tmp_cache, 0, base_dir,
02952 len +1 +1, 0, NULL), NULL);
02953
02954 tmp_cache->data[len++]=PATH_SEPARATOR;
02955 tmp_cache->data[len]=0;
02956
02957
02958
02959
02960
02961 tmp_cache->len=len;
02962 }
02963
02964 len=tmp_cache->len;
02965 base_dir=tmp_cache->data;
02966 BUG_ON(base_dir[len] != 0);
02967 }
02968
02969 STOPIF( cch__add(cache, 0, base_dir,
02970
02971 len + 1 + strlen(to_prepend) + strlen(to_append) + 1 + 3,
02972 &filename), NULL);
02973
02974 if (base_dir[len-1] == PATH_SEPARATOR)
02975 {
02976 strcpy( filename + len, to_prepend);
02977 len+=strlen(to_prepend);
02978 }
02979
02980 strcpy( filename + len, to_append);
02981
02982
02983 STOPIF( apr_file_mktemp(handle, filename,
02984 APR_CREATE | APR_READ | APR_WRITE | APR_EXCL |
02985 (output ? 0 : APR_DELONCLOSE),
02986 pool),
02987 "Cannot create a temporary file for \"%s\"", filename);
02988
02989 if (output) *output=filename;
02990
02991 ex:
02992 return status;
02993 }
02994
02998 int waa__set_working_copy(const char const *wc_dir)
02999 {
03000 int status;
03001
03002 status=0;
03003 BUG_ON(*wc_dir != PATH_SEPARATOR);
03004 wc_path_len=strlen(wc_dir);
03005 STOPIF( hlp__strnalloc( wc_path_len, &wc_path, wc_dir), NULL);
03006
03007 ex:
03008 return status;
03009 }
03010
03011
03015 int waa__create_working_copy(const char const *wc_dir)
03016 {
03017 int status;
03018 char *dir;
03019
03020 if (wc_dir)
03021 STOPIF(waa__set_working_copy(wc_dir), NULL);
03022
03023 BUG_ON(!wc_path);
03024
03025
03026 STOPIF( waa__get_waa_directory( wc_path, &dir, NULL, NULL,
03027 GWD_WAA | GWD_MKDIR), NULL);
03028 STOPIF( waa__mkdir(dir, 1), NULL);
03029
03030
03031 STOPIF( waa__get_waa_directory( wc_path, &dir, NULL, NULL,
03032 GWD_CONF | GWD_MKDIR), NULL);
03033 STOPIF( waa__mkdir(dir, 1), NULL);
03034
03035
03036
03037 STOPIF( waa__make_info_link(wc_path, "_base", wc_path), NULL);
03038
03039 ex:
03040 return status;
03041 }
03042