00001
00002
00003
00004
00005
00006
00007
00008 #include <unistd.h>
00009 #include <stdio.h>
00010 #include <fcntl.h>
00011 #include <time.h>
00012
00013 #include <subversion-1/svn_delta.h>
00014 #include <subversion-1/svn_ra.h>
00015
00016 #include "revert.h"
00017 #include "waa.h"
00018 #include "est_ops.h"
00019 #include "racallback.h"
00020 #include "warnings.h"
00021 #include "resolve.h"
00022 #include "checksum.h"
00023 #include "props.h"
00024 #include "helper.h"
00025 #include "url.h"
00026 #include "update.h"
00027 #include "cp_mv.h"
00028 #include "status.h"
00029
00030
00129 enum rev___dir_change_flag_e {
00130 NOT_CHANGED=0,
00131 REVERT_MTIME=1,
00132 SET_CURRENT=2,
00133 GET_TSTAMP=0x1000,
00134 };
00135
00136
00138 static int number_reverted=0;
00139 static svn_revnum_t last_rev;
00140
00141
00142 #define REV___GETFILE_MAX_CACHE (4)
00143
00144
00170 int rev__get_text_to_stream( char *loc_url, svn_revnum_t revision,
00171 const char *decoder,
00172 svn_stream_t *output,
00173 struct estat *sts_for_manber,
00174 struct estat *output_sts,
00175 apr_hash_t **props,
00176 apr_pool_t *pool)
00177 {
00178 int status;
00179 svn_error_t *status_svn;
00180 svn_string_t *prop_val;
00181 struct encoder_t *encoder;
00182 char *relative_url, *utf8_url;
00183 apr_hash_t *properties;
00184 char target_rev[10];
00185
00186
00187 encoder=NULL;
00188 status=0;
00189 DEBUGP("getting file %s@%s from %s", loc_url,
00190 hlp__rev_to_string(revision), current_url->url);
00191
00192
00193 if (strncmp(loc_url, "./", 2) == 0)
00194 {
00195
00196 relative_url=loc_url+2;
00197 }
00198 else
00199 {
00200
00201
00202
00203
00204
00205 if (strncmp(current_url->url, loc_url, current_url->urllen) == 0 &&
00206 loc_url[current_url->urllen] == '/')
00207 loc_url += current_url->urllen+1;
00208
00209
00210
00211
00212 }
00213
00214 STOPIF( hlp__local2utf8(loc_url, &utf8_url, -1), NULL);
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224 if (sts_for_manber)
00225 STOPIF( cs__new_manber_filter(sts_for_manber,
00226 output, &output, pool), NULL);
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261 if (decoder == DECODER_UNKNOWN)
00262 {
00263 STOPIF_SVNERR_TEXT( svn_ra_get_file,
00264 (current_url->session,
00265 loc_url, revision,
00266 NULL,
00267 &revision, &properties,
00268 pool),
00269 "Fetching entry \"%s/%s\"@%s",
00270 current_url->url,
00271 loc_url, hlp__rev_to_string(revision));
00272
00273 prop_val=apr_hash_get(properties, propval_updatepipe, APR_HASH_KEY_STRING);
00274 decoder=prop_val ? prop_val->data : NULL;
00275 }
00276
00277
00278
00279
00280 if (decoder)
00281 {
00282 snprintf(target_rev, sizeof(target_rev),
00283 "%llu", (t_ull)revision);
00284 setenv(FSVS_EXP_TARGET_REVISION, target_rev, 1);
00285
00286 STOPIF( hlp__encode_filter(output, decoder, 1,
00287 loc_url, &output, &encoder, pool), NULL);
00288 if (output_sts)
00289 encoder->output_md5= &(output_sts->md5);
00290 }
00291
00292
00293 STOPIF_SVNERR_TEXT( svn_ra_get_file,
00294 (current_url->session,
00295 loc_url, revision,
00296 output,
00297 &revision, &properties,
00298 pool),
00299 "Fetching entry %s/%s@%s",
00300 current_url->url,
00301 loc_url, hlp__rev_to_string(revision));
00302 DEBUGP("got revision %llu", (t_ull)revision);
00303
00304
00305 STOPIF_SVNERR( svn_stream_close, (output));
00306 output=NULL;
00307
00308 if (output_sts)
00309 {
00310 output_sts->repos_rev = revision;
00311 STOPIF( prp__set_from_aprhash( output_sts, properties,
00312 ONLY_KEEP_USERDEF, NULL, pool), NULL);
00313 }
00314
00315 if (props)
00316 *props=properties;
00317
00318
00319 ex:
00320 return status;
00321 }
00322
00323
00337 int rev__get_text_to_tmpfile(char *loc_url, svn_revnum_t revision,
00338 char *encoder,
00339 char *filename_base, char **filename,
00340 struct estat *sts_for_manber,
00341 struct estat *output_sts, apr_hash_t **props,
00342 apr_pool_t *pool)
00343 {
00344 int status;
00345 apr_file_t *apr_f;
00346 svn_stream_t *output;
00347
00348
00349 status=0;
00350
00351 STOPIF( waa__get_tmp_name( filename_base, filename, &apr_f, pool), NULL);
00352 output=svn_stream_from_aprfile(apr_f, pool);
00353
00354 STOPIF( rev__get_text_to_stream( loc_url, revision, encoder,
00355 output, sts_for_manber, output_sts, props, pool), NULL);
00356
00357
00358 STOPIF( apr_file_close(apr_f), NULL);
00359
00360 ex:
00361 return status;
00362 }
00363
00364
00368 int rev__get_text_into_buffer(char *loc_url, svn_revnum_t revision,
00369 const char *decoder,
00370 svn_stringbuf_t **output,
00371 struct estat *sts_for_manber,
00372 struct estat *output_sts,
00373 apr_hash_t **props,
00374 apr_pool_t *pool)
00375 {
00376 int status;
00377 svn_stringbuf_t *string;
00378 svn_stream_t *stream;
00379
00380 status=0;
00381 string=svn_stringbuf_create("", pool);
00382 stream=svn_stream_from_stringbuf(string, pool);
00383
00384 STOPIF( rev__get_text_to_stream(loc_url, revision,
00385 decoder, stream, sts_for_manber, output_sts, props, pool), NULL);
00386
00387 *output=string;
00388 ex:
00389 return status;
00390 }
00391
00392
00404 int rev__install_file(struct estat *sts, svn_revnum_t revision,
00405 char *decoder,
00406 apr_pool_t *pool)
00407 {
00408 int status;
00409 char *filename;
00410 char *filename_tmp;
00411 apr_hash_t *props;
00412 svn_stream_t *stream;
00413 apr_file_t *a_stream;
00414 apr_pool_t *subpool;
00415 char *special_data;
00416 char *url;
00417 svn_revnum_t rev_to_take;
00418
00419
00420 BUG_ON(!pool);
00421 STOPIF( ops__build_path(&filename, sts), NULL);
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431 STOPIF( waa__mkdir(filename, 0), NULL);
00432
00433
00434 STOPIF( apr_pool_create(&subpool, pool),
00435 "Creating the filehandle pool");
00436
00437
00438
00439
00440
00441 STOPIF( waa__delete_byext(filename, WAA__FILE_MD5s_EXT, 1), NULL);
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452 STOPIF( waa__get_tmp_name( filename, &filename_tmp, &a_stream, subpool),
00453 NULL);
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463 stream=svn_stream_from_aprfile(a_stream, subpool);
00464
00465
00466 if (sts->url)
00467 {
00468 STOPIF( hlp__local2utf8( filename+2, &url, -1), NULL);
00469 rev_to_take=sts->repos_rev;
00470 current_url=sts->url;
00471 }
00472 else if (sts->flags & RF___IS_COPY)
00473 {
00474 STOPIF( cm__get_source( sts, filename, &url, &rev_to_take, 0), NULL);
00475 STOPIF( url__find( url, ¤t_url), NULL);
00476 STOPIF( hlp__local2utf8( url, &url, -1), NULL);
00477 }
00478 else
00479 BUG("cannot get file %s", filename);
00480
00481 if (revision == 0)
00482 {
00483
00484 STOPIF( up__fetch_decoder(sts), NULL);
00485 decoder=sts->decoder;
00486 }
00487 else
00488 {
00489
00490 rev_to_take=revision;
00491 decoder=DECODER_UNKNOWN;
00492 }
00493
00494
00495 STOPIF( url__open_session(NULL, NULL), NULL);
00496
00497
00498
00499 STOPIF( rev__get_text_to_stream( url, rev_to_take, decoder,
00500 stream, sts, NULL, &props, pool), NULL);
00501
00502
00503 if (apr_hash_get(props, propname_special, APR_HASH_KEY_STRING))
00504 {
00505 STOPIF( ops__read_special_entry( a_stream, &special_data,
00506 0, NULL, filename_tmp, subpool), NULL);
00507
00508
00509 STOPIF( up__handle_special(sts, filename_tmp,
00510 special_data, subpool), NULL);
00511 }
00512 else
00513 {
00514
00515
00516
00517 sts->st.mode = (sts->st.mode & ~S_IFMT) | S_IFREG;
00518 sts->local_mode_packed=sts->new_rev_mode_packed=
00519 MODE_T_to_PACKED(sts->st.mode);
00520 }
00521
00522
00523 STOPIF( prp__set_from_aprhash(sts, props, STORE_IN_FS,
00524 NULL, subpool), NULL);
00525
00526
00527
00528
00529
00530 sts->remote_status |= FS_META_CHANGED;
00531 DEBUGP("setting meta-data");
00532 STOPIF( up__set_meta_data(sts, filename_tmp), NULL);
00533
00534 STOPIF( apr_file_close(a_stream), NULL);
00535
00536
00537 DEBUGP("rename to %s", filename);
00538
00539 STOPIF_CODE_ERR( rename(filename_tmp, filename)==-1, errno,
00540 "Cannot rename '%s' to '%s'", filename_tmp, filename);
00541
00542
00543 STOPIF( hlp__lstat( filename, &(sts->st)),
00544 "Cannot lstat('%s')", filename);
00545
00546
00547 sts->url=current_url;
00548
00549
00550 sts->parent->to_be_sorted=1;
00551
00552 apr_pool_destroy(subpool);
00553 subpool=NULL;
00554
00555
00556 ex:
00557
00558
00559 if (status)
00560 unlink(filename_tmp);
00561
00562 return status;
00563 }
00564
00565
00572 int rev__merge(struct estat *sts,
00573 const char *file1,
00574 const char *common,
00575 const char *file2)
00576 {
00577 int status;
00578 pid_t pid;
00579 char *output;
00580 int hdl;
00581 struct sstat_t stat;
00582 int retval;
00583
00584
00585 STOPIF( ops__build_path(&output, sts), NULL);
00586
00587
00588 STOPIF( hlp__lstat(file2, &stat), NULL);
00589
00590
00591 pid=fork();
00592 STOPIF_CODE_ERR( pid == -1, errno, "Cannot fork()" );
00593 if (pid == 0)
00594 {
00595
00596
00597
00598
00599
00600
00601
00602 hdl=open(output, O_WRONLY | O_CREAT, 0700);
00603 STOPIF_CODE_ERR( hdl == -1, errno,
00604 "Cannot open merge output \"%s\"", output);
00605 STOPIF_CODE_ERR( dup2(hdl, STDOUT_FILENO) == -1, errno,
00606 "Cannot dup2");
00607
00608
00609
00610
00611 setenv(FSVS_EXP_CURR_ENTRY, output+2, 1);
00612
00613 STOPIF_CODE_ERR( execlp( opt__get_string(OPT__MERGE_PRG),
00614 opt__get_string(OPT__MERGE_PRG),
00615 opt__get_string(OPT__MERGE_OPT),
00616 file1, common, file2,
00617 NULL) == -1, errno,
00618 "Starting the merge program \"%s\" failed",
00619 opt__get_string(OPT__MERGE_PRG));
00620
00621 }
00622
00623 STOPIF_CODE_ERR( pid != waitpid(pid, &retval, 0), errno, "waitpid");
00624
00625 DEBUGP("merge returns %d (signal %d)",
00626 WEXITSTATUS(retval), WTERMSIG(retval));
00627
00628
00629 STOPIF_CODE_ERR( WIFSIGNALED(retval) || !WIFEXITED(retval), EINVAL,
00630 "\"%s\" quits by signal %d.",
00631 opt__get_string(OPT__MERGE_PRG),
00632 WTERMSIG(retval));
00633
00634 if (WEXITSTATUS(retval) == 0)
00635 {
00636 DEBUGP("Remove temporary files.");
00637
00638
00639 if (unlink(file1) == -1) status=errno;
00640 if (unlink(file2) == -1) status=errno;
00641 if (unlink(common) == -1) status=errno;
00642 STOPIF(status, "Removing one or more temporary files "
00643 "(merge of \"%s\") failed", output);
00644 }
00645 else
00646 {
00647 DEBUGP("non-zero return");
00648 STOPIF_CODE_ERR( WEXITSTATUS(retval) != 1, EINVAL,
00649 "\"%s\" exited with error code %d",
00650 opt__get_string(OPT__MERGE_PRG),
00651 WEXITSTATUS(retval));
00652
00653 STOPIF( res__mark_conflict(sts,
00654 file1, file2, common, NULL), NULL);
00655
00656
00657 }
00658
00659
00660 sts->st.mtim.tv_sec=time(NULL);
00661
00662
00663
00664 STOPIF( up__set_meta_data(sts, NULL), NULL);
00665 sts->st=stat;
00666
00667
00668 ex:
00669 return status;
00670 }
00671
00672
00675 int rev__get_props(struct estat *sts,
00676 char *utf8_path,
00677 svn_revnum_t revision,
00678 apr_pool_t *pool)
00679 {
00680 int status;
00681 svn_error_t *status_svn;
00682 apr_hash_t *props;
00683 char *filename;
00684
00685
00686 if (!utf8_path)
00687 {
00688 STOPIF( ops__build_path(&filename, sts), NULL);
00689 STOPIF( hlp__local2utf8(filename+2, &utf8_path, -1), NULL);
00690 }
00691
00692 STOPIF_SVNERR( svn_ra_get_file,
00693 (current_url->session,
00694 utf8_path,
00695 revision,
00696 NULL,
00697 NULL,
00698 &props,
00699 pool) );
00700 STOPIF( prp__set_from_aprhash(sts, props, STORE_IN_FS, NULL, pool), NULL);
00701
00702 ex:
00703 return status;
00704 }
00705
00706
00709 int rev___handle_dir_mtime(struct estat *dir,
00710 enum rev___dir_change_flag_e dir_flag)
00711 {
00712 int status;
00713 char *path;
00714
00715
00716
00717
00718
00719
00720
00721 status=0;
00722 DEBUGP("dir_flag says %X", dir_flag);
00723
00724
00725 if (dir_flag & SET_CURRENT) goto a;
00726 if (dir_flag & REVERT_MTIME) goto b;
00727 if (dir->remote_status & FS_META_CHANGED) goto c;
00728 if (dir_flag & GET_TSTAMP) goto d;
00729
00730
00731
00732
00733
00734
00735
00736
00737
00738 goto x;
00739
00740 a:
00741
00742
00743 time( & dir->st.mtim.tv_sec );
00744 b:
00745
00746 dir->remote_status |= FS_META_MTIME;
00747 c:
00748 STOPIF( up__set_meta_data(dir, NULL), NULL);
00749 d:
00750
00751 STOPIF( ops__build_path(&path, dir), NULL);
00752 STOPIF( hlp__lstat(path, &dir->st), NULL);
00753
00754
00755 if (dir->entry_status & FS_CHANGED)
00756 dir->flags |= RF_CHECK;
00757
00758 x:
00759
00760 ex:
00761 return status;
00762 }
00763
00764
00782 int rev___revert_to_base(struct estat *sts,
00783 enum rev___dir_change_flag_e *dir_change_flag,
00784 apr_pool_t *pool)
00785 {
00786 int status;
00787 svn_revnum_t wanted;
00788 struct estat copy;
00789 char *path;
00790
00791
00792 status=0;
00793 STOPIF( ops__build_path(&path, sts), NULL);
00794
00795
00796
00797
00798
00799 if ( (sts->flags & RF_UNVERSION))
00800 {
00801
00802 sts->flags &= ~RF_UNVERSION;
00803 DEBUGP("removing unversion on %s", path);
00804 }
00805 else if ( sts->flags & RF_ADD )
00806 {
00807
00808 sts->to_be_ignored=1;
00809 DEBUGP("removing add-flag on %s", path);
00810 }
00811 else if (!( (sts->flags & (RF_COPY_BASE | RF_COPY_SUB)) || sts->url ) )
00812 {
00813
00814
00815
00816
00817 printf("Cannot revert unknown entry \"%s\".\n", path);
00818 status=0;
00819 goto ex;
00820 }
00821 else
00822 {
00823
00824 DEBUGP("have an URL for %s", path);
00825
00826 if ( sts->flags & RF_CONFLICT )
00827 {
00828 *dir_change_flag |= REVERT_MTIME;
00829 STOPIF( res__remove_aux_files(sts), NULL);
00830 }
00831
00832
00833
00834 if (!opt_target_revisions_given &&
00835 !(sts->entry_status & FS__CHANGE_MASK))
00836 goto ex;
00837
00838
00839 wanted=opt_target_revisions_given ? opt_target_revision : sts->repos_rev;
00840
00841
00842
00843
00844
00845
00846
00847 if (sts->parent && (!number_reverted || last_rev != wanted))
00848 {
00849 if (opt__get_int(OPT__VERBOSE) > VERBOSITY_VERYQUIET)
00850 printf("Reverting to revision %s:\n", hlp__rev_to_string(wanted));
00851 last_rev=wanted;
00852 }
00853 number_reverted++;
00854
00855
00856
00857 copy=*sts;
00858
00859 DEBUGP("l_st=%s, r_st=%s, old=%p",
00860 st__status_string_fromint(sts->entry_status),
00861 st__status_string_fromint(sts->remote_status),
00862 sts->old);
00863
00864
00865 if (!S_ISDIR(sts->st.mode))
00866 {
00867 DEBUGP("file was changed, reverting");
00868
00869
00870
00871
00872
00873
00874
00875
00876 STOPIF( rev__install_file(sts, wanted, sts->decoder, pool),
00877 "Unable to revert entry '%s'", path);
00878 *dir_change_flag |= REVERT_MTIME;
00879 }
00880 else
00881 {
00882 #if 0
00883 if (sts->entry_status & FS_NEW)
00884 conflict();
00885 #endif
00886 if (sts->entry_status & FS_REMOVED)
00887 {
00888
00889 status = (mkdir(path, sts->st.mode & 07777) == -1) ? errno : 0;
00890 if (status == EEXIST)
00891 {
00892 DEBUGP("old=%p", sts->old);
00893 }
00894 DEBUGP("mkdir(%s) says %d", path, status);
00895 STOPIF(status, "Cannot create directory '%s'", path);
00896 *dir_change_flag |= REVERT_MTIME;
00897
00898
00899
00900 sts->remote_status |= FS_META_CHANGED;
00901 }
00902 else
00903 {
00904
00905
00906
00907
00908
00909
00910 sts->remote_status=sts->entry_status;
00911 }
00912
00913 STOPIF( up__set_meta_data(sts, NULL), NULL);
00914 if (sts->entry_status)
00915 sts->flags |= RF_CHECK;
00916 }
00917 }
00918
00919
00920
00921 sts->flags |= RF_PRINT;
00922
00923 ex:
00924 return status;
00925 }
00926
00927
00929 int rev___no_local_change(struct estat *sts)
00930 {
00931 sts->entry_status=0;
00932 return st__progress(sts);
00933 }
00934
00935
00952 int rev___local_revert(struct estat *dir,
00953 apr_pool_t *pool)
00954 {
00955 int status;
00956 int i, do_undo;
00957 struct estat *sts;
00958 apr_pool_t *subpool;
00959 enum rev___dir_change_flag_e dir_flag;
00960
00961
00962 status=0;
00963 subpool=NULL;
00964 dir_flag= NOT_CHANGED;
00965
00966 for(i=0; i<dir->entry_count; i++)
00967 {
00968 sts=dir->by_inode[i];
00969 STOPIF( apr_pool_create(&subpool, pool), "Cannot get a subpool");
00970
00971 do_undo = sts->do_this_entry &&
00972 (sts->entry_status & FS__CHANGE_MASK) &&
00973 ops__allowed_by_filter(sts);
00974
00975 DEBUGP("on %s: do_undo=%d, st=%s", sts->name, do_undo,
00976 st__status_string_fromint(sts->entry_status));
00977
00978 if (do_undo)
00979 STOPIF( rev___revert_to_base(sts, &dir_flag, subpool), NULL);
00980
00981 if (S_ISDIR(sts->st.mode) &&
00982 (sts->entry_status & FS_CHILD_CHANGED))
00983 STOPIF( rev___local_revert(sts, subpool), NULL);
00984
00985 if (do_undo)
00986 STOPIF( st__status(sts), NULL);
00987
00988
00989 apr_pool_destroy(subpool);
00990 subpool=NULL;
00991 }
00992
00993
00994
00995 STOPIF( ops__free_marked(dir, 0), NULL);
00996
00997
00998 if (!dir->parent)
00999 STOPIF( st__status(dir), NULL);
01000
01001
01002 STOPIF( rev___handle_dir_mtime(dir, dir_flag), NULL);
01003
01004 ex:
01005 return status;
01006 }
01007
01008
01012 int rev__work(struct estat *root, int argc, char *argv[])
01013 {
01014 int status;
01015 char **normalized;
01016 time_t delay_start;
01017 svn_revnum_t rev;
01018
01019
01020 status=0;
01021
01022 opt_recursive--;
01023
01024 if (!argc) ac__Usage_this();
01025
01026 STOPIF( waa__find_common_base(argc, argv, &normalized), NULL);
01027
01028 STOPIF( url__load_nonempty_list(NULL, 0), NULL);
01029
01030 if (opt_target_revisions_given)
01031 {
01032 STOPIF( wa__warn( WRN__MIXED_REV_WC, EINVAL,
01033 "Sorry, fsvs currently doesn't allow mixed revision working copies.\n"
01034 "Entries will still be compared against the BASE revision.\n"),
01035 NULL);
01036
01037
01038 action->local_callback=rev___no_local_change;
01039 }
01040 else
01041 {
01042
01043 action->local_callback=st__progress;
01044 }
01045
01046
01047
01048
01049
01050
01051
01052 status=waa__read_or_build_tree(root, argc, normalized, argv, NULL, 1);
01053 if (status == -ENOENT)
01054 STOPIF(status,
01055 "!We know nothing about previous or current versions, as this tree\n"
01056 "was never checked in.\n"
01057 "If you need such an entry reverted, you could either write the needed\n"
01058 "patch (and send it to dev@fsvs.tigris.org), or try with a 'sync-repos'\n"
01059 "command before (if you know a good revision number)\n");
01060 else
01061 STOPIF(status, NULL);
01062
01063 STOPIF( st__progress_uninit(), NULL);
01064
01065
01066 if (opt_target_revisions_given)
01067 {
01068 while ( ! ( status=url__iterator(&rev) ) )
01069 {
01070 STOPIF( cb__record_changes(root, rev, current_url->pool), NULL);
01071 }
01072 STOPIF_CODE_ERR( status != EOF, status, NULL);
01073
01074 STOPIF( rev__do_changed(root, global_pool), NULL);
01075 }
01076 else
01077 {
01078
01079
01080
01081
01082
01083
01084
01085
01086 STOPIF( rev___local_revert(root, global_pool), NULL);
01087 }
01088
01089
01090
01091
01092
01093
01094
01095
01096
01097
01098
01099
01100
01101
01102
01103 if (!opt_target_revisions_given)
01104 {
01105 delay_start=time(NULL);
01106 STOPIF( waa__output_tree(root), NULL);
01107 STOPIF( hlp__delay(delay_start, DELAY_REVERT), NULL);
01108 }
01109
01110 ex:
01111 return status;
01112 }
01113
01114
01119 int rev___undo_change(struct estat *sts,
01120 enum rev___dir_change_flag_e *dir_change_flag,
01121 apr_pool_t *pool)
01122 {
01123 int status;
01124 char *fn;
01125 const char *unique_name_mine,
01126 *unique_name_remote,
01127 *unique_name_common;
01128 char revnum[12];
01129 int j;
01130 struct estat *removed;
01131 struct sstat_t st;
01132
01133
01134 STOPIF( ops__build_path( &fn, sts), NULL);
01135 DEBUGP_dump_estat(sts);
01136
01137
01138
01139
01140
01141 unique_name_mine=NULL;
01142
01143
01144 if (sts->entry_status & FS_CHANGED)
01145 switch (opt__get_int(OPT__CONFLICT))
01146 {
01147 case CONFLICT_STOP:
01148 STOPIF( EBUSY, "!The entry %s has changed locally", fn);
01149 break;
01150
01151 case CONFLICT_LOCAL:
01152
01153 STOPIF_CODE_EPIPE( printf("Conflict for %s skipped.\n", fn), NULL);
01154 goto ex;
01155
01156 case CONFLICT_REMOTE:
01157
01158 break;
01159
01160 case CONFLICT_MERGE:
01161 case CONFLICT_BOTH:
01162
01163 STOPIF( hlp__rename_to_unique(fn, ".mine",
01164 &unique_name_mine, pool), NULL);
01165
01166 break;
01167
01168 default:
01169 BUG("unknown conflict resolution");
01170 }
01171
01172
01173
01174
01175
01176
01177
01178
01179
01180
01181
01182 removed=sts->old ? sts->old : sts;
01183 if (removed->remote_status & FS_REMOVED)
01184 {
01185
01186
01187
01188 if ((sts->entry_status & FS_REPLACED) != FS_REMOVED &&
01189 !unique_name_mine)
01190 {
01191
01192 if (TEST_PACKED(S_ISDIR, removed->old_rev_mode_packed))
01193 {
01194 STOPIF( up__rmdir(removed, sts->url), NULL);
01195 }
01196 else
01197 STOPIF( up__unlink(removed, fn), NULL);
01198 }
01199
01200 *dir_change_flag|=REVERT_MTIME;
01201 }
01202
01203
01204
01205 if (TEST_PACKED(S_ISGARBAGE, sts->local_mode_packed))
01206 {
01207 DEBUGP("cleaning garbage");
01208 STOPIF_CODE_ERR( unlink(fn) == -1, errno,
01209 "Cannot remove garbage entry %s", fn);
01210 }
01211
01212
01213
01214
01215
01216 sts->parent->to_be_sorted=1;
01217
01218 if ((sts->remote_status & FS_REPLACED) == FS_REMOVED)
01219 {
01220 sts->to_be_ignored=1;
01221 goto ex;
01222 }
01223 current_url=sts->url;
01224
01225 if (S_ISDIR(sts->st.mode))
01226 {
01227 *dir_change_flag|=REVERT_MTIME;
01228 STOPIF( waa__mkdir_mask(fn, 1, sts->st.mode), NULL);
01229
01230
01231
01232
01233
01234 }
01235 else if (sts->remote_status & (FS_CHANGED | FS_REPLACED))
01236
01237 {
01238 STOPIF( rev__install_file(sts, 0, sts->decoder, pool), NULL);
01239 *dir_change_flag|=REVERT_MTIME;
01240
01241
01242
01243 if (unique_name_mine)
01244 {
01245 *dir_change_flag|=SET_CURRENT;
01246
01247
01248
01249 snprintf(revnum, sizeof(revnum)-1,
01250 ".r%llu", (t_ull)sts->repos_rev);
01251 revnum[sizeof(revnum)-1]=0;
01252
01253 STOPIF( hlp__rename_to_unique(fn, revnum,
01254 &unique_name_remote, pool), NULL);
01255
01256
01257
01258 if (sts->flags & RF_CONFLICT)
01259 {
01260 STOPIF_CODE_EPIPE(
01261 printf("\"%s\" already marked as conflict.\n", fn),
01262 NULL);
01263 STOPIF( res__mark_conflict(sts,
01264 unique_name_mine, unique_name_remote, NULL), NULL);
01265 }
01266 else if (opt__get_int(OPT__CONFLICT) == CONFLICT_BOTH)
01267 {
01268 STOPIF( res__mark_conflict(sts,
01269 unique_name_mine, unique_name_remote, NULL), NULL);
01270
01271
01272
01273
01274 j=creat(fn, 0777);
01275 if (j != -1) j=close(j);
01276
01277 STOPIF_CODE_ERR(j == -1, errno,
01278 "Error creating \"%s\"", fn);
01279
01280
01281
01282 st=sts->st;
01283 STOPIF( up__set_meta_data(sts, fn), NULL);
01284 sts->st=st;
01285 }
01286 else if (opt__get_int(OPT__CONFLICT) == CONFLICT_MERGE)
01287 {
01288 STOPIF( rev__install_file(sts, sts->old_rev,
01289 NULL, pool), NULL);
01290
01291 snprintf(revnum, sizeof(revnum)-1,
01292 ".r%llu", (t_ull)sts->old_rev);
01293 revnum[sizeof(revnum)-1]=0;
01294
01295 STOPIF( hlp__rename_to_unique(fn, revnum,
01296 &unique_name_common, pool), NULL);
01297
01298 STOPIF( rev__merge(sts,
01299 unique_name_mine,
01300 unique_name_common,
01301 unique_name_remote), NULL);
01302 }
01303 else
01304 BUG("why a conflict?");
01305 }
01306 }
01307 else
01308 {
01309
01310
01311
01312 if (sts->remote_status & FS_PROPERTIES)
01313 STOPIF( rev__get_props(sts, NULL, sts->repos_rev, pool), NULL);
01314
01315 if (sts->remote_status & FS_META_CHANGED)
01316 {
01317
01318
01319
01320 STOPIF( up__set_meta_data(sts, fn), NULL);
01321 }
01322 }
01323
01324
01325 ex:
01326 return status;
01327 }
01328
01329
01332 int rev__do_changed(struct estat *dir,
01333 apr_pool_t *pool)
01334 {
01335 int status;
01336 int i;
01337 struct estat *sts;
01338 apr_pool_t *subpool;
01339 enum rev___dir_change_flag_e dir_flag;
01340
01341
01342 status=0;
01343 subpool=NULL;
01344 dir_flag= (dir->entry_status & FS_NEW) ||
01345 (dir->remote_status & FS_NEW) ? REVERT_MTIME : NOT_CHANGED;
01346
01347
01348
01349 if (!(dir->remote_status & FS_CHILD_CHANGED))
01350 DEBUGP("%s: no children changed", dir->name);
01351 else for(i=0; i<dir->entry_count; i++)
01352 {
01353 sts=dir->by_inode[i];
01354
01355 STOPIF( apr_pool_create(&subpool, pool), "Cannot get a subpool");
01356
01357 if (sts->remote_status & FS__CHANGE_MASK)
01358 STOPIF( rev___undo_change(sts, &dir_flag, subpool), NULL);
01359
01360
01361
01362
01363 if (S_ISDIR(sts->st.mode) &&
01364 (sts->remote_status & FS_REPLACED) != FS_REMOVED)
01365 {
01366 apr_pool_destroy(subpool);
01367 subpool=NULL;
01368 STOPIF( apr_pool_create(&subpool, pool), "subpool creation");
01369
01370 STOPIF( rev__do_changed(sts, subpool), NULL);
01371 }
01372
01373 STOPIF( st__rm_status(sts), NULL);
01374
01375 apr_pool_destroy(subpool);
01376 subpool=NULL;
01377 }
01378
01379
01380
01381 STOPIF( ops__free_marked(dir, 0), NULL);
01382
01383
01384 if (!dir->parent)
01385 STOPIF( st__rm_status(dir), NULL);
01386
01387
01388
01389
01390
01391
01392 if (dir->entry_status & FS__CHANGE_MASK)
01393 dir->flags |= RF_CHECK;
01394
01395 STOPIF( rev___handle_dir_mtime(dir, dir_flag), NULL);
01396
01397
01398 ex:
01399 return status;
01400 }
01401
01402
01403