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, GDBM_WRCREAT, props), NULL);
01795 
01796 ex:
01797     if (own_pool)
01798         apr_pool_destroy(pool);
01799 
01800     return status;
01801 }
01802 
01803 
01805 int ops__make_shadow_entry(struct estat *sts, int flags)
01806 {
01807     int status;
01808     struct estat *copy;
01809 
01810 
01811     BUG_ON(sts->old);
01812 
01813     STOPIF( ops__allocate(1, ©, NULL), NULL);
01814     memcpy(copy, sts, sizeof(*copy));
01815 
01816     if (flags == SHADOWED_BY_REMOTE)
01817     {
01818         sts->remote_status=FS_REPLACED;
01819         copy->remote_status=FS_REMOVED;
01820     }
01821     else if (flags == SHADOWED_BY_LOCAL)
01822     {
01823         sts->remote_status=FS_REMOVED;
01824         copy->remote_status=FS_REPLACED;
01825     }
01826 
01827     
01828 
01829 
01830     copy->cache_index=0;
01831     sts->old=copy;
01832 
01833 ex:
01834     return status;
01835 }
01836 
01837 
01838 #ifndef ENABLE_RELEASE
01839 
01842 void DEBUGP_dump_estat(struct estat *sts)
01843 {
01844     char *path;
01845 
01846     
01847 
01848 
01849 
01850     
01851 
01852 
01853 
01854 
01855     if (ops__build_path(&path, sts))
01856         DEBUGP("*** Dump of ... %s/%s",
01857                 sts->parent ? sts->parent->name : "/",
01858                 sts->name);
01859     else
01860         DEBUGP("*** Dump of %s", path);
01861 
01862     DEBUGP("flags=%s", st__flags_string_fromint(sts->flags));
01863     DEBUGP("entry_status=%s", st__status_string_fromint(sts->entry_status));
01864     DEBUGP("remote_status=%s", st__status_string_fromint(sts->remote_status));
01865 
01866     DEBUGP("types: st=%s, local=%s, new=%s, old=%s",
01867                 st__type_string(sts->st.mode),
01868                 st__type_string(PACKED_to_MODE_T(sts->local_mode_packed)),
01869                 st__type_string(PACKED_to_MODE_T(sts->new_rev_mode_packed)),
01870                 st__type_string(PACKED_to_MODE_T(sts->old_rev_mode_packed)));
01871 
01872     if (S_ISDIR(sts->st.mode))
01873         DEBUGP("directory: %d children", sts->entry_count);
01874     else
01875         DEBUGP("non-dir: decoder=%s, md5=%s", sts->decoder,
01876                 cs__md5tohex_buffered(sts->md5));
01877 
01878     
01879     DEBUGP("mode=0%o size=%llu uid=%u gid=%u inode=%llu",
01880             sts->st.mode & 07777, (t_ull)sts->st.size, 
01881             sts->st.uid, sts->st.gid,
01882             (t_ull)sts->st.ino);
01883 
01884     DEBUGP("others:%s%s%s%s%s%s%s%s%s",
01885             sts->old ? " old" : "",
01886             sts->was_output ? " was_output" : "",
01887             sts->decoder_is_correct ? " decoder_ok" : "",
01888             sts->do_userselected ? " do_usersel" : "",
01889             sts->do_child_wanted ? " do_chld_w" : "",
01890             sts->do_this_entry ? " do_this" : "",
01891             sts->do_filter_allows ? " filter_allows" : "",
01892             sts->do_filter_allows_done ? " filter_allows_done" : "",
01893             sts->to_be_ignored ? " ignored" : "");
01894 }
01895 #endif
01896 
01897