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 <unistd.h>
00014 #include <stdlib.h>
00015 #include <time.h>
00016
00017
00018 #include "global.h"
00019 #include "status.h"
00020 #include "cache.h"
00021 #include "actions.h"
00022 #include "est_ops.h"
00023 #include "ignore.h"
00024 #include "direnum.h"
00025 #include "warnings.h"
00026 #include "helper.h"
00027 #include "checksum.h"
00028 #include "url.h"
00029
00039 struct free_estat
00040 {
00042 struct free_estat *next;
00044 int count;
00045 };
00046
00047
00048
00054 const char ops__dir_info_format_p[]="%07llo %8x %8x %x %s %s "
00055 "%lld %ld %u %lx %lld %lld %u "
00056 "%u %u %s";
00057 #define WAA_MAX_DIR_INFO_CHARS (11+1+8+1+8+1+8+1+APR_MD5_DIGESTSIZE*2+1 \
00058 +18+1+9+1+9+1+16+1+18+1+18+1+9+1+ \
00059 9+1+9+1+NAME_MAX+1+1)
00060
00061
00069 const char link_spec[]="link ",
00070 cdev_spec[]="cdev",
00071 bdev_spec[]="bdev";
00072
00073 static struct free_estat *free_list = NULL;
00074
00075
00076
00082 int ops__string_to_dev(struct estat *sts, char *data, char **info)
00083 {
00084 int maj, min;
00085 int ft, mode, len;
00086 char delimiter;
00087 int status;
00088
00089
00090 status=0;
00091 if (0 == strncmp(data, link_spec, strlen(link_spec)))
00092 {
00093 mode=S_IFLNK;
00094 if (info)
00095 *info=data+5;
00096 }
00097 else
00098 {
00099 if (0 == strncmp(data, cdev_spec, strlen(cdev_spec)))
00100 {
00101 data+=strlen(cdev_spec);
00102 mode=S_IFCHR;
00103 }
00104 else if (0 == strncmp(data, bdev_spec, strlen(bdev_spec)))
00105 {
00106 data+=strlen(bdev_spec);
00107 mode=S_IFBLK;
00108 }
00109 else mode=0;
00110
00111
00112 ft=sscanf(data, "%c0x%X:0x%X%n", &delimiter, &maj, &min, &len);
00113
00114 STOPIF_CODE_ERR(mode == 0 ||
00115 ft != 3 ||
00116 (delimiter != ':' && delimiter != ' '),
00117 EINVAL,
00118 "'%s' is not parseable as a special description", data);
00119
00120 if (info) *info=data+len;
00121
00122 #ifdef DEVICE_NODES_DISABLED
00123 DEVICE_NODES_DISABLED();
00124 #else
00125 sts->st.rdev=MKDEV(maj, min);
00126 #endif
00127 }
00128
00129 sts->st.mode= (sts->st.mode & ~S_IFMT) | mode;
00130 sts->local_mode_packed = MODE_T_to_PACKED(mode);
00131
00132 ex:
00133 return status;
00134 }
00135
00136
00141 int ops__link_to_string(struct estat *sts, char *filename,
00142 char **erg)
00143 {
00144 static struct cache_t *cache=NULL;
00145 char *cp;
00146 int l, status, hlen;
00147
00148
00149 STOPIF( cch__new_cache(&cache, 4), NULL);
00150
00151
00152 status=0;
00153 BUG_ON(!S_ISLNK(sts->st.mode));
00154
00155 if (!filename)
00156 STOPIF( ops__build_path(&filename, sts), NULL);
00157
00158 hlen=strlen(link_spec);
00159 l=sts->st.size + hlen + 1 + 8;
00160 STOPIF( cch__add(cache, 0, NULL, l, &cp), NULL);
00161
00162 strcpy(cp, link_spec);
00163 STOPIF_CODE_ERR( readlink(filename, cp+hlen, sts->st.size) == -1,
00164 errno, "can't read link %s", filename);
00165
00166 cp[hlen+sts->st.size]=0;
00167 *erg=cp;
00168
00169 ex:
00170 return status;
00171 }
00172
00173
00174 char *ops___dev_to_string(struct estat *sts, char delimiter)
00175 {
00176 static char buffer[64];
00177
00178
00179 BUG_ON(!(sts->remote_status & FS_NEW) &&
00180 !(S_ISBLK(sts->st.mode) || S_ISCHR(sts->st.mode)),
00181 "%s: mode is 0%o", sts->name, sts->st.mode);
00182
00183 #ifdef DEVICE_NODES_DISABLED
00184 DEVICE_NODES_DISABLED();
00185 #else
00186 sprintf(buffer, "%s%c0x%x:0x%x",
00187 S_ISBLK(sts->st.mode) ? bdev_spec : cdev_spec,
00188 delimiter,
00189 (int)MAJOR(sts->st.rdev),
00190 (int)MINOR(sts->st.rdev));
00191 #endif
00192
00193 return buffer;
00194 }
00195
00196
00199 char *ops__dev_to_waa_string(struct estat *sts)
00200 {
00201 return ops___dev_to_string(sts, ':');
00202 }
00203
00204
00207 char *ops__dev_to_filedata(struct estat *sts)
00208 {
00209 return ops___dev_to_string(sts, ' ');
00210 }
00211
00212
00216 int ops__stat_to_action(struct estat *sts, struct sstat_t *new)
00217 {
00218 struct sstat_t *old;
00219 int ft_old, ft_new;
00220 int file_status;
00221
00222
00223 old=&(sts->st);
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240 file_status =
00241 old->mtim.tv_sec != new->mtim.tv_sec ? FS_META_MTIME : 0;
00242
00243
00244
00245
00246 if (old->uid != new->uid)
00247 file_status |= FS_META_OWNER;
00248 if (old->gid != new->gid)
00249 file_status |= FS_META_GROUP;
00250
00251 if (old->mode != new->mode)
00252 file_status |= FS_META_UMODE;
00253
00254
00255 ft_old = old->mode & S_IFMT;
00256 ft_new = new->mode & S_IFMT;
00257
00258 if (ft_old != ft_new)
00259 {
00260 file_status |= FS_REPLACED;
00261 goto ex;
00262 }
00263
00264
00265 BUG_ON(sts->to_be_ignored);
00266 switch (ft_new)
00267 {
00268 case S_IFBLK:
00269 case S_IFCHR:
00270 DEBUGP("old=%llu new=%llu", (t_ull)old->rdev, (t_ull)new->rdev);
00271 file_status |=
00272 (old->rdev == new->rdev)
00273 ? FS_NO_CHANGE : FS_REPLACED;
00274 break;
00275
00276 case S_IFLNK:
00277 case S_IFREG:
00278 if (old->size != new->size)
00279 file_status |= FS_CHANGED;
00280 else
00281
00282
00283
00284
00285
00286 if ((file_status & FS_META_MTIME) ||
00287 (old->ctim.tv_sec != new->ctim.tv_sec &&
00288 !(sts->flags & RF___IS_COPY)) )
00289 file_status |= FS_LIKELY;
00290 break;
00291
00292 case S_IFDIR:
00293
00294
00295
00296
00297 if ( (file_status & FS_META_MTIME) ||
00298 old->ctim.tv_sec != new->ctim.tv_sec )
00299 file_status |= FS_LIKELY;
00300 break;
00301
00302 default:
00303 BUG_ON(1);
00304
00305 file_status=FS_NO_CHANGE;
00306 }
00307
00308 ex:
00309 DEBUGP("change: types 0%o vs 0%o; 0x%x=%s",
00310 ft_old, ft_new,
00311 file_status,
00312 st__status_string_fromint(file_status));
00313 return file_status;
00314 }
00315
00316
00331 int ops__load_1entry(char **mem_pos, struct estat *sts, char **filename,
00332 ino_t *parent_i)
00333 {
00334 char *buffer, *before;
00335 int status;
00336 ino_t parent_inode;
00337 unsigned internal_number, e_t;
00338
00339
00340
00341 status=0;
00342 buffer=*mem_pos;
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355 before=hlp__skip_ws(buffer);
00356 sts->st.mode = strtoul(before, &buffer, 8);
00357 sts->old_rev_mode_packed =
00358 sts->new_rev_mode_packed =
00359 sts->local_mode_packed = MODE_T_to_PACKED(sts->st.mode);
00360 if (before == buffer) goto inval;
00361
00362
00363 if (*(buffer++) != ' ') goto inval;
00364
00365
00366
00367 sts->st.ctim.tv_sec= strtoul(buffer, &buffer, 16);
00368 sts->st.mtim.tv_sec= strtoul(buffer, &buffer, 16);
00369 before=hlp__skip_ws(buffer);
00370 sts->flags= strtoul(before, &buffer, 16);
00371 if (before == buffer) goto inval;
00372 if (*(buffer++) != ' ') goto inval;
00373
00374
00375
00376 buffer=hlp__skip_ws(buffer);
00377 if (S_ISBLK(sts->st.mode) || S_ISCHR(sts->st.mode))
00378 STOPIF( ops__string_to_dev(sts, buffer, &buffer), NULL);
00379 else
00380 buffer=hlp__get_word(buffer, NULL);
00381
00382
00383 buffer=hlp__skip_ws(buffer);
00384 if (!S_ISDIR(sts->st.mode))
00385 STOPIF( cs__char2md5( buffer, &buffer, sts->md5),
00386 "Parsing the md5 failed");
00387 else
00388 buffer=hlp__get_word(buffer, NULL);
00389
00390
00391
00392 sts->st.size = strtoul(buffer, &buffer, 10);
00393 sts->old_rev = sts->repos_rev = strtoul(buffer, &buffer, 10);
00394 internal_number = strtoul(buffer, &buffer, 10);
00395 sts->st.dev = strtoul(buffer, &buffer, 16);
00396 sts->st.ino = strtoul(buffer, &buffer, 10);
00397 parent_inode= strtoul(buffer, &buffer, 10);
00398 e_t = strtoul(buffer, &buffer, 10);
00399 sts->st.uid = strtoul(buffer, &buffer, 10);
00400 before=hlp__skip_ws(buffer);
00401 sts->st.gid = strtoul(before, &buffer, 10);
00402 if (before == buffer) goto inval;
00403
00404
00405
00406 if (S_ISDIR(sts->st.mode))
00407 sts->entry_count = e_t;
00408
00409
00410 BUG_ON(e_t && !S_ISDIR(sts->st.mode));
00411
00412
00413
00414
00415 if (*buffer != ' ') goto inval;
00416 *filename=buffer+1;
00417
00418
00419
00420
00421 if (parent_inode)
00422 {
00423
00424
00425 if (internal_number)
00426 STOPIF( url__find_by_intnum(internal_number, &(sts->url)), NULL);
00427 }
00428 else
00429 {
00430
00431
00432 sts->url= urllist_count ?
00433 urllist[urllist_count-1] :
00434 NULL;
00435 }
00436
00437 if (parent_i) *parent_i=parent_inode;
00438
00439
00440
00441
00442
00443
00444 *mem_pos = *filename + strlen(*filename) + 1;
00445 if (**mem_pos == '\n') (*mem_pos)++;
00446
00447 ex:
00448 return status;
00449
00450
00451 inval:
00452 STOPIF( EINVAL, "Error parsing entry line \"%s\";\n"
00453 "your entry list is corrupt, ask the users mailing list, please.",
00454 *mem_pos);
00455
00456
00457 goto ex;
00458 }
00459
00460
00463 int ops___entries_to_write(struct estat *dir)
00464 {
00465 struct estat **list;
00466 int count;
00467
00468 count=0;
00469 if (!dir->entry_count) return 0;
00470 list=dir->by_inode;
00471 while (*list)
00472 {
00473 if (ops__should_entry_be_written_in_list(*list))
00474 count++;
00475 list++;
00476 }
00477
00478 return count;
00479 }
00480
00481
00491 int ops__save_1entry(struct estat *sts,
00492 ino_t parent_ino,
00493 int filehandle)
00494 {
00495 int len;
00496 static char buffer[WAA_MAX_DIR_INFO_CHARS+2] =
00497 {
00498
00499 [sizeof(buffer)-1]=0xff,
00500 [sizeof(buffer)-2]=0x0,
00501 };
00502 int is_dir, is_dev, status, is_spec;
00503 int intnum;
00504
00505
00506 #if 0
00507 if (sts->parent)
00508 {
00509
00510
00511
00512
00513
00514 BUG_ON(!sts->url &&
00515 !(sts->flags & (RF_COPY_SUB | RF_COPY_BASE | RF_ADD)));
00516 }
00517 #endif
00518
00519 is_dir = S_ISDIR(sts->st.mode);
00520 is_dev = S_ISBLK(sts->st.mode) || S_ISCHR(sts->st.mode);
00521 is_spec = S_ISBLK(sts->st.mode) || S_ISCHR(sts->st.mode) ||
00522 S_ISLNK(sts->st.mode);
00523
00524
00525 if (sts->match_pattern)
00526 STOPIF( ops__apply_group(sts, NULL, NULL), NULL);
00527
00528
00529 if (sts->url)
00530 intnum=sts->url->internal_number;
00531 else
00532 {
00533
00534
00535 if (sts->parent)
00536 DEBUGP("Non-root entry %s has no URL", sts->name);
00537 intnum=0;
00538 }
00539
00540 len=sprintf(buffer, ops__dir_info_format_p,
00541 (t_ull)sts->st.mode,
00542 (int)sts->st.ctim.tv_sec,
00543 (int)sts->st.mtim.tv_sec,
00544 sts->flags & RF___SAVE_MASK,
00545 ( is_dev ? ops__dev_to_waa_string(sts) : "nd" ),
00546 ( is_dir ? "x" : cs__md5tohex_buffered(sts->md5) ),
00547 (t_ull)sts->st.size,
00548 sts->repos_rev == SET_REVNUM ? sts->url->current_rev : sts->repos_rev,
00549 intnum,
00550 (t_ul)sts->st.dev,
00551 (t_ull)sts->st.ino,
00552 (t_ull)parent_ino,
00553
00554
00555 is_dir ? ops___entries_to_write(sts) : 0,
00556 sts->st.uid,
00557 sts->st.gid,
00558 sts->name
00559 );
00560 BUG_ON(len > sizeof(buffer)-2);
00561 len++;
00562 buffer[len++]='\n';
00563
00564
00565 BUG_ON(buffer[sizeof(buffer)-1]!=0xff ||
00566 buffer[sizeof(buffer)-2]!=0x0);
00567
00568 is_dir=write(filehandle, buffer, len);
00569 STOPIF_CODE_ERR(is_dir != len, errno,
00570 "write entry");
00571
00572 status=0;
00573
00574 ex:
00575 return status;
00576 }
00577
00578
00583 char *ops__get_filename(char *path)
00584 {
00585 char *cp;
00586
00587 cp=strrchr(path, PATH_SEPARATOR);
00588 return cp ? cp+1 : path;
00589 }
00590
00591
00600 static inline const char *ops___split_fnpart(const char *path)
00601 {
00602 char *cp;
00603
00604 cp=strchr(path, PATH_SEPARATOR);
00605 if (!cp) return NULL;
00606
00607
00608 while (*cp == PATH_SEPARATOR) *(cp++)=0;
00609
00610
00611 if (!*cp) return NULL;
00612
00613 return cp;
00614 }
00615
00616
00621 int ops__build_path2(char *path, int max, struct estat *sts)
00622 {
00623 int l,i;
00624
00625
00626
00627
00628
00629 l=sts->parent ? sts->path_len - sts->parent->path_len - 1 : 1;
00630 if (l+1 > max) return 0;
00631
00632 if (sts->parent)
00633 {
00634 i=ops__build_path2(path, max - (l+1), sts->parent);
00635
00636
00637 if (!i) return 0;
00638 }
00639 else
00640 {
00641 i=0;
00642 }
00643
00644 memcpy(path+i, sts->name, l);
00645 path[i+l+0]=PATH_SEPARATOR;
00646 path[i+l+1]=0;
00647
00648 return i+l+1;
00649 }
00650
00651
00660 int ops__calc_path_len(struct estat *sts)
00661 {
00662 int plen;
00663
00664 if (sts->parent)
00665 {
00666 if (!sts->parent->path_len)
00667 ops__calc_path_len(sts->parent);
00668
00669 plen=sts->parent->path_len+1;
00670 }
00671 else
00672 plen=0;
00673
00674 sts->path_len = plen + strlen(sts->name);
00675 return sts->path_len;
00676 }
00677
00678
00696 int ops__build_path(char **value, struct estat *sts)
00697 {
00698 static struct cache_t *cache=NULL;
00699 int status, i;
00700 unsigned needed_space;
00701 char *data;
00702
00703
00704
00705
00706 STOPIF( cch__new_cache(&cache, 48), NULL);
00707
00708
00709 if (sts->cache_index>0 &&
00710 sts->cache_index<=cache->max &&
00711 cache->entries[sts->cache_index-1]->id == (cache_value_t)sts &&
00712 cache->entries[sts->cache_index-1]->data[0])
00713 {
00714
00715 i=sts->cache_index-1;
00716 DEBUGP("%p found in cache index %d; lru %d",
00717 sts, i, cache->lru);
00718 cch__set_active(cache, i);
00719 goto ex;
00720 }
00721
00722 if (!sts->path_len)
00723 ops__calc_path_len(sts);
00724
00725 needed_space=sts->path_len+1;
00726
00727 STOPIF( cch__add(cache, (cache_value_t)sts, NULL,
00728 needed_space, &data), NULL);
00729
00730
00731 status=ops__build_path2(data, needed_space, sts);
00732 if (status == 0)
00733 {
00734
00735
00736 BUG("path len counting went wrong");
00737 }
00738
00739 data[status-1]=0;
00740 sts->cache_index=cache->lru+1;
00741 status=0;
00742
00743 ex:
00744
00745 if (!status) *value=cache->entries[cache->lru]->data;
00746 return status;
00747 }
00748
00749
00755 int ops__new_entries(struct estat *dir,
00756 int count,
00757 struct estat **new_entries)
00758 {
00759 int status;
00760
00761
00762 status=0;
00763
00764 IF_FREE(dir->by_name);
00765
00766 STOPIF( hlp__realloc( &dir->by_inode,
00767 (dir->entry_count+count+1) * sizeof(dir->by_inode[0])), NULL);
00768
00769 memcpy(dir->by_inode+dir->entry_count,
00770 new_entries, count*sizeof(dir->by_inode[0]));
00771 dir->entry_count += count;
00772 dir->by_inode[dir->entry_count]=NULL;
00773
00774
00775 dir->to_be_sorted=1;
00776
00777 ex:
00778 return status;
00779 }
00780
00781
00787 int ops__find_entry_byname(struct estat *dir, char *name,
00788 struct estat **sts,
00789 int ignored_too)
00790 {
00791 int status;
00792 struct estat **sts_p;
00793 char *filename;
00794
00795
00796 status=0;
00797 BUG_ON(!S_ISDIR(dir->st.mode));
00798
00799 if (!dir->by_name)
00800 STOPIF(dir__sortbyname(dir), NULL);
00801
00802
00803 filename=ops__get_filename(name);
00804
00805
00806 sts_p=bsearch(filename, dir->by_name, dir->entry_count,
00807 sizeof(dir->by_name[0]),
00808 (comparison_fn_t)dir___f_sort_by_nameCS);
00809
00810 if (sts_p)
00811 DEBUGP("found %s on %p; ignored: 0x%x", name, sts_p,
00812 (*sts_p)->to_be_ignored);
00813
00814
00815 *sts=sts_p && (!(*sts_p)->to_be_ignored || ignored_too) ?
00816 *sts_p : NULL;
00817
00818 if (!*sts)
00819 DEBUGP("Searching for %s (%s) found no entry (ignored_too=%d)",
00820 filename, name, ignored_too);
00821
00822 ex:
00823 return status;
00824 }
00825
00826
00827 #if 0
00828
00831 int ops__find_entry_byinode(struct estat *dir,
00832 dev_t dev,
00833 ino_t inode,
00834 struct estat **sts)
00835 {
00836 int status;
00837 struct estat **sts_p;
00838 struct estat sts_cmp;
00839
00840
00841 status=0;
00842 BUG_ON(!S_ISDIR(dir->st.mode));
00843
00844 if (!dir->by_inode)
00845 STOPIF(dir__sortbyinode(dir), NULL);
00846
00847 sts_cmp.st.dev=dev;
00848 sts_cmp.st.ino=inode;
00849
00850
00851 sts_p=bsearch(&sts_cmp, dir->by_inode, dir->entry_count,
00852 sizeof(dir->by_inode[0]),
00853 (comparison_fn_t)dir___f_sort_by_inode);
00854
00855 *sts=sts_p && ((*sts_p)->entry_status != FT_IGNORE) ?
00856 *sts_p : NULL;
00857
00858 ex:
00859 return status;
00860 }
00861 #endif
00862
00863
00865 static inline void ops___move_array(struct estat **array, int index, int len)
00866 {
00867
00868
00869 memmove( array+index, array+index+1,
00870
00871 (len-index-1+1) * sizeof(*array) );
00872 }
00873
00874
00877 int ops__allocate(int needed,
00878 struct estat **where, int *count)
00879 {
00880 struct free_estat *free_p;
00881 int status, remain;
00882 int returned;
00883
00884
00885 status=0;
00886 BUG_ON(needed <=0, "not even a single block needed?");
00887
00888 DEBUGP("need %d blocks, freelist=%p", needed, free_list);
00889 if (free_list)
00890 {
00891 free_p=free_list;
00892 VALGRIND_MAKE_MEM_DEFINED(free_p, sizeof(*free_p));
00893
00894 if (free_p->count <= needed)
00895 {
00896
00897 free_list=free_p->next;
00898
00899 returned=free_p->count;
00900 *where=(struct estat*)free_p;
00901 }
00902 else
00903 {
00904
00905
00906
00907
00908
00909
00910
00911
00912 returned=needed;
00913
00914 remain=free_p->count-needed;
00915 *where=((struct estat*)free_p) + remain;
00916 free_p->count=remain;
00917 DEBUGP("splitting block; %d remain", remain);
00918 }
00919
00920 VALGRIND_MAKE_MEM_DEFINED(*where, sizeof(**where)*returned);
00921
00922 memset(*where, 0, sizeof(**where) * returned);
00923 }
00924 else
00925 {
00926 DEBUGP("no free list, allocating");
00927
00928 returned=needed;
00929
00930 if (needed < 8192/sizeof(**where))
00931 needed=8192/sizeof(**where);
00932 STOPIF( hlp__calloc( where, needed, sizeof(**where)), NULL);
00933
00934 if (needed > returned)
00935 {
00936 free_list=(struct free_estat*)(*where+returned);
00937 free_list->next=NULL;
00938 free_list->count=needed-returned;
00939 }
00940 }
00941
00942 DEBUGP("giving %d blocks at %p", returned, *where);
00943 BUG_ON(!returned, "Not even a single block returned!!");
00944 if (count)
00945 *count=returned;
00946
00947
00948
00949
00950 VALGRIND_MAKE_MEM_DEFINED(*where, sizeof(**where) * returned);
00951
00952 ex:
00953 return status;
00954 }
00955
00956
00959 int ops__free_entry(struct estat **sts_p)
00960 {
00961 int i, status;
00962 struct estat *sts=*sts_p;
00963 struct free_estat *free_p, *free_p2;
00964 struct free_estat **prev;
00965 struct free_estat *block;
00966
00967
00968 status=0;
00969 if (sts->old)
00970 STOPIF( ops__free_entry(& sts->old), NULL);
00971 if (S_ISDIR(sts->st.mode))
00972 {
00973 BUG_ON(sts->entry_count && !sts->by_inode);
00974
00975 for(i=0; i<sts->entry_count; i++)
00976 STOPIF( ops__free_entry(sts->by_inode+i), NULL);
00977
00978 IF_FREE(sts->by_inode);
00979 IF_FREE(sts->by_name);
00980 IF_FREE(sts->strings);
00981 sts->st.mode=0;
00982 }
00983
00984
00985
00986
00987
00988
00989
00990
00991
00992
00993
00994
00995
00996
00997
00998 DEBUGP("freeing block %p", *sts_p);
00999
01000 block=(struct free_estat*)*sts_p;
01001
01002 free_p=free_list;
01003 prev=&free_list;
01004 while (free_p)
01005 {
01006 VALGRIND_MAKE_MEM_DEFINED(free_p, sizeof(*free_p));
01007 if ((char*)block + sizeof(struct estat) == (char*)free_p)
01008 {
01009
01010 block->count = free_p->count+1;
01011 block->next = free_p->next;
01012 if (prev != &free_list)
01013 VALGRIND_MAKE_MEM_DEFINED(prev, sizeof(*prev));
01014 *prev = block;
01015 if (prev != &free_list)
01016 VALGRIND_MAKE_MEM_NOACCESS(prev, sizeof(*prev));
01017 break;
01018 }
01019
01020 if ((char*)block == (char*)free_p+sizeof(struct estat)*free_p->count)
01021 {
01022 free_p->count++;
01023 break;
01024 }
01025
01026 prev=&free_p->next;
01027 free_p2=free_p;
01028
01029 free_p=*prev;
01030
01031 VALGRIND_MAKE_MEM_NOACCESS(free_p2, sizeof(*free_p2));
01032 }
01033
01034
01035 if (free_p)
01036 {
01037 DEBUGP("merged to %p; now size %d", block, free_p->count);
01038 VALGRIND_MAKE_MEM_NOACCESS(free_p, sizeof(*free_p));
01039 }
01040 else
01041 {
01042 block->next=free_list;
01043 block->count=1;
01044 free_list=block;
01045 DEBUGP("new entry in free list");
01046 }
01047
01048 VALGRIND_MAKE_MEM_NOACCESS( block, sizeof(struct estat));
01049
01050 *sts_p=NULL;
01051
01052 ex:
01053 return status;
01054 }
01055
01056
01067 int ops__delete_entry(struct estat *dir,
01068 struct estat *sts,
01069 int index_byinode,
01070 int index_byname)
01071 {
01072 int i;
01073 int status;
01074
01075 BUG_ON( (sts ? 1 : 0) +
01076 (index_byinode >=0 ? 1 : 0) +
01077 (index_byname >=0 ? 1 : 0)
01078 != 1,
01079 "must have exactly 1 definition!!!");
01080
01081
01082 BUG_ON(!S_ISDIR(dir->st.mode), "can remove only from directory");
01083
01084 if (!sts)
01085 {
01086 if (index_byinode != UNKNOWN_INDEX)
01087 {
01088 BUG_ON(index_byinode > dir->entry_count, "i > c");
01089 sts=dir->by_inode[index_byinode];
01090 }
01091 else
01092 {
01093 BUG_ON(index_byname > dir->entry_count, "i > c");
01094 sts=dir->by_name[index_byname];
01095 }
01096 }
01097
01098
01099 i=0;
01100 if (dir->by_inode)
01101 {
01102 if (index_byinode == UNKNOWN_INDEX)
01103 {
01104
01105
01106
01107 for(index_byinode=dir->entry_count-1;
01108 index_byinode>=0;
01109 index_byinode--)
01110 if (dir->by_inode[index_byinode] == sts) break;
01111
01112 BUG_ON(index_byinode == UNKNOWN_INDEX);
01113 }
01114
01115 ops___move_array(dir->by_inode, index_byinode,
01116 dir->entry_count);
01117 i=1;
01118 }
01119
01120 if (dir->by_name)
01121 {
01122 if (index_byname == UNKNOWN_INDEX)
01123 {
01124
01125
01126 for(index_byname=dir->entry_count-1;
01127 index_byname>=0;
01128 index_byname--)
01129 if (dir->by_name[index_byname] == sts) break;
01130
01131 BUG_ON(index_byname == UNKNOWN_INDEX);
01132 }
01133
01134 ops___move_array(dir->by_name, index_byname,
01135 dir->entry_count);
01136 i=1;
01137 }
01138
01139 STOPIF( ops__free_entry(&sts), NULL);
01140
01141 ex:
01142 DEBUGP("entry count was %d; flag to remove is %d",
01143 dir->entry_count, i);
01144 if (i)
01145 dir->entry_count--;
01146 return i ? 0 : ENOENT;
01147 }
01148
01149
01156 int ops__free_marked(struct estat *dir, int fast_mode)
01157 {
01158 struct estat **src, **dst;
01159 int i, new_count;
01160 int status;
01161
01162
01163 BUG_ON(!S_ISDIR(dir->st.mode));
01164 status=0;
01165
01166 IF_FREE(dir->by_name);
01167
01168 src=dst=dir->by_inode;
01169 new_count=0;
01170 for(i=0; i<dir->entry_count; i++)
01171 {
01172 if (!(*src)->to_be_ignored)
01173 {
01174 *dst=*src;
01175 dst++;
01176 new_count++;
01177 }
01178 else
01179 {
01180 if (!fast_mode)
01181 STOPIF( ops__free_entry(src), NULL);
01182 }
01183
01184 src++;
01185 }
01186
01187 if (new_count != dir->entry_count)
01188 {
01189 if (!fast_mode)
01190 {
01191
01192 STOPIF( hlp__realloc( &dir->by_inode,
01193 sizeof(*(dir->by_inode)) * (new_count+1) ), NULL);
01194 }
01195
01196 dir->by_inode[new_count]=NULL;
01197 dir->entry_count=new_count;
01198 }
01199
01200 ex:
01201 return status;
01202 }
01203
01204
01228 int ops__traverse(struct estat *current, char *fullpath,
01229 int flags,
01230 int sts_flags,
01231 struct estat **ret)
01232 {
01233 int status;
01234 char *next_part;
01235 struct estat *sts;
01236 int quit;
01237 char *copy, *path;
01238
01239
01240 status=0;
01241 STOPIF( hlp__strdup( ©, fullpath), NULL);
01242 path=copy;
01243
01244 quit=0;
01245 while (path)
01246 {
01247 next_part=(char*)ops___split_fnpart(path);
01248
01249 BUG_ON(!path[0]);
01250
01251
01252 if (path[0] == '.' &&
01253 path[1] == '\0')
01254 {
01255
01256 path=next_part;
01257 continue;
01258 }
01259
01260 if (path[0] == '.' &&
01261 path[1] == '.' &&
01262 path[2] == '\0')
01263 {
01264
01265
01266 BUG("Path '%s' includes '..'!", fullpath);
01267 }
01268
01269
01270
01271
01272 STOPIF( ops__find_entry_byname(current, path, &sts, 1), NULL);
01273
01274 if (!sts)
01275 {
01276
01277
01278
01279 if (!(flags & OPS__CREATE))
01280 {
01281 if (flags & OPS__FAIL_NOT_LIST)
01282 STOPIF_CODE_ERR( 1, ENOENT,
01283 "!The entry '%s' was not found.", fullpath);
01284
01285 status=ENOENT;
01286 goto ex;
01287 }
01288
01289
01290 STOPIF( ops__allocate(1, &sts, NULL), NULL);
01291 STOPIF( hlp__strdup( &sts->name, path), NULL);
01292
01293 if (flags & OPS__ON_UPD_LIST)
01294 STOPIF( waa__insert_entry_block(sts, 1), NULL);
01295
01296
01297 sts->st.mode=S_IFDIR | 0700;
01298 sts->st.size=0;
01299 sts->entry_count=0;
01300 sts->parent=current;
01301
01302 sts->flags=sts_flags | RF_ISNEW;
01303
01304
01305 STOPIF( ops__new_entries(current, 1, &sts), NULL);
01306 }
01307
01308 current=sts;
01309
01310 path=next_part;
01311 }
01312
01313 *ret=current;
01314
01315 ex:
01316 IF_FREE(copy);
01317 return status;
01318 }
01319
01320
01336 int ops__update_single_entry(struct estat *sts, struct sstat_t *output)
01337 {
01338 int status;
01339 struct sstat_t st;
01340 int i;
01341 char *fullpath;
01342
01343
01344 STOPIF( ops__build_path(&fullpath, sts), NULL);
01345
01346
01347
01348 if (sts->parent)
01349 if (sts->parent->entry_status & FS_REMOVED)
01350 {
01351 goto removed;
01352 }
01353
01354
01355 status=hlp__lstat(fullpath, &st);
01356
01357 if (status)
01358 {
01359 DEBUGP("lstat whines %d", status);
01360
01361
01362
01363
01364 if (abs(status) != ENOENT)
01365 STOPIF(status, "cannot lstat(%s)", fullpath);
01366
01367 removed:
01368
01369 if (st.mode)
01370 memset(&st, 0, sizeof(st));
01371
01372 sts->entry_status=FS_REMOVED;
01373
01374 status=0;
01375 }
01376 else
01377 {
01378
01379 sts->entry_status=ops__stat_to_action(sts, &st);
01380
01381
01382 if ( ((opt__get_int(OPT__CHANGECHECK) & CHCHECK_FILE) &&
01383 (sts->entry_status & FS_LIKELY)) ||
01384 (opt__get_int(OPT__CHANGECHECK) & CHCHECK_ALLFILES) )
01385 {
01386
01387
01388
01389 if (S_ISREG(st.mode) || S_ISLNK(st.mode))
01390 {
01391
01392 STOPIF( cs__compare_file(sts, fullpath, &i), NULL);
01393
01394 if (i>0)
01395 sts->entry_status= (sts->entry_status & ~ FS_LIKELY) | FS_CHANGED;
01396 else if (i==0)
01397 sts->entry_status= sts->entry_status & ~(FS_LIKELY | FS_CHANGED);
01398 }
01399
01400
01401
01402 }
01403 }
01404
01405
01406
01407
01408
01409 if (output)
01410 *output=st;
01411 else
01412 if (action->overwrite_sts_st) sts->st=st;
01413
01414 DEBUGP("known %s: action=%X, flags=%X, mode=0%o, status=%d",
01415 fullpath, sts->entry_status, sts->flags, sts->st.mode, status);
01416
01417 sts->local_mode_packed = MODE_T_to_PACKED(st.mode);
01418
01419 ex:
01420 return status;
01421 }
01422
01423
01427 inline void ops___set_todo_bits(struct estat *sts)
01428 {
01429
01430
01431 if (opt_recursive>0)
01432 sts->do_userselected |= sts->parent->do_userselected;
01433
01434
01435 if (opt_recursive>=0)
01436 sts->do_this_entry |= sts->parent->do_userselected | sts->do_userselected;
01437 }
01438
01439
01442 void ops__set_todo_bits(struct estat *sts)
01443 {
01444
01445 sts->do_filter_allows=1;
01446 sts->do_filter_allows_done=1;
01447
01448 if (sts->parent)
01449 ops___set_todo_bits(sts);
01450
01451 DEBUGP("user_sel,this=%d.%d parent=%d.%d",
01452 sts->do_userselected,
01453 sts->do_this_entry,
01454 sts->parent ? sts->parent->do_userselected : 0,
01455 sts->parent ? sts->parent->do_this_entry : 0);
01456
01457 return;
01458 }
01459
01460
01467 int ops__update_filter_set_bits(struct estat *sts)
01468 {
01469 int status;
01470 struct sstat_t stat;
01471
01472 status=0;
01473
01474 if (sts->parent)
01475 ops__set_todo_bits(sts);
01476
01477 if (sts->do_this_entry)
01478 {
01479 STOPIF( ops__update_single_entry(sts, &stat), NULL);
01480
01481 if (ops__calc_filter_bit(sts))
01482 {
01483
01484 if ((sts->entry_status & FS_REPLACED) != FS_REMOVED)
01485 if (action->overwrite_sts_st)
01486 sts->st = stat;
01487 }
01488 }
01489
01490 DEBUGP("filter says %d", sts->do_filter_allows);
01491
01492 ex:
01493 return status;
01494 }
01495
01500 void ops__copy_single_entry(struct estat *src, struct estat *dest)
01501 {
01502 dest->st=src->st;
01503
01504 dest->repos_rev=SVN_INVALID_REVNUM;
01505
01506
01507
01508
01509 dest->url=NULL;
01510
01511
01512 if (S_ISDIR(dest->st.mode))
01513 {
01514 #if 0
01515
01516 dest->by_inode=NULL;
01517 dest->by_name=NULL;
01518 dest->entry_count=0;
01519 dest->strings=NULL;
01520 dest->other_revs=0;
01521 dest->to_be_sorted=0;
01522 #endif
01523 }
01524 else
01525 {
01526 memcpy(dest->md5, src->md5, sizeof(dest->md5));
01527 #if 0
01528 {
01529 memset(dest->md5, 0, sizeof(dest->md5));
01530
01531 dest->change_flag=CF_NOTCHANGED;
01532 dest->decoder=src->decoder;
01533 dest->has_orig_md5=src->has_orig_md5;
01534 }
01535 #endif
01536 }
01537
01538 #if 0
01539
01540 dest->child_index=0;
01541 dest->dir_pool=NULL;
01542 #endif
01543
01544 dest->flags=RF_ISNEW | RF_COPY_SUB;
01545
01546
01547 dest->path_len=0;
01548
01549
01550
01551 dest->entry_status=FS_NEW;
01552 dest->remote_status=FS_NEW;
01553
01554 dest->cache_index=0;
01555 dest->decoder_is_correct=src->decoder_is_correct;
01556
01557 dest->was_output=0;
01558 dest->do_userselected = dest->do_child_wanted = dest->do_this_entry = 0;
01559 dest->arg=NULL;
01560 }
01561
01562
01572 int ops__correlate_dirs(struct estat *dir_A, struct estat *dir_B,
01573 ops__correlate_fn1_t only_A,
01574 ops__correlate_fn2_t both,
01575 ops__correlate_fn1_t only_B,
01576 ops__correlate_fn2_t for_every)
01577 {
01578 int status, comp;
01579 struct estat **list_A, **list_B;
01580
01581
01582 status=0;
01583 DEBUGP("correlating %s and %s", dir_A->name, dir_B->name);
01584
01585
01586 STOPIF( dir__sortbyname(dir_A), NULL);
01587 STOPIF( dir__sortbyname(dir_B), NULL);
01588
01589 list_A=dir_A->by_name;
01590 list_B=dir_B->by_name;
01591
01592 while (*list_A)
01593 {
01594 if (!*list_B) goto a_only;
01595
01596 comp=dir___f_sort_by_name( list_A, list_B );
01597 DEBUGP("comp %s, %s => %d",
01598 (*list_A)->name,
01599 (*list_B)->name, comp);
01600
01601 if (comp == 0)
01602 {
01603
01604 if (both)
01605 STOPIF( both(*list_A, *list_B), NULL);
01606 if (for_every)
01607 STOPIF( for_every(*list_A, *list_B), NULL);
01608
01609 list_A++;
01610 list_B++;
01611 }
01612 else if (comp > 0)
01613 {
01614
01615 if (only_B)
01616 STOPIF( only_B(*list_B, list_B), NULL);
01617 if (for_every)
01618 STOPIF( for_every(NULL, *list_B), NULL);
01619
01620 list_B++;
01621 }
01622 else
01623 {
01624 a_only:
01625
01626 if (only_A)
01627 STOPIF( only_A(*list_A, list_A), NULL);
01628 if (for_every)
01629 STOPIF( for_every(*list_A, NULL), NULL);
01630
01631 list_A++;
01632 }
01633 }
01634
01635
01636 if (only_B || for_every)
01637 {
01638 while (*list_B)
01639 {
01640 if (only_B)
01641 STOPIF( only_B(*list_B, list_B), NULL);
01642 if (for_every)
01643 STOPIF( for_every(NULL, *list_B), NULL);
01644
01645 list_B++;
01646 }
01647 }
01648
01649 ex:
01650 return status;
01651 }
01652
01653
01666
01667
01668
01669
01670 int ops__read_special_entry(apr_file_t *a_stream,
01671 char **data,
01672 int max, ssize_t *real_len,
01673 char *filename,
01674 apr_pool_t *pool)
01675 {
01676 int status;
01677 apr_off_t special_len, bof;
01678 apr_size_t len_read;
01679 char *special_data;
01680
01681
01682 status=0;
01683 special_len=0;
01684
01685
01686
01687
01688 if (filename)
01689 STOPIF_CODE_ERR( unlink(filename) == -1, errno,
01690 "Cannot remove temporary file \"%s\"", filename);
01691
01692
01693
01694 STOPIF( apr_file_seek(a_stream, APR_CUR, &special_len), NULL);
01695
01696
01697 if (!max) max=8192;
01698 STOPIF_CODE_ERR( special_len > max, E2BIG,
01699 "!The special entry \"%s\" is too long (%llu bytes, max %llu).\n"
01700 "Please contact the dev@ mailing list.",
01701 filename, (t_ull)special_len, (t_ull)max);
01702
01703
01704
01705 bof=0;
01706 STOPIF( apr_file_seek(a_stream, APR_SET, &bof), NULL);
01707
01708 if (pool)
01709
01710 special_data= apr_palloc( pool, special_len+1);
01711 else
01712 STOPIF( hlp__alloc( &special_data, special_len+1), NULL);
01713
01714
01715
01716 len_read=special_len;
01717 STOPIF( apr_file_read( a_stream, special_data, &len_read), NULL);
01718 STOPIF_CODE_ERR( len_read != special_len, ENODATA,
01719 "Reading was cut off at byte %llu of %llu",
01720 (t_ull)len_read, (t_ull)special_len);
01721 special_data[len_read]=0;
01722
01723 DEBUGP("got special value %s", special_data);
01724
01725 if (real_len) *real_len=special_len;
01726 *data=special_data;
01727
01728 ex:
01729 return status;
01730 }
01731
01732
01735 int ops__are_children_interesting(struct estat *dir)
01736 {
01737 struct estat tmp;
01738
01739 tmp.parent=dir;
01740 tmp.do_this_entry = tmp.do_userselected = tmp.do_child_wanted = 0;
01741
01742 ops___set_todo_bits(&tmp);
01743
01744 return tmp.do_this_entry;
01745 }
01746
01747
01754 int ops__apply_group(struct estat *sts, hash_t *props,
01755 apr_pool_t *pool)
01756 {
01757 int status;
01758 struct grouping_t *group;
01759 int own_pool;
01760
01761
01762 status=0;
01763 own_pool=0;
01764 if (props) *props=NULL;
01765
01766 if (!sts->match_pattern) goto return_prop;
01767
01768 group= sts->match_pattern->group_def;
01769 BUG_ON(!group);
01770
01771 DEBUGP("applying %s to %s", sts->match_pattern->group_name, sts->name);
01772
01773 if (group->auto_props)
01774 {
01775 if (!pool)
01776 {
01777 own_pool=1;
01778 STOPIF( apr_pool_create_ex(&pool, global_pool, NULL, NULL), NULL);
01779 }
01780
01781 STOPIF( prp__set_from_aprhash(sts, group->auto_props,
01782 STORE_IN_FS, props, pool), NULL);
01783 sts->flags |= RF_PUSHPROPS;
01784 }
01785
01786 if (!sts->url)
01787 sts->url=group->url;
01788 sts->to_be_ignored=group->is_ignore;
01789
01790 sts->match_pattern=NULL;
01791
01792 return_prop:
01793 if (props && !*props)
01794 STOPIF( prp__open_byestat( sts,
01795 GDBM_WRCREAT | HASH_REMEMBER_FILENAME, props), NULL);
01796
01797 ex:
01798 if (own_pool)
01799 apr_pool_destroy(pool);
01800
01801 return status;
01802 }
01803
01804
01806 int ops__make_shadow_entry(struct estat *sts, int flags)
01807 {
01808 int status;
01809 struct estat *copy;
01810
01811
01812 BUG_ON(sts->old);
01813
01814 STOPIF( ops__allocate(1, ©, NULL), NULL);
01815 memcpy(copy, sts, sizeof(*copy));
01816
01817 if (flags == SHADOWED_BY_REMOTE)
01818 {
01819 sts->remote_status=FS_REPLACED;
01820 copy->remote_status=FS_REMOVED;
01821 }
01822 else if (flags == SHADOWED_BY_LOCAL)
01823 {
01824 sts->remote_status=FS_REMOVED;
01825 copy->remote_status=FS_REPLACED;
01826 }
01827
01828
01829
01830
01831 copy->cache_index=0;
01832 sts->old=copy;
01833
01834 ex:
01835 return status;
01836 }
01837
01838
01839 #ifndef ENABLE_RELEASE
01840
01843 void DEBUGP_dump_estat(struct estat *sts)
01844 {
01845 char *path;
01846
01847
01848
01849
01850
01851
01852
01853
01854
01855
01856 if (ops__build_path(&path, sts))
01857 DEBUGP("*** Dump of ... %s/%s",
01858 sts->parent ? sts->parent->name : "/",
01859 sts->name);
01860 else
01861 DEBUGP("*** Dump of %s", path);
01862
01863 DEBUGP("flags=%s", st__flags_string_fromint(sts->flags));
01864 DEBUGP("entry_status=%s", st__status_string_fromint(sts->entry_status));
01865 DEBUGP("remote_status=%s", st__status_string_fromint(sts->remote_status));
01866
01867 DEBUGP("types: st=%s, local=%s, new=%s, old=%s",
01868 st__type_string(sts->st.mode),
01869 st__type_string(PACKED_to_MODE_T(sts->local_mode_packed)),
01870 st__type_string(PACKED_to_MODE_T(sts->new_rev_mode_packed)),
01871 st__type_string(PACKED_to_MODE_T(sts->old_rev_mode_packed)));
01872
01873 if (S_ISDIR(sts->st.mode))
01874 DEBUGP("directory: %d children", sts->entry_count);
01875 else
01876 DEBUGP("non-dir: decoder=%s, md5=%s", sts->decoder,
01877 cs__md5tohex_buffered(sts->md5));
01878
01879
01880 DEBUGP("mode=0%o size=%llu uid=%u gid=%u inode=%llu",
01881 sts->st.mode & 07777, (t_ull)sts->st.size,
01882 sts->st.uid, sts->st.gid,
01883 (t_ull)sts->st.ino);
01884
01885 DEBUGP("others:%s%s%s%s%s%s%s%s%s",
01886 sts->old ? " old" : "",
01887 sts->was_output ? " was_output" : "",
01888 sts->decoder_is_correct ? " decoder_ok" : "",
01889 sts->do_userselected ? " do_usersel" : "",
01890 sts->do_child_wanted ? " do_chld_w" : "",
01891 sts->do_this_entry ? " do_this" : "",
01892 sts->do_filter_allows ? " filter_allows" : "",
01893 sts->do_filter_allows_done ? " filter_allows_done" : "",
01894 sts->to_be_ignored ? " ignored" : "");
01895 }
01896 #endif
01897
01898