00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00040 #include <apr_md5.h>
00041 #include <apr_pools.h>
00042 #include <apr_user.h>
00043 #include <apr_file_io.h>
00044 #include <subversion-1/svn_delta.h>
00045 #include <subversion-1/svn_ra.h>
00046 #include <subversion-1/svn_error.h>
00047 #include <subversion-1/svn_string.h>
00048 #include <subversion-1/svn_time.h>
00049 
00050 #include <sys/types.h>
00051 #include <unistd.h>
00052 #include <ctype.h>
00053 #include <time.h>
00054 #include <fcntl.h>
00055 
00056 
00057 #include "global.h"
00058 #include "helper.h"
00059 #include "url.h"
00060 #include "status.h"
00061 #include "racallback.h"
00062 #include "props.h"
00063 #include "checksum.h"
00064 #include "revert.h"
00065 #include "warnings.h"
00066 #include "est_ops.h"
00067 #include "waa.h"
00068 #include "commit.h"
00069 #include "racallback.h"
00070 
00071 
00072 
00073 static char *filename,
00074                         *filename_tmp=NULL;
00075 static unsigned tmp_len=0;
00076 
00077 
00083 int up__fetch_decoder(struct estat *sts)
00084 {
00085     int status, st2;
00086     hash_t db;
00087     datum value;
00088 
00089 
00090     db=NULL;
00091     status=0;
00092     
00093     if (!action->needs_decoder || 
00094             sts->decoder) goto ex;
00095 
00096     status=prp__open_byestat(sts, GDBM_READER, &db);
00097     if (status == ENOENT)
00098         status=0;
00099     else
00100     {
00101         STOPIF(status, NULL);
00102 
00103         
00104 
00105 
00106         if (prp__get(db, propval_updatepipe, &value) == 0)
00107             STOPIF( hlp__strdup( &sts->decoder, value.dptr), NULL);
00108     }
00109 
00110     ex:
00111     if (db)
00112     {
00113         st2=hsh__close(db, status);
00114         if (!status) STOPIF(st2, NULL);
00115     }
00116     return status;
00117 }
00118 
00119 
00129 int up__parse_prop(struct estat *sts, 
00130         const char *utf8_name, 
00131         const svn_string_t *utf8_value,
00132         int *not_handled,
00133         apr_pool_t *pool)
00134 {
00135     char *cp, *loc_name, *loc_value;
00136     int i,status;
00137     apr_uid_t uid;
00138     apr_gid_t gid;
00139     apr_time_t at;
00140     svn_error_t *status_svn;
00141 
00142 
00143     
00144 
00145 
00146     
00147 
00148     STOPIF( hlp__utf82local(utf8_name, &loc_name, -1), NULL);
00149 
00150     status=0;
00151     if (!utf8_value)
00152     {
00153         DEBUGP("got NULL property for %s: %s", sts->name, loc_name);
00154         
00155         loc_value=NULL;
00156     }
00157     else
00158     {
00159         STOPIF( hlp__utf82local(utf8_value->data, &loc_value, -1), NULL);
00160         DEBUGP("got property for %s: %s=%s",
00161                 sts->name, loc_name, loc_value);
00162     }
00163 
00164 
00165     
00166 
00167     if (0 == strcmp(utf8_name, propname_owner))
00168     {
00169         
00170 
00171         i=strtoul(utf8_value->data, &cp, 0);
00172         if (cp == utf8_value->data)
00173             STOPIF( wa__warn(WRN__META_USER_INVALID, EINVAL,
00174                         "cannot read uid in %s", loc_value),
00175                     NULL);
00176         else
00177         {
00178             cp=hlp__skip_ws(cp);
00179             if (*cp)
00180             {
00181                 status=hlp__get_uid(cp, &uid, pool);
00182                 if (status == APR_SUCCESS)
00183                     i=uid;
00184                 
00185                 status=0;
00186             }
00187 
00188             if (sts->st.uid != i)
00189             {
00190                 sts->remote_status |= FS_META_OWNER;
00191                 if (!action->is_compare)
00192                 {
00193                     sts->st.uid = i;
00194                     DEBUGP("marking owner %s to %d", 
00195                             loc_value, sts->st.uid);
00196                 }
00197             }
00198         }
00199     }
00200     else if (0 == strcmp(utf8_name, propname_group))
00201     {
00202         i=strtoul(utf8_value->data, &cp, 0);
00203         if (cp == utf8_value->data)
00204             STOPIF( wa__warn(WRN__META_USER_INVALID, EINVAL,
00205                         "cannot read gid in %s", loc_value),
00206                     NULL);
00207         else
00208         {
00209 
00210             cp=hlp__skip_ws(cp);
00211             if (*cp)
00212             {
00213                 status=hlp__get_gid(cp, &gid, pool);
00214                 if (status == APR_SUCCESS)
00215                     i=gid;
00216                 status=0;
00217             }
00218 
00219             if (sts->st.gid != i)
00220             {
00221                 sts->remote_status |= FS_META_GROUP;
00222                 if (!action->is_compare)
00223                 {
00224                     sts->st.gid = i;
00225                     DEBUGP("marking group %s to %d", 
00226                             loc_value, sts->st.gid);
00227                 }
00228             }
00229         }
00230     }
00231     else if (0 == strcmp(utf8_name, propname_mtime))
00232     {
00233         status_svn=svn_time_from_cstring(&at, utf8_value->data, pool);
00234         if (status_svn)
00235             STOPIF( wa__warn(WRN__META_MTIME_INVALID, EINVAL,
00236                         "modification time string invalid: %s", loc_value),
00237                     NULL);
00238         else
00239         {
00240             if (sts->st.mtim.tv_sec != apr_time_sec(at) ||
00241                     sts->st.mtim.tv_nsec != apr_time_usec(at) * 1000)
00242             {
00243                 sts->remote_status |= FS_META_MTIME;
00244 
00245                 if (!action->is_compare)
00246                 {
00247                     
00248 
00249 
00250                     
00251                     {
00252                         sts->st.mtim.tv_sec=apr_time_sec(at);
00253                         
00254                         sts->st.mtim.tv_nsec=apr_time_usec(at) * 1000;
00255                     }
00256                     DEBUGP("marking mtime \"%s\" to %24.24s", 
00257                             loc_value,
00258                             ctime(& (sts->st.mtim.tv_sec) ));
00259                 }
00260             }
00261         }
00262     }
00263     else if (0 == strcmp(utf8_name, propname_umode))
00264     {
00265         i=strtoul(utf8_value->data, &cp, 0);
00266         if (*cp || i>07777)
00267             STOPIF( wa__warn(WRN__META_UMASK_INVALID, EINVAL,
00268                         "no valid permissions found in %s", loc_value),
00269                     NULL);
00270         else
00271         {
00272             if ((sts->st.mode & 07777) != i)
00273             {
00274                 sts->remote_status |= FS_META_UMODE;
00275                 if (!action->is_compare)
00276                 {
00277                     sts->st.mode = (sts->st.mode & ~07777) | i;
00278                     DEBUGP("marking mode \"%s\" to 0%o", 
00279                             loc_value, sts->st.mode & 07777);
00280                 }
00281             }
00282         }
00283     }
00284     else if (0 == strcmp(utf8_name, propname_special) &&
00285             0 == strcmp(utf8_value->data, propval_special))
00286     {
00287         if (TEST_PACKED(S_ISANYSPECIAL, sts->new_rev_mode_packed))
00288         {
00289             DEBUGP("already marked as special");
00290         }
00291         else
00292         {
00293             
00294 
00295             if (!(S_ISLNK(PACKED_to_MODE_T(sts->new_rev_mode_packed)) ||
00296                         S_ISCHR(PACKED_to_MODE_T(sts->new_rev_mode_packed)) ||
00297                         S_ISBLK(PACKED_to_MODE_T(sts->new_rev_mode_packed))) )
00298             {
00299                 sts->st.mode = (sts->st.mode & ~S_IFMT) | S_IFANYSPECIAL;
00300                 sts->new_rev_mode_packed = MODE_T_to_PACKED(sts->st.mode);
00301             }
00302             DEBUGP("this is a special node");
00303         }
00304     }
00305     else if (0 == strcmp(utf8_name, propname_origmd5))
00306     {
00307         
00308 
00309 
00310         BUG_ON(S_ISDIR(sts->st.mode));
00311         STOPIF( cs__char2md5( utf8_value->data, NULL, sts->md5), NULL);
00312         DEBUGP("got a orig-md5: %s", cs__md5tohex_buffered(sts->md5));
00313         sts->has_orig_md5=1;
00314     }
00315     else
00316     {
00317         if (strcmp(utf8_name, propval_updatepipe) == 0)
00318         {
00319             if (action->needs_decoder)
00320             {
00321                 
00322 
00323 
00324 
00325 
00326                 STOPIF( hlp__strdup( &sts->decoder, utf8_value->data), NULL);
00327                 sts->decoder_is_correct=1;
00328                 DEBUGP("got a decoder: %s", sts->decoder);
00329             }
00330         }
00331 
00332         
00333         if (!hlp__is_special_property_name(utf8_name))
00334         {
00335             sts->remote_status |= FS_PROPERTIES;
00336 
00337             DEBUGP("property %s: %s=%s", 
00338                     sts->name,
00339                     loc_name, loc_value);
00340             if (not_handled) *not_handled=1;
00341         }
00342     }
00343 
00344 
00345 ex:
00346     return status;
00347 
00348 #if 0
00349 inval:
00350     
00351 
00352     
00353     status=ops__build_path(&cp, sts);
00354     STOPIF(EINVAL, "incorrect utf8_value for property %s ignored: "
00355             "file %s: \"%s\"",
00356             name, 
00357             status == 0 ? cp : sts->name, 
00358             utf8_value->data);
00359 #endif
00360 }
00361 
00362 
00366 int up__unlink(struct estat *sts, char *filename)
00367 {
00368     int status;
00369 
00370 
00371     status=0;
00372     if (!filename)
00373         STOPIF( ops__build_path(&filename, sts), NULL );
00374 
00375     
00376     if (sts->entry_status & FS_CHANGED)
00377         STOPIF_CODE_ERR(1, EBUSY, 
00378                 "File %s has been changed - won't remove", filename);
00379 
00380     if (unlink(filename) == -1)
00381     {
00382         status=errno;
00383         
00384         if (status == ENOENT) status=0;
00385     }
00386     else
00387     {
00388         STOPIF( waa__delete_byext(filename, WAA__FILE_MD5s_EXT, 1), NULL);
00389         STOPIF( waa__delete_byext(filename, WAA__PROP_EXT, 1), NULL);
00390     }
00391 
00392     DEBUGP("unlink(%s)", filename);
00393 
00394 ex:
00395     return status;
00396 }
00397 
00398 
00412 int up__rmdir(struct estat *sts, struct url_t *url)
00413 {
00414     int status, i, has_others;
00415     struct estat *cur;
00416     char *path;
00417 
00418 
00419     status=0;
00420     has_others=0;
00421 
00422     
00423     for(i=0; i<sts->entry_count; i++)
00424     {
00425         cur=sts->by_inode[i];
00426 
00427         if (url && cur->url != url)
00428             has_others++;
00429         else
00430         {
00431             
00432 
00433 
00434             
00435 
00436             status=up__unlink(cur, NULL);
00437             if (status == EISDIR)
00438                 status=up__rmdir(cur, url);
00439 
00440             STOPIF( status, "unlink of %s failed", cur->name);
00441         }
00442     }
00443 
00444     if (!has_others)
00445     {
00446         STOPIF( ops__build_path(&path, sts), NULL );
00447         status = rmdir(path) == -1 ? errno : 0;
00448 
00449         DEBUGP("removing %s: %d", path, status);
00450         if (status == ENOENT) status=0;
00451         STOPIF( status, "Cannot remove directory %s", path);
00452     }
00453 
00454 ex:
00455     return status;
00456 }
00457 
00458 
00520 int up__set_meta_data(struct estat *sts, char *filename)
00521 {
00522     struct timeval tv[2];
00523     int status;
00524     mode_t current_mode;
00525 
00526 
00527     status=0;
00528     current_mode= PACKED_to_MODE_T(sts->new_rev_mode_packed);
00529 
00530     if (!filename)
00531         STOPIF( ops__build_path(&filename, sts), NULL );
00532 
00533     DEBUGP_dump_estat(sts);
00534 
00535     
00536 
00537 
00538 
00539     if (CHOWN_BOOL || !S_ISLNK(current_mode))
00540     {
00541         if (sts->remote_status & (FS_META_OWNER | FS_META_GROUP))
00542         {
00543             DEBUGP("setting %s to %d.%d",
00544                     filename, sts->st.uid, sts->st.gid);
00545             status=CHOWN_FUNC(filename, sts->st.uid, sts->st.gid);
00546             if (status == -1)
00547             {
00548                 STOPIF( wa__warn( errno==EPERM ? WRN__CHOWN_EPERM : WRN__CHOWN_OTHER,
00549                             errno, "Cannot chown \"%s\" to %d:%d", 
00550                             filename, sts->st.uid, sts->st.gid),
00551                         NULL );
00552             }
00553         }
00554     }
00555     else
00556     {
00557         DEBUGP("a symlink, but no lchown: %s", filename);
00558     }
00559 
00560     
00561 
00562     if (!S_ISLNK(current_mode))
00563     {
00564         if (sts->remote_status & FS_META_UMODE)
00565         {
00566             
00567 
00568 
00569             DEBUGP("setting %s's mode to 0%o", 
00570                     filename, sts->st.mode & 07777);
00571             status=chmod(filename, sts->st.mode & 07777);
00572             if (status == -1)
00573             {
00574                 STOPIF( wa__warn( errno == EPERM ? WRN__CHMOD_EPERM : WRN__CHMOD_OTHER, 
00575                             errno, "Cannot chmod \"%s\" to 0%3o", 
00576                             filename, sts->st.mode & 07777 ), 
00577                         NULL );
00578             }
00579         }
00580     }
00581 
00582     if (UTIMES_BOOL || !S_ISLNK(current_mode))
00583     {
00584         if (sts->remote_status & FS_META_MTIME)
00585         {
00586             
00587             tv[1].tv_sec =sts->st.mtim.tv_sec;
00588             tv[1].tv_usec=sts->st.mtim.tv_nsec/1000;
00589             
00590 
00591 
00592             tv[0].tv_sec =sts->st.mtim.tv_sec;
00593             tv[0].tv_usec=sts->st.mtim.tv_nsec/1000;
00594             DEBUGP("setting %s's mtime %24.24s", 
00595                     filename, ctime(& (sts->st.mtim.tv_sec) ));
00596             STOPIF_CODE_ERR( UTIMES_FUNC(filename, tv) == -1,
00597                     errno, "utimes(%s)", filename);
00598         }
00599     }
00600     else
00601     {
00602         DEBUGP("a symlink, but no lutimes: %s", filename);
00603     }
00604 
00605     STOPIF( hlp__lstat(filename, & sts->st), NULL);
00606 
00607 ex:
00608     return status;
00609 }
00610 
00611 
00618 int up__handle_special(struct estat *sts, 
00619         char *path,
00620         char *data,
00621         apr_pool_t *pool)
00622 {
00623     int status;
00624     char *cp;
00625 
00626 
00627     STOPIF( ops__string_to_dev(sts, data, &cp), NULL);
00628     STOPIF( hlp__utf82local(cp, &cp, -1), NULL);
00629 
00630     
00631     sts->new_rev_mode_packed=sts->local_mode_packed;
00632 
00633     sts->stringbuf_tgt=NULL;
00634     DEBUGP("special %s has mode 0%o", path, sts->st.mode);
00635 
00636     
00637     
00638     switch (PACKED_to_MODE_T(sts->new_rev_mode_packed) & S_IFMT)
00639     {
00640         case S_IFBLK:
00641         case S_IFCHR:
00642             STOPIF_CODE_ERR( mknod(path, sts->st.mode, sts->st.rdev) == -1,
00643                     errno, "mknod(%s)", path) ;
00644             break;
00645 
00646         case S_IFLNK:
00647             STOPIF_CODE_ERR( symlink(cp, path) == -1, 
00648                     errno, "symlink(%s, %s)", cp, path);
00649             break;
00650 
00651         default:
00652             STOPIF_CODE_ERR(1, EINVAL, 
00653                     "what kind of node is this??? (mode=0%o)", sts->st.mode);
00654     }
00655 
00656 ex:
00657     return status;
00658 }
00659 
00660 
00661 
00662 svn_error_t *up__set_target_revision(void *edit_baton,
00663         svn_revnum_t rev,
00664         apr_pool_t *pool)
00665 {
00666     struct estat *sts=edit_baton;
00667     int status;
00668 
00669 
00670     status=0;
00671     
00672 
00673 
00674     target_revision=rev;
00675     sts->repos_rev=rev;
00676 
00677     RETURN_SVNERR(status);
00678 }
00679 
00680 
00681 svn_error_t *up__open_root(void *edit_baton,
00682         svn_revnum_t base_revision,
00683         apr_pool_t *dir_pool UNUSED,
00684         void **root_baton)
00685 {
00686     struct estat *sts=edit_baton;
00687 
00688     sts->repos_rev=base_revision;
00689     *root_baton=sts;
00690 
00691     return SVN_NO_ERROR; 
00692 }
00693 
00694 
00695 svn_error_t *up__add_directory(const char *utf8_path,
00696         void *parent_baton,
00697         const char *utf8_copy_path,
00698         svn_revnum_t copy_rev,
00699         apr_pool_t *dir_pool UNUSED,
00700         void **child_baton)
00701 {
00702     struct estat *dir=parent_baton;
00703     struct estat *sts;
00704     int status;
00705     char* path;
00706 
00707 
00708     STOPIF( cb__add_entry(dir, utf8_path, &path, utf8_copy_path, 
00709                 copy_rev, S_IFDIR, NULL, 1,
00710                 child_baton), NULL );
00711     sts=(struct estat*)*child_baton;
00712 
00713     if (!action->is_compare)
00714     {
00715         
00716 
00717         
00718         STOPIF_CODE_ERR( mkdir(path, 0700) == -1, errno, 
00719                 "mkdir(%s)", path);
00720 
00721         
00722         STOPIF( hlp__lstat(path, &(sts->st)),
00723                 "lstat(%s)", path); 
00724     }
00725 
00726     status=0;
00727 
00728 ex:
00729     RETURN_SVNERR(status);
00730 }
00731 
00732 
00733 
00734 svn_error_t *up__change_dir_prop(void *dir_baton,
00735         const char *utf8_name,
00736         const svn_string_t *value,
00737         apr_pool_t *pool)
00738 {
00739     struct estat *sts=dir_baton;
00740     int status;
00741 
00742     status=0;
00743     if (!sts->url || url__current_has_precedence(sts->url))
00744         STOPIF( up__parse_prop(sts, utf8_name, value, NULL, pool), NULL);
00745 
00746 ex:
00747     RETURN_SVNERR(status);
00748 }
00749 
00750 
00751 svn_error_t *up__close_directory(
00752         void *dir_baton,
00753         apr_pool_t *pool)
00754 {
00755     struct estat *sts=dir_baton;
00756     int status;
00757 
00758 
00759     STOPIF( ops__build_path(&filename, sts), NULL);
00760     
00761     STOPIF( up__set_meta_data(sts, filename), NULL);
00762     
00763     STOPIF( hlp__lstat( filename, &(sts->st)),
00764             "Cannot lstat('%s')", filename);
00765     
00766     STOPIF( st__status(sts), NULL);
00767 
00768     
00769     sts->flags |= RF_CHECK;
00770 
00771 ex:
00772     RETURN_SVNERR(status);
00773 }
00774 
00775 
00777 svn_error_t *up__absent_directory(const char *utf8_path,
00778         void *parent_baton,
00779         apr_pool_t *pool)
00780 {
00781     struct estat *dir UNUSED =parent_baton;
00782 
00783     DEBUGP("in %s", __PRETTY_FUNCTION__);
00784 
00785     return SVN_NO_ERROR; 
00786 }
00787 
00788 
00789 svn_error_t *up__add_file(const char *utf8_path,
00790         void *parent_baton,
00791         const char *utf8_copy_path,
00792         svn_revnum_t copy_rev,
00793         apr_pool_t *file_pool,
00794         void **file_baton)
00795 {
00796     struct estat *dir=parent_baton;
00797     int status;
00798 
00799     STOPIF( cb__add_entry(dir, utf8_path, NULL, utf8_copy_path, copy_rev,
00800                 S_IFREG, NULL, 1, file_baton), NULL);
00801 
00802 ex:
00803     RETURN_SVNERR(status);
00804 }
00805 
00806 
00807 svn_error_t *up__apply_textdelta(void *file_baton,
00808         const char *base_checksum,
00809         apr_pool_t *pool,
00810         svn_txdelta_window_handler_t *handler,
00811         void **handler_baton)
00812 {
00813     struct estat *sts=file_baton;
00814     svn_stream_t *svn_s_src, *svn_s_tgt;
00815     int status;
00816     char *cp;
00817     char* fn_utf8;
00818     apr_file_t *source, *target;
00819     struct encoder_t *encoder;
00820     svn_stringbuf_t *stringbuf_src;
00821 
00822 
00823     stringbuf_src=NULL;
00824     encoder=NULL;
00825     STOPIF( ops__build_path(&filename, sts), NULL);
00826 
00827     if (action->is_compare) 
00828     {
00829         
00830 
00831         cp="";
00832         goto into_stringbufs;
00833     }
00834 
00835     STOPIF_CODE_ERR( sts->entry_status & FS_CHANGED, EBUSY, 
00836             "file '%s' was changed locally and cannot be updated", filename);
00837 #if 0
00838     
00839 
00840 
00841     STOPIF_CODE_ERR( sts->entry_status & FS_REMOVED, ENOENT, 
00842             "file '%s' was deleted locally", filename);
00843 #endif
00844 
00845     status=strlen(filename)+10;
00846     if (status > tmp_len)
00847     {
00848         
00849         status= (status+1024) & ~(1024-1);
00850         STOPIF( hlp__realloc( &filename_tmp, status), NULL);
00851 
00852         tmp_len=status;
00853     }
00854 
00855     strcpy(filename_tmp, filename);
00856     strcat(filename_tmp, ".up.tmp");
00857 
00858     DEBUGP("target is %s (0%o),", filename, sts->st.mode);
00859     DEBUGP("  temp is %s", filename_tmp);
00860 
00861     if (!S_ISREG(sts->st.mode))
00862     {
00863         
00864         if (S_ISLNK(sts->st.mode))
00865         {
00866             STOPIF( ops__link_to_string(sts, filename, &cp),
00867                     NULL);
00868             STOPIF( hlp__local2utf8(cp, &cp, -1), NULL);
00869         }
00870         else
00871             cp=ops__dev_to_filedata(sts);
00872 
00873 into_stringbufs:
00874         stringbuf_src=svn_stringbuf_create(cp, pool);
00875         sts->stringbuf_tgt=svn_stringbuf_create("", pool);
00876 
00877         svn_s_src=svn_stream_from_stringbuf(stringbuf_src, pool);
00878         svn_s_tgt=svn_stream_from_stringbuf(sts->stringbuf_tgt, pool);
00879         status=0;
00880     }
00881     else
00882     {
00906         
00907 
00908 
00909 
00910         
00911 
00912         STOPIF( apr_pool_create(&(sts->filehandle_pool), global_pool),
00913                 "Creating the filehandle pool");
00914 
00915         
00916 
00917         STOPIF( apr_file_open(&source, 
00918                     (sts->remote_status & (FS_NEW|FS_CHANGED|FS_REMOVED)) ? 
00919                     "/dev/null" : filename, 
00920                     APR_READ, 0, sts->filehandle_pool),
00921                 NULL);
00922 
00923         
00924 
00925         STOPIF( apr_file_open(&target, filename_tmp, 
00926                     APR_WRITE | APR_CREATE | APR_TRUNCATE,
00927                     APR_UREAD | APR_UWRITE, sts->filehandle_pool),
00928                 NULL);
00929 
00930         svn_s_src=svn_stream_from_aprfile(source, sts->filehandle_pool);
00931         svn_s_tgt=svn_stream_from_aprfile(target, sts->filehandle_pool);
00932 
00933         
00934         if (!action->is_import_export)
00935             STOPIF( cs__new_manber_filter(sts, svn_s_tgt, &svn_s_tgt, 
00936                         sts->filehandle_pool),
00937                     NULL);
00938 
00939         if (sts->decoder)
00940         {
00941             STOPIF( hlp__encode_filter(svn_s_tgt, sts->decoder, 1, 
00942                         filename, &svn_s_tgt, &encoder, sts->filehandle_pool), NULL);
00943             
00944             encoder->output_md5= &(sts->md5);
00945         }
00946     }
00947 
00948     STOPIF( hlp__local2utf8(filename, &fn_utf8, -1), NULL );
00949     svn_txdelta_apply(svn_s_src, svn_s_tgt, 
00950             action->is_compare ? NULL : sts->md5, 
00951             fn_utf8, pool,
00952             handler, handler_baton);
00953 
00954 
00955     sts->remote_status |= FS_CHANGED;
00956 
00957 ex:
00958     RETURN_SVNERR(status);
00959 }
00960 
00961 
00962 svn_error_t *up__change_file_prop(void *file_baton,
00963         const char *utf8_name,
00964         const svn_string_t *value,
00965         apr_pool_t *pool)
00966 {
00967     struct estat *sts=file_baton;
00968     int status;
00969 
00970     status=0;
00971     if (!sts->url || url__current_has_precedence(sts->url))
00972         STOPIF( up__parse_prop(sts, utf8_name, value, NULL, pool), NULL);
00973 
00974     
00975     BUG_ON(sts->remote_status & FS_CHANGED,
00976             "Entry has already been fetched, properties too late!");
00977 ex:
00978     RETURN_SVNERR(status);
00979 }
00980 
00981 
00982 svn_error_t *up__close_file(void *file_baton,
00983         const char *text_checksum,
00984         apr_pool_t *pool)
00985 {
00986     struct estat *sts=file_baton;
00987     int status;
00988 
00989     if (action->is_compare && text_checksum)
00990     {
00991         if (memcmp(text_checksum, sts->md5, sizeof(sts->md5)) != 0)
00992             sts->remote_status |= FS_CHANGED;
00993     }
00994     else
00995     {
00996         
00997         DEBUGP("close file (0%o): md5=%s",
00998                 sts->st.mode, cs__md5tohex_buffered(sts->md5));
00999 
01000 
01001         BUG_ON(!sts->st.mode);
01002 
01003         if (S_ISREG(sts->st.mode))
01004         {
01005             status=0;
01006             
01007             
01008 
01009             if (sts->filehandle_pool)
01010                 apr_pool_destroy(sts->filehandle_pool);
01011             sts->filehandle_pool=NULL;
01012             
01013             
01014 
01015 
01016         }
01017         else
01018         {
01019             DEBUGP("closing special file");
01020             sts->stringbuf_tgt->data[ sts->stringbuf_tgt->len ]=0;
01021             STOPIF( up__handle_special(sts, filename_tmp, 
01022                         sts->stringbuf_tgt->data, pool), NULL);
01023         }
01024 
01025 
01026         
01027         STOPIF( up__set_meta_data(sts, filename_tmp), NULL);
01028 
01029         
01030         STOPIF_CODE_ERR( rename(filename_tmp, filename)==-1, errno,
01031                 "Cannot rename '%s' to '%s'", filename_tmp, filename);
01032 
01033         
01034         STOPIF( hlp__lstat( filename, &(sts->st)),
01035                 "Cannot lstat('%s')", filename);
01036     }
01037 
01038     
01039     STOPIF( st__status(sts), NULL);
01040 
01041 ex:
01042     RETURN_SVNERR(status);
01043 }
01044 
01045 
01047 svn_error_t *up__absent_file(const char *utf8_path,
01048         void *parent_baton,
01049         apr_pool_t *pool)
01050 {
01051     struct estat *dir UNUSED=parent_baton;
01052 
01053     DEBUGP("in %s", __PRETTY_FUNCTION__);
01054     return SVN_NO_ERROR; 
01055 }
01056 
01057 
01058 svn_error_t *up__close_edit(void *edit_baton, 
01059         apr_pool_t *pool)
01060 {
01061     struct estat *sts UNUSED=edit_baton;
01062 
01063     return SVN_NO_ERROR; 
01064 }
01065 
01066 
01068 svn_error_t *up__abort_edit(void *edit_baton,
01069         apr_pool_t *pool)
01070 {
01071     struct estat *sts UNUSED=edit_baton;
01072 
01073     return SVN_NO_ERROR; 
01074 }
01075 
01076 
01077 
01078 
01079 
01080 
01081 
01082 int ac___up_set_paths(struct estat *dir, 
01083         const svn_ra_reporter2_t *reporter,
01084         void *report_baton, 
01085         apr_pool_t *pool)
01086 {
01087     int status, i;
01088     struct estat *sts;
01089     svn_error_t *status_svn;
01090     char *fn;
01091 
01092 
01093     status=0;
01094     for(i=0; i<dir->entry_count; i++)
01095     {
01096         sts=dir->by_inode[i];
01097         if (S_ISDIR(sts->st.mode))
01098             STOPIF( ac___up_set_paths(sts, reporter, report_baton, pool),
01099                     NULL);
01100         else
01101             if (sts->entry_status & (FS_CHANGED | FS_REMOVED))
01102             {
01103                 STOPIF( ops__build_path(&fn, sts), NULL );
01104                 DEBUGP("  changed: %s", fn);
01105                 
01106                 STOPIF_SVNERR( reporter->delete_path,
01107                         (report_baton, fn+2, pool));
01108             }
01109     }
01110 
01111 ex:
01112     return status;
01113 }
01114 
01115 
01121 int up__work(struct estat *root, int argc, char *argv[])
01122 {
01123     int status;
01124     svn_error_t *status_svn;
01125     svn_revnum_t rev;
01126     time_t delay_start;
01127 
01128 
01129     status=0;
01130     status_svn=NULL;
01131     STOPIF( waa__find_base(root, &argc, &argv), NULL);
01132 
01133     STOPIF( url__load_nonempty_list(NULL, 0), NULL);
01134 
01135     STOPIF_CODE_ERR(!urllist_count, EINVAL,
01136             "There's no URL defined");
01137 
01138     STOPIF( url__mark_todo(), NULL);
01139 
01140     STOPIF_CODE_ERR( argc != 0, EINVAL,
01141             "Cannot do partial updates!");
01142 
01143 
01144     opt__set_int(OPT__CHANGECHECK, PRIO_MUSTHAVE,
01145             opt__get_int(OPT__CHANGECHECK) | CHCHECK_FILE);
01146 
01147     
01148  
01149     STOPIF( waa__read_or_build_tree(root, argc, argv, argv, NULL, 0), NULL);
01150 
01151     while ( ! ( status=url__iterator(&rev) ) )
01152     {
01153         STOPIF( cb__record_changes(root, rev, global_pool), NULL);
01154 
01155         if (action->is_compare)
01156         {
01157             
01158             if (opt__get_int(OPT__VERBOSE) > VERBOSITY_VERYQUIET)
01159                 printf("Remote-status against revision\t%ld.\n", rev);
01160         }
01161         else
01162         {
01163             
01164             DEBUGP("setting revision to %llu", (t_ull)rev);
01165             STOPIF( ci__set_revision(root, rev), NULL);
01166 
01167             if (opt__get_int(OPT__VERBOSE) > VERBOSITY_VERYQUIET)
01168                 printf("Updating %s to revision\t%ld.\n", 
01169                         current_url->url, rev);
01170         }
01171     }
01172     STOPIF_CODE_ERR( status != EOF, status, NULL);
01173     status=0;
01174 
01175     if (action->is_compare)
01176     {
01177     }
01178     else
01179     {
01180         DEBUGP("fetching from repository");
01181         STOPIF( rev__do_changed(root, global_pool), NULL);
01182 
01183         
01184 
01185         delay_start=time(NULL);
01186         STOPIF( waa__output_tree(root), NULL);
01187         STOPIF( url__output_list(), NULL);
01188         STOPIF( hlp__delay(delay_start, DELAY_UPDATE), NULL);
01189     }
01190 
01191 
01192 ex:
01193     STOP_HANDLE_SVNERR(status_svn);
01194 ex2:
01195     return status;
01196 }
01197 
01198 
01199 
01200 
01201 
01202 
01203 
01204 
01205 
01206 
01207 
01208 
01209 
01210 
01211 
01212 
01213 
01214 
01215 
01216 
01217 
01218 
01219 
01220 
01221 
01222 
01223