1251881Speter/* 2251881Speter * workqueue.c : manipulating work queue items 3251881Speter * 4251881Speter * ==================================================================== 5251881Speter * Licensed to the Apache Software Foundation (ASF) under one 6251881Speter * or more contributor license agreements. See the NOTICE file 7251881Speter * distributed with this work for additional information 8251881Speter * regarding copyright ownership. The ASF licenses this file 9251881Speter * to you under the Apache License, Version 2.0 (the 10251881Speter * "License"); you may not use this file except in compliance 11251881Speter * with the License. You may obtain a copy of the License at 12251881Speter * 13251881Speter * http://www.apache.org/licenses/LICENSE-2.0 14251881Speter * 15251881Speter * Unless required by applicable law or agreed to in writing, 16251881Speter * software distributed under the License is distributed on an 17251881Speter * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 18251881Speter * KIND, either express or implied. See the License for the 19251881Speter * specific language governing permissions and limitations 20251881Speter * under the License. 21251881Speter * ==================================================================== 22251881Speter */ 23251881Speter 24251881Speter#include <apr_pools.h> 25251881Speter 26299742Sdim#include "svn_private_config.h" 27251881Speter#include "svn_types.h" 28251881Speter#include "svn_pools.h" 29251881Speter#include "svn_dirent_uri.h" 30251881Speter#include "svn_subst.h" 31251881Speter#include "svn_hash.h" 32251881Speter#include "svn_io.h" 33251881Speter 34251881Speter#include "wc.h" 35251881Speter#include "wc_db.h" 36251881Speter#include "workqueue.h" 37251881Speter#include "adm_files.h" 38251881Speter#include "conflicts.h" 39251881Speter#include "translate.h" 40251881Speter 41299742Sdim#include "private/svn_io_private.h" 42251881Speter#include "private/svn_skel.h" 43251881Speter 44251881Speter 45251881Speter/* Workqueue operation names. */ 46251881Speter#define OP_FILE_COMMIT "file-commit" 47251881Speter#define OP_FILE_INSTALL "file-install" 48251881Speter#define OP_FILE_REMOVE "file-remove" 49251881Speter#define OP_FILE_MOVE "file-move" 50251881Speter#define OP_FILE_COPY_TRANSLATED "file-translate" 51251881Speter#define OP_SYNC_FILE_FLAGS "sync-file-flags" 52251881Speter#define OP_PREJ_INSTALL "prej-install" 53251881Speter#define OP_DIRECTORY_REMOVE "dir-remove" 54251881Speter#define OP_DIRECTORY_INSTALL "dir-install" 55251881Speter 56251881Speter#define OP_POSTUPGRADE "postupgrade" 57251881Speter 58251881Speter/* Legacy items */ 59251881Speter#define OP_BASE_REMOVE "base-remove" 60251881Speter#define OP_RECORD_FILEINFO "record-fileinfo" 61251881Speter#define OP_TMP_SET_TEXT_CONFLICT_MARKERS "tmp-set-text-conflict-markers" 62251881Speter#define OP_TMP_SET_PROPERTY_CONFLICT_MARKER "tmp-set-property-conflict-marker" 63251881Speter 64251881Speter/* For work queue debugging. Generates output about its operation. */ 65251881Speter/* #define SVN_DEBUG_WORK_QUEUE */ 66251881Speter 67251881Spetertypedef struct work_item_baton_t work_item_baton_t; 68251881Speter 69251881Speterstruct work_item_dispatch { 70251881Speter const char *name; 71251881Speter svn_error_t *(*func)(work_item_baton_t *wqb, 72251881Speter svn_wc__db_t *db, 73251881Speter const svn_skel_t *work_item, 74251881Speter const char *wri_abspath, 75251881Speter svn_cancel_func_t cancel_func, 76251881Speter void *cancel_baton, 77251881Speter apr_pool_t *scratch_pool); 78251881Speter}; 79251881Speter 80251881Speter/* Forward definition */ 81251881Speterstatic svn_error_t * 82251881Speterget_and_record_fileinfo(work_item_baton_t *wqb, 83251881Speter const char *local_abspath, 84251881Speter svn_boolean_t ignore_enoent, 85251881Speter apr_pool_t *scratch_pool); 86251881Speter 87251881Speter/* ------------------------------------------------------------------------ */ 88251881Speter/* OP_REMOVE_BASE */ 89251881Speter 90251881Speter/* Removes a BASE_NODE and all it's data, leaving any adds and copies as is. 91251881Speter Do this as a depth first traversal to make sure than any parent still exists 92251881Speter on error conditions. 93251881Speter */ 94251881Speter 95251881Speter/* Process the OP_REMOVE_BASE work item WORK_ITEM. 96251881Speter * See svn_wc__wq_build_remove_base() which generates this work item. 97251881Speter * Implements (struct work_item_dispatch).func. */ 98251881Speterstatic svn_error_t * 99251881Speterrun_base_remove(work_item_baton_t *wqb, 100251881Speter svn_wc__db_t *db, 101251881Speter const svn_skel_t *work_item, 102251881Speter const char *wri_abspath, 103251881Speter svn_cancel_func_t cancel_func, 104251881Speter void *cancel_baton, 105251881Speter apr_pool_t *scratch_pool) 106251881Speter{ 107251881Speter const svn_skel_t *arg1 = work_item->children->next; 108251881Speter const char *local_relpath; 109251881Speter const char *local_abspath; 110251881Speter svn_revnum_t not_present_rev = SVN_INVALID_REVNUM; 111251881Speter apr_int64_t val; 112251881Speter 113251881Speter local_relpath = apr_pstrmemdup(scratch_pool, arg1->data, arg1->len); 114251881Speter SVN_ERR(svn_wc__db_from_relpath(&local_abspath, db, wri_abspath, 115251881Speter local_relpath, scratch_pool, scratch_pool)); 116251881Speter SVN_ERR(svn_skel__parse_int(&val, arg1->next, scratch_pool)); 117251881Speter 118251881Speter if (arg1->next->next) 119251881Speter { 120251881Speter not_present_rev = (svn_revnum_t)val; 121251881Speter 122251881Speter SVN_ERR(svn_skel__parse_int(&val, arg1->next->next, scratch_pool)); 123251881Speter } 124251881Speter else 125251881Speter { 126251881Speter svn_boolean_t keep_not_present; 127251881Speter 128251881Speter SVN_ERR_ASSERT(SVN_WC__VERSION <= 28); /* Case unused in later versions*/ 129251881Speter 130251881Speter keep_not_present = (val != 0); 131251881Speter 132251881Speter if (keep_not_present) 133251881Speter { 134251881Speter SVN_ERR(svn_wc__db_base_get_info(NULL, NULL, 135251881Speter ¬_present_rev, NULL, 136251881Speter NULL, NULL, NULL, 137251881Speter NULL, NULL, NULL, NULL, NULL, NULL, 138251881Speter NULL, NULL, NULL, 139251881Speter db, local_abspath, 140251881Speter scratch_pool, scratch_pool)); 141251881Speter } 142251881Speter } 143251881Speter 144251881Speter SVN_ERR(svn_wc__db_base_remove(db, local_abspath, 145251881Speter FALSE /* keep_as_working */, 146299742Sdim SVN_IS_VALID_REVNUM(not_present_rev), FALSE, 147251881Speter not_present_rev, 148251881Speter NULL, NULL, scratch_pool)); 149251881Speter 150251881Speter return SVN_NO_ERROR; 151251881Speter} 152251881Speter 153251881Speter/* ------------------------------------------------------------------------ */ 154251881Speter 155251881Speter/* ------------------------------------------------------------------------ */ 156251881Speter 157251881Speter/* OP_FILE_COMMIT */ 158251881Speter 159251881Speter 160251881Speter/* FILE_ABSPATH is the new text base of the newly-committed versioned file, 161251881Speter * in repository-normal form (aka "detranslated" form). Adjust the working 162251881Speter * file accordingly. 163251881Speter * 164251881Speter * If eol and/or keyword translation would cause the working file to 165251881Speter * change, then overwrite the working file with a translated copy of 166251881Speter * the new text base (but only if the translated copy differs from the 167251881Speter * current working file -- if they are the same, do nothing, to avoid 168251881Speter * clobbering timestamps unnecessarily). 169251881Speter * 170251881Speter * Set the working file's executability according to its svn:executable 171251881Speter * property. 172251881Speter * 173251881Speter * Set the working file's read-only attribute according to its properties 174251881Speter * and lock status (see svn_wc__maybe_set_read_only()). 175251881Speter * 176251881Speter * If the working file was re-translated or had its executability or 177251881Speter * read-only state changed, 178251881Speter * then set OVERWROTE_WORKING to TRUE. If the working file isn't 179251881Speter * touched at all, then set to FALSE. 180251881Speter * 181251881Speter * Use SCRATCH_POOL for any temporary allocation. 182251881Speter */ 183251881Speterstatic svn_error_t * 184251881Speterinstall_committed_file(svn_boolean_t *overwrote_working, 185251881Speter svn_wc__db_t *db, 186251881Speter const char *file_abspath, 187251881Speter svn_cancel_func_t cancel_func, 188251881Speter void *cancel_baton, 189251881Speter apr_pool_t *scratch_pool) 190251881Speter{ 191251881Speter svn_boolean_t same; 192251881Speter const char *tmp_wfile; 193251881Speter svn_boolean_t special; 194251881Speter 195251881Speter /* start off assuming that the working file isn't touched. */ 196251881Speter *overwrote_working = FALSE; 197251881Speter 198251881Speter /* In the commit, newlines and keywords may have been 199251881Speter * canonicalized and/or contracted... Or they may not have 200251881Speter * been. It's kind of hard to know. Here's how we find out: 201251881Speter * 202251881Speter * 1. Make a translated tmp copy of the committed text base, 203251881Speter * translated according to the versioned file's properties. 204251881Speter * Or, if no committed text base exists (the commit must have 205251881Speter * been a propchange only), make a translated tmp copy of the 206251881Speter * working file. 207251881Speter * 2. Compare the translated tmpfile to the working file. 208251881Speter * 3. If different, copy the tmpfile over working file. 209251881Speter * 210251881Speter * This means we only rewrite the working file if we absolutely 211251881Speter * have to, which is good because it avoids changing the file's 212251881Speter * timestamp unless necessary, so editors aren't tempted to 213251881Speter * reread the file if they don't really need to. 214251881Speter */ 215251881Speter 216251881Speter /* Copy and translate the new base-to-be file (if found, else the working 217251881Speter * file) from repository-normal form to working form, writing a new 218251881Speter * temporary file if any translation was actually done. Set TMP_WFILE to 219251881Speter * the translated file's path, which may be the source file's path if no 220251881Speter * translation was done. Set SAME to indicate whether the new working 221251881Speter * text is the same as the old working text (or TRUE if it's a special 222251881Speter * file). */ 223251881Speter { 224251881Speter const char *tmp = file_abspath; 225251881Speter 226251881Speter /* Copy and translate, if necessary. The output file will be deleted at 227251881Speter * scratch_pool cleanup. 228251881Speter * ### That's not quite safe: we might rename the file and then maybe 229251881Speter * its path will get re-used for another temp file before pool clean-up. 230251881Speter * Instead, we should take responsibility for deleting it. */ 231251881Speter SVN_ERR(svn_wc__internal_translated_file(&tmp_wfile, tmp, db, 232251881Speter file_abspath, 233251881Speter SVN_WC_TRANSLATE_FROM_NF, 234251881Speter cancel_func, cancel_baton, 235251881Speter scratch_pool, scratch_pool)); 236251881Speter 237251881Speter /* If the translation is a no-op, the text base and the working copy 238251881Speter * file contain the same content, because we use the same props here 239251881Speter * as were used to detranslate from working file to text base. 240251881Speter * 241251881Speter * In that case: don't replace the working file, but make sure 242251881Speter * it has the right executable and read_write attributes set. 243251881Speter */ 244251881Speter 245251881Speter SVN_ERR(svn_wc__get_translate_info(NULL, NULL, 246251881Speter NULL, 247251881Speter &special, 248251881Speter db, file_abspath, NULL, FALSE, 249251881Speter scratch_pool, scratch_pool)); 250251881Speter /* Translated file returns the exact pointer if not translated. */ 251251881Speter if (! special && tmp != tmp_wfile) 252251881Speter SVN_ERR(svn_io_files_contents_same_p(&same, tmp_wfile, 253251881Speter file_abspath, scratch_pool)); 254251881Speter else 255251881Speter same = TRUE; 256251881Speter } 257251881Speter 258251881Speter if (! same) 259251881Speter { 260251881Speter SVN_ERR(svn_io_file_rename(tmp_wfile, file_abspath, scratch_pool)); 261251881Speter *overwrote_working = TRUE; 262251881Speter } 263251881Speter 264251881Speter /* ### should be using OP_SYNC_FILE_FLAGS, or an internal version of 265251881Speter ### that here. do we need to set *OVERWROTE_WORKING? */ 266251881Speter 267251881Speter /* ### Re: OVERWROTE_WORKING, the following function is rather liberal 268251881Speter ### with setting that flag, so we should probably decide if we really 269251881Speter ### care about it when syncing flags. */ 270251881Speter SVN_ERR(svn_wc__sync_flags_with_props(overwrote_working, db, file_abspath, 271251881Speter scratch_pool)); 272251881Speter 273251881Speter return SVN_NO_ERROR; 274251881Speter} 275251881Speter 276251881Speterstatic svn_error_t * 277251881Speterprocess_commit_file_install(svn_wc__db_t *db, 278251881Speter const char *local_abspath, 279251881Speter svn_cancel_func_t cancel_func, 280251881Speter void *cancel_baton, 281251881Speter apr_pool_t *scratch_pool) 282251881Speter{ 283251881Speter svn_boolean_t overwrote_working; 284251881Speter 285251881Speter /* Install the new file, which may involve expanding keywords. 286251881Speter A copy of this file should have been dropped into our `tmp/text-base' 287251881Speter directory during the commit process. Part of this process 288251881Speter involves recording the textual timestamp for this entry. We'd like 289251881Speter to just use the timestamp of the working file, but it is possible 290251881Speter that at some point during the commit, the real working file might 291251881Speter have changed again. 292251881Speter */ 293251881Speter 294251881Speter SVN_ERR(install_committed_file(&overwrote_working, db, 295251881Speter local_abspath, 296251881Speter cancel_func, cancel_baton, 297251881Speter scratch_pool)); 298251881Speter 299251881Speter /* We will compute and modify the size and timestamp */ 300251881Speter if (overwrote_working) 301251881Speter { 302251881Speter apr_finfo_t finfo; 303251881Speter 304251881Speter SVN_ERR(svn_io_stat(&finfo, local_abspath, 305251881Speter APR_FINFO_MIN | APR_FINFO_LINK, scratch_pool)); 306251881Speter SVN_ERR(svn_wc__db_global_record_fileinfo(db, local_abspath, 307251881Speter finfo.size, finfo.mtime, 308251881Speter scratch_pool)); 309251881Speter } 310251881Speter else 311251881Speter { 312251881Speter svn_boolean_t modified; 313251881Speter 314251881Speter /* The working copy file hasn't been overwritten. We just 315251881Speter removed the recorded size and modification time from the nodes 316251881Speter record by calling svn_wc__db_global_commit(). 317251881Speter 318251881Speter Now we have some file in our working copy that might be what 319251881Speter we just committed, but we are not certain at this point. 320251881Speter 321251881Speter We still have a write lock here, so we check if the file is 322251881Speter what we expect it to be and if it is the right file we update 323251881Speter the recorded information. (If it isn't we keep the null data). 324251881Speter 325251881Speter Instead of reimplementing all this here, we just call a function 326251881Speter that already does implement this when it notices that we have the 327251881Speter right kind of lock (and we ignore the result) 328251881Speter */ 329251881Speter SVN_ERR(svn_wc__internal_file_modified_p(&modified, 330251881Speter db, local_abspath, FALSE, 331251881Speter scratch_pool)); 332251881Speter } 333251881Speter return SVN_NO_ERROR; 334251881Speter} 335251881Speter 336251881Speter 337251881Speterstatic svn_error_t * 338251881Speterrun_file_commit(work_item_baton_t *wqb, 339251881Speter svn_wc__db_t *db, 340251881Speter const svn_skel_t *work_item, 341251881Speter const char *wri_abspath, 342251881Speter svn_cancel_func_t cancel_func, 343251881Speter void *cancel_baton, 344251881Speter apr_pool_t *scratch_pool) 345251881Speter{ 346251881Speter const svn_skel_t *arg1 = work_item->children->next; 347251881Speter const char *local_relpath; 348251881Speter const char *local_abspath; 349251881Speter 350251881Speter local_relpath = apr_pstrmemdup(scratch_pool, arg1->data, arg1->len); 351251881Speter SVN_ERR(svn_wc__db_from_relpath(&local_abspath, db, wri_abspath, 352251881Speter local_relpath, scratch_pool, scratch_pool)); 353251881Speter 354251881Speter /* We don't both parsing the other two values in the skel. */ 355251881Speter 356251881Speter return svn_error_trace( 357251881Speter process_commit_file_install(db, local_abspath, 358251881Speter cancel_func, cancel_baton, 359251881Speter scratch_pool)); 360251881Speter} 361251881Speter 362251881Spetersvn_error_t * 363251881Spetersvn_wc__wq_build_file_commit(svn_skel_t **work_item, 364251881Speter svn_wc__db_t *db, 365251881Speter const char *local_abspath, 366251881Speter svn_boolean_t props_mod, 367251881Speter apr_pool_t *result_pool, 368251881Speter apr_pool_t *scratch_pool) 369251881Speter{ 370251881Speter const char *local_relpath; 371251881Speter *work_item = svn_skel__make_empty_list(result_pool); 372251881Speter 373251881Speter SVN_ERR(svn_wc__db_to_relpath(&local_relpath, db, local_abspath, 374251881Speter local_abspath, result_pool, scratch_pool)); 375251881Speter 376251881Speter svn_skel__prepend_str(local_relpath, *work_item, result_pool); 377251881Speter 378251881Speter svn_skel__prepend_str(OP_FILE_COMMIT, *work_item, result_pool); 379251881Speter 380251881Speter return SVN_NO_ERROR; 381251881Speter} 382251881Speter 383251881Speter/* ------------------------------------------------------------------------ */ 384251881Speter/* OP_POSTUPGRADE */ 385251881Speter 386251881Speterstatic svn_error_t * 387251881Speterrun_postupgrade(work_item_baton_t *wqb, 388251881Speter svn_wc__db_t *db, 389251881Speter const svn_skel_t *work_item, 390251881Speter const char *wri_abspath, 391251881Speter svn_cancel_func_t cancel_func, 392251881Speter void *cancel_baton, 393251881Speter apr_pool_t *scratch_pool) 394251881Speter{ 395251881Speter const char *entries_path; 396251881Speter const char *format_path; 397251881Speter const char *wcroot_abspath; 398251881Speter svn_error_t *err; 399251881Speter 400251881Speter err = svn_wc__wipe_postupgrade(wri_abspath, FALSE, 401251881Speter cancel_func, cancel_baton, scratch_pool); 402251881Speter if (err && err->apr_err == SVN_ERR_ENTRY_NOT_FOUND) 403251881Speter /* No entry, this can happen when the wq item is rerun. */ 404251881Speter svn_error_clear(err); 405251881Speter else 406251881Speter SVN_ERR(err); 407251881Speter 408251881Speter SVN_ERR(svn_wc__db_get_wcroot(&wcroot_abspath, db, wri_abspath, 409251881Speter scratch_pool, scratch_pool)); 410251881Speter 411251881Speter entries_path = svn_wc__adm_child(wcroot_abspath, SVN_WC__ADM_ENTRIES, 412251881Speter scratch_pool); 413251881Speter format_path = svn_wc__adm_child(wcroot_abspath, SVN_WC__ADM_FORMAT, 414251881Speter scratch_pool); 415251881Speter 416251881Speter /* Write the 'format' and 'entries' files. 417251881Speter 418251881Speter ### The order may matter for some sufficiently old clients.. but 419251881Speter ### this code only runs during upgrade after the files had been 420251881Speter ### removed earlier during the upgrade. */ 421299742Sdim SVN_ERR(svn_io_write_atomic(format_path, SVN_WC__NON_ENTRIES_STRING, 422251881Speter sizeof(SVN_WC__NON_ENTRIES_STRING) - 1, 423299742Sdim NULL, scratch_pool)); 424251881Speter 425299742Sdim SVN_ERR(svn_io_write_atomic(entries_path, SVN_WC__NON_ENTRIES_STRING, 426251881Speter sizeof(SVN_WC__NON_ENTRIES_STRING) - 1, 427299742Sdim NULL, scratch_pool)); 428251881Speter 429251881Speter return SVN_NO_ERROR; 430251881Speter} 431251881Speter 432251881Spetersvn_error_t * 433251881Spetersvn_wc__wq_build_postupgrade(svn_skel_t **work_item, 434251881Speter apr_pool_t *result_pool) 435251881Speter{ 436251881Speter *work_item = svn_skel__make_empty_list(result_pool); 437251881Speter 438251881Speter svn_skel__prepend_str(OP_POSTUPGRADE, *work_item, result_pool); 439251881Speter 440251881Speter return SVN_NO_ERROR; 441251881Speter} 442251881Speter 443251881Speter/* ------------------------------------------------------------------------ */ 444251881Speter 445251881Speter/* OP_FILE_INSTALL */ 446251881Speter 447251881Speter/* Process the OP_FILE_INSTALL work item WORK_ITEM. 448251881Speter * See svn_wc__wq_build_file_install() which generates this work item. 449251881Speter * Implements (struct work_item_dispatch).func. */ 450251881Speterstatic svn_error_t * 451251881Speterrun_file_install(work_item_baton_t *wqb, 452251881Speter svn_wc__db_t *db, 453251881Speter const svn_skel_t *work_item, 454251881Speter const char *wri_abspath, 455251881Speter svn_cancel_func_t cancel_func, 456251881Speter void *cancel_baton, 457251881Speter apr_pool_t *scratch_pool) 458251881Speter{ 459251881Speter const svn_skel_t *arg1 = work_item->children->next; 460251881Speter const svn_skel_t *arg4 = arg1->next->next->next; 461251881Speter const char *local_relpath; 462251881Speter const char *local_abspath; 463251881Speter svn_boolean_t use_commit_times; 464251881Speter svn_boolean_t record_fileinfo; 465251881Speter svn_boolean_t special; 466251881Speter svn_stream_t *src_stream; 467251881Speter svn_subst_eol_style_t style; 468251881Speter const char *eol; 469251881Speter apr_hash_t *keywords; 470251881Speter const char *temp_dir_abspath; 471251881Speter svn_stream_t *dst_stream; 472251881Speter apr_int64_t val; 473251881Speter const char *wcroot_abspath; 474251881Speter const char *source_abspath; 475251881Speter const svn_checksum_t *checksum; 476251881Speter apr_hash_t *props; 477251881Speter apr_time_t changed_date; 478251881Speter 479251881Speter local_relpath = apr_pstrmemdup(scratch_pool, arg1->data, arg1->len); 480251881Speter SVN_ERR(svn_wc__db_from_relpath(&local_abspath, db, wri_abspath, 481251881Speter local_relpath, scratch_pool, scratch_pool)); 482251881Speter 483251881Speter SVN_ERR(svn_skel__parse_int(&val, arg1->next, scratch_pool)); 484251881Speter use_commit_times = (val != 0); 485251881Speter SVN_ERR(svn_skel__parse_int(&val, arg1->next->next, scratch_pool)); 486251881Speter record_fileinfo = (val != 0); 487251881Speter 488251881Speter SVN_ERR(svn_wc__db_read_node_install_info(&wcroot_abspath, 489251881Speter &checksum, &props, 490251881Speter &changed_date, 491251881Speter db, local_abspath, wri_abspath, 492251881Speter scratch_pool, scratch_pool)); 493251881Speter 494251881Speter if (arg4 != NULL) 495251881Speter { 496251881Speter /* Use the provided path for the source. */ 497251881Speter local_relpath = apr_pstrmemdup(scratch_pool, arg4->data, arg4->len); 498251881Speter SVN_ERR(svn_wc__db_from_relpath(&source_abspath, db, wri_abspath, 499251881Speter local_relpath, 500251881Speter scratch_pool, scratch_pool)); 501251881Speter } 502251881Speter else if (! checksum) 503251881Speter { 504251881Speter /* This error replaces a previous assertion. Reporting an error from here 505251881Speter leaves the workingqueue operation in place, so the working copy is 506251881Speter still broken! 507251881Speter 508251881Speter But when we report this error the user at least knows what node has 509251881Speter this specific problem, so maybe we can find out why users see this 510251881Speter error */ 511251881Speter return svn_error_createf(SVN_ERR_WC_CORRUPT_TEXT_BASE, NULL, 512251881Speter _("Can't install '%s' from pristine store, " 513251881Speter "because no checksum is recorded for this " 514251881Speter "file"), 515251881Speter svn_dirent_local_style(local_abspath, 516251881Speter scratch_pool)); 517251881Speter } 518251881Speter else 519251881Speter { 520251881Speter SVN_ERR(svn_wc__db_pristine_get_future_path(&source_abspath, 521251881Speter wcroot_abspath, 522251881Speter checksum, 523251881Speter scratch_pool, scratch_pool)); 524251881Speter } 525251881Speter 526251881Speter SVN_ERR(svn_stream_open_readonly(&src_stream, source_abspath, 527251881Speter scratch_pool, scratch_pool)); 528251881Speter 529251881Speter /* Fetch all the translation bits. */ 530251881Speter SVN_ERR(svn_wc__get_translate_info(&style, &eol, 531251881Speter &keywords, 532251881Speter &special, db, local_abspath, 533251881Speter props, FALSE, 534251881Speter scratch_pool, scratch_pool)); 535251881Speter if (special) 536251881Speter { 537251881Speter /* When this stream is closed, the resulting special file will 538251881Speter atomically be created/moved into place at LOCAL_ABSPATH. */ 539251881Speter SVN_ERR(svn_subst_create_specialfile(&dst_stream, local_abspath, 540251881Speter scratch_pool, scratch_pool)); 541251881Speter 542251881Speter /* Copy the "repository normal" form of the special file into the 543251881Speter special stream. */ 544251881Speter SVN_ERR(svn_stream_copy3(src_stream, dst_stream, 545251881Speter cancel_func, cancel_baton, 546251881Speter scratch_pool)); 547251881Speter 548251881Speter /* No need to set exec or read-only flags on special files. */ 549251881Speter 550251881Speter /* ### Shouldn't this record a timestamp and size, etc.? */ 551251881Speter return SVN_NO_ERROR; 552251881Speter } 553251881Speter 554251881Speter if (svn_subst_translation_required(style, eol, keywords, 555251881Speter FALSE /* special */, 556251881Speter TRUE /* force_eol_check */)) 557251881Speter { 558251881Speter /* Wrap it in a translating (expanding) stream. */ 559251881Speter src_stream = svn_subst_stream_translated(src_stream, eol, 560251881Speter TRUE /* repair */, 561251881Speter keywords, 562251881Speter TRUE /* expand */, 563251881Speter scratch_pool); 564251881Speter } 565251881Speter 566251881Speter /* Where is the Right Place to put a temp file in this working copy? */ 567251881Speter SVN_ERR(svn_wc__db_temp_wcroot_tempdir(&temp_dir_abspath, 568251881Speter db, wcroot_abspath, 569251881Speter scratch_pool, scratch_pool)); 570251881Speter 571251881Speter /* Translate to a temporary file. We don't want the user seeing a partial 572251881Speter file, nor let them muck with it while we translate. We may also need to 573251881Speter get its TRANSLATED_SIZE before the user can monkey it. */ 574299742Sdim SVN_ERR(svn_stream__create_for_install(&dst_stream, temp_dir_abspath, 575299742Sdim scratch_pool, scratch_pool)); 576251881Speter 577251881Speter /* Copy from the source to the dest, translating as we go. This will also 578251881Speter close both streams. */ 579251881Speter SVN_ERR(svn_stream_copy3(src_stream, dst_stream, 580251881Speter cancel_func, cancel_baton, 581251881Speter scratch_pool)); 582251881Speter 583251881Speter /* All done. Move the file into place. */ 584299742Sdim /* With a single db we might want to install files in a missing directory. 585299742Sdim Simply trying this scenario on error won't do any harm and at least 586299742Sdim one user reported this problem on IRC. */ 587299742Sdim SVN_ERR(svn_stream__install_stream(dst_stream, local_abspath, 588299742Sdim TRUE /* make_parents*/, scratch_pool)); 589251881Speter 590251881Speter /* Tweak the on-disk file according to its properties. */ 591251881Speter#ifndef WIN32 592251881Speter if (props && svn_hash_gets(props, SVN_PROP_EXECUTABLE)) 593251881Speter SVN_ERR(svn_io_set_file_executable(local_abspath, TRUE, FALSE, 594251881Speter scratch_pool)); 595251881Speter#endif 596251881Speter 597251881Speter /* Note that this explicitly checks the pristine properties, to make sure 598251881Speter that when the lock is locally set (=modification) it is not read only */ 599251881Speter if (props && svn_hash_gets(props, SVN_PROP_NEEDS_LOCK)) 600251881Speter { 601251881Speter svn_wc__db_status_t status; 602251881Speter svn_wc__db_lock_t *lock; 603251881Speter SVN_ERR(svn_wc__db_read_info(&status, NULL, NULL, NULL, NULL, NULL, NULL, 604251881Speter NULL, NULL, NULL, NULL, NULL, NULL, NULL, 605251881Speter NULL, NULL, &lock, NULL, NULL, NULL, NULL, 606251881Speter NULL, NULL, NULL, NULL, NULL, NULL, 607251881Speter db, local_abspath, 608251881Speter scratch_pool, scratch_pool)); 609251881Speter 610251881Speter if (!lock && status != svn_wc__db_status_added) 611251881Speter SVN_ERR(svn_io_set_file_read_only(local_abspath, FALSE, scratch_pool)); 612251881Speter } 613251881Speter 614251881Speter if (use_commit_times) 615251881Speter { 616251881Speter if (changed_date) 617251881Speter SVN_ERR(svn_io_set_file_affected_time(changed_date, 618251881Speter local_abspath, 619251881Speter scratch_pool)); 620251881Speter } 621251881Speter 622251881Speter /* ### this should happen before we rename the file into place. */ 623251881Speter if (record_fileinfo) 624251881Speter { 625251881Speter SVN_ERR(get_and_record_fileinfo(wqb, local_abspath, 626251881Speter FALSE /* ignore_enoent */, 627251881Speter scratch_pool)); 628251881Speter } 629251881Speter 630251881Speter return SVN_NO_ERROR; 631251881Speter} 632251881Speter 633251881Speter 634251881Spetersvn_error_t * 635251881Spetersvn_wc__wq_build_file_install(svn_skel_t **work_item, 636251881Speter svn_wc__db_t *db, 637251881Speter const char *local_abspath, 638251881Speter const char *source_abspath, 639251881Speter svn_boolean_t use_commit_times, 640251881Speter svn_boolean_t record_fileinfo, 641251881Speter apr_pool_t *result_pool, 642251881Speter apr_pool_t *scratch_pool) 643251881Speter{ 644251881Speter const char *local_relpath; 645251881Speter const char *wri_abspath; 646251881Speter *work_item = svn_skel__make_empty_list(result_pool); 647251881Speter 648251881Speter /* Use the directory of the file to install as wri_abspath to avoid 649251881Speter filestats on just obtaining the wc-root */ 650251881Speter wri_abspath = svn_dirent_dirname(local_abspath, scratch_pool); 651251881Speter 652251881Speter /* If a SOURCE_ABSPATH was provided, then put it into the skel. If this 653251881Speter value is not provided, then the file's pristine contents will be used. */ 654251881Speter if (source_abspath != NULL) 655251881Speter { 656251881Speter SVN_ERR(svn_wc__db_to_relpath(&local_relpath, db, wri_abspath, 657251881Speter source_abspath, 658251881Speter result_pool, scratch_pool)); 659251881Speter 660251881Speter svn_skel__prepend_str(local_relpath, *work_item, result_pool); 661251881Speter } 662251881Speter 663251881Speter SVN_ERR(svn_wc__db_to_relpath(&local_relpath, db, wri_abspath, 664251881Speter local_abspath, result_pool, scratch_pool)); 665251881Speter 666251881Speter svn_skel__prepend_int(record_fileinfo, *work_item, result_pool); 667251881Speter svn_skel__prepend_int(use_commit_times, *work_item, result_pool); 668251881Speter svn_skel__prepend_str(local_relpath, *work_item, result_pool); 669251881Speter svn_skel__prepend_str(OP_FILE_INSTALL, *work_item, result_pool); 670251881Speter 671251881Speter return SVN_NO_ERROR; 672251881Speter} 673251881Speter 674251881Speter 675251881Speter/* ------------------------------------------------------------------------ */ 676251881Speter 677251881Speter/* OP_FILE_REMOVE */ 678251881Speter 679251881Speter/* Process the OP_FILE_REMOVE work item WORK_ITEM. 680251881Speter * See svn_wc__wq_build_file_remove() which generates this work item. 681251881Speter * Implements (struct work_item_dispatch).func. */ 682251881Speterstatic svn_error_t * 683251881Speterrun_file_remove(work_item_baton_t *wqb, 684251881Speter svn_wc__db_t *db, 685251881Speter const svn_skel_t *work_item, 686251881Speter const char *wri_abspath, 687251881Speter svn_cancel_func_t cancel_func, 688251881Speter void *cancel_baton, 689251881Speter apr_pool_t *scratch_pool) 690251881Speter{ 691251881Speter const svn_skel_t *arg1 = work_item->children->next; 692251881Speter const char *local_relpath; 693251881Speter const char *local_abspath; 694251881Speter 695251881Speter local_relpath = apr_pstrmemdup(scratch_pool, arg1->data, arg1->len); 696251881Speter SVN_ERR(svn_wc__db_from_relpath(&local_abspath, db, wri_abspath, 697251881Speter local_relpath, scratch_pool, scratch_pool)); 698251881Speter 699251881Speter /* Remove the path, no worrying if it isn't there. */ 700251881Speter return svn_error_trace(svn_io_remove_file2(local_abspath, TRUE, 701251881Speter scratch_pool)); 702251881Speter} 703251881Speter 704251881Speter 705251881Spetersvn_error_t * 706251881Spetersvn_wc__wq_build_file_remove(svn_skel_t **work_item, 707251881Speter svn_wc__db_t *db, 708251881Speter const char *wri_abspath, 709251881Speter const char *local_abspath, 710251881Speter apr_pool_t *result_pool, 711251881Speter apr_pool_t *scratch_pool) 712251881Speter{ 713251881Speter const char *local_relpath; 714251881Speter *work_item = svn_skel__make_empty_list(result_pool); 715251881Speter 716251881Speter SVN_ERR(svn_wc__db_to_relpath(&local_relpath, db, wri_abspath, 717251881Speter local_abspath, result_pool, scratch_pool)); 718251881Speter 719251881Speter svn_skel__prepend_str(local_relpath, *work_item, result_pool); 720251881Speter svn_skel__prepend_str(OP_FILE_REMOVE, *work_item, result_pool); 721251881Speter 722251881Speter return SVN_NO_ERROR; 723251881Speter} 724251881Speter 725251881Speter/* ------------------------------------------------------------------------ */ 726251881Speter 727251881Speter/* OP_DIRECTORY_REMOVE */ 728251881Speter 729251881Speter/* Process the OP_FILE_REMOVE work item WORK_ITEM. 730251881Speter * See svn_wc__wq_build_file_remove() which generates this work item. 731251881Speter * Implements (struct work_item_dispatch).func. */ 732251881Speterstatic svn_error_t * 733251881Speterrun_dir_remove(work_item_baton_t *wqb, 734251881Speter svn_wc__db_t *db, 735251881Speter const svn_skel_t *work_item, 736251881Speter const char *wri_abspath, 737251881Speter svn_cancel_func_t cancel_func, 738251881Speter void *cancel_baton, 739251881Speter apr_pool_t *scratch_pool) 740251881Speter{ 741251881Speter const svn_skel_t *arg1 = work_item->children->next; 742251881Speter const char *local_relpath; 743251881Speter const char *local_abspath; 744251881Speter svn_boolean_t recursive; 745251881Speter 746251881Speter local_relpath = apr_pstrmemdup(scratch_pool, arg1->data, arg1->len); 747251881Speter SVN_ERR(svn_wc__db_from_relpath(&local_abspath, db, wri_abspath, 748251881Speter local_relpath, scratch_pool, scratch_pool)); 749251881Speter 750251881Speter recursive = FALSE; 751251881Speter if (arg1->next) 752251881Speter { 753251881Speter apr_int64_t val; 754251881Speter SVN_ERR(svn_skel__parse_int(&val, arg1->next, scratch_pool)); 755251881Speter 756251881Speter recursive = (val != 0); 757251881Speter } 758251881Speter 759251881Speter /* Remove the path, no worrying if it isn't there. */ 760251881Speter if (recursive) 761251881Speter return svn_error_trace( 762251881Speter svn_io_remove_dir2(local_abspath, TRUE, 763251881Speter cancel_func, cancel_baton, 764251881Speter scratch_pool)); 765251881Speter else 766251881Speter { 767251881Speter svn_error_t *err; 768251881Speter 769251881Speter err = svn_io_dir_remove_nonrecursive(local_abspath, scratch_pool); 770251881Speter 771251881Speter if (err && (APR_STATUS_IS_ENOENT(err->apr_err) 772251881Speter || SVN__APR_STATUS_IS_ENOTDIR(err->apr_err) 773251881Speter || APR_STATUS_IS_ENOTEMPTY(err->apr_err))) 774251881Speter { 775251881Speter svn_error_clear(err); 776251881Speter err = NULL; 777251881Speter } 778251881Speter 779251881Speter return svn_error_trace(err); 780251881Speter } 781251881Speter} 782251881Speter 783251881Spetersvn_error_t * 784251881Spetersvn_wc__wq_build_dir_remove(svn_skel_t **work_item, 785251881Speter svn_wc__db_t *db, 786251881Speter const char *wri_abspath, 787251881Speter const char *local_abspath, 788251881Speter svn_boolean_t recursive, 789251881Speter apr_pool_t *result_pool, 790251881Speter apr_pool_t *scratch_pool) 791251881Speter{ 792251881Speter const char *local_relpath; 793251881Speter *work_item = svn_skel__make_empty_list(result_pool); 794251881Speter 795251881Speter SVN_ERR(svn_wc__db_to_relpath(&local_relpath, db, wri_abspath, 796251881Speter local_abspath, result_pool, scratch_pool)); 797251881Speter 798251881Speter if (recursive) 799251881Speter svn_skel__prepend_int(TRUE, *work_item, result_pool); 800251881Speter 801251881Speter svn_skel__prepend_str(local_relpath, *work_item, result_pool); 802251881Speter svn_skel__prepend_str(OP_DIRECTORY_REMOVE, *work_item, result_pool); 803251881Speter 804251881Speter return SVN_NO_ERROR; 805251881Speter} 806251881Speter 807251881Speter/* ------------------------------------------------------------------------ */ 808251881Speter 809251881Speter/* OP_FILE_MOVE */ 810251881Speter 811251881Speter/* Process the OP_FILE_MOVE work item WORK_ITEM. 812251881Speter * See svn_wc__wq_build_file_move() which generates this work item. 813251881Speter * Implements (struct work_item_dispatch).func. */ 814251881Speterstatic svn_error_t * 815251881Speterrun_file_move(work_item_baton_t *wqb, 816251881Speter svn_wc__db_t *db, 817251881Speter const svn_skel_t *work_item, 818251881Speter const char *wri_abspath, 819251881Speter svn_cancel_func_t cancel_func, 820251881Speter void *cancel_baton, 821251881Speter apr_pool_t *scratch_pool) 822251881Speter{ 823251881Speter const svn_skel_t *arg1 = work_item->children->next; 824251881Speter const char *src_abspath, *dst_abspath; 825251881Speter const char *local_relpath; 826251881Speter svn_error_t *err; 827251881Speter 828251881Speter local_relpath = apr_pstrmemdup(scratch_pool, arg1->data, arg1->len); 829251881Speter SVN_ERR(svn_wc__db_from_relpath(&src_abspath, db, wri_abspath, local_relpath, 830251881Speter scratch_pool, scratch_pool)); 831251881Speter local_relpath = apr_pstrmemdup(scratch_pool, arg1->next->data, 832251881Speter arg1->next->len); 833251881Speter SVN_ERR(svn_wc__db_from_relpath(&dst_abspath, db, wri_abspath, local_relpath, 834251881Speter scratch_pool, scratch_pool)); 835251881Speter 836251881Speter /* Use svn_io_file_move() instead of svn_io_file_rename() to allow cross 837251881Speter device copies. We should not fail in the workqueue. */ 838251881Speter 839251881Speter err = svn_io_file_move(src_abspath, dst_abspath, scratch_pool); 840251881Speter 841251881Speter /* If the source is not found, we assume the wq op is already handled */ 842251881Speter if (err && APR_STATUS_IS_ENOENT(err->apr_err)) 843251881Speter svn_error_clear(err); 844251881Speter else 845251881Speter SVN_ERR(err); 846251881Speter 847251881Speter return SVN_NO_ERROR; 848251881Speter} 849251881Speter 850251881Speter 851251881Spetersvn_error_t * 852251881Spetersvn_wc__wq_build_file_move(svn_skel_t **work_item, 853251881Speter svn_wc__db_t *db, 854251881Speter const char *wri_abspath, 855251881Speter const char *src_abspath, 856251881Speter const char *dst_abspath, 857251881Speter apr_pool_t *result_pool, 858251881Speter apr_pool_t *scratch_pool) 859251881Speter{ 860251881Speter svn_node_kind_t kind; 861251881Speter const char *local_relpath; 862251881Speter *work_item = svn_skel__make_empty_list(result_pool); 863251881Speter 864251881Speter SVN_ERR_ASSERT(svn_dirent_is_absolute(wri_abspath)); 865251881Speter SVN_ERR_ASSERT(svn_dirent_is_absolute(src_abspath)); 866251881Speter SVN_ERR_ASSERT(svn_dirent_is_absolute(dst_abspath)); 867251881Speter 868251881Speter /* File must exist */ 869251881Speter SVN_ERR(svn_io_check_path(src_abspath, &kind, result_pool)); 870251881Speter 871251881Speter if (kind == svn_node_none) 872251881Speter return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL, 873251881Speter _("'%s' not found"), 874251881Speter svn_dirent_local_style(src_abspath, 875251881Speter scratch_pool)); 876251881Speter 877251881Speter SVN_ERR(svn_wc__db_to_relpath(&local_relpath, db, wri_abspath, dst_abspath, 878251881Speter result_pool, scratch_pool)); 879251881Speter svn_skel__prepend_str(local_relpath, *work_item, result_pool); 880251881Speter 881251881Speter SVN_ERR(svn_wc__db_to_relpath(&local_relpath, db, wri_abspath, src_abspath, 882251881Speter result_pool, scratch_pool)); 883251881Speter svn_skel__prepend_str(local_relpath, *work_item, result_pool); 884251881Speter 885251881Speter svn_skel__prepend_str(OP_FILE_MOVE, *work_item, result_pool); 886251881Speter 887251881Speter return SVN_NO_ERROR; 888251881Speter} 889251881Speter 890251881Speter/* ------------------------------------------------------------------------ */ 891251881Speter 892251881Speter/* OP_FILE_COPY_TRANSLATED */ 893251881Speter 894251881Speter/* Process the OP_FILE_COPY_TRANSLATED work item WORK_ITEM. 895251881Speter * See run_file_copy_translated() which generates this work item. 896251881Speter * Implements (struct work_item_dispatch).func. */ 897251881Speterstatic svn_error_t * 898251881Speterrun_file_copy_translated(work_item_baton_t *wqb, 899251881Speter svn_wc__db_t *db, 900251881Speter const svn_skel_t *work_item, 901251881Speter const char *wri_abspath, 902251881Speter svn_cancel_func_t cancel_func, 903251881Speter void *cancel_baton, 904251881Speter apr_pool_t *scratch_pool) 905251881Speter{ 906251881Speter const svn_skel_t *arg1 = work_item->children->next; 907251881Speter const char *local_abspath, *src_abspath, *dst_abspath; 908251881Speter const char *local_relpath; 909251881Speter svn_subst_eol_style_t style; 910251881Speter const char *eol; 911251881Speter apr_hash_t *keywords; 912251881Speter svn_boolean_t special; 913251881Speter 914251881Speter local_relpath = apr_pstrmemdup(scratch_pool, arg1->data, arg1->len); 915251881Speter SVN_ERR(svn_wc__db_from_relpath(&local_abspath, db, wri_abspath, 916251881Speter local_relpath, scratch_pool, scratch_pool)); 917251881Speter 918251881Speter local_relpath = apr_pstrmemdup(scratch_pool, arg1->next->data, 919251881Speter arg1->next->len); 920251881Speter SVN_ERR(svn_wc__db_from_relpath(&src_abspath, db, wri_abspath, 921251881Speter local_relpath, scratch_pool, scratch_pool)); 922251881Speter 923251881Speter local_relpath = apr_pstrmemdup(scratch_pool, arg1->next->next->data, 924251881Speter arg1->next->next->len); 925251881Speter SVN_ERR(svn_wc__db_from_relpath(&dst_abspath, db, wri_abspath, 926251881Speter local_relpath, scratch_pool, scratch_pool)); 927251881Speter 928251881Speter SVN_ERR(svn_wc__get_translate_info(&style, &eol, 929251881Speter &keywords, 930251881Speter &special, 931251881Speter db, local_abspath, NULL, FALSE, 932251881Speter scratch_pool, scratch_pool)); 933251881Speter 934251881Speter SVN_ERR(svn_subst_copy_and_translate4(src_abspath, dst_abspath, 935251881Speter eol, TRUE /* repair */, 936251881Speter keywords, TRUE /* expand */, 937251881Speter special, 938251881Speter cancel_func, cancel_baton, 939251881Speter scratch_pool)); 940251881Speter return SVN_NO_ERROR; 941251881Speter} 942251881Speter 943251881Speter 944251881Spetersvn_error_t * 945251881Spetersvn_wc__wq_build_file_copy_translated(svn_skel_t **work_item, 946251881Speter svn_wc__db_t *db, 947251881Speter const char *local_abspath, 948251881Speter const char *src_abspath, 949251881Speter const char *dst_abspath, 950251881Speter apr_pool_t *result_pool, 951251881Speter apr_pool_t *scratch_pool) 952251881Speter{ 953251881Speter svn_node_kind_t kind; 954251881Speter const char *local_relpath; 955251881Speter 956251881Speter *work_item = svn_skel__make_empty_list(result_pool); 957251881Speter 958251881Speter SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath)); 959251881Speter SVN_ERR_ASSERT(svn_dirent_is_absolute(src_abspath)); 960251881Speter SVN_ERR_ASSERT(svn_dirent_is_absolute(dst_abspath)); 961251881Speter 962251881Speter /* File must exist */ 963251881Speter SVN_ERR(svn_io_check_path(src_abspath, &kind, result_pool)); 964251881Speter 965251881Speter if (kind == svn_node_none) 966251881Speter return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL, 967251881Speter _("'%s' not found"), 968251881Speter svn_dirent_local_style(src_abspath, 969251881Speter scratch_pool)); 970251881Speter 971251881Speter SVN_ERR(svn_wc__db_to_relpath(&local_relpath, db, local_abspath, dst_abspath, 972251881Speter result_pool, scratch_pool)); 973251881Speter svn_skel__prepend_str(local_relpath, *work_item, result_pool); 974251881Speter 975251881Speter SVN_ERR(svn_wc__db_to_relpath(&local_relpath, db, local_abspath, src_abspath, 976251881Speter result_pool, scratch_pool)); 977251881Speter svn_skel__prepend_str(local_relpath, *work_item, result_pool); 978251881Speter 979251881Speter SVN_ERR(svn_wc__db_to_relpath(&local_relpath, db, local_abspath, 980251881Speter local_abspath, result_pool, scratch_pool)); 981251881Speter svn_skel__prepend_str(local_relpath, *work_item, result_pool); 982251881Speter 983251881Speter svn_skel__prepend_str(OP_FILE_COPY_TRANSLATED, *work_item, result_pool); 984251881Speter 985251881Speter return SVN_NO_ERROR; 986251881Speter} 987251881Speter 988251881Speter/* ------------------------------------------------------------------------ */ 989251881Speter 990251881Speter/* OP_DIRECTORY_INSTALL */ 991251881Speter 992251881Speterstatic svn_error_t * 993251881Speterrun_dir_install(work_item_baton_t *wqb, 994251881Speter svn_wc__db_t *db, 995251881Speter const svn_skel_t *work_item, 996251881Speter const char *wri_abspath, 997251881Speter svn_cancel_func_t cancel_func, 998251881Speter void *cancel_baton, 999251881Speter apr_pool_t *scratch_pool) 1000251881Speter{ 1001251881Speter const svn_skel_t *arg1 = work_item->children->next; 1002251881Speter const char *local_relpath; 1003251881Speter const char *local_abspath; 1004251881Speter 1005251881Speter local_relpath = apr_pstrmemdup(scratch_pool, arg1->data, arg1->len); 1006251881Speter SVN_ERR(svn_wc__db_from_relpath(&local_abspath, db, wri_abspath, 1007251881Speter local_relpath, scratch_pool, scratch_pool)); 1008251881Speter 1009251881Speter SVN_ERR(svn_wc__ensure_directory(local_abspath, scratch_pool)); 1010251881Speter 1011251881Speter return SVN_NO_ERROR; 1012251881Speter} 1013251881Speter 1014251881Spetersvn_error_t * 1015251881Spetersvn_wc__wq_build_dir_install(svn_skel_t **work_item, 1016251881Speter svn_wc__db_t *db, 1017251881Speter const char *local_abspath, 1018299742Sdim apr_pool_t *result_pool, 1019299742Sdim apr_pool_t *scratch_pool) 1020251881Speter{ 1021251881Speter const char *local_relpath; 1022251881Speter 1023251881Speter *work_item = svn_skel__make_empty_list(result_pool); 1024251881Speter 1025251881Speter SVN_ERR(svn_wc__db_to_relpath(&local_relpath, db, local_abspath, 1026251881Speter local_abspath, result_pool, scratch_pool)); 1027251881Speter svn_skel__prepend_str(local_relpath, *work_item, result_pool); 1028251881Speter 1029251881Speter svn_skel__prepend_str(OP_DIRECTORY_INSTALL, *work_item, result_pool); 1030251881Speter 1031251881Speter return SVN_NO_ERROR; 1032251881Speter} 1033251881Speter 1034251881Speter 1035251881Speter/* ------------------------------------------------------------------------ */ 1036251881Speter 1037251881Speter/* OP_SYNC_FILE_FLAGS */ 1038251881Speter 1039251881Speter/* Process the OP_SYNC_FILE_FLAGS work item WORK_ITEM. 1040251881Speter * See svn_wc__wq_build_sync_file_flags() which generates this work item. 1041251881Speter * Implements (struct work_item_dispatch).func. */ 1042251881Speterstatic svn_error_t * 1043251881Speterrun_sync_file_flags(work_item_baton_t *wqb, 1044251881Speter svn_wc__db_t *db, 1045251881Speter const svn_skel_t *work_item, 1046251881Speter const char *wri_abspath, 1047251881Speter svn_cancel_func_t cancel_func, 1048251881Speter void *cancel_baton, 1049251881Speter apr_pool_t *scratch_pool) 1050251881Speter{ 1051251881Speter const svn_skel_t *arg1 = work_item->children->next; 1052251881Speter const char *local_relpath; 1053251881Speter const char *local_abspath; 1054251881Speter 1055251881Speter local_relpath = apr_pstrmemdup(scratch_pool, arg1->data, arg1->len); 1056251881Speter SVN_ERR(svn_wc__db_from_relpath(&local_abspath, db, wri_abspath, 1057251881Speter local_relpath, scratch_pool, scratch_pool)); 1058251881Speter 1059251881Speter return svn_error_trace(svn_wc__sync_flags_with_props(NULL, db, 1060251881Speter local_abspath, scratch_pool)); 1061251881Speter} 1062251881Speter 1063251881Speter 1064251881Spetersvn_error_t * 1065251881Spetersvn_wc__wq_build_sync_file_flags(svn_skel_t **work_item, 1066251881Speter svn_wc__db_t *db, 1067251881Speter const char *local_abspath, 1068251881Speter apr_pool_t *result_pool, 1069251881Speter apr_pool_t *scratch_pool) 1070251881Speter{ 1071251881Speter const char *local_relpath; 1072251881Speter *work_item = svn_skel__make_empty_list(result_pool); 1073251881Speter 1074251881Speter SVN_ERR(svn_wc__db_to_relpath(&local_relpath, db, local_abspath, 1075251881Speter local_abspath, result_pool, scratch_pool)); 1076251881Speter 1077251881Speter svn_skel__prepend_str(local_relpath, *work_item, result_pool); 1078251881Speter svn_skel__prepend_str(OP_SYNC_FILE_FLAGS, *work_item, result_pool); 1079251881Speter 1080251881Speter return SVN_NO_ERROR; 1081251881Speter} 1082251881Speter 1083251881Speter 1084251881Speter/* ------------------------------------------------------------------------ */ 1085251881Speter 1086251881Speter/* OP_PREJ_INSTALL */ 1087251881Speter 1088251881Speterstatic svn_error_t * 1089251881Speterrun_prej_install(work_item_baton_t *wqb, 1090251881Speter svn_wc__db_t *db, 1091251881Speter const svn_skel_t *work_item, 1092251881Speter const char *wri_abspath, 1093251881Speter svn_cancel_func_t cancel_func, 1094251881Speter void *cancel_baton, 1095251881Speter apr_pool_t *scratch_pool) 1096251881Speter{ 1097251881Speter const svn_skel_t *arg1 = work_item->children->next; 1098251881Speter const char *local_relpath; 1099251881Speter const char *local_abspath; 1100251881Speter svn_skel_t *conflicts; 1101251881Speter const svn_skel_t *prop_conflict_skel; 1102251881Speter const char *tmp_prejfile_abspath; 1103251881Speter const char *prejfile_abspath; 1104251881Speter 1105251881Speter local_relpath = apr_pstrmemdup(scratch_pool, arg1->data, arg1->len); 1106251881Speter SVN_ERR(svn_wc__db_from_relpath(&local_abspath, db, wri_abspath, 1107251881Speter local_relpath, scratch_pool, scratch_pool)); 1108251881Speter 1109299742Sdim SVN_ERR(svn_wc__db_read_conflict(&conflicts, NULL, NULL, db, local_abspath, 1110251881Speter scratch_pool, scratch_pool)); 1111251881Speter 1112251881Speter SVN_ERR(svn_wc__conflict_read_prop_conflict(&prejfile_abspath, 1113251881Speter NULL, NULL, NULL, NULL, 1114251881Speter db, local_abspath, conflicts, 1115251881Speter scratch_pool, scratch_pool)); 1116251881Speter 1117251881Speter if (arg1->next != NULL) 1118299742Sdim prop_conflict_skel = arg1->next; /* Before Subversion 1.9 */ 1119251881Speter else 1120299742Sdim prop_conflict_skel = NULL; /* Read from DB */ 1121251881Speter 1122251881Speter /* Construct a property reject file in the temporary area. */ 1123251881Speter SVN_ERR(svn_wc__create_prejfile(&tmp_prejfile_abspath, 1124251881Speter db, local_abspath, 1125251881Speter prop_conflict_skel, 1126299742Sdim cancel_func, cancel_baton, 1127251881Speter scratch_pool, scratch_pool)); 1128251881Speter 1129251881Speter /* ... and atomically move it into place. */ 1130251881Speter SVN_ERR(svn_io_file_rename(tmp_prejfile_abspath, 1131251881Speter prejfile_abspath, 1132251881Speter scratch_pool)); 1133251881Speter 1134251881Speter return SVN_NO_ERROR; 1135251881Speter} 1136251881Speter 1137251881Speter 1138251881Spetersvn_error_t * 1139251881Spetersvn_wc__wq_build_prej_install(svn_skel_t **work_item, 1140251881Speter svn_wc__db_t *db, 1141251881Speter const char *local_abspath, 1142299742Sdim /*svn_skel_t *conflict_skel,*/ 1143251881Speter apr_pool_t *result_pool, 1144251881Speter apr_pool_t *scratch_pool) 1145251881Speter{ 1146251881Speter const char *local_relpath; 1147251881Speter *work_item = svn_skel__make_empty_list(result_pool); 1148251881Speter 1149251881Speter SVN_ERR(svn_wc__db_to_relpath(&local_relpath, db, local_abspath, 1150251881Speter local_abspath, result_pool, scratch_pool)); 1151251881Speter 1152299742Sdim /* ### In Subversion 1.7 and 1.8 we created a legacy property conflict skel 1153299742Sdim here: 1154299742Sdim if (conflict_skel != NULL) 1155299742Sdim svn_skel__prepend(conflict_skel, *work_item); 1156299742Sdim */ 1157251881Speter svn_skel__prepend_str(local_relpath, *work_item, result_pool); 1158251881Speter svn_skel__prepend_str(OP_PREJ_INSTALL, *work_item, result_pool); 1159251881Speter 1160251881Speter return SVN_NO_ERROR; 1161251881Speter} 1162251881Speter 1163251881Speter 1164251881Speter/* ------------------------------------------------------------------------ */ 1165251881Speter 1166251881Speter/* OP_RECORD_FILEINFO */ 1167251881Speter 1168251881Speter 1169251881Speterstatic svn_error_t * 1170251881Speterrun_record_fileinfo(work_item_baton_t *wqb, 1171251881Speter svn_wc__db_t *db, 1172251881Speter const svn_skel_t *work_item, 1173251881Speter const char *wri_abspath, 1174251881Speter svn_cancel_func_t cancel_func, 1175251881Speter void *cancel_baton, 1176251881Speter apr_pool_t *scratch_pool) 1177251881Speter{ 1178251881Speter const svn_skel_t *arg1 = work_item->children->next; 1179251881Speter const char *local_relpath; 1180251881Speter const char *local_abspath; 1181251881Speter apr_time_t set_time = 0; 1182251881Speter 1183251881Speter local_relpath = apr_pstrmemdup(scratch_pool, arg1->data, arg1->len); 1184251881Speter 1185251881Speter SVN_ERR(svn_wc__db_from_relpath(&local_abspath, db, wri_abspath, 1186251881Speter local_relpath, scratch_pool, scratch_pool)); 1187251881Speter 1188251881Speter if (arg1->next) 1189251881Speter { 1190251881Speter apr_int64_t val; 1191251881Speter 1192251881Speter SVN_ERR(svn_skel__parse_int(&val, arg1->next, scratch_pool)); 1193251881Speter set_time = (apr_time_t)val; 1194251881Speter } 1195251881Speter 1196251881Speter if (set_time != 0) 1197251881Speter { 1198251881Speter svn_node_kind_t kind; 1199251881Speter svn_boolean_t is_special; 1200251881Speter 1201251881Speter /* Do not set the timestamp on special files. */ 1202251881Speter SVN_ERR(svn_io_check_special_path(local_abspath, &kind, &is_special, 1203251881Speter scratch_pool)); 1204251881Speter 1205251881Speter /* Don't set affected time when local_abspath does not exist or is 1206251881Speter a special file */ 1207251881Speter if (kind == svn_node_file && !is_special) 1208251881Speter SVN_ERR(svn_io_set_file_affected_time(set_time, local_abspath, 1209251881Speter scratch_pool)); 1210251881Speter 1211251881Speter /* Note that we can't use the value we get here for recording as the 1212251881Speter filesystem might have a different timestamp granularity */ 1213251881Speter } 1214251881Speter 1215251881Speter 1216251881Speter return svn_error_trace(get_and_record_fileinfo(wqb, local_abspath, 1217251881Speter TRUE /* ignore_enoent */, 1218251881Speter scratch_pool)); 1219251881Speter} 1220251881Speter 1221251881Speter/* ------------------------------------------------------------------------ */ 1222251881Speter 1223251881Speter/* OP_TMP_SET_TEXT_CONFLICT_MARKERS */ 1224251881Speter 1225251881Speter 1226251881Speterstatic svn_error_t * 1227251881Speterrun_set_text_conflict_markers(work_item_baton_t *wqb, 1228251881Speter svn_wc__db_t *db, 1229251881Speter const svn_skel_t *work_item, 1230251881Speter const char *wri_abspath, 1231251881Speter svn_cancel_func_t cancel_func, 1232251881Speter void *cancel_baton, 1233251881Speter apr_pool_t *scratch_pool) 1234251881Speter{ 1235251881Speter const svn_skel_t *arg = work_item->children->next; 1236251881Speter const char *local_relpath; 1237251881Speter const char *local_abspath; 1238251881Speter const char *old_abspath = NULL; 1239251881Speter const char *new_abspath = NULL; 1240251881Speter const char *wrk_abspath = NULL; 1241251881Speter 1242251881Speter local_relpath = apr_pstrmemdup(scratch_pool, arg->data, arg->len); 1243251881Speter SVN_ERR(svn_wc__db_from_relpath(&local_abspath, db, wri_abspath, 1244251881Speter local_relpath, scratch_pool, scratch_pool)); 1245251881Speter 1246251881Speter arg = arg->next; 1247251881Speter local_relpath = arg->len ? apr_pstrmemdup(scratch_pool, arg->data, arg->len) 1248251881Speter : NULL; 1249251881Speter 1250251881Speter if (local_relpath) 1251251881Speter { 1252251881Speter SVN_ERR(svn_wc__db_from_relpath(&old_abspath, db, wri_abspath, 1253251881Speter local_relpath, 1254251881Speter scratch_pool, scratch_pool)); 1255251881Speter } 1256251881Speter 1257251881Speter arg = arg->next; 1258251881Speter local_relpath = arg->len ? apr_pstrmemdup(scratch_pool, arg->data, arg->len) 1259251881Speter : NULL; 1260251881Speter if (local_relpath) 1261251881Speter { 1262251881Speter SVN_ERR(svn_wc__db_from_relpath(&new_abspath, db, wri_abspath, 1263251881Speter local_relpath, 1264251881Speter scratch_pool, scratch_pool)); 1265251881Speter } 1266251881Speter 1267251881Speter arg = arg->next; 1268251881Speter local_relpath = arg->len ? apr_pstrmemdup(scratch_pool, arg->data, arg->len) 1269251881Speter : NULL; 1270251881Speter 1271251881Speter if (local_relpath) 1272251881Speter { 1273251881Speter SVN_ERR(svn_wc__db_from_relpath(&wrk_abspath, db, wri_abspath, 1274251881Speter local_relpath, 1275251881Speter scratch_pool, scratch_pool)); 1276251881Speter } 1277251881Speter 1278251881Speter /* Upgrade scenario: We have a workqueue item that describes how to install a 1279251881Speter non skel conflict. Fetch all the information we can to create a new style 1280251881Speter conflict. */ 1281251881Speter /* ### Before format 30 this is/was a common code path as we didn't install 1282251881Speter ### the conflict directly in the db. It just calls the wc_db code 1283251881Speter ### to set the right fields. */ 1284251881Speter 1285251881Speter { 1286251881Speter /* Check if we should combine with a property conflict... */ 1287251881Speter svn_skel_t *conflicts; 1288251881Speter 1289299742Sdim SVN_ERR(svn_wc__db_read_conflict(&conflicts, NULL, NULL, db, local_abspath, 1290251881Speter scratch_pool, scratch_pool)); 1291251881Speter 1292251881Speter if (! conflicts) 1293251881Speter { 1294251881Speter /* No conflict exists, create a basic skel */ 1295251881Speter conflicts = svn_wc__conflict_skel_create(scratch_pool); 1296251881Speter 1297251881Speter SVN_ERR(svn_wc__conflict_skel_set_op_update(conflicts, NULL, NULL, 1298251881Speter scratch_pool, 1299251881Speter scratch_pool)); 1300251881Speter } 1301251881Speter 1302251881Speter /* Add the text conflict to the existing onflict */ 1303251881Speter SVN_ERR(svn_wc__conflict_skel_add_text_conflict(conflicts, db, 1304251881Speter local_abspath, 1305251881Speter wrk_abspath, 1306251881Speter old_abspath, 1307251881Speter new_abspath, 1308251881Speter scratch_pool, 1309251881Speter scratch_pool)); 1310251881Speter 1311251881Speter SVN_ERR(svn_wc__db_op_mark_conflict(db, local_abspath, conflicts, 1312251881Speter NULL, scratch_pool)); 1313251881Speter } 1314251881Speter return SVN_NO_ERROR; 1315251881Speter} 1316251881Speter 1317251881Speter/* ------------------------------------------------------------------------ */ 1318251881Speter 1319251881Speter/* OP_TMP_SET_PROPERTY_CONFLICT_MARKER */ 1320251881Speter 1321251881Speterstatic svn_error_t * 1322251881Speterrun_set_property_conflict_marker(work_item_baton_t *wqb, 1323251881Speter svn_wc__db_t *db, 1324251881Speter const svn_skel_t *work_item, 1325251881Speter const char *wri_abspath, 1326251881Speter svn_cancel_func_t cancel_func, 1327251881Speter void *cancel_baton, 1328251881Speter apr_pool_t *scratch_pool) 1329251881Speter{ 1330251881Speter const svn_skel_t *arg = work_item->children->next; 1331251881Speter const char *local_relpath; 1332251881Speter const char *local_abspath; 1333251881Speter const char *prej_abspath = NULL; 1334251881Speter 1335251881Speter local_relpath = apr_pstrmemdup(scratch_pool, arg->data, arg->len); 1336251881Speter 1337251881Speter SVN_ERR(svn_wc__db_from_relpath(&local_abspath, db, wri_abspath, 1338251881Speter local_relpath, scratch_pool, scratch_pool)); 1339251881Speter 1340251881Speter 1341251881Speter arg = arg->next; 1342251881Speter local_relpath = arg->len ? apr_pstrmemdup(scratch_pool, arg->data, arg->len) 1343251881Speter : NULL; 1344251881Speter 1345251881Speter if (local_relpath) 1346251881Speter SVN_ERR(svn_wc__db_from_relpath(&prej_abspath, db, wri_abspath, 1347251881Speter local_relpath, 1348251881Speter scratch_pool, scratch_pool)); 1349251881Speter 1350251881Speter { 1351251881Speter /* Check if we should combine with a text conflict... */ 1352251881Speter svn_skel_t *conflicts; 1353251881Speter apr_hash_t *prop_names; 1354251881Speter 1355299742Sdim SVN_ERR(svn_wc__db_read_conflict(&conflicts, NULL, NULL, 1356299742Sdim db, local_abspath, 1357251881Speter scratch_pool, scratch_pool)); 1358251881Speter 1359251881Speter if (! conflicts) 1360251881Speter { 1361251881Speter /* No conflict exists, create a basic skel */ 1362251881Speter conflicts = svn_wc__conflict_skel_create(scratch_pool); 1363251881Speter 1364251881Speter SVN_ERR(svn_wc__conflict_skel_set_op_update(conflicts, NULL, NULL, 1365251881Speter scratch_pool, 1366251881Speter scratch_pool)); 1367251881Speter } 1368251881Speter 1369251881Speter prop_names = apr_hash_make(scratch_pool); 1370251881Speter SVN_ERR(svn_wc__conflict_skel_add_prop_conflict(conflicts, db, 1371251881Speter local_abspath, 1372251881Speter prej_abspath, 1373251881Speter NULL, NULL, NULL, 1374251881Speter prop_names, 1375251881Speter scratch_pool, 1376251881Speter scratch_pool)); 1377251881Speter 1378251881Speter SVN_ERR(svn_wc__db_op_mark_conflict(db, local_abspath, conflicts, 1379251881Speter NULL, scratch_pool)); 1380251881Speter } 1381251881Speter return SVN_NO_ERROR; 1382251881Speter} 1383251881Speter 1384251881Speter/* ------------------------------------------------------------------------ */ 1385251881Speter 1386251881Speterstatic const struct work_item_dispatch dispatch_table[] = { 1387251881Speter { OP_FILE_COMMIT, run_file_commit }, 1388251881Speter { OP_FILE_INSTALL, run_file_install }, 1389251881Speter { OP_FILE_REMOVE, run_file_remove }, 1390251881Speter { OP_FILE_MOVE, run_file_move }, 1391251881Speter { OP_FILE_COPY_TRANSLATED, run_file_copy_translated }, 1392251881Speter { OP_SYNC_FILE_FLAGS, run_sync_file_flags }, 1393251881Speter { OP_PREJ_INSTALL, run_prej_install }, 1394251881Speter { OP_DIRECTORY_REMOVE, run_dir_remove }, 1395251881Speter { OP_DIRECTORY_INSTALL, run_dir_install }, 1396251881Speter 1397251881Speter /* Upgrade steps */ 1398251881Speter { OP_POSTUPGRADE, run_postupgrade }, 1399251881Speter 1400251881Speter /* Legacy workqueue items. No longer created */ 1401251881Speter { OP_BASE_REMOVE, run_base_remove }, 1402251881Speter { OP_RECORD_FILEINFO, run_record_fileinfo }, 1403251881Speter { OP_TMP_SET_TEXT_CONFLICT_MARKERS, run_set_text_conflict_markers }, 1404251881Speter { OP_TMP_SET_PROPERTY_CONFLICT_MARKER, run_set_property_conflict_marker }, 1405251881Speter 1406251881Speter /* Sentinel. */ 1407251881Speter { NULL } 1408251881Speter}; 1409251881Speter 1410251881Speterstruct work_item_baton_t 1411251881Speter{ 1412251881Speter apr_pool_t *result_pool; /* Pool to allocate result in */ 1413251881Speter 1414251881Speter svn_boolean_t used; /* needs reset */ 1415251881Speter 1416251881Speter apr_hash_t *record_map; /* const char * -> svn_io_dirent2_t map */ 1417251881Speter}; 1418251881Speter 1419251881Speter 1420251881Speterstatic svn_error_t * 1421251881Speterdispatch_work_item(work_item_baton_t *wqb, 1422251881Speter svn_wc__db_t *db, 1423251881Speter const char *wri_abspath, 1424251881Speter const svn_skel_t *work_item, 1425251881Speter svn_cancel_func_t cancel_func, 1426251881Speter void *cancel_baton, 1427251881Speter apr_pool_t *scratch_pool) 1428251881Speter{ 1429251881Speter const struct work_item_dispatch *scan; 1430251881Speter 1431251881Speter /* Scan the dispatch table for a function to handle this work item. */ 1432251881Speter for (scan = &dispatch_table[0]; scan->name != NULL; ++scan) 1433251881Speter { 1434251881Speter if (svn_skel__matches_atom(work_item->children, scan->name)) 1435251881Speter { 1436251881Speter 1437251881Speter#ifdef SVN_DEBUG_WORK_QUEUE 1438251881Speter SVN_DBG(("dispatch: operation='%s'\n", scan->name)); 1439251881Speter#endif 1440251881Speter SVN_ERR((*scan->func)(wqb, db, work_item, wri_abspath, 1441251881Speter cancel_func, cancel_baton, 1442251881Speter scratch_pool)); 1443251881Speter 1444251881Speter#ifdef SVN_RUN_WORK_QUEUE_TWICE 1445251881Speter#ifdef SVN_DEBUG_WORK_QUEUE 1446251881Speter SVN_DBG(("dispatch: operation='%s'\n", scan->name)); 1447251881Speter#endif 1448251881Speter /* Being able to run every workqueue item twice is one 1449251881Speter requirement for workqueues to be restartable. */ 1450251881Speter SVN_ERR((*scan->func)(db, work_item, wri_abspath, 1451251881Speter cancel_func, cancel_baton, 1452251881Speter scratch_pool)); 1453251881Speter#endif 1454251881Speter 1455251881Speter break; 1456251881Speter } 1457251881Speter } 1458251881Speter 1459251881Speter if (scan->name == NULL) 1460251881Speter { 1461251881Speter /* We should know about ALL possible work items here. If we do not, 1462251881Speter then something is wrong. Most likely, some kind of format/code 1463251881Speter skew. There is nothing more we can do. Erasing or ignoring this 1464251881Speter work item could leave the WC in an even more broken state. 1465251881Speter 1466251881Speter Contrary to issue #1581, we cannot simply remove work items and 1467251881Speter continue, so bail out with an error. */ 1468251881Speter return svn_error_createf(SVN_ERR_WC_BAD_ADM_LOG, NULL, 1469251881Speter _("Unrecognized work item in the queue")); 1470251881Speter } 1471251881Speter 1472251881Speter return SVN_NO_ERROR; 1473251881Speter} 1474251881Speter 1475251881Speter 1476251881Spetersvn_error_t * 1477251881Spetersvn_wc__wq_run(svn_wc__db_t *db, 1478251881Speter const char *wri_abspath, 1479251881Speter svn_cancel_func_t cancel_func, 1480251881Speter void *cancel_baton, 1481251881Speter apr_pool_t *scratch_pool) 1482251881Speter{ 1483251881Speter apr_pool_t *iterpool = svn_pool_create(scratch_pool); 1484251881Speter apr_uint64_t last_id = 0; 1485251881Speter work_item_baton_t wib = { 0 }; 1486251881Speter wib.result_pool = svn_pool_create(scratch_pool); 1487251881Speter 1488251881Speter#ifdef SVN_DEBUG_WORK_QUEUE 1489251881Speter SVN_DBG(("wq_run: wri='%s'\n", wri_abspath)); 1490251881Speter { 1491251881Speter static int count = 0; 1492251881Speter const char *count_env_var = getenv("SVN_DEBUG_WORK_QUEUE"); 1493299742Sdim int count_env_val; 1494251881Speter 1495299742Sdim SVN_ERR(svn_cstring_atoi(&count_env_val, count_env_var)); 1496299742Sdim 1497299742Sdim if (count_env_var && ++count == count_env_val) 1498251881Speter return svn_error_create(SVN_ERR_CANCELLED, NULL, "fake cancel"); 1499251881Speter } 1500251881Speter#endif 1501251881Speter 1502251881Speter while (TRUE) 1503251881Speter { 1504251881Speter apr_uint64_t id; 1505251881Speter svn_skel_t *work_item; 1506251881Speter svn_error_t *err; 1507251881Speter 1508251881Speter svn_pool_clear(iterpool); 1509251881Speter 1510251881Speter if (! wib.used) 1511251881Speter { 1512251881Speter /* Make sure to do this *early* in the loop iteration. There may 1513251881Speter be a LAST_ID that needs to be marked as completed, *before* we 1514251881Speter start worrying about anything else. */ 1515251881Speter SVN_ERR(svn_wc__db_wq_fetch_next(&id, &work_item, db, wri_abspath, 1516251881Speter last_id, iterpool, iterpool)); 1517251881Speter } 1518251881Speter else 1519251881Speter { 1520251881Speter /* Make sure to do this *early* in the loop iteration. There may 1521251881Speter be a LAST_ID that needs to be marked as completed, *before* we 1522251881Speter start worrying about anything else. */ 1523251881Speter SVN_ERR(svn_wc__db_wq_record_and_fetch_next(&id, &work_item, 1524251881Speter db, wri_abspath, 1525251881Speter last_id, wib.record_map, 1526251881Speter iterpool, 1527251881Speter wib.result_pool)); 1528251881Speter 1529251881Speter svn_pool_clear(wib.result_pool); 1530251881Speter wib.record_map = NULL; 1531251881Speter wib.used = FALSE; 1532251881Speter } 1533251881Speter 1534251881Speter /* Stop work queue processing, if requested. A future 'svn cleanup' 1535251881Speter should be able to continue the processing. Note that we may 1536251881Speter have WORK_ITEM, but we'll just skip its processing for now. */ 1537251881Speter if (cancel_func) 1538251881Speter SVN_ERR(cancel_func(cancel_baton)); 1539251881Speter 1540251881Speter /* If we have a WORK_ITEM, then process the sucker. Otherwise, 1541251881Speter we're done. */ 1542251881Speter if (work_item == NULL) 1543251881Speter break; 1544251881Speter 1545251881Speter err = dispatch_work_item(&wib, db, wri_abspath, work_item, 1546251881Speter cancel_func, cancel_baton, iterpool); 1547251881Speter if (err) 1548251881Speter { 1549251881Speter const char *skel = svn_skel__unparse(work_item, scratch_pool)->data; 1550251881Speter 1551251881Speter return svn_error_createf(SVN_ERR_WC_BAD_ADM_LOG, err, 1552251881Speter _("Failed to run the WC DB work queue " 1553251881Speter "associated with '%s', work item %d %s"), 1554251881Speter svn_dirent_local_style(wri_abspath, 1555251881Speter scratch_pool), 1556251881Speter (int)id, skel); 1557251881Speter } 1558251881Speter 1559251881Speter /* The work item finished without error. Mark it completed 1560251881Speter in the next loop. */ 1561251881Speter last_id = id; 1562251881Speter } 1563251881Speter 1564251881Speter svn_pool_destroy(iterpool); 1565251881Speter return SVN_NO_ERROR; 1566251881Speter} 1567251881Speter 1568251881Speter 1569251881Spetersvn_skel_t * 1570251881Spetersvn_wc__wq_merge(svn_skel_t *work_item1, 1571251881Speter svn_skel_t *work_item2, 1572251881Speter apr_pool_t *result_pool) 1573251881Speter{ 1574251881Speter /* If either argument is NULL, then just return the other. */ 1575251881Speter if (work_item1 == NULL) 1576251881Speter return work_item2; 1577251881Speter if (work_item2 == NULL) 1578251881Speter return work_item1; 1579251881Speter 1580251881Speter /* We have two items. Figure out how to join them. */ 1581251881Speter if (SVN_WC__SINGLE_WORK_ITEM(work_item1)) 1582251881Speter { 1583251881Speter if (SVN_WC__SINGLE_WORK_ITEM(work_item2)) 1584251881Speter { 1585251881Speter /* Both are singular work items. Construct a list, then put 1586251881Speter both work items into it (in the proper order). */ 1587251881Speter 1588251881Speter svn_skel_t *result = svn_skel__make_empty_list(result_pool); 1589251881Speter 1590251881Speter svn_skel__prepend(work_item2, result); 1591251881Speter svn_skel__prepend(work_item1, result); 1592251881Speter return result; 1593251881Speter } 1594251881Speter 1595251881Speter /* WORK_ITEM2 is a list of work items. We can simply shove WORK_ITEM1 1596251881Speter in the front to keep the ordering. */ 1597251881Speter svn_skel__prepend(work_item1, work_item2); 1598251881Speter return work_item2; 1599251881Speter } 1600251881Speter /* WORK_ITEM1 is a list of work items. */ 1601251881Speter 1602251881Speter if (SVN_WC__SINGLE_WORK_ITEM(work_item2)) 1603251881Speter { 1604251881Speter /* Put WORK_ITEM2 onto the end of the WORK_ITEM1 list. */ 1605251881Speter svn_skel__append(work_item1, work_item2); 1606251881Speter return work_item1; 1607251881Speter } 1608251881Speter 1609251881Speter /* We have two lists of work items. We need to chain all of the work 1610251881Speter items into one big list. We will leave behind the WORK_ITEM2 skel, 1611251881Speter as we only want its children. */ 1612251881Speter svn_skel__append(work_item1, work_item2->children); 1613251881Speter return work_item1; 1614251881Speter} 1615251881Speter 1616251881Speter 1617251881Speterstatic svn_error_t * 1618251881Speterget_and_record_fileinfo(work_item_baton_t *wqb, 1619251881Speter const char *local_abspath, 1620251881Speter svn_boolean_t ignore_enoent, 1621251881Speter apr_pool_t *scratch_pool) 1622251881Speter{ 1623251881Speter const svn_io_dirent2_t *dirent; 1624251881Speter 1625251881Speter SVN_ERR(svn_io_stat_dirent2(&dirent, local_abspath, FALSE, ignore_enoent, 1626251881Speter wqb->result_pool, scratch_pool)); 1627251881Speter 1628251881Speter if (dirent->kind != svn_node_file) 1629251881Speter return SVN_NO_ERROR; 1630251881Speter 1631251881Speter wqb->used = TRUE; 1632251881Speter 1633251881Speter if (! wqb->record_map) 1634251881Speter wqb->record_map = apr_hash_make(wqb->result_pool); 1635251881Speter 1636251881Speter svn_hash_sets(wqb->record_map, apr_pstrdup(wqb->result_pool, local_abspath), 1637251881Speter dirent); 1638251881Speter 1639251881Speter return SVN_NO_ERROR; 1640251881Speter} 1641