00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00014 #include <errno.h>
00015 #include <time.h>
00016 #include <unistd.h>
00017 
00018 #include <subversion-1/svn_ra.h>
00019 #include <subversion-1/svn_auth.h>
00020 #include <subversion-1/svn_client.h>
00021 #include <subversion-1/svn_cmdline.h>
00022 
00023 
00024 
00025 #include "global.h"
00026 #include "helper.h"
00027 #include "update.h"
00028 #include "est_ops.h"
00029 #include "checksum.h"
00030 #include "status.h"
00031 #include "cache.h"
00032 #include "url.h"
00033 #include "racallback.h"
00034 
00035 
00036 svn_error_t *cb__init(apr_pool_t *pool)
00037 {
00038     int status;
00039     svn_error_t *status_svn;
00040     apr_hash_t *cfg_hash;
00041     svn_config_t *cfg;
00042 
00043 
00044     STOPIF( hlp__get_svn_config(&cfg_hash), NULL);
00045 
00046     cfg = apr_hash_get(cfg_hash, SVN_CONFIG_CATEGORY_CONFIG,
00047             APR_HASH_KEY_STRING);
00048 
00049 
00050     
00051     STOPIF_SVNERR( svn_cmdline_setup_auth_baton,
00052             (&cb__cb_table.auth_baton,
00053              !(isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)),
00054              opt__get_int(OPT__AUTHOR) ? 
00055              opt__get_string(OPT__AUTHOR) : NULL,
00056              NULL, 
00057              opt__get_string(OPT__CONFIG_DIR),
00058              0, 
00059              cfg,
00060              NULL, 
00061              NULL, 
00062              pool)
00063             );
00064 
00065     BUG_ON(!cb__cb_table.auth_baton);
00066 
00067 ex:
00068     RETURN_SVNERR(status);
00069 }
00070 
00071 
00072 
00073 
00074 
00076 
00078 svn_error_t *cb__open_tmp (apr_file_t **fp,
00079         void *callback_baton,
00080         apr_pool_t *pool)
00081 {
00082     int status;
00083 
00084 
00085     STOPIF( waa__get_tmp_name( NULL, NULL, fp, pool), NULL);
00086 
00087 ex:
00088     RETURN_SVNERR(status);
00089 }
00090 
00091 
00092 struct svn_ra_callbacks_t cb__cb_table=
00093 {
00094     .open_tmp_file = cb__open_tmp,
00095     .auth_baton = NULL,
00096 
00097     .get_wc_prop = NULL,
00098     .set_wc_prop=NULL,
00099     .push_wc_prop=NULL,
00100     .invalidate_wc_props=NULL,
00101 };
00102 
00103 
00104 
00105 
00106 
00107 
00108 
00109 
00110 svn_revnum_t cb___dest_rev;
00111 
00113 svn_error_t *cb__txdelta_discard(svn_txdelta_window_t *window UNUSED, 
00114         void *baton UNUSED)
00115 {
00116     return NULL;
00117 }
00118 
00119 
00130 int cb__add_entry(struct estat *dir, 
00131         const char *utf8_path, char **loc_path,
00132         const char *utf8_copy_path, 
00133         svn_revnum_t copy_rev,
00134         int mode,
00135         int *has_existed,
00136         int may_create,
00137         void **new)
00138 {
00139     int status;
00140     struct estat *sts;
00141     char *filename;
00142     char* path;
00143     char* copy_path;
00144     int overwrite;
00145     struct sstat_t st;
00146 
00147 
00148     overwrite=0;
00149     STOPIF( hlp__utf82local(utf8_path, &path, -1), NULL );
00150     if (loc_path) *loc_path=path;
00151     STOPIF( hlp__utf82local(utf8_copy_path, ©_path, -1), NULL );
00152 
00153     STOPIF_CODE_ERR(copy_path, EINVAL,
00154             "don't know how to handle copy_path %s@%ld", 
00155             copy_path, copy_rev);
00156 
00157     
00158 
00159     filename = ops__get_filename(path);
00160     STOPIF( ops__find_entry_byname(dir, filename, &sts, 0),
00161             "cannot lookup entry %s", path);
00162     DEBUGP("entry %s, mode 0%03o; %sfound, may %screate", path, mode, 
00163             sts ? "" : "not ",
00164             may_create ? "" : "not ");
00165 
00166 
00167     if (sts)
00168     {
00169         if (has_existed) *has_existed=EEXIST;
00170 
00171         if (!url__current_has_precedence(sts->url))
00172             goto no_change;
00173 
00174         
00175 
00176 
00177 
00178         if (sts->remote_status & FS_REMOVED)
00179         {
00180             STOPIF( ops__make_shadow_entry(sts, SHADOWED_BY_REMOTE), NULL);
00181             overwrite=1;
00182         }
00183     }
00184     else
00185     {
00186         STOPIF_CODE_ERR(!may_create, ENOENT, NULL);
00187 
00188         STOPIF( ops__allocate(1, &sts, NULL), NULL);
00189         memset(sts, 0, sizeof(*sts));
00190 
00191         
00192 
00193 
00194 
00195 
00196         STOPIF( hlp__strdup(&sts->name, filename), NULL);
00197 
00198         sts->remote_status = FS_NEW;
00199         overwrite=1;
00200         
00201         STOPIF( ops__new_entries(dir, 1, &sts), NULL);
00202 
00203         
00204         dir->remote_status |= FS_CHANGED;
00205 
00206         if (has_existed) *has_existed=0;
00207     }
00208 
00209 
00210     if (overwrite)
00211     {
00212         sts->parent=dir;
00213 
00214         
00215 
00216 
00217     sts->entry_count=0;
00218     sts->by_inode=NULL;
00219     sts->by_name=NULL;
00220     sts->strings=NULL;
00221 
00222     sts->decoder=NULL;
00223     sts->has_orig_md5=0;
00224         memset(& sts->md5, 0, sizeof(sts->md5));
00225 
00226         memset(& sts->st, 0, sizeof(sts->st));
00227 
00228         
00229 
00230 
00231         if (!(mode & 0777))
00232             mode |= S_ISDIR(mode) ? 0700 : 0600;
00233         
00234         sts->st.mode = mode; 
00235 
00236         
00237         time( & sts->st.mtim.tv_sec );
00238 
00239         
00240         sts->st.uid=getuid(); 
00241         sts->st.gid=getgid(); 
00242     }
00243 
00244     sts->url=current_url;
00245     ops__mark_parent_cc(sts, remote_status);
00246 
00247     
00248     sts->new_rev_mode_packed = MODE_T_to_PACKED(mode);
00249 
00250 
00251     if (sts->local_mode_packed == S_IFUNDEF)
00252     {
00253         
00254 
00255         status=hlp__lstat(path, &st);
00256         if (status == ENOENT)
00257         {
00258             
00259 
00260         }
00261         else if (!status || status == -ENOENT)
00262         {
00263             
00264             sts->local_mode_packed=MODE_T_to_PACKED(st.mode);
00265         }
00266         else
00267         {
00268             
00269 
00270 
00271         }
00272         
00273         status=0;
00274     }
00275 
00276     DEBUGP("%s is locally a %s",
00277             path, st__type_string(PACKED_to_MODE_T(sts->local_mode_packed)));
00278 
00279 
00280 no_change:  
00281     
00282 
00283     *new = sts;
00284 
00285 ex:
00286     return status;
00287 }
00288 
00289 
00290 inline int cb___store_prop(struct estat *sts, 
00291         const char *utf8_name, const svn_string_t *value,
00292         apr_pool_t *pool)
00293 {
00294     int status;
00295     int user_prop;
00296     apr_pool_t *u_p_pool;
00297     char *copy;
00298     #ifdef DEBUG
00299     static long u_p_count=0,
00300                             u_p_bytes=0;
00301     #endif
00302 
00303 
00304     status=0;
00305     if (!url__current_has_precedence(sts->url)) goto ex;
00306 
00307 
00308     user_prop=0;
00309     STOPIF( up__parse_prop(sts, utf8_name, value, &user_prop, pool), NULL);
00310     ops__mark_parent_cc(sts, remote_status);
00311     DEBUGP("have name=%s; user? %d", utf8_name, user_prop);
00312 
00313 
00314     if (action->keep_user_prop && user_prop)
00315     {
00316         if (!sts->user_prop)
00317         {
00318             
00319 
00320             STOPIF( apr_pool_create(&u_p_pool, sts->url ? 
00321                         sts->url->pool : global_pool), NULL);
00322 
00323             sts->user_prop=apr_hash_make(u_p_pool);
00324             apr_hash_set(sts->user_prop, "", 0, u_p_pool);
00325         }
00326         else
00327             u_p_pool=apr_hash_get(sts->user_prop, "", 0);
00328 
00329 
00330         
00331 
00332 
00333         copy=apr_palloc(u_p_pool, strlen(utf8_name)+1);
00334         strcpy(copy, utf8_name);
00335         apr_hash_set(sts->user_prop, copy, APR_HASH_KEY_STRING, 
00336                 svn_string_dup(value, u_p_pool) );
00337 
00338 #ifdef ENABLE_DEBUG
00339         u_p_count++;
00340         u_p_bytes += value->len + sizeof(char*) + sizeof(*value);
00341         DEBUGP("%lu user-props stored, with %lu bytes.",
00342                 u_p_count, u_p_bytes);
00343 #endif
00344     }
00345 
00346 ex:
00347     return status;
00348 }
00349 
00350 
00351 svn_error_t *cb___set_target_revision(void *edit_baton,
00352         svn_revnum_t rev,
00353         apr_pool_t *pool)
00354 {
00355     int status;
00356     struct estat *root UNUSED=edit_baton;
00357 
00358     status=0;
00359     DEBUGP("setting revision to %llu", (t_ull)rev);
00360     cb___dest_rev=rev;
00361     RETURN_SVNERR(status);
00362 }
00363 
00364 
00365 svn_error_t *cb___open_root(void *edit_baton,
00366         svn_revnum_t base_revision,
00367         apr_pool_t *dir_pool UNUSED,
00368         void **root_baton)
00369 {
00370     struct estat *sts=edit_baton;
00371 
00372     *root_baton=sts;
00373 
00374     return SVN_NO_ERROR; 
00375 }
00376 
00377 
00378 svn_error_t *cb___delete_entry(const char *utf8_path,
00379         svn_revnum_t revision UNUSED,
00380         void *parent_baton,
00381         apr_pool_t *pool)
00382 {
00383     int status;
00384     struct estat *dir=parent_baton;
00385     struct estat *sts;
00386     char* path;
00387 
00388     STOPIF( hlp__utf82local(utf8_path, &path, -1), NULL );
00389 
00390     STOPIF( ops__find_entry_byname(dir, path, &sts, 0), NULL);
00391 
00392     if (sts)
00393     {
00394         DEBUGP("deleting entry %s", path);
00395 
00396         ops__mark_parent_cc(sts, remote_status);
00397 
00398         sts->remote_status = FS_REMOVED;
00399 
00400         if (action->repos_feedback)
00401             STOPIF( action->repos_feedback(sts), NULL);
00402 
00406         sts->url = urllist[urllist_count-1];
00407     }
00408     else
00409     {
00410         DEBUGP("entry %s not found!", path);
00412     }
00413 
00414 ex:
00415     RETURN_SVNERR(status);
00416 }
00417 
00418 
00419 svn_error_t *cb___add_directory(const char *utf8_path,
00420         void *parent_baton,
00421         const char *utf8_copy_path,
00422         svn_revnum_t copy_rev,
00423         apr_pool_t *dir_pool,
00424         void **child_baton)
00425 {
00426     struct estat *dir=parent_baton;
00427     struct estat *sts;
00428     int status;
00429     int has_existed;
00430 
00431     STOPIF( cb__add_entry(dir, utf8_path, NULL, utf8_copy_path, 
00432                 copy_rev, S_IFDIR, &has_existed, 1,
00433                 child_baton), NULL );
00434     sts=*child_baton;
00435 
00436     if (!has_existed)
00437     {
00438         
00439 
00440 
00441         sts->entry_count=0;
00442         sts->by_inode = sts->by_name = NULL;
00443         sts->strings = NULL;
00444         sts->other_revs=sts->to_be_sorted=0;
00445     }
00446 
00447 ex:
00448     RETURN_SVNERR(status);
00449 }
00450 
00451 
00452 svn_error_t *cb___open_directory(const char *utf8_path,
00453         void *parent_baton,
00454         svn_revnum_t base_revision UNUSED,
00455         apr_pool_t *dir_pool,
00456         void **child_baton)
00457 {
00458     struct estat *dir=parent_baton;
00459     int status;
00460 
00462     STOPIF( cb__add_entry(dir, utf8_path, NULL, NULL, 0, 
00463                 S_IFDIR, NULL, 0, child_baton), NULL);
00464 
00465 ex:
00466     RETURN_SVNERR(status);
00467 }
00468 
00469 
00470 svn_error_t *cb___change_dir_prop(void *dir_baton,
00471         const char *utf8_name,
00472         const svn_string_t *value,
00473         apr_pool_t *pool)
00474 {
00475     int status;
00476 
00477     
00478     STOPIF( cb___store_prop(dir_baton, utf8_name, value, pool), NULL);
00479 
00480 ex:
00481     RETURN_SVNERR(status);
00482 }
00483 
00484 
00485 int cb___close(struct estat *sts)
00486 {
00487     int status;
00488 
00489     status=0;
00490     sts->repos_rev = cb___dest_rev;
00491 
00492     if (action->repos_feedback)
00493         STOPIF( action->repos_feedback(sts), NULL);
00494 
00495 ex:
00496     return status;
00497 }
00498 
00499 
00500 svn_error_t *cb___close_directory(
00501         void *dir_baton,
00502         apr_pool_t *pool)
00503 {
00504     struct estat *sts=dir_baton;
00505     int status;
00506 
00507     
00508 
00509     IF_FREE(sts->by_name);
00510 
00511     STOPIF( cb___close(sts), NULL);
00512 
00513 ex:
00514     RETURN_SVNERR(status);
00515 }
00516 
00517 
00519 svn_error_t *cb___absent_directory(const char *utf8_path,
00520         void *parent_baton,
00521         apr_pool_t *pool)
00522 {
00523     struct estat *dir UNUSED =parent_baton;
00524 
00525     DEBUGP("in %s", __PRETTY_FUNCTION__);
00526 
00527     return SVN_NO_ERROR; 
00528 }
00529 
00530 
00531 svn_error_t *cb___add_file(const char *utf8_path,
00532         void *parent_baton,
00533         const char *utf8_copy_path,
00534         svn_revnum_t copy_rev,
00535         apr_pool_t *file_pool,
00536         void **file_baton)
00537 {
00538     struct estat *dir=parent_baton;
00539     struct estat *sts;
00540     int status;
00541 
00542     STOPIF( cb__add_entry(dir, utf8_path, NULL, utf8_copy_path, 
00543                 copy_rev, S_IFREG, NULL, 1, file_baton),
00544             NULL);
00545     sts=*file_baton;
00546 
00547     
00548 
00549 
00550 
00551 
00552 
00553 
00554 
00555 ex:
00556     RETURN_SVNERR(status);
00557 }
00558 
00559 
00560 svn_error_t *cb___open_file(const char *utf8_path,
00561         void *parent_baton,
00562         svn_revnum_t base_revision,
00563         apr_pool_t *file_pool,
00564         void **file_baton)
00565 {
00566     struct estat *dir=parent_baton;
00567     struct estat *sts;
00568     int status;
00569     int was_there;
00570 
00571     STOPIF( cb__add_entry(dir, utf8_path, NULL, NULL, 0,
00572                 S_IFREG, &was_there, 0, file_baton), NULL);
00573     sts=(struct estat*)*file_baton;
00574 
00575     if (was_there)
00576         STOPIF( up__fetch_decoder(sts), NULL);
00577 
00578     sts->decoder_is_correct=1;
00579 
00580 ex:
00581     RETURN_SVNERR(status);
00582 }
00583 
00584 
00585 svn_error_t *cb___apply_textdelta(void *file_baton,
00586         const char *base_checksum UNUSED,
00587         apr_pool_t *pool UNUSED,
00588         svn_txdelta_window_handler_t *handler,
00589         void **handler_baton)
00590 {
00591     struct estat *sts UNUSED=file_baton;
00592     int status;
00593 
00594     status=0;
00595     if (url__current_has_precedence(sts->url))
00596         ops__mark_changed_parentcc(sts, remote_status);
00597 
00598     *handler = cb__txdelta_discard;
00599     *handler_baton=sts;
00600 
00601     RETURN_SVNERR(status);
00602 }
00603 
00604 
00605 svn_error_t *cb___change_file_prop(void *file_baton,
00606         const char *utf8_name,
00607         const svn_string_t *value,
00608         apr_pool_t *pool)
00609 {
00610     int status;
00611 
00612     
00613     STOPIF( cb___store_prop(file_baton, utf8_name, value, pool), NULL);
00614 
00615 ex:
00616     RETURN_SVNERR(status);
00617 }
00618 
00619 
00620 svn_error_t *cb___close_file(void *file_baton,
00621         const char *text_checksum,
00622         apr_pool_t *pool)
00623 {
00624     struct estat *sts=file_baton;
00625     int status;
00626 
00627 
00628     STOPIF( cb___close(sts), NULL);
00629 
00630     if (!S_ISDIR(sts->st.mode))
00631     { 
00632         if (sts->has_orig_md5 || sts->decoder)
00633             DEBUGP("Has an original MD5, %s not used", text_checksum);
00634         else
00635             if (text_checksum)
00636                 STOPIF( cs__char2md5(text_checksum, NULL, sts->md5 ), NULL);
00637     }
00638 
00639 ex:
00640     RETURN_SVNERR(status);
00641 }
00642 
00643 
00645 svn_error_t *cb___absent_file(const char *utf8_path,
00646         void *parent_baton,
00647         apr_pool_t *pool)
00648 {
00649     struct estat *dir UNUSED=parent_baton;
00650 
00651     DEBUGP("in %s", __PRETTY_FUNCTION__);
00652     return SVN_NO_ERROR; 
00653 }
00654 
00655 
00656 svn_error_t *cb___close_edit(void *edit_baton, 
00657         apr_pool_t *pool UNUSED)
00658 {
00659     int status;
00660     struct estat *root UNUSED=edit_baton;
00661 
00662     status=0;
00663     
00664 
00665 
00666     RETURN_SVNERR(status);
00667 }
00668 
00669 
00671 svn_error_t *cb___abort_edit(void *edit_baton,
00672         apr_pool_t *pool UNUSED)
00673 {
00674     struct estat *sts UNUSED=edit_baton;
00675 
00676     return SVN_NO_ERROR; 
00677 }
00678 
00679 
00680 
00681 
00682 const svn_delta_editor_t cb___change_recorder = 
00683 {
00684     .set_target_revision    = cb___set_target_revision,
00685 
00686     .open_root                      = cb___open_root,
00687 
00688     .delete_entry                   = cb___delete_entry,
00689     .add_directory              = cb___add_directory,
00690     .open_directory             = cb___open_directory,
00691     .change_dir_prop            = cb___change_dir_prop,
00692     .close_directory            = cb___close_directory,
00693     .absent_directory       = cb___absent_directory,
00694 
00695     .add_file                       = cb___add_file,
00696     .open_file                      = cb___open_file,
00697     .apply_textdelta            = cb___apply_textdelta,
00698     .change_file_prop       = cb___change_file_prop,
00699     .close_file                     = cb___close_file,
00700     .absent_file                    = cb___absent_file,
00701 
00702     .close_edit                     = cb___close_edit,
00703     .abort_edit                     = cb___abort_edit,
00704 };
00705 
00709 int cb___report_path_rev(struct estat *dir, 
00710         const svn_ra_reporter2_t *reporter,
00711         void *report_baton, 
00712         apr_pool_t *pool)
00713 {
00714     int status, i;
00715     struct estat *sts;
00716     svn_error_t *status_svn;
00717     char *fn;
00718 
00719 
00720     status=0;
00721     for(i=0; i<dir->entry_count; i++)
00722     {
00723         sts=dir->by_inode[i];
00724 
00725         STOPIF( ops__build_path(&fn, sts), NULL );
00726         
00727         
00728         
00729 
00730         
00731         if ( sts->repos_rev != sts->parent->repos_rev)
00732         {
00733             DEBUGP("reporting %s at %llu", fn, (t_ull)sts->repos_rev);
00734             STOPIF_SVNERR( reporter->set_path,
00735                     (report_baton, fn+2, sts->repos_rev, 0, "", pool));
00736         }
00737 
00738         if (S_ISDIR(sts->st.mode) && sts->other_revs)
00739         {
00740             STOPIF( cb___report_path_rev(sts, reporter, report_baton, pool),
00741                     NULL);
00742         }   
00743     }
00744 
00745 ex:
00746     return status;
00747 }
00748 
00749 
00753 int cb__record_changes(struct estat *root,
00754         svn_revnum_t target,
00755         apr_pool_t *pool)
00756 {
00757     int status;
00758 
00759     STOPIF( cb__record_changes_mixed(root, target, 
00760                 NULL, 0, pool), NULL);
00761 ex:
00762     return status;
00763 }
00764 
00765 
00799 int cb__record_changes_mixed(struct estat *root,
00800         svn_revnum_t target,
00801         char *other_paths[], svn_revnum_t other_revs,
00802         apr_pool_t *pool)
00803 {
00804     int status;
00805     svn_error_t *status_svn;
00806     void *report_baton;
00807     const svn_ra_reporter2_t *reporter;
00808     int sent_wcroot;
00809     char *cur, **op;
00810 
00811 
00812     status=0;
00813     cb___dest_rev=target;
00814     STOPIF_SVNERR( svn_ra_do_status,
00815             (current_url->session,
00816              &reporter,
00817              &report_baton,
00818              "",
00819              target,
00820              TRUE,
00821              &cb___change_recorder,
00822              root,
00823              pool) );
00824 
00825     sent_wcroot=0;
00826     cur=NULL;
00827     op=NULL;
00828     if (other_paths)
00829     {
00830         op=other_paths;
00831         while ( (cur=*op) )
00832         {
00833             if (cur[0] == '.' && cur[1] == 0)
00834                 break;
00835             op++;
00836         }
00837     }
00838 
00839     
00840 
00841 
00842     if (cur)
00843         STOPIF_SVNERR( reporter->set_path,
00844                 (report_baton,
00845                  "", other_revs,
00846                  FALSE, NULL, pool));
00847     else if (current_url->current_rev == 0)
00848         STOPIF_SVNERR( reporter->set_path,
00849                 (report_baton,
00850                  "", target,
00851                  TRUE, NULL, pool));
00852     else
00853         STOPIF_SVNERR( reporter->set_path,
00854                 (report_baton,
00855                  "", current_url->current_rev,
00856                  FALSE, NULL, pool));
00857 
00858     if (other_paths)
00859     {
00860     
00861 
00862 
00863 
00864 
00865         while ( (cur=*other_paths) )
00866         {
00867              
00868             if (op != other_paths) 
00869             {
00870                 DEBUGP("reporting %s@%llu", cur, (t_ull)other_revs);
00871 
00872                 if (cur[0] == '.' && cur[1] == PATH_SEPARATOR) 
00873                     cur+=2;
00874 
00875                 STOPIF_SVNERR( reporter->set_path,
00876                         (report_baton, cur, other_revs, FALSE, NULL, pool));
00877             }
00878 
00879             other_paths++;
00880         }
00881     }
00882 
00883 
00884     DEBUGP("Getting changes from %llu to %llu", 
00885             (t_ull)current_url->current_rev,
00886             (t_ull)target);
00887 #if 0
00888     STOPIF( cb___report_path_rev( root, reporter, report_baton, pool), NULL);
00889 #endif
00890 
00891     STOPIF_SVNERR( reporter->finish_report, 
00892             (report_baton, global_pool));
00893 
00894     current_url->current_rev=cb___dest_rev;
00895 
00896 ex:
00897     return status;
00898 }
00899 
00900 
00904 int cb__does_path_exist(svn_ra_session_t *session, 
00905         char *path, svn_revnum_t rev, 
00906         int *exists,
00907         apr_pool_t *pool)
00908 {
00909     int status;
00910     svn_dirent_t *dirent;
00911     svn_error_t *status_svn;
00912 
00913 
00914     status=0;
00915 
00916     STOPIF_SVNERR( svn_ra_stat,
00917             (session, path, rev, &dirent, pool));
00918     *exists = dirent != NULL;
00919 
00920 ex:
00921     return status;
00922 }
00923