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
00595
00596 fh=-1;
00597 orig=NULL;
00598
00599
00600
00601
00602
00603 use_temp_file=(flags & O_APPEND) ? 0 :
00604 (flags & (O_WRONLY | O_RDWR | O_CREAT));
00605
00606 STOPIF( waa__get_waa_directory(path, &dest, &eos, &start_spec,
00607 waa__get_gwd_flag(extension) ), NULL);
00608
00609 if (!extension)
00610 {
00611
00612 BUG_ON(eos == dest);
00613 eos[-1]=0;
00614 return hlp__lstat(dest, NULL);
00615 }
00616
00617 strcpy(eos, extension);
00618 BUG_ON( action->is_readonly &&
00619 (flags & (O_WRONLY | O_RDWR | O_APPEND | O_CREAT)),
00620 "Action marked read-only, got flags 0x%x for %s", flags, eos);
00621
00622 if (use_temp_file)
00623 {
00624 STOPIF( hlp__strdup( &orig, dest), NULL);
00625
00626
00627 strcat(eos, ext_tmp);
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638 cp=strchr(start_spec, PATH_SEPARATOR);
00639 while (cp)
00640 {
00641 *cp='_';
00642 cp=strchr(cp+1, PATH_SEPARATOR);
00643 }
00644
00645
00646 STOPIF( hlp__strdup( &dest, dest), NULL);
00647 DEBUGP("tmp for target %s is %s", orig, dest);
00648 }
00649 else
00650 DEBUGP("reading target %s", dest);
00651
00652
00653 if (flags & O_APPEND)
00654 STOPIF( waa__mkdir(dest, 0), NULL);
00655
00656
00657
00658 fh=open(dest, flags, 0777);
00659 if (fh<0)
00660 {
00661 status=errno;
00662 if (status == ENOENT) goto ex;
00663 STOPIF(status, "open %s with flags 0x%X",
00664 dest, flags);
00665 }
00666
00667 DEBUGP("got fh %d", fh);
00668
00669
00670
00671
00672 if (use_temp_file)
00673 {
00674 if (fh >= target_name_array_len)
00675 {
00676
00677 status=target_name_array_len;
00678
00679
00680 target_name_array_len=fh+8;
00681 DEBUGP("reallocate target name array to %d", target_name_array_len);
00682 STOPIF( hlp__realloc( &target_name_array,
00683 sizeof(*target_name_array) * target_name_array_len), NULL);
00684
00685
00686 memset(target_name_array + status, 0,
00687 sizeof(*target_name_array) * (target_name_array_len-status));
00688 }
00689
00690
00691 target_name_array[fh].dest_name=orig;
00692 target_name_array[fh].temp_name=dest;
00693 }
00694
00695 *filehandle=fh;
00696 status=0;
00697
00698 ex:
00699 if (status && fh>-1) close(fh);
00700 return status;
00701 }
00702
00703
00712 int waa__close(int filehandle, int has_failed)
00713 {
00714 int status, do_unlink;
00715 struct waa___temp_names_t *target;
00716
00717
00718
00719
00720 do_unlink=1;
00721 status=0;
00722
00723 target= target_name_array ? target_name_array+filehandle : NULL;
00724
00725 if (target)
00726 DEBUGP("filehandle %d should be %s", filehandle, target->dest_name);
00727 else
00728 DEBUGP("filehandle %d wasn't opened via waa__open()!", filehandle);
00729
00730 status=close(filehandle);
00731 if (!has_failed)
00732 {
00733 STOPIF_CODE_ERR(status == -1, errno, "closing tmp file");
00734
00735 if (target)
00736 {
00737
00738
00739 STOPIF( waa__mkdir(target->dest_name, 0), NULL);
00740
00741
00742 STOPIF_CODE_ERR(
00743 rename(target->temp_name, target->dest_name) == -1,
00744 errno, "renaming tmp file from %s to %s",
00745 target->temp_name, target->dest_name);
00746 }
00747
00748 do_unlink=0;
00749 }
00750
00751 status=0;
00752
00753 ex:
00754
00755
00756 if (do_unlink && target)
00757 {
00758 do_unlink=0;
00759 STOPIF_CODE_ERR( unlink(target->temp_name) == -1, errno,
00760 "Cannot remove temporary file %s", target->temp_name);
00761 }
00762
00763 if (target)
00764 {
00765 IF_FREE(target->temp_name);
00766 IF_FREE(target->dest_name);
00767 }
00768
00769 return status;
00770 }
00771
00772
00779 int waa__make_info_link(char *directory, char *name, char *dest)
00780 {
00781 int status;
00782 char *path, *eos;
00783
00784
00785 STOPIF( waa__get_waa_directory(directory, &path, &eos, NULL,
00786 GWD_CONF | GWD_MKDIR), NULL);
00787
00788 strcpy(eos, name);
00789
00790 if (access(path, F_OK) != 0)
00791 STOPIF_CODE_ERR( symlink(dest, path) == -1,
00792 errno, "cannot create informational symlink '%s' -> '%s'",
00793 path, dest);
00794
00795 ex:
00796 return status;
00797 }
00798
00799
00808 int waa__given_or_current_wd(char *name, char **erg)
00809 {
00810 int status;
00811
00812
00813 status=0;
00814 if (name)
00815 STOPIF( hlp__strdup( erg, name), NULL);
00816 else
00817 STOPIF( waa__save_cwd( erg, NULL, 0), NULL);
00818
00819 ex:
00820 return status;
00821 }
00822
00823
00836 int waa__delete_byext(char *path,
00837 char *extension,
00838 int ignore_not_exist)
00839 {
00840 int status;
00841 char *cp, *eos;
00842 int i;
00843
00844
00845 status=0;
00846 if (extension)
00847 {
00848 STOPIF( waa__get_waa_directory(path, &cp, &eos, NULL,
00849 waa__get_gwd_flag(extension)), NULL);
00850 strcpy(eos, extension);
00851
00852
00853 eos--;
00854 BUG_ON(*eos != PATH_SEPARATOR);
00855 }
00856 else
00857 {
00858 cp=path;
00859 eos=strrchr(cp, PATH_SEPARATOR);
00860 BUG_ON(!eos);
00861 }
00862
00863 DEBUGP("unlink %s", cp);
00864 if (unlink(cp) == -1)
00865 {
00866 status=errno;
00867 if (status == ENOENT && ignore_not_exist) status=0;
00868
00869 STOPIF(status, "Cannot remove spool entry %s", cp);
00870 }
00871
00872
00873
00874
00875
00876
00877 for(i=0; i<3; i++)
00878 {
00879 *eos=0;
00880
00881 if (rmdir(cp) == -1) break;
00882
00883 eos=strrchr(cp, PATH_SEPARATOR);
00884
00885 BUG_ON(!eos, "Got invalid path to remove");
00886 }
00887
00888 DEBUGP("last removed was %s", cp);
00889
00890 ex:
00891 return status;
00892 }
00893
00894
00903 int waa__open_byext(char *entry_name,
00904 char *extension,
00905 int mode,
00906 int *fh)
00907 {
00908 int status;
00909 char *entry;
00910
00911
00912 status=0;
00913 entry=NULL;
00914 STOPIF( waa__given_or_current_wd(entry_name, &entry), NULL );
00915
00916 status=waa__open(entry, extension, mode, fh);
00917 if (status == ENOENT) goto ex;
00918 STOPIF(status, NULL);
00919
00920 ex:
00921 IF_FREE(entry);
00922 return status;
00923 }
00924
00925
00928 int waa__open_dir(char *wc_base,
00929 int write,
00930 int *fh)
00931 {
00932 return waa__open_byext(wc_base, WAA__DIR_EXT, write, fh);
00933 }
00934
00935
00939 int waa__build_tree(struct estat *dir)
00940 {
00941 int status;
00942 struct estat *sts;
00943 int i, ignore, have_ignored, have_found;
00944
00945 status=0;
00946
00947 STOPIF( waa__dir_enum( dir, 0, 0), NULL);
00948
00949
00950 DEBUGP("found %d entries ...", dir->entry_count);
00951 have_ignored=0;
00952 have_found=0;
00953 for(i=0; i<dir->entry_count; i++)
00954 {
00955 sts=dir->by_inode[i];
00956
00957 STOPIF( ign__is_ignore(sts, &ignore), NULL);
00958 if (ignore>0)
00959 {
00960 DEBUGP("ignoring entry %s", sts->name);
00961
00962 sts->to_be_ignored=1;
00963 have_ignored=1;
00964 continue;
00965 }
00966
00967
00968 sts->entry_status=FS_NEW;
00969 ops__set_todo_bits(sts);
00970 approx_entry_count++;
00971 have_found++;
00972
00973 if (S_ISDIR(sts->st.mode))
00974 {
00975 if (ops__are_children_interesting(sts))
00976 {
00977 STOPIF_CODE_ERR( chdir(sts->name) == -1, errno,
00978 "chdir(%s)", sts->name);
00979
00980 STOPIF( waa__build_tree(sts), NULL );
00981
00982
00983 STOPIF_CODE_ERR( chdir("..") == -1, errno,
00984 "parent has gone");
00985 }
00986 }
00987
00988 STOPIF( ac__dispatch(sts), NULL);
00989 }
00990
00991 if (have_ignored)
00992
00993 STOPIF( ops__free_marked(dir, 0), NULL);
00994
00995 if (have_found)
00996 ops__mark_changed_parentcc(dir, entry_status);
00997
00998 ex:
00999 return status;
01000 }
01001
01002
01005 int waa___find_position(struct estat **new,
01006 struct estat ***array, int count)
01007 {
01008 int smaller, middle, bigger_eq;
01009 int status;
01010
01011
01012
01013 if (count == 0)
01014 return 0;
01015
01016
01017
01018
01019
01020
01021
01022
01023
01024
01025
01026 if (dir___f_sort_by_inode(new, array[0]) < 0)
01027 {
01028 DEBUGP("short path taken for 0<1");
01029 return 0;
01030 }
01031
01032 if (count == 1) return 1;
01033
01034
01035 if (dir___f_sort_by_inode(new, array[count-1]) >= 0)
01036 {
01037 DEBUGP("short path taken for >count");
01038 return count;
01039 }
01040 smaller=1;
01041
01042
01043
01044
01045 bigger_eq=count-1;
01046
01047 #if 0
01048 if (1)
01049 {
01050 char tmp[count*(18+1)+10];
01051 int i, n;
01052 for (i=n=0; i<count; i++)
01053 {
01054 n += sprintf(tmp+n,"%llu ", (t_ull)(*array[i])->st.ino);
01055 }
01056 DEBUGP("having %d [ %s]", count, tmp);
01057 DEBUGP("looking for %llu", (t_ull)(*new)->st.ino);
01058 }
01059 #endif
01060
01061 while (1)
01062 {
01063 middle=(bigger_eq+smaller)/2;
01064 DEBUGP("at %d=%llu - %d=%llu - %d=%llu",
01065 smaller, (t_ull)(*array[smaller])->st.ino,
01066 middle, (t_ull)(*array[middle])->st.ino,
01067 bigger_eq, (t_ull)(*array[bigger_eq])->st.ino);
01068
01069 status=dir___f_sort_by_inode(new, array[middle]);
01070 if (status > 0)
01071 smaller=middle+1;
01072 else if (status < 0)
01073 bigger_eq=middle;
01074 else
01075 {
01076
01077
01078
01079 DEBUGP("Jackpot, hardlink!");
01080 bigger_eq=middle;
01081 break;
01082 }
01083 if (bigger_eq<=smaller) break;
01084 }
01085
01086 DEBUGP("believing in %d %llu",
01087 bigger_eq, (t_ull)(*array[bigger_eq])->st.ino);
01088
01089
01090 #if DEBUG
01091 BUG_ON((bigger_eq < count-1 && dir___f_sort_by_inode(new, array[bigger_eq])>0) ||
01092 (bigger_eq >0 && dir___f_sort_by_inode(new, array[bigger_eq-1])<0));
01093 #endif
01094
01095 return bigger_eq;
01096 }
01097
01098
01211 int waa__output_tree(struct estat *root)
01212 {
01213 struct estat ***directory, *sts, **sts_pp;
01214 int max_dir, i, alloc_dir;
01215 unsigned this_len;
01216 int status, waa_info_hdl;
01217 unsigned complete_count, string_space;
01218 char header[HEADER_LEN] = "UNFINISHED";
01219
01220
01221 waa_info_hdl=-1;
01222 directory=NULL;
01223 STOPIF( waa__open_dir(NULL, WAA__WRITE, &waa_info_hdl), NULL);
01224
01225
01226 status=strlen(header);
01227 memset(header + status, '\n', sizeof(header)-status);
01228 i=write(waa_info_hdl, header, sizeof(header));
01229 STOPIF_CODE_ERR( i != sizeof(header), errno,
01230 "header was not written");
01231
01232
01233
01234
01235 alloc_dir=1024;
01236 STOPIF( hlp__calloc( &directory, alloc_dir+1, sizeof(*directory)), NULL);
01237
01238
01239
01240 root->url=NULL;
01241
01242 STOPIF( ops__save_1entry(root, 0, waa_info_hdl), NULL);
01243 root->file_index=complete_count=1;
01244
01245
01246 root->path_len=string_space=strlen(root->name);
01247 max_path_len=root->path_len;
01248
01249
01250
01251
01252 if (!root->entry_count) goto save_header;
01253
01254
01255
01256 if (root->to_be_sorted)
01257 {
01258 DEBUGP("re-sorting root");
01259 STOPIF( dir__sortbyinode(root), NULL);
01260 }
01261
01262
01263
01264 directory[0]=root->by_inode;
01265 max_dir=1;
01266
01267
01268 while (max_dir)
01269 {
01270
01271 sts=( *directory[0] );
01272
01273
01274
01275 directory[0]++;
01276
01277
01278 if (*directory[0] == NULL)
01279 {
01280
01281 max_dir--;
01282 DEBUGP("finished subdir");
01283 memmove(directory, directory+1, sizeof(*directory)*max_dir);
01284 }
01285 else if (max_dir>1)
01286 {
01287
01288
01289 i=waa___find_position(directory[0], directory+1, max_dir-1);
01290 if (i)
01291 {
01292
01293
01294
01295
01296
01297
01298
01299
01300 sts_pp=directory[0];
01301 memmove(directory, directory+1, sizeof(*directory)*i);
01302 directory[i]=sts_pp;
01303 DEBUGP("old current moves to #%u: %llu < %llu",
01304 i,
01305 (t_ull)(*directory[i-1])->st.ino,
01306 (t_ull)(*directory[i ])->st.ino);
01307 }
01308 }
01309
01310
01311
01312 if (!ops__should_entry_be_written_in_list(sts))
01313 continue;
01314
01315
01316
01317 STOPIF( ops__save_1entry(sts, sts->parent->file_index, waa_info_hdl),
01318 NULL);
01319
01320 complete_count++;
01321
01322 sts->file_index=complete_count;
01323
01324 this_len=strlen(sts->name)+1;
01325 string_space += this_len;
01326
01327 if (!sts->path_len)
01328 ops__calc_path_len(sts);
01329 if (sts->path_len > max_path_len)
01330 max_path_len = sts->path_len;
01331
01332
01333 if (ops__has_children(sts))
01334 {
01335
01336
01337
01338
01339
01340
01341
01342
01343
01344
01345 if (max_dir >= alloc_dir)
01346 {
01347 alloc_dir *= 2;
01348 STOPIF( hlp__realloc( &directory, (alloc_dir+1) * sizeof(*directory)), NULL);
01349 DEBUGP("reallocated directory pointers to %u entries", alloc_dir);
01350 }
01351
01352
01353
01354 if (sts->to_be_sorted)
01355 STOPIF( dir__sortbyinode(sts), NULL);
01356
01357
01358
01359 i=waa___find_position(sts->by_inode, directory, max_dir);
01360
01361
01362
01363
01364
01365
01366
01367 memmove(directory+i+1, directory+i,
01368 sizeof(*directory)*(max_dir-i));
01369
01370 directory[i]=sts->by_inode;
01371 DEBUGP("new subdir %llu #%u", (t_ull)(*directory[i])->st.ino, i);
01372 max_dir++;
01373 }
01374
01375 #ifdef DEBUG
01376 for(i=1; i<max_dir; i++)
01377 BUG_ON(
01378 dir___f_sort_by_inode( directory[i-1], directory[i] ) >0);
01379 #endif
01380 }
01381
01382
01383 save_header:
01384
01385
01386 status=snprintf(header, sizeof(header), waa__header_line,
01387 WAA_VERSION, (t_ul)sizeof(header),
01388 complete_count, alloc_dir, string_space+4,
01389 max_path_len+4);
01390 BUG_ON(status >= sizeof(header)-1, "header space not large enough");
01391
01392
01393 memset(header + status, ' ', sizeof(header)-1 -status);
01394 header[sizeof(header)-2]='$';
01395 STOPIF_CODE_ERR( lseek(waa_info_hdl, 0, SEEK_SET) == -1, errno,
01396 "seeking to start of file");
01397 status=write(waa_info_hdl, header, sizeof(header));
01398 STOPIF_CODE_ERR( status != sizeof(header), errno,
01399 "re-writing header failed");
01400
01401 status=0;
01402
01403 ex:
01404 if (waa_info_hdl != -1)
01405 {
01406 i=waa__close(waa_info_hdl, status);
01407 waa_info_hdl=-1;
01408 STOPIF( i, "closing tree handle");
01409 }
01410
01411 if (directory) IF_FREE(directory);
01412
01413 return status;
01414 }
01415
01416
01429 int waa__update_dir(struct estat *old)
01430 {
01431 int dir_hdl, status;
01432 struct estat current;
01433 int nr_new, i;
01434 char *path;
01435
01436
01437 status=nr_new=0;
01438 dir_hdl=-1;
01439
01440 current=*old;
01441 current.by_inode=current.by_name=NULL;
01442 current.entry_count=0;
01443
01444 STOPIF( ops__build_path(&path, old), NULL);
01445
01446
01447
01448 dir_hdl=open(".", O_RDONLY | O_DIRECTORY);
01449 STOPIF_CODE_ERR( dir_hdl==-1, errno,
01450 "saving current directory with open(.)");
01451
01452 DEBUGP("update_dir: chdir(%s)", path);
01453 if (chdir(path) == -1)
01454 {
01455 if (errno == EACCES) goto ex;
01456 STOPIF( errno, "chdir(%s)", path);
01457 }
01458
01459
01460 STOPIF( waa__dir_enum( ¤t, 0, 1), NULL);
01461 DEBUGP("update_dir: direnum found %d; old has %d (%d)",
01462 current.entry_count, old->entry_count,
01463 status);
01464
01465 if (current.entry_count == 0) goto after_compare;
01466
01467
01468
01469
01470
01471
01472
01473
01474
01475
01476
01477
01478
01479
01480
01481
01482
01483
01484
01485
01486
01487
01488
01489 int new_entry(struct estat *sts, struct estat **sts_p)
01490 {
01491 int status;
01492 int ignore;
01493
01494 STOPIF( ign__is_ignore(sts, &ignore), NULL);
01495 if (ignore>0)
01496 DEBUGP("ignoring entry %s", sts->name);
01497 else
01498 {
01499 sts->parent=old;
01500
01501 *sts_p=NULL;
01502 current.by_inode[nr_new]=sts;
01503 nr_new++;
01504
01505 DEBUGP("found a new one!");
01506 sts->entry_status=FS_NEW;
01507 sts->flags |= RF_ISNEW;
01508
01509
01510
01511 ops__set_todo_bits(sts);
01512 STOPIF( ac__dispatch(sts), NULL);
01513
01514 ops__mark_parent_cc(sts, entry_status);
01515 approx_entry_count++;
01516
01517
01518
01519 if (S_ISDIR(sts->st.mode) &&
01520 ops__are_children_interesting(sts) &&
01521 (opt__get_int(OPT__FILTER) & FS_NEW))
01522 {
01523 STOPIF_CODE_ERR( chdir(sts->name) == -1, errno,
01524 "chdir(%s)", sts->name);
01525
01526 STOPIF( waa__build_tree(sts), NULL);
01527
01528 STOPIF_CODE_ERR( chdir("..") == -1, errno,
01529 "parent went away");
01530 }
01531
01532 }
01533
01534 ex:
01535 return status;
01536 }
01537
01538 nr_new=0;
01539 STOPIF( ops__correlate_dirs( old, ¤t,
01540 NULL, NULL, new_entry, NULL), NULL);
01541
01542
01543 DEBUGP("%d new entries", nr_new);
01544
01545 status=0;
01546 if (nr_new)
01547 {
01548 STOPIF( ops__new_entries(old, nr_new, current.by_inode),
01549 "adding %d new entries", nr_new);
01550 }
01551
01552
01553
01554 for(i=0; i < current.entry_count; i++)
01555 if (current.by_name[i] )
01556 STOPIF( ops__free_entry( current.by_name+i ), NULL);
01557
01558
01559 IF_FREE(current.by_inode);
01560 IF_FREE(current.by_name);
01561
01562
01563
01564
01565 after_compare:
01566
01567
01568
01569 old->entry_status &= ~FS_LIKELY;
01570
01571
01572
01573
01574 if (nr_new)
01575 ops__mark_changed_parentcc(old, entry_status);
01576
01577 ex:
01578 if (dir_hdl!=-1)
01579 {
01580 i=fchdir(dir_hdl);
01581 STOPIF_CODE_ERR(i == -1 && !status, errno,
01582 "cannot fchdir() back");
01583 i=close(dir_hdl);
01584 STOPIF_CODE_ERR(i == -1 && !status, errno,
01585 "cannot close dirhandle");
01586 }
01587 DEBUGP("update_dir reports %d new found, status %d", nr_new, status);
01588 return status;
01589 }
01590
01591
01593 #define TREE_DAMAGED(condition, ...) \
01594 STOPIF_CODE_ERR( condition, EINVAL, \
01595 "!The entries file seems to be damaged -- \n" \
01596 " %s.\n" \
01597 "\n" \
01598 "Please read the users@ mailing list.\n" \
01599 " If you know what you're doing you could " \
01600 "try using 'sync-repos'\n" \
01601 " (but please _read_the_documentation_!)\n" \
01602 " 'We apologize for the inconvenience.'", \
01603 __VA_ARGS__);
01604
01605
01612 int waa__input_tree(struct estat *root,
01613 struct waa__entry_blocks_t **blocks,
01614 action_t *callback)
01615 {
01616 int status, waa_info_hdl=-1;
01617 int i, cur, first;
01618 unsigned count, subdirs, string_space;
01619
01620
01621
01622 ino_t parent;
01623 char header[HEADER_LEN];
01624 char *filename;
01625 struct estat *sts, *stat_mem;
01626 char *strings;
01627 int sts_free;
01628 char *dir_mmap, *dir_end, *dir_curr;
01629 off_t length;
01630 t_ul header_len;
01631 struct waa__entry_blocks_t *cur_block;
01632 struct estat *sts_tmp;
01633
01634
01635 waa__entry_block.first=root;
01636 waa__entry_block.count=1;
01637 waa__entry_block.next=waa__entry_block.prev=NULL;
01638 cur_block=&waa__entry_block;
01639
01640 length=0;
01641 dir_mmap=NULL;
01642 status=waa__open_dir(NULL, WAA__READ, &waa_info_hdl);
01643 if (status == ENOENT)
01644 {
01645 status=-ENOENT;
01646 goto ex;
01647 }
01648 STOPIF(status, "cannot open .dir file");
01649
01650 length=lseek(waa_info_hdl, 0, SEEK_END);
01651 STOPIF_CODE_ERR( length == (off_t)-1, errno,
01652 "Cannot get length of .dir file");
01653
01654 DEBUGP("mmap()ping %llu bytes", (t_ull)length);
01655 dir_mmap=mmap(NULL, length,
01656 PROT_READ, MAP_SHARED,
01657 waa_info_hdl, 0);
01658
01659
01660 status=errno;
01661 i=close(waa_info_hdl);
01662 STOPIF_CODE_ERR( !dir_mmap, status, "mmap failed");
01663 STOPIF_CODE_ERR( i, errno, "close() failed");
01664
01665 dir_end=dir_mmap+length;
01666
01667 TREE_DAMAGED( length < (HEADER_LEN+5) ||
01668 dir_mmap[HEADER_LEN-1] != '\n' ||
01669 dir_mmap[HEADER_LEN-2] != '$',
01670 "the header is not correctly terminated");
01671
01672
01673
01674 memcpy(header, dir_mmap, HEADER_LEN-2);
01675 header[HEADER_LEN-2]=0;
01676 status=sscanf(header, waa__header_line,
01677 &i, &header_len,
01678 &count, &subdirs, &string_space,
01679 &max_path_len);
01680 DEBUGP("got %d header fields", status);
01681 TREE_DAMAGED( status != 6,
01682 "not all needed header fields could be parsed");
01683 dir_curr=dir_mmap+HEADER_LEN;
01684
01685 TREE_DAMAGED( i != WAA_VERSION || header_len != HEADER_LEN,
01686 "the header has a wrong version");
01687
01688
01689 approx_entry_count=count;
01690
01691
01692
01693
01694
01695 max_path_len+=1024;
01696
01697 DEBUGP("reading %d subdirs, %d entries, %d bytes string-space",
01698 subdirs, count, string_space);
01699
01700
01701
01702
01703
01704
01705
01706
01707 TREE_DAMAGED( dir_mmap[length-2] != '\0' || dir_mmap[length-1] != '\n',
01708 "the file is not correctly terminated");
01709
01710 DEBUGP("ok, found \\0 or \\0\\n at end");
01711
01712 STOPIF( hlp__alloc( &strings, string_space), NULL);
01713 root->strings=strings;
01714
01715
01716 cur=0;
01717 sts_free=1;
01718 first=1;
01719
01720 while ( count > 0)
01721 {
01722 DEBUGP("curr=%p, end=%p, count=%d",
01723 dir_curr, dir_end, count);
01724 TREE_DAMAGED( dir_curr>=dir_end,
01725 "An entry line has a wrong number of entries");
01726
01727 if (sts_free == 0)
01728 {
01729
01730
01731
01732 STOPIF( ops__allocate(count, &stat_mem, &sts_free), NULL );
01733
01734 STOPIF( waa__insert_entry_block(stat_mem, sts_free), NULL);
01735
01736 cur_block=waa__entry_block.next;
01737 }
01738
01739 sts_free--;
01740 count--;
01741
01742 sts=first ? root : stat_mem+cur;
01743
01744 DEBUGP("about to parse %p = '%-.40s...'", dir_curr, dir_curr);
01745 STOPIF( ops__load_1entry(&dir_curr, sts, &filename, &parent), NULL);
01746
01747
01748
01749 TREE_DAMAGED( (parent && first) ||
01750 (!parent && !first) ||
01751 (parent && parent-1>cur),
01752 "the parent pointers are invalid");
01753
01754 if (first) first=0;
01755 else cur++;
01756
01757
01758 strcpy(strings, filename);
01759 sts->name=strings;
01760 strings += strlen(filename)+1;
01761 BUG_ON(strings - root->strings > string_space);
01762
01763 if (parent)
01764 {
01765 if (parent == 1) sts->parent=root;
01766 else
01767 {
01768 i=parent-2;
01769 BUG_ON(i >= cur);
01770 sts->parent=stat_mem+i;
01771 }
01772
01773
01774 sts->parent->by_inode[ sts->parent->child_index++ ] = sts;
01775 BUG_ON(sts->parent->child_index > sts->parent->entry_count,
01776 "too many children for parent");
01777
01778
01779 if (sts->repos_rev != sts->parent->repos_rev)
01780 {
01781 sts_tmp=sts->parent;
01782 while (sts_tmp && !sts_tmp->other_revs)
01783 {
01784 sts_tmp->other_revs = 1;
01785 sts_tmp=sts_tmp->parent;
01786 }
01787 }
01788 }
01789
01790
01791 if (S_ISDIR(sts->st.mode))
01792 {
01793
01794 if (sts->entry_count)
01795 {
01796 STOPIF( hlp__alloc( &sts->by_inode,
01797 sizeof(*sts->by_inode) * (sts->entry_count+1)), NULL);
01798 sts->by_inode[sts->entry_count]=NULL;
01799 sts->child_index=0;
01800 }
01801 }
01802
01803 if (callback)
01804 STOPIF( callback(sts), NULL);
01805 }
01806
01807
01808 ex:
01809
01810 if (blocks)
01811 *blocks=&waa__entry_block;
01812
01813 if (dir_mmap)
01814 {
01815 i=munmap(dir_mmap, length);
01816 if (!status)
01817 STOPIF_CODE_ERR(i, errno, "munmap() failed");
01818 }
01819
01820 return status;
01821 }
01822
01823
01835 inline int waa___check_dir_for_update(struct estat *sts)
01836 {
01837 int status;
01838
01839
01840 status=0;
01841
01842 if (!sts->do_this_entry) goto ex;
01843
01844
01845
01846
01847
01848
01849
01850
01851 if ((sts->entry_status ||
01852 (opt__get_int(OPT__CHANGECHECK) & CHCHECK_DIRS) ||
01853 (sts->flags & RF_ADD) ||
01854 (sts->flags & RF_CHECK) ) &&
01855 ops__are_children_interesting(sts) &&
01856 action->do_update_dir)
01857 {
01858
01859 DEBUGP("dir_to_print | CHECK for %s", sts->name);
01860 STOPIF( waa__update_dir(sts), NULL);
01861
01862
01863
01864 ops__calc_filter_bit(sts);
01865 }
01866
01867
01868
01869 if (ops__allowed_by_filter(sts))
01870 STOPIF( ac__dispatch(sts), NULL);
01871
01872 ex:
01873 return status;
01874 }
01875
01876
01881 int waa___finish_directory(struct estat *sts)
01882 {
01883 int status;
01884 struct estat *walker;
01885
01886
01887 status=0;
01888
01889 walker=sts;
01890 while (1)
01891 {
01892 DEBUGP("checking directory %s: %u unfini, %d of %d (%s)",
01893 walker->name,
01894 walker->unfinished,
01895 walker->child_index, walker->entry_count,
01896 st__status_string(walker));
01897
01898 if (walker->unfinished > 0) break;
01899
01900
01901
01902
01903 if (walker->entry_count == 0)
01904 BUG_ON(walker != sts);
01905 else if (walker->child_index < walker->entry_count)
01906 break;
01907
01908 DEBUGP("walker=%s; status=%s",
01909 walker->name,
01910 st__status_string_fromint(walker->entry_status));
01911
01912 if (!TEST_PACKED(S_ISDIR, walker->local_mode_packed) ||
01913 (walker->entry_status & FS_REPLACED) == FS_REMOVED)
01914 {
01915
01916
01917
01918
01919 }
01920 else if (!(opt__get_int(OPT__FILTER) & FS_NEW))
01921 {
01922
01923
01924 if (ops__allowed_by_filter(walker))
01925 STOPIF( ac__dispatch(walker), NULL);
01926 }
01927 else
01928 {
01929
01930
01931 STOPIF( waa___check_dir_for_update(walker), NULL);
01932
01933
01934 walker->unfinished+=0x1000;
01935 }
01936
01937
01938
01939 walker=walker->parent;
01940 if (!walker) break;
01941
01942
01943 DEBUGP("%s has a finished child, now %d unfinished",
01944 walker->name, walker->unfinished);
01945
01946
01947 if (walker->unfinished)
01948 walker->unfinished--;
01949 }
01950
01951 if (walker == sts->parent && walker)
01952 DEBUGP("deferring parent %s/%s (%d unfinished)",
01953 walker->name, sts->name, walker->unfinished);
01954
01955 ex:
01956 return status;
01957 }
01958
01959
02022 int waa__update_tree(struct estat *root,
02023 struct waa__entry_blocks_t *cur_block)
02024 {
02025 int status;
02026 struct estat *sts;
02027
02028
02029 if (! (root->do_userselected || root->do_child_wanted) )
02030 {
02031
02032
02033 root->do_userselected =
02034 root->do_this_entry =
02035 root->do_filter_allows_done =
02036 root->do_filter_allows = 1;
02037 DEBUGP("Full tree update");
02038 }
02039
02040
02041 action->keep_children=1;
02042
02043 status=0;
02044 while (cur_block)
02045 {
02046
02047 sts=cur_block->first;
02048 DEBUGP("doing update for %s ... %d left in %p",
02049 sts->name, cur_block->count, cur_block);
02050
02051
02052
02053 if (S_ISDIR(sts->st.mode))
02054 sts->child_index = sts->unfinished = 0;
02055
02056 STOPIF( ops__update_filter_set_bits(sts), NULL);
02057
02058 if (!(sts->do_this_entry || sts->do_child_wanted))
02059 goto next;
02060
02061
02062
02063 if (sts->entry_status)
02064 ops__mark_parent_cc(sts, entry_status);
02065
02066 if (sts->parent)
02067 {
02068 if (TEST_PACKED(S_ISDIR, sts->old_rev_mode_packed))
02069 sts->parent->unfinished++;
02070
02071 if (sts->parent->entry_status & FS_REMOVED)
02072 goto next;
02073 }
02074
02075 if (sts->entry_status & FS_REMOVED)
02076 {
02077 if (sts->parent)
02078 {
02079
02080 sts->parent->entry_status &= (~FS_LIKELY);
02081 sts->parent->entry_status |= FS_CHANGED;
02082
02083 }
02084
02085
02086
02087 if (TEST_PACKED(S_ISDIR, sts->old_rev_mode_packed) &&
02088 !action->keep_children)
02089 sts->entry_count=0;
02090
02091
02092
02093 if (TEST_PACKED(S_ISDIR, sts->old_rev_mode_packed))
02094
02095
02096 sts->parent->unfinished--;
02097 }
02098
02099
02100 if (S_ISDIR(PACKED_to_MODE_T(sts->local_mode_packed)) &&
02101 (sts->entry_status & FS_REPLACED) == FS_REPLACED)
02102 {
02103
02104
02105
02106
02107
02108
02109
02110
02111 DEBUGP("new directory %s", sts->name);
02112 sts->entry_count=0;
02113 sts->unfinished=0;
02114 sts->by_inode=sts->by_name=NULL;
02115 sts->strings=NULL;
02116
02117
02118 }
02119
02120
02121 next:
02122
02123
02124 if (TEST_PACKED(S_ISDIR, sts->local_mode_packed) &&
02125 sts->entry_count==0)
02126 {
02127 DEBUGP("doing empty directory %s %d", sts->name, sts->do_this_entry);
02128
02129
02130 STOPIF( waa___finish_directory(sts), NULL);
02131 }
02132
02133
02134
02135
02136
02137 if (!TEST_PACKED(S_ISDIR, sts->local_mode_packed) &&
02138 sts->do_this_entry)
02139 STOPIF( ac__dispatch(sts), NULL);
02140
02141
02142
02143
02144
02145
02146 if (sts->parent && action->keep_children )
02147 {
02148 sts->parent->child_index++;
02149
02150
02151 if (sts->parent->child_index >= sts->parent->entry_count
02152 && sts->parent->do_this_entry)
02153 {
02154 DEBUGP("checking parent %s/%s", sts->parent->name, sts->name);
02155
02156
02157
02158
02159 STOPIF( waa___finish_directory(sts->parent), NULL);
02160 }
02161 else
02162 DEBUGP("deferring parent %s/%s%s: %d of %d, %d unfini",
02163 sts->parent->name, sts->name,
02164 sts->parent->do_this_entry ? "" : " (no do_this_entry)",
02165 sts->parent->child_index, sts->parent->entry_count,
02166 sts->parent->unfinished);
02167 }
02168
02169
02170
02171
02172 cur_block->first++;
02173 cur_block->count--;
02174 if (cur_block->count <= 0)
02175 {
02176
02177
02178 cur_block=cur_block->next;
02179 }
02180 }
02181
02182
02183 ex:
02184 return status;
02185 }
02186
02187
02199 int waa__read_or_build_tree(struct estat *root,
02200 int argc, char *normalized[], char *orig[],
02201 action_t *callback,
02202 int return_ENOENT)
02203 {
02204 int status;
02205 struct waa__entry_blocks_t *blocks;
02206
02207
02208 status=0;
02209 status=waa__input_tree(root, &blocks, callback);
02210 DEBUGP("read tree = %d", status);
02211
02212 if (status == -ENOENT)
02213 {
02214
02215 if (return_ENOENT)
02216 return -ENOENT;
02217 }
02218 else
02219 STOPIF( status, NULL);
02220
02221 if (opt__get_int(OPT__PATH) == PATH_CACHEDENVIRON)
02222 STOPIF( hlp__match_path_envs(root), NULL);
02223
02224
02225 STOPIF( waa__partial_update(root, argc, normalized,
02226 orig, blocks), NULL);
02227
02228
02229
02230 if (action->local_uninit)
02231 STOPIF( action->local_uninit(), NULL);
02232
02233 ex:
02234 return status;
02235 }
02236
02237
02287 int waa__find_common_base2(int argc, char *args[],
02288 char ***normalized,
02289 int flags)
02290 {
02291 int status, i, j;
02292 int len;
02293 char *cp, *confname;
02294 char *paths[argc], *base_copy;
02295 char **norm;
02296 char *nullp[2];
02297 char *last_ps;
02298 const char *path2copy, *basepath2copy;
02299
02300
02301 char canon[PATH_MAX];
02302 static const char ps[]={PATH_SEPARATOR, 0};
02303 int fnlen;
02304
02305
02306 status=0;
02307 norm=NULL;
02308
02309
02310 if (argc == 0)
02311 {
02312 argc=1;
02313 nullp[0]=start_path;
02314 nullp[1]=NULL;
02315 args=nullp;
02316 DEBUGP("faked a single parameter to %s", *args);
02317 }
02318
02319
02320
02321
02322
02323
02324
02325 len = argc * sizeof(char*) + sizeof(NULL);
02326 STOPIF( hlp__alloc( &norm, len), NULL);
02327
02328
02329
02330
02331 len=0;
02332 status=0;
02333 for(i=0; i<argc; i++)
02334 {
02335 last_ps=strrchr(args[i], PATH_SEPARATOR);
02336
02337 if (!last_ps)
02338 {
02339 only_rel_path:
02340
02341
02342
02343 fnlen=start_path_len+1+strlen(args[i])+1;
02344 path2copy=args[i];
02345 basepath2copy=start_path;
02346 }
02347 else if (flags & FCB__NO_REALPATH)
02348 {
02349
02350 if (args[i][0] != PATH_SEPARATOR) goto only_rel_path;
02351
02352 fnlen=strlen(args[i])+1;
02353 basepath2copy=ps;
02354 path2copy=args[i];
02355 }
02356 else if (last_ps == args[i])
02357 {
02358
02359 fnlen=strlen(args[i])+1;
02360 basepath2copy=ps;
02361 path2copy=args[i];
02362 }
02363 else if (last_ps)
02364 {
02365
02366 *last_ps=0;
02367 status=realpath(args[i], canon) ? 0 : errno;
02368
02369 STOPIF( status, "realpath(%s)", args[i]);
02370 *last_ps=PATH_SEPARATOR;
02371
02372 fnlen=strlen(canon)+1+strlen(last_ps+1)+1;
02373 BUG_ON(fnlen >= PATH_MAX, "path longer than PATH_MAX");
02374
02375 path2copy=last_ps;
02376 basepath2copy=canon;
02377 }
02378 else
02379 BUG_ON(1);
02380
02381
02382 STOPIF( hlp__alloc( paths+i, fnlen+1), NULL);
02383 paths[i]++;
02384 hlp__pathcopy(paths[i], &j, basepath2copy, ps, path2copy, NULL);
02385
02386 if (len<j) len=j;
02387 while (len > 1 && paths[i][len-1] == PATH_SEPARATOR)
02388 paths[i][--len]=0;
02389 DEBUGP("got argument #%d as %s[%d]", i, paths[i], len);
02390 }
02391
02392
02393
02394
02395 len=strlen(paths[0]);
02396 for(i=1; i<argc; i++)
02397 {
02398 DEBUGP("len before #%d is %d", i, len);
02399 for(j=0; j<len; j++)
02400
02401 if (paths[i][j] != paths[0][j])
02402 len=j;
02403 }
02404 DEBUGP("len after is %d", len);
02405
02406
02407
02408
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 if (paths[0][len] == PATH_SEPARATOR ||
02436 paths[0][len] == 0)
02437 {
02438 DEBUGP("Is a directory, possible a wc root.");
02439 }
02440 else
02441 {
02442 DEBUGP("Reverting to next %c", PATH_SEPARATOR);
02443
02444 len--;
02445
02446 while (paths[0][len] != PATH_SEPARATOR && len >0)
02447 len--;
02448 }
02449
02450 BUG_ON(len < 0, "Paths not even equal in separator - "
02451 "they have nothing in common!");
02452
02453
02454 if (len == 0)
02455 {
02456
02457 len=1;
02458 DEBUGP("we're at root.");
02459 }
02460
02461 STOPIF( hlp__strnalloc(len, &base_copy, paths[0]), NULL);
02462 DEBUGP("starting search at %s", base_copy);
02463
02464
02465
02466
02467
02468 while (1)
02469 {
02470
02471
02472
02473 DEBUGP("looking for %s", base_copy);
02474 status=waa__open(base_copy, NULL, 0, 0);
02475
02476
02477 if (!status) break;
02478
02479 if (len <= 1) break;
02480
02481 base_copy[len]=0;
02482 cp=rindex(base_copy, PATH_SEPARATOR);
02483 if (cp)
02484 {
02485
02486 if (cp == base_copy)
02487 cp++;
02488
02489 *cp=0;
02490 len=cp - base_copy;
02491 }
02492 }
02493
02494 DEBUGP("after loop is len=%d, base=%s, and status=%d",
02495 len, base_copy, status);
02496
02497
02498
02499
02500
02501 STOPIF( status, "!Couldn't find a working copy with matching base.");
02502
02503
02504 wc_path=base_copy;
02505 wc_path_len=len;
02506
02507 DEBUGP("found working copy base at %s", wc_path);
02508 STOPIF_CODE_ERR( chdir(wc_path) == -1, errno, "chdir(%s)", wc_path);
02509
02510 setenv(FSVS_EXP_WC_ROOT, wc_path, 1);
02511
02512
02513
02514
02515 for(i=0; i<argc; i++)
02516 {
02517 DEBUGP("path is %s", paths[i]);
02518
02519
02520 if (paths[i][len] == 0)
02521 norm[i] = ".";
02522 else
02523 {
02524 if (len == 1)
02525
02526 norm[i]=paths[i]+1;
02527 else
02528 norm[i]=paths[i]+len+1;
02529
02530
02531
02532 if (flags & FCB__PUT_DOTSLASH)
02533 {
02534 norm[i]-=2;
02535 *norm[i] = '.';
02536 }
02537 }
02538 DEBUGP("we set norm[%d]=%s from %s", i, norm[i], paths[i]);
02539 }
02540 norm[argc]=NULL;
02541
02542
02543
02544
02545
02546
02547
02548 STOPIF( waa__get_waa_directory( wc_path, &confname, &cp, NULL, GWD_CONF),
02549 NULL);
02550 setenv( FSVS_EXP_WC_CONF, confname, 1);
02551 STOPIF( opt__load_settings(confname, "config", PRIO_ETC_WC ), NULL);
02552
02553
02554
02555
02556
02557
02558
02559
02560
02561
02562
02563 if (!action->only_opt_filter ||
02564 opt__get_int(OPT__FILTER) == 0)
02565 opt__set_int(OPT__FILTER, PRIO_MUSTHAVE, FILTER__ALL);
02566
02567 DEBUGP("filter has mask 0x%X (%s)",
02568 opt__get_int(OPT__FILTER),
02569 st__status_string_fromint(opt__get_int(OPT__FILTER)));
02570
02571
02572 ex:
02573 if (status && status!=ENOENT)
02574 {
02575
02576 IF_FREE(norm);
02577 }
02578 else
02579 {
02580
02581 if (normalized)
02582 *normalized=norm;
02583 }
02584
02585 return status;
02586 }
02587
02588
02595 int waa__partial_update(struct estat *root,
02596 int argc, char *normalized[], char *orig[],
02597 struct waa__entry_blocks_t *blocks)
02598 {
02599 int status;
02600 struct estat *sts;
02601 int i, flags;
02602 int faked_arg0;
02603
02604
02605 status=0;
02606
02607
02608
02609
02610 faked_arg0=(argc == 0 && *normalized);
02611
02612 if (faked_arg0) argc=1;
02613
02614 for(i=0; i<argc; i++)
02615 {
02616 DEBUGP("update %d=%s", i, normalized[i]);
02617
02618
02619
02620
02621
02622
02623 status=hlp__lstat(normalized[i], NULL);
02624
02625 if (abs(status) == ENOENT)
02626 flags=OPS__ON_UPD_LIST | OPS__FAIL_NOT_LIST;
02627 else
02628 {
02629 STOPIF( status, "Cannot query entry %s", normalized[i]);
02630 flags = OPS__ON_UPD_LIST | OPS__CREATE;
02631 }
02632
02633 status=ops__traverse(root, normalized[i], flags, RF_ADD, &sts);
02634 if (status == ENOENT)
02635 {
02636 STOPIF_CODE_ERR( !(flags & OPS__CREATE), ENOENT,
02637 "!Entry '%s' is not known.", normalized[i]);
02638 BUG_ON(1);
02639 }
02640 else
02641 STOPIF(status, NULL);
02642
02643
02644 if (opt__get_int(OPT__PATH) == PATH_PARMRELATIVE && !sts->arg)
02645 sts->arg= faked_arg0 ? "" : orig[i];
02646
02647
02648 sts->do_userselected = sts->do_this_entry = 1;
02649 while ( (sts = sts->parent) )
02650 {
02651
02652
02653
02654
02655
02656
02657
02658 if (sts->flags & RF_ISNEW)
02659 STOPIF( ops__update_single_entry(sts, &sts->st), NULL);
02660
02661 sts->do_child_wanted = 1;
02662 }
02663 }
02664
02665 STOPIF( waa__update_tree(root, blocks), NULL);
02666
02667 ex:
02668 return status;
02669 }
02670
02671
02673 int waa__new_entry_block(struct estat *entry, int count,
02674 struct waa__entry_blocks_t *previous)
02675 {
02676 int status;
02677 struct waa__entry_blocks_t *eblock;
02678
02679
02680 status=0;
02681 STOPIF( hlp__alloc( &eblock, sizeof(*eblock)), NULL);
02682 eblock->first=entry;
02683 eblock->count=count;
02684
02685
02686
02687
02688 eblock->next=previous->next;
02689 eblock->prev=previous;
02690 previous->next=eblock;
02691 if (eblock->next)
02692 eblock->next->prev=eblock;
02693
02694 ex:
02695 return status;
02696 }
02697
02698
02701 int waa__find_base(struct estat *root, int *argc, char ***args)
02702 {
02703 int status;
02704 char **normalized;
02705
02706 status=0;
02707
02708
02709 root->arg="";
02710
02711 STOPIF( waa__find_common_base( *argc, *args, &normalized), NULL);
02712 if (*argc > 0 && strcmp(normalized[0], ".") == 0)
02713 {
02714
02715 root->arg = **args;
02716
02717 (*args) ++;
02718 (*argc) --;
02719 }
02720
02721 STOPIF_CODE_ERR( *argc, EINVAL,
02722 "!Only a working copy root is a valid path.");
02723
02724
02725 **args = normalized[0];
02726
02727 ex:
02728 return status;
02729 }
02730
02731
02733 inline int waa___recurse_tree(struct estat **list, action_t handler,
02734 int (*me)(struct estat *, action_t ))
02735 {
02736 struct estat *sts;
02737 int status;
02738
02739 status=0;
02740 while ( (sts=*list) )
02741 {
02742 if (sts->do_this_entry && ops__allowed_by_filter(sts))
02743 STOPIF( handler(sts), NULL);
02744
02745
02746
02747
02748
02749
02750 if ((sts->do_child_wanted || sts->do_userselected) &&
02751 sts->entry_count &&
02752 (sts->local_mode_packed ?
02753 TEST_PACKED(S_ISDIR, sts->local_mode_packed) :
02754 ((sts->entry_status & FS_REMOVED) &&
02755 S_ISDIR(sts->st.mode) &&
02756 opt__get_int(OPT__ALL_REMOVED)==OPT__YES)) )
02757
02758
02759
02760
02761
02762 STOPIF( me(sts, handler), NULL);
02763 list++;
02764 }
02765
02766 ex:
02767 return status;
02768 }
02769
02770
02773 int waa__do_sorted_tree(struct estat *root, action_t handler)
02774 {
02775 int status;
02776
02777 status=0;
02778
02779
02780 if (!root->parent && root->do_this_entry)
02781 STOPIF( handler(root), NULL);
02782
02783 if ( !root->by_name)
02784 STOPIF( dir__sortbyname(root), NULL);
02785
02786 STOPIF( waa___recurse_tree(root->by_name, handler,
02787 waa__do_sorted_tree), NULL);
02788
02789 ex:
02790 IF_FREE(root->by_name);
02791
02792 return status;
02793 }
02794
02795
02803 int waa__dir_enum(struct estat *this,
02804 int est_count,
02805 int by_name)
02806 {
02807 int status;
02808 struct sstat_t cwd_stat;
02809
02810
02811 status=0;
02812 STOPIF( hlp__lstat(".", &cwd_stat), NULL);
02813
02814 DEBUGP("checking: %llu to %llu",
02815 (t_ull)cwd_stat.ino,
02816 (t_ull)waa_stat.ino);
02817
02818 if (cwd_stat.dev == waa_stat.dev &&
02819 cwd_stat.ino == waa_stat.ino)
02820 goto ex;
02821
02822
02823 STOPIF( dir__enumerator(this, est_count, by_name), NULL);
02824
02825 ex:
02826 return status;
02827 }
02828
02829
02839 int waa__copy_entries(struct estat *src, struct estat *dest)
02840 {
02841 int status;
02842 struct estat *newdata, **to_append, **tmp;
02843 int append_count, left, space;
02844
02845
02846 to_append=NULL;
02847 status=0;
02848
02849 ops__copy_single_entry(src, dest);
02850 if (!S_ISDIR(src->st.mode))
02851 goto ex;
02852
02853
02854 append_count=0;
02855 STOPIF( hlp__calloc( &to_append,
02856 src->entry_count+1, sizeof(src->by_name[0])), NULL);
02857
02858 int remember_to_copy(struct estat *sts, struct estat **sts_p)
02859 {
02860 to_append[append_count]=sts;
02861 append_count++;
02862 return 0;
02863 }
02864
02865 STOPIF( ops__correlate_dirs( src, dest,
02866 remember_to_copy,
02867 waa__copy_entries,
02868 NULL, NULL), NULL);
02869
02870
02871
02872
02873
02874
02875
02876
02877 space=0;
02878 for( tmp=to_append, left=append_count; left>0; left--, tmp++, space--)
02879 {
02880 if (space)
02881 newdata++;
02882 else
02883 STOPIF( ops__allocate( left, &newdata, &space), NULL);
02884
02885 newdata->parent=dest;
02886 newdata->name=(*tmp)->name;
02887
02888 STOPIF( waa__copy_entries(*tmp, newdata), NULL);
02889
02890
02891
02892 (*tmp) = newdata;
02893 }
02894
02895 STOPIF( ops__new_entries(dest, append_count, to_append), NULL);
02896
02897
02898 ex:
02899 IF_FREE(to_append);
02900 return status;
02901 }
02902
02903
02912 int waa__get_tmp_name(const char *base_dir,
02913 char **output, apr_file_t **handle,
02914 apr_pool_t *pool)
02915 {
02916 int status;
02917 static struct cache_t *cache;
02918 static struct cache_entry_t *tmp_cache=NULL;
02919 static const char to_append[]=".XXXXXX";
02920 static const char to_prepend[]="fsvs";
02921 char *filename;
02922 int len;
02923
02924
02925 STOPIF( cch__new_cache(&cache, 12), NULL);
02926
02927 len= base_dir ? strlen(base_dir) : 0;
02928 if (!len)
02929 {
02930 if (!tmp_cache)
02931 {
02932
02933
02934
02935 STOPIF( apr_temp_dir_get(&base_dir, pool),
02936 "Getting a temporary directory path");
02937
02938 len=strlen(base_dir);
02939
02940 STOPIF( cch__entry_set( &tmp_cache, 0, base_dir,
02941 len +1 +1, 0, NULL), NULL);
02942
02943 tmp_cache->data[len++]=PATH_SEPARATOR;
02944 tmp_cache->data[len]=0;
02945
02946
02947
02948
02949
02950 tmp_cache->len=len;
02951 }
02952
02953 len=tmp_cache->len;
02954 base_dir=tmp_cache->data;
02955 BUG_ON(base_dir[len] != 0);
02956 }
02957
02958 STOPIF( cch__add(cache, 0, base_dir,
02959
02960 len + 1 + strlen(to_prepend) + strlen(to_append) + 1 + 3,
02961 &filename), NULL);
02962
02963 if (base_dir[len-1] == PATH_SEPARATOR)
02964 {
02965 strcpy( filename + len, to_prepend);
02966 len+=strlen(to_prepend);
02967 }
02968
02969 strcpy( filename + len, to_append);
02970
02971
02972 STOPIF( apr_file_mktemp(handle, filename,
02973 APR_CREATE | APR_READ | APR_WRITE | APR_EXCL |
02974 (output ? 0 : APR_DELONCLOSE),
02975 pool),
02976 "Cannot create a temporary file for \"%s\"", filename);
02977
02978 if (output) *output=filename;
02979
02980 ex:
02981 return status;
02982 }
02983
02987 int waa__set_working_copy(const char const *wc_dir)
02988 {
02989 int status;
02990
02991 status=0;
02992 BUG_ON(*wc_dir != PATH_SEPARATOR);
02993 wc_path_len=strlen(wc_dir);
02994 STOPIF( hlp__strnalloc( wc_path_len, &wc_path, wc_dir), NULL);
02995
02996 ex:
02997 return status;
02998 }
02999
03000
03004 int waa__create_working_copy(const char const *wc_dir)
03005 {
03006 int status;
03007 char *dir;
03008
03009 if (wc_dir)
03010 STOPIF(waa__set_working_copy(wc_dir), NULL);
03011
03012 BUG_ON(!wc_path);
03013
03014
03015 STOPIF( waa__get_waa_directory( wc_path, &dir, NULL, NULL,
03016 GWD_WAA | GWD_MKDIR), NULL);
03017 STOPIF( waa__mkdir(dir, 1), NULL);
03018
03019
03020 STOPIF( waa__get_waa_directory( wc_path, &dir, NULL, NULL,
03021 GWD_CONF | GWD_MKDIR), NULL);
03022 STOPIF( waa__mkdir(dir, 1), NULL);
03023
03024
03025
03026 STOPIF( waa__make_info_link(wc_path, "_base", wc_path), NULL);
03027
03028 ex:
03029 return status;
03030 }
03031