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 26251881Speter#include "svn_types.h" 27251881Speter#include "svn_pools.h" 28251881Speter#include "svn_dirent_uri.h" 29251881Speter#include "svn_subst.h" 30251881Speter#include "svn_hash.h" 31251881Speter#include "svn_io.h" 32251881Speter 33251881Speter#include "wc.h" 34251881Speter#include "wc_db.h" 35251881Speter#include "workqueue.h" 36251881Speter#include "adm_files.h" 37251881Speter#include "conflicts.h" 38251881Speter#include "translate.h" 39251881Speter 40251881Speter#include "svn_private_config.h" 41251881Speter#include "private/svn_skel.h" 42251881Speter 43251881Speter 44251881Speter/* Workqueue operation names. */ 45251881Speter#define OP_FILE_COMMIT "file-commit" 46251881Speter#define OP_FILE_INSTALL "file-install" 47251881Speter#define OP_FILE_REMOVE "file-remove" 48251881Speter#define OP_FILE_MOVE "file-move" 49251881Speter#define OP_FILE_COPY_TRANSLATED "file-translate" 50251881Speter#define OP_SYNC_FILE_FLAGS "sync-file-flags" 51251881Speter#define OP_PREJ_INSTALL "prej-install" 52251881Speter#define OP_DIRECTORY_REMOVE "dir-remove" 53251881Speter#define OP_DIRECTORY_INSTALL "dir-install" 54251881Speter 55251881Speter#define OP_POSTUPGRADE "postupgrade" 56251881Speter 57251881Speter/* Legacy items */ 58251881Speter#define OP_BASE_REMOVE "base-remove" 59251881Speter#define OP_RECORD_FILEINFO "record-fileinfo" 60251881Speter#define OP_TMP_SET_TEXT_CONFLICT_MARKERS "tmp-set-text-conflict-markers" 61251881Speter#define OP_TMP_SET_PROPERTY_CONFLICT_MARKER "tmp-set-property-conflict-marker" 62251881Speter 63251881Speter/* For work queue debugging. Generates output about its operation. */ 64251881Speter/* #define SVN_DEBUG_WORK_QUEUE */ 65251881Speter 66251881Spetertypedef struct work_item_baton_t work_item_baton_t; 67251881Speter 68251881Speterstruct work_item_dispatch { 69251881Speter const char *name; 70251881Speter svn_error_t *(*func)(work_item_baton_t *wqb, 71251881Speter svn_wc__db_t *db, 72251881Speter const svn_skel_t *work_item, 73251881Speter const char *wri_abspath, 74251881Speter svn_cancel_func_t cancel_func, 75251881Speter void *cancel_baton, 76251881Speter apr_pool_t *scratch_pool); 77251881Speter}; 78251881Speter 79251881Speter/* Forward definition */ 80251881Speterstatic svn_error_t * 81251881Speterget_and_record_fileinfo(work_item_baton_t *wqb, 82251881Speter const char *local_abspath, 83251881Speter svn_boolean_t ignore_enoent, 84251881Speter apr_pool_t *scratch_pool); 85251881Speter 86251881Speter/* ------------------------------------------------------------------------ */ 87251881Speter/* OP_REMOVE_BASE */ 88251881Speter 89251881Speter/* Removes a BASE_NODE and all it's data, leaving any adds and copies as is. 90251881Speter Do this as a depth first traversal to make sure than any parent still exists 91251881Speter on error conditions. 92251881Speter */ 93251881Speter 94251881Speter/* Process the OP_REMOVE_BASE work item WORK_ITEM. 95251881Speter * See svn_wc__wq_build_remove_base() which generates this work item. 96251881Speter * Implements (struct work_item_dispatch).func. */ 97251881Speterstatic svn_error_t * 98251881Speterrun_base_remove(work_item_baton_t *wqb, 99251881Speter svn_wc__db_t *db, 100251881Speter const svn_skel_t *work_item, 101251881Speter const char *wri_abspath, 102251881Speter svn_cancel_func_t cancel_func, 103251881Speter void *cancel_baton, 104251881Speter apr_pool_t *scratch_pool) 105251881Speter{ 106251881Speter const svn_skel_t *arg1 = work_item->children->next; 107251881Speter const char *local_relpath; 108251881Speter const char *local_abspath; 109251881Speter svn_revnum_t not_present_rev = SVN_INVALID_REVNUM; 110251881Speter apr_int64_t val; 111251881Speter 112251881Speter local_relpath = apr_pstrmemdup(scratch_pool, arg1->data, arg1->len); 113251881Speter SVN_ERR(svn_wc__db_from_relpath(&local_abspath, db, wri_abspath, 114251881Speter local_relpath, scratch_pool, scratch_pool)); 115251881Speter SVN_ERR(svn_skel__parse_int(&val, arg1->next, scratch_pool)); 116251881Speter 117251881Speter if (arg1->next->next) 118251881Speter { 119251881Speter not_present_rev = (svn_revnum_t)val; 120251881Speter 121251881Speter SVN_ERR(svn_skel__parse_int(&val, arg1->next->next, scratch_pool)); 122251881Speter } 123251881Speter else 124251881Speter { 125251881Speter svn_boolean_t keep_not_present; 126251881Speter 127251881Speter SVN_ERR_ASSERT(SVN_WC__VERSION <= 28); /* Case unused in later versions*/ 128251881Speter 129251881Speter keep_not_present = (val != 0); 130251881Speter 131251881Speter if (keep_not_present) 132251881Speter { 133251881Speter SVN_ERR(svn_wc__db_base_get_info(NULL, NULL, 134251881Speter ¬_present_rev, NULL, 135251881Speter NULL, NULL, NULL, 136251881Speter NULL, NULL, NULL, NULL, NULL, NULL, 137251881Speter NULL, NULL, NULL, 138251881Speter db, local_abspath, 139251881Speter scratch_pool, scratch_pool)); 140251881Speter } 141251881Speter } 142251881Speter 143251881Speter SVN_ERR(svn_wc__db_base_remove(db, local_abspath, 144251881Speter FALSE /* keep_as_working */, 145251881Speter TRUE /* queue_deletes */, 146253734Speter FALSE /* remove_locks */, 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 const char *adm_path; 399251881Speter const char *temp_path; 400251881Speter svn_error_t *err; 401251881Speter 402251881Speter err = svn_wc__wipe_postupgrade(wri_abspath, FALSE, 403251881Speter cancel_func, cancel_baton, scratch_pool); 404251881Speter if (err && err->apr_err == SVN_ERR_ENTRY_NOT_FOUND) 405251881Speter /* No entry, this can happen when the wq item is rerun. */ 406251881Speter svn_error_clear(err); 407251881Speter else 408251881Speter SVN_ERR(err); 409251881Speter 410251881Speter SVN_ERR(svn_wc__db_get_wcroot(&wcroot_abspath, db, wri_abspath, 411251881Speter scratch_pool, scratch_pool)); 412251881Speter 413251881Speter adm_path = svn_wc__adm_child(wcroot_abspath, NULL, scratch_pool); 414251881Speter entries_path = svn_wc__adm_child(wcroot_abspath, SVN_WC__ADM_ENTRIES, 415251881Speter scratch_pool); 416251881Speter format_path = svn_wc__adm_child(wcroot_abspath, SVN_WC__ADM_FORMAT, 417251881Speter scratch_pool); 418251881Speter 419251881Speter /* Write the 'format' and 'entries' files. 420251881Speter 421251881Speter ### The order may matter for some sufficiently old clients.. but 422251881Speter ### this code only runs during upgrade after the files had been 423251881Speter ### removed earlier during the upgrade. */ 424251881Speter SVN_ERR(svn_io_write_unique(&temp_path, adm_path, SVN_WC__NON_ENTRIES_STRING, 425251881Speter sizeof(SVN_WC__NON_ENTRIES_STRING) - 1, 426251881Speter svn_io_file_del_none, scratch_pool)); 427251881Speter SVN_ERR(svn_io_file_rename(temp_path, format_path, scratch_pool)); 428251881Speter 429251881Speter SVN_ERR(svn_io_write_unique(&temp_path, adm_path, SVN_WC__NON_ENTRIES_STRING, 430251881Speter sizeof(SVN_WC__NON_ENTRIES_STRING) - 1, 431251881Speter svn_io_file_del_none, scratch_pool)); 432251881Speter SVN_ERR(svn_io_file_rename(temp_path, entries_path, scratch_pool)); 433251881Speter 434251881Speter return SVN_NO_ERROR; 435251881Speter} 436251881Speter 437251881Spetersvn_error_t * 438251881Spetersvn_wc__wq_build_postupgrade(svn_skel_t **work_item, 439251881Speter apr_pool_t *result_pool) 440251881Speter{ 441251881Speter *work_item = svn_skel__make_empty_list(result_pool); 442251881Speter 443251881Speter svn_skel__prepend_str(OP_POSTUPGRADE, *work_item, result_pool); 444251881Speter 445251881Speter return SVN_NO_ERROR; 446251881Speter} 447251881Speter 448251881Speter/* ------------------------------------------------------------------------ */ 449251881Speter 450251881Speter/* OP_FILE_INSTALL */ 451251881Speter 452251881Speter/* Process the OP_FILE_INSTALL work item WORK_ITEM. 453251881Speter * See svn_wc__wq_build_file_install() which generates this work item. 454251881Speter * Implements (struct work_item_dispatch).func. */ 455251881Speterstatic svn_error_t * 456251881Speterrun_file_install(work_item_baton_t *wqb, 457251881Speter svn_wc__db_t *db, 458251881Speter const svn_skel_t *work_item, 459251881Speter const char *wri_abspath, 460251881Speter svn_cancel_func_t cancel_func, 461251881Speter void *cancel_baton, 462251881Speter apr_pool_t *scratch_pool) 463251881Speter{ 464251881Speter const svn_skel_t *arg1 = work_item->children->next; 465251881Speter const svn_skel_t *arg4 = arg1->next->next->next; 466251881Speter const char *local_relpath; 467251881Speter const char *local_abspath; 468251881Speter svn_boolean_t use_commit_times; 469251881Speter svn_boolean_t record_fileinfo; 470251881Speter svn_boolean_t special; 471251881Speter svn_stream_t *src_stream; 472251881Speter svn_subst_eol_style_t style; 473251881Speter const char *eol; 474251881Speter apr_hash_t *keywords; 475251881Speter const char *temp_dir_abspath; 476251881Speter svn_stream_t *dst_stream; 477251881Speter const char *dst_abspath; 478251881Speter apr_int64_t val; 479251881Speter const char *wcroot_abspath; 480251881Speter const char *source_abspath; 481251881Speter const svn_checksum_t *checksum; 482251881Speter apr_hash_t *props; 483251881Speter apr_time_t changed_date; 484251881Speter 485251881Speter local_relpath = apr_pstrmemdup(scratch_pool, arg1->data, arg1->len); 486251881Speter SVN_ERR(svn_wc__db_from_relpath(&local_abspath, db, wri_abspath, 487251881Speter local_relpath, scratch_pool, scratch_pool)); 488251881Speter 489251881Speter SVN_ERR(svn_skel__parse_int(&val, arg1->next, scratch_pool)); 490251881Speter use_commit_times = (val != 0); 491251881Speter SVN_ERR(svn_skel__parse_int(&val, arg1->next->next, scratch_pool)); 492251881Speter record_fileinfo = (val != 0); 493251881Speter 494251881Speter SVN_ERR(svn_wc__db_read_node_install_info(&wcroot_abspath, 495251881Speter &checksum, &props, 496251881Speter &changed_date, 497251881Speter db, local_abspath, wri_abspath, 498251881Speter scratch_pool, scratch_pool)); 499251881Speter 500251881Speter if (arg4 != NULL) 501251881Speter { 502251881Speter /* Use the provided path for the source. */ 503251881Speter local_relpath = apr_pstrmemdup(scratch_pool, arg4->data, arg4->len); 504251881Speter SVN_ERR(svn_wc__db_from_relpath(&source_abspath, db, wri_abspath, 505251881Speter local_relpath, 506251881Speter scratch_pool, scratch_pool)); 507251881Speter } 508251881Speter else if (! checksum) 509251881Speter { 510251881Speter /* This error replaces a previous assertion. Reporting an error from here 511251881Speter leaves the workingqueue operation in place, so the working copy is 512251881Speter still broken! 513251881Speter 514251881Speter But when we report this error the user at least knows what node has 515251881Speter this specific problem, so maybe we can find out why users see this 516251881Speter error */ 517251881Speter return svn_error_createf(SVN_ERR_WC_CORRUPT_TEXT_BASE, NULL, 518251881Speter _("Can't install '%s' from pristine store, " 519251881Speter "because no checksum is recorded for this " 520251881Speter "file"), 521251881Speter svn_dirent_local_style(local_abspath, 522251881Speter scratch_pool)); 523251881Speter } 524251881Speter else 525251881Speter { 526251881Speter SVN_ERR(svn_wc__db_pristine_get_future_path(&source_abspath, 527251881Speter wcroot_abspath, 528251881Speter checksum, 529251881Speter scratch_pool, scratch_pool)); 530251881Speter } 531251881Speter 532251881Speter SVN_ERR(svn_stream_open_readonly(&src_stream, source_abspath, 533251881Speter scratch_pool, scratch_pool)); 534251881Speter 535251881Speter /* Fetch all the translation bits. */ 536251881Speter SVN_ERR(svn_wc__get_translate_info(&style, &eol, 537251881Speter &keywords, 538251881Speter &special, db, local_abspath, 539251881Speter props, FALSE, 540251881Speter scratch_pool, scratch_pool)); 541251881Speter if (special) 542251881Speter { 543251881Speter /* When this stream is closed, the resulting special file will 544251881Speter atomically be created/moved into place at LOCAL_ABSPATH. */ 545251881Speter SVN_ERR(svn_subst_create_specialfile(&dst_stream, local_abspath, 546251881Speter scratch_pool, scratch_pool)); 547251881Speter 548251881Speter /* Copy the "repository normal" form of the special file into the 549251881Speter special stream. */ 550251881Speter SVN_ERR(svn_stream_copy3(src_stream, dst_stream, 551251881Speter cancel_func, cancel_baton, 552251881Speter scratch_pool)); 553251881Speter 554251881Speter /* No need to set exec or read-only flags on special files. */ 555251881Speter 556251881Speter /* ### Shouldn't this record a timestamp and size, etc.? */ 557251881Speter return SVN_NO_ERROR; 558251881Speter } 559251881Speter 560251881Speter if (svn_subst_translation_required(style, eol, keywords, 561251881Speter FALSE /* special */, 562251881Speter TRUE /* force_eol_check */)) 563251881Speter { 564251881Speter /* Wrap it in a translating (expanding) stream. */ 565251881Speter src_stream = svn_subst_stream_translated(src_stream, eol, 566251881Speter TRUE /* repair */, 567251881Speter keywords, 568251881Speter TRUE /* expand */, 569251881Speter scratch_pool); 570251881Speter } 571251881Speter 572251881Speter /* Where is the Right Place to put a temp file in this working copy? */ 573251881Speter SVN_ERR(svn_wc__db_temp_wcroot_tempdir(&temp_dir_abspath, 574251881Speter db, wcroot_abspath, 575251881Speter scratch_pool, scratch_pool)); 576251881Speter 577251881Speter /* Translate to a temporary file. We don't want the user seeing a partial 578251881Speter file, nor let them muck with it while we translate. We may also need to 579251881Speter get its TRANSLATED_SIZE before the user can monkey it. */ 580251881Speter SVN_ERR(svn_stream_open_unique(&dst_stream, &dst_abspath, 581251881Speter temp_dir_abspath, 582251881Speter svn_io_file_del_none, 583251881Speter scratch_pool, scratch_pool)); 584251881Speter 585251881Speter /* Copy from the source to the dest, translating as we go. This will also 586251881Speter close both streams. */ 587251881Speter SVN_ERR(svn_stream_copy3(src_stream, dst_stream, 588251881Speter cancel_func, cancel_baton, 589251881Speter scratch_pool)); 590251881Speter 591251881Speter /* All done. Move the file into place. */ 592251881Speter 593251881Speter { 594251881Speter svn_error_t *err; 595251881Speter 596251881Speter err = svn_io_file_rename(dst_abspath, local_abspath, scratch_pool); 597251881Speter 598251881Speter /* With a single db we might want to install files in a missing directory. 599251881Speter Simply trying this scenario on error won't do any harm and at least 600251881Speter one user reported this problem on IRC. */ 601251881Speter if (err && APR_STATUS_IS_ENOENT(err->apr_err)) 602251881Speter { 603251881Speter svn_error_t *err2; 604251881Speter 605251881Speter err2 = svn_io_make_dir_recursively(svn_dirent_dirname(local_abspath, 606251881Speter scratch_pool), 607251881Speter scratch_pool); 608251881Speter 609251881Speter if (err2) 610251881Speter /* Creating directory didn't work: Return all errors */ 611251881Speter return svn_error_trace(svn_error_compose_create(err, err2)); 612251881Speter else 613251881Speter /* We could create a directory: retry install */ 614251881Speter svn_error_clear(err); 615251881Speter 616251881Speter SVN_ERR(svn_io_file_rename(dst_abspath, local_abspath, scratch_pool)); 617251881Speter } 618251881Speter else 619251881Speter SVN_ERR(err); 620251881Speter } 621251881Speter 622251881Speter /* Tweak the on-disk file according to its properties. */ 623251881Speter#ifndef WIN32 624251881Speter if (props && svn_hash_gets(props, SVN_PROP_EXECUTABLE)) 625251881Speter SVN_ERR(svn_io_set_file_executable(local_abspath, TRUE, FALSE, 626251881Speter scratch_pool)); 627251881Speter#endif 628251881Speter 629251881Speter /* Note that this explicitly checks the pristine properties, to make sure 630251881Speter that when the lock is locally set (=modification) it is not read only */ 631251881Speter if (props && svn_hash_gets(props, SVN_PROP_NEEDS_LOCK)) 632251881Speter { 633251881Speter svn_wc__db_status_t status; 634251881Speter svn_wc__db_lock_t *lock; 635251881Speter SVN_ERR(svn_wc__db_read_info(&status, NULL, NULL, NULL, NULL, NULL, NULL, 636251881Speter NULL, NULL, NULL, NULL, NULL, NULL, NULL, 637251881Speter NULL, NULL, &lock, NULL, NULL, NULL, NULL, 638251881Speter NULL, NULL, NULL, NULL, NULL, NULL, 639251881Speter db, local_abspath, 640251881Speter scratch_pool, scratch_pool)); 641251881Speter 642251881Speter if (!lock && status != svn_wc__db_status_added) 643251881Speter SVN_ERR(svn_io_set_file_read_only(local_abspath, FALSE, scratch_pool)); 644251881Speter } 645251881Speter 646251881Speter if (use_commit_times) 647251881Speter { 648251881Speter if (changed_date) 649251881Speter SVN_ERR(svn_io_set_file_affected_time(changed_date, 650251881Speter local_abspath, 651251881Speter scratch_pool)); 652251881Speter } 653251881Speter 654251881Speter /* ### this should happen before we rename the file into place. */ 655251881Speter if (record_fileinfo) 656251881Speter { 657251881Speter SVN_ERR(get_and_record_fileinfo(wqb, local_abspath, 658251881Speter FALSE /* ignore_enoent */, 659251881Speter scratch_pool)); 660251881Speter } 661251881Speter 662251881Speter return SVN_NO_ERROR; 663251881Speter} 664251881Speter 665251881Speter 666251881Spetersvn_error_t * 667251881Spetersvn_wc__wq_build_file_install(svn_skel_t **work_item, 668251881Speter svn_wc__db_t *db, 669251881Speter const char *local_abspath, 670251881Speter const char *source_abspath, 671251881Speter svn_boolean_t use_commit_times, 672251881Speter svn_boolean_t record_fileinfo, 673251881Speter apr_pool_t *result_pool, 674251881Speter apr_pool_t *scratch_pool) 675251881Speter{ 676251881Speter const char *local_relpath; 677251881Speter const char *wri_abspath; 678251881Speter *work_item = svn_skel__make_empty_list(result_pool); 679251881Speter 680251881Speter /* Use the directory of the file to install as wri_abspath to avoid 681251881Speter filestats on just obtaining the wc-root */ 682251881Speter wri_abspath = svn_dirent_dirname(local_abspath, scratch_pool); 683251881Speter 684251881Speter /* If a SOURCE_ABSPATH was provided, then put it into the skel. If this 685251881Speter value is not provided, then the file's pristine contents will be used. */ 686251881Speter if (source_abspath != NULL) 687251881Speter { 688251881Speter SVN_ERR(svn_wc__db_to_relpath(&local_relpath, db, wri_abspath, 689251881Speter source_abspath, 690251881Speter result_pool, scratch_pool)); 691251881Speter 692251881Speter svn_skel__prepend_str(local_relpath, *work_item, result_pool); 693251881Speter } 694251881Speter 695251881Speter SVN_ERR(svn_wc__db_to_relpath(&local_relpath, db, wri_abspath, 696251881Speter local_abspath, result_pool, scratch_pool)); 697251881Speter 698251881Speter svn_skel__prepend_int(record_fileinfo, *work_item, result_pool); 699251881Speter svn_skel__prepend_int(use_commit_times, *work_item, result_pool); 700251881Speter svn_skel__prepend_str(local_relpath, *work_item, result_pool); 701251881Speter svn_skel__prepend_str(OP_FILE_INSTALL, *work_item, result_pool); 702251881Speter 703251881Speter return SVN_NO_ERROR; 704251881Speter} 705251881Speter 706251881Speter 707251881Speter/* ------------------------------------------------------------------------ */ 708251881Speter 709251881Speter/* OP_FILE_REMOVE */ 710251881Speter 711251881Speter/* Process the OP_FILE_REMOVE work item WORK_ITEM. 712251881Speter * See svn_wc__wq_build_file_remove() which generates this work item. 713251881Speter * Implements (struct work_item_dispatch).func. */ 714251881Speterstatic svn_error_t * 715251881Speterrun_file_remove(work_item_baton_t *wqb, 716251881Speter svn_wc__db_t *db, 717251881Speter const svn_skel_t *work_item, 718251881Speter const char *wri_abspath, 719251881Speter svn_cancel_func_t cancel_func, 720251881Speter void *cancel_baton, 721251881Speter apr_pool_t *scratch_pool) 722251881Speter{ 723251881Speter const svn_skel_t *arg1 = work_item->children->next; 724251881Speter const char *local_relpath; 725251881Speter const char *local_abspath; 726251881Speter 727251881Speter local_relpath = apr_pstrmemdup(scratch_pool, arg1->data, arg1->len); 728251881Speter SVN_ERR(svn_wc__db_from_relpath(&local_abspath, db, wri_abspath, 729251881Speter local_relpath, scratch_pool, scratch_pool)); 730251881Speter 731251881Speter /* Remove the path, no worrying if it isn't there. */ 732251881Speter return svn_error_trace(svn_io_remove_file2(local_abspath, TRUE, 733251881Speter scratch_pool)); 734251881Speter} 735251881Speter 736251881Speter 737251881Spetersvn_error_t * 738251881Spetersvn_wc__wq_build_file_remove(svn_skel_t **work_item, 739251881Speter svn_wc__db_t *db, 740251881Speter const char *wri_abspath, 741251881Speter const char *local_abspath, 742251881Speter apr_pool_t *result_pool, 743251881Speter apr_pool_t *scratch_pool) 744251881Speter{ 745251881Speter const char *local_relpath; 746251881Speter *work_item = svn_skel__make_empty_list(result_pool); 747251881Speter 748251881Speter SVN_ERR(svn_wc__db_to_relpath(&local_relpath, db, wri_abspath, 749251881Speter local_abspath, result_pool, scratch_pool)); 750251881Speter 751251881Speter svn_skel__prepend_str(local_relpath, *work_item, result_pool); 752251881Speter svn_skel__prepend_str(OP_FILE_REMOVE, *work_item, result_pool); 753251881Speter 754251881Speter return SVN_NO_ERROR; 755251881Speter} 756251881Speter 757251881Speter/* ------------------------------------------------------------------------ */ 758251881Speter 759251881Speter/* OP_DIRECTORY_REMOVE */ 760251881Speter 761251881Speter/* Process the OP_FILE_REMOVE work item WORK_ITEM. 762251881Speter * See svn_wc__wq_build_file_remove() which generates this work item. 763251881Speter * Implements (struct work_item_dispatch).func. */ 764251881Speterstatic svn_error_t * 765251881Speterrun_dir_remove(work_item_baton_t *wqb, 766251881Speter svn_wc__db_t *db, 767251881Speter const svn_skel_t *work_item, 768251881Speter const char *wri_abspath, 769251881Speter svn_cancel_func_t cancel_func, 770251881Speter void *cancel_baton, 771251881Speter apr_pool_t *scratch_pool) 772251881Speter{ 773251881Speter const svn_skel_t *arg1 = work_item->children->next; 774251881Speter const char *local_relpath; 775251881Speter const char *local_abspath; 776251881Speter svn_boolean_t recursive; 777251881Speter 778251881Speter local_relpath = apr_pstrmemdup(scratch_pool, arg1->data, arg1->len); 779251881Speter SVN_ERR(svn_wc__db_from_relpath(&local_abspath, db, wri_abspath, 780251881Speter local_relpath, scratch_pool, scratch_pool)); 781251881Speter 782251881Speter recursive = FALSE; 783251881Speter if (arg1->next) 784251881Speter { 785251881Speter apr_int64_t val; 786251881Speter SVN_ERR(svn_skel__parse_int(&val, arg1->next, scratch_pool)); 787251881Speter 788251881Speter recursive = (val != 0); 789251881Speter } 790251881Speter 791251881Speter /* Remove the path, no worrying if it isn't there. */ 792251881Speter if (recursive) 793251881Speter return svn_error_trace( 794251881Speter svn_io_remove_dir2(local_abspath, TRUE, 795251881Speter cancel_func, cancel_baton, 796251881Speter scratch_pool)); 797251881Speter else 798251881Speter { 799251881Speter svn_error_t *err; 800251881Speter 801251881Speter err = svn_io_dir_remove_nonrecursive(local_abspath, scratch_pool); 802251881Speter 803251881Speter if (err && (APR_STATUS_IS_ENOENT(err->apr_err) 804251881Speter || SVN__APR_STATUS_IS_ENOTDIR(err->apr_err) 805251881Speter || APR_STATUS_IS_ENOTEMPTY(err->apr_err))) 806251881Speter { 807251881Speter svn_error_clear(err); 808251881Speter err = NULL; 809251881Speter } 810251881Speter 811251881Speter return svn_error_trace(err); 812251881Speter } 813251881Speter} 814251881Speter 815251881Spetersvn_error_t * 816251881Spetersvn_wc__wq_build_dir_remove(svn_skel_t **work_item, 817251881Speter svn_wc__db_t *db, 818251881Speter const char *wri_abspath, 819251881Speter const char *local_abspath, 820251881Speter svn_boolean_t recursive, 821251881Speter apr_pool_t *result_pool, 822251881Speter apr_pool_t *scratch_pool) 823251881Speter{ 824251881Speter const char *local_relpath; 825251881Speter *work_item = svn_skel__make_empty_list(result_pool); 826251881Speter 827251881Speter SVN_ERR(svn_wc__db_to_relpath(&local_relpath, db, wri_abspath, 828251881Speter local_abspath, result_pool, scratch_pool)); 829251881Speter 830251881Speter if (recursive) 831251881Speter svn_skel__prepend_int(TRUE, *work_item, result_pool); 832251881Speter 833251881Speter svn_skel__prepend_str(local_relpath, *work_item, result_pool); 834251881Speter svn_skel__prepend_str(OP_DIRECTORY_REMOVE, *work_item, result_pool); 835251881Speter 836251881Speter return SVN_NO_ERROR; 837251881Speter} 838251881Speter 839251881Speter/* ------------------------------------------------------------------------ */ 840251881Speter 841251881Speter/* OP_FILE_MOVE */ 842251881Speter 843251881Speter/* Process the OP_FILE_MOVE work item WORK_ITEM. 844251881Speter * See svn_wc__wq_build_file_move() which generates this work item. 845251881Speter * Implements (struct work_item_dispatch).func. */ 846251881Speterstatic svn_error_t * 847251881Speterrun_file_move(work_item_baton_t *wqb, 848251881Speter svn_wc__db_t *db, 849251881Speter const svn_skel_t *work_item, 850251881Speter const char *wri_abspath, 851251881Speter svn_cancel_func_t cancel_func, 852251881Speter void *cancel_baton, 853251881Speter apr_pool_t *scratch_pool) 854251881Speter{ 855251881Speter const svn_skel_t *arg1 = work_item->children->next; 856251881Speter const char *src_abspath, *dst_abspath; 857251881Speter const char *local_relpath; 858251881Speter svn_error_t *err; 859251881Speter 860251881Speter local_relpath = apr_pstrmemdup(scratch_pool, arg1->data, arg1->len); 861251881Speter SVN_ERR(svn_wc__db_from_relpath(&src_abspath, db, wri_abspath, local_relpath, 862251881Speter scratch_pool, scratch_pool)); 863251881Speter local_relpath = apr_pstrmemdup(scratch_pool, arg1->next->data, 864251881Speter arg1->next->len); 865251881Speter SVN_ERR(svn_wc__db_from_relpath(&dst_abspath, db, wri_abspath, local_relpath, 866251881Speter scratch_pool, scratch_pool)); 867251881Speter 868251881Speter /* Use svn_io_file_move() instead of svn_io_file_rename() to allow cross 869251881Speter device copies. We should not fail in the workqueue. */ 870251881Speter 871251881Speter err = svn_io_file_move(src_abspath, dst_abspath, scratch_pool); 872251881Speter 873251881Speter /* If the source is not found, we assume the wq op is already handled */ 874251881Speter if (err && APR_STATUS_IS_ENOENT(err->apr_err)) 875251881Speter svn_error_clear(err); 876251881Speter else 877251881Speter SVN_ERR(err); 878251881Speter 879251881Speter return SVN_NO_ERROR; 880251881Speter} 881251881Speter 882251881Speter 883251881Spetersvn_error_t * 884251881Spetersvn_wc__wq_build_file_move(svn_skel_t **work_item, 885251881Speter svn_wc__db_t *db, 886251881Speter const char *wri_abspath, 887251881Speter const char *src_abspath, 888251881Speter const char *dst_abspath, 889251881Speter apr_pool_t *result_pool, 890251881Speter apr_pool_t *scratch_pool) 891251881Speter{ 892251881Speter svn_node_kind_t kind; 893251881Speter const char *local_relpath; 894251881Speter *work_item = svn_skel__make_empty_list(result_pool); 895251881Speter 896251881Speter SVN_ERR_ASSERT(svn_dirent_is_absolute(wri_abspath)); 897251881Speter SVN_ERR_ASSERT(svn_dirent_is_absolute(src_abspath)); 898251881Speter SVN_ERR_ASSERT(svn_dirent_is_absolute(dst_abspath)); 899251881Speter 900251881Speter /* File must exist */ 901251881Speter SVN_ERR(svn_io_check_path(src_abspath, &kind, result_pool)); 902251881Speter 903251881Speter if (kind == svn_node_none) 904251881Speter return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL, 905251881Speter _("'%s' not found"), 906251881Speter svn_dirent_local_style(src_abspath, 907251881Speter scratch_pool)); 908251881Speter 909251881Speter SVN_ERR(svn_wc__db_to_relpath(&local_relpath, db, wri_abspath, dst_abspath, 910251881Speter result_pool, scratch_pool)); 911251881Speter svn_skel__prepend_str(local_relpath, *work_item, result_pool); 912251881Speter 913251881Speter SVN_ERR(svn_wc__db_to_relpath(&local_relpath, db, wri_abspath, src_abspath, 914251881Speter result_pool, scratch_pool)); 915251881Speter svn_skel__prepend_str(local_relpath, *work_item, result_pool); 916251881Speter 917251881Speter svn_skel__prepend_str(OP_FILE_MOVE, *work_item, result_pool); 918251881Speter 919251881Speter return SVN_NO_ERROR; 920251881Speter} 921251881Speter 922251881Speter/* ------------------------------------------------------------------------ */ 923251881Speter 924251881Speter/* OP_FILE_COPY_TRANSLATED */ 925251881Speter 926251881Speter/* Process the OP_FILE_COPY_TRANSLATED work item WORK_ITEM. 927251881Speter * See run_file_copy_translated() which generates this work item. 928251881Speter * Implements (struct work_item_dispatch).func. */ 929251881Speterstatic svn_error_t * 930251881Speterrun_file_copy_translated(work_item_baton_t *wqb, 931251881Speter svn_wc__db_t *db, 932251881Speter const svn_skel_t *work_item, 933251881Speter const char *wri_abspath, 934251881Speter svn_cancel_func_t cancel_func, 935251881Speter void *cancel_baton, 936251881Speter apr_pool_t *scratch_pool) 937251881Speter{ 938251881Speter const svn_skel_t *arg1 = work_item->children->next; 939251881Speter const char *local_abspath, *src_abspath, *dst_abspath; 940251881Speter const char *local_relpath; 941251881Speter svn_subst_eol_style_t style; 942251881Speter const char *eol; 943251881Speter apr_hash_t *keywords; 944251881Speter svn_boolean_t special; 945251881Speter 946251881Speter local_relpath = apr_pstrmemdup(scratch_pool, arg1->data, arg1->len); 947251881Speter SVN_ERR(svn_wc__db_from_relpath(&local_abspath, db, wri_abspath, 948251881Speter local_relpath, scratch_pool, scratch_pool)); 949251881Speter 950251881Speter local_relpath = apr_pstrmemdup(scratch_pool, arg1->next->data, 951251881Speter arg1->next->len); 952251881Speter SVN_ERR(svn_wc__db_from_relpath(&src_abspath, db, wri_abspath, 953251881Speter local_relpath, scratch_pool, scratch_pool)); 954251881Speter 955251881Speter local_relpath = apr_pstrmemdup(scratch_pool, arg1->next->next->data, 956251881Speter arg1->next->next->len); 957251881Speter SVN_ERR(svn_wc__db_from_relpath(&dst_abspath, db, wri_abspath, 958251881Speter local_relpath, scratch_pool, scratch_pool)); 959251881Speter 960251881Speter SVN_ERR(svn_wc__get_translate_info(&style, &eol, 961251881Speter &keywords, 962251881Speter &special, 963251881Speter db, local_abspath, NULL, FALSE, 964251881Speter scratch_pool, scratch_pool)); 965251881Speter 966251881Speter SVN_ERR(svn_subst_copy_and_translate4(src_abspath, dst_abspath, 967251881Speter eol, TRUE /* repair */, 968251881Speter keywords, TRUE /* expand */, 969251881Speter special, 970251881Speter cancel_func, cancel_baton, 971251881Speter scratch_pool)); 972251881Speter return SVN_NO_ERROR; 973251881Speter} 974251881Speter 975251881Speter 976251881Spetersvn_error_t * 977251881Spetersvn_wc__wq_build_file_copy_translated(svn_skel_t **work_item, 978251881Speter svn_wc__db_t *db, 979251881Speter const char *local_abspath, 980251881Speter const char *src_abspath, 981251881Speter const char *dst_abspath, 982251881Speter apr_pool_t *result_pool, 983251881Speter apr_pool_t *scratch_pool) 984251881Speter{ 985251881Speter svn_node_kind_t kind; 986251881Speter const char *local_relpath; 987251881Speter 988251881Speter *work_item = svn_skel__make_empty_list(result_pool); 989251881Speter 990251881Speter SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath)); 991251881Speter SVN_ERR_ASSERT(svn_dirent_is_absolute(src_abspath)); 992251881Speter SVN_ERR_ASSERT(svn_dirent_is_absolute(dst_abspath)); 993251881Speter 994251881Speter /* File must exist */ 995251881Speter SVN_ERR(svn_io_check_path(src_abspath, &kind, result_pool)); 996251881Speter 997251881Speter if (kind == svn_node_none) 998251881Speter return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL, 999251881Speter _("'%s' not found"), 1000251881Speter svn_dirent_local_style(src_abspath, 1001251881Speter scratch_pool)); 1002251881Speter 1003251881Speter SVN_ERR(svn_wc__db_to_relpath(&local_relpath, db, local_abspath, dst_abspath, 1004251881Speter result_pool, scratch_pool)); 1005251881Speter svn_skel__prepend_str(local_relpath, *work_item, result_pool); 1006251881Speter 1007251881Speter SVN_ERR(svn_wc__db_to_relpath(&local_relpath, db, local_abspath, src_abspath, 1008251881Speter result_pool, scratch_pool)); 1009251881Speter svn_skel__prepend_str(local_relpath, *work_item, result_pool); 1010251881Speter 1011251881Speter SVN_ERR(svn_wc__db_to_relpath(&local_relpath, db, local_abspath, 1012251881Speter local_abspath, result_pool, scratch_pool)); 1013251881Speter svn_skel__prepend_str(local_relpath, *work_item, result_pool); 1014251881Speter 1015251881Speter svn_skel__prepend_str(OP_FILE_COPY_TRANSLATED, *work_item, result_pool); 1016251881Speter 1017251881Speter return SVN_NO_ERROR; 1018251881Speter} 1019251881Speter 1020251881Speter/* ------------------------------------------------------------------------ */ 1021251881Speter 1022251881Speter/* OP_DIRECTORY_INSTALL */ 1023251881Speter 1024251881Speterstatic svn_error_t * 1025251881Speterrun_dir_install(work_item_baton_t *wqb, 1026251881Speter svn_wc__db_t *db, 1027251881Speter const svn_skel_t *work_item, 1028251881Speter const char *wri_abspath, 1029251881Speter svn_cancel_func_t cancel_func, 1030251881Speter void *cancel_baton, 1031251881Speter apr_pool_t *scratch_pool) 1032251881Speter{ 1033251881Speter const svn_skel_t *arg1 = work_item->children->next; 1034251881Speter const char *local_relpath; 1035251881Speter const char *local_abspath; 1036251881Speter 1037251881Speter local_relpath = apr_pstrmemdup(scratch_pool, arg1->data, arg1->len); 1038251881Speter SVN_ERR(svn_wc__db_from_relpath(&local_abspath, db, wri_abspath, 1039251881Speter local_relpath, scratch_pool, scratch_pool)); 1040251881Speter 1041251881Speter SVN_ERR(svn_wc__ensure_directory(local_abspath, scratch_pool)); 1042251881Speter 1043251881Speter return SVN_NO_ERROR; 1044251881Speter} 1045251881Speter 1046251881Spetersvn_error_t * 1047251881Spetersvn_wc__wq_build_dir_install(svn_skel_t **work_item, 1048251881Speter svn_wc__db_t *db, 1049251881Speter const char *local_abspath, 1050251881Speter apr_pool_t *scratch_pool, 1051251881Speter apr_pool_t *result_pool) 1052251881Speter{ 1053251881Speter const char *local_relpath; 1054251881Speter 1055251881Speter *work_item = svn_skel__make_empty_list(result_pool); 1056251881Speter 1057251881Speter SVN_ERR(svn_wc__db_to_relpath(&local_relpath, db, local_abspath, 1058251881Speter local_abspath, result_pool, scratch_pool)); 1059251881Speter svn_skel__prepend_str(local_relpath, *work_item, result_pool); 1060251881Speter 1061251881Speter svn_skel__prepend_str(OP_DIRECTORY_INSTALL, *work_item, result_pool); 1062251881Speter 1063251881Speter return SVN_NO_ERROR; 1064251881Speter} 1065251881Speter 1066251881Speter 1067251881Speter/* ------------------------------------------------------------------------ */ 1068251881Speter 1069251881Speter/* OP_SYNC_FILE_FLAGS */ 1070251881Speter 1071251881Speter/* Process the OP_SYNC_FILE_FLAGS work item WORK_ITEM. 1072251881Speter * See svn_wc__wq_build_sync_file_flags() which generates this work item. 1073251881Speter * Implements (struct work_item_dispatch).func. */ 1074251881Speterstatic svn_error_t * 1075251881Speterrun_sync_file_flags(work_item_baton_t *wqb, 1076251881Speter svn_wc__db_t *db, 1077251881Speter const svn_skel_t *work_item, 1078251881Speter const char *wri_abspath, 1079251881Speter svn_cancel_func_t cancel_func, 1080251881Speter void *cancel_baton, 1081251881Speter apr_pool_t *scratch_pool) 1082251881Speter{ 1083251881Speter const svn_skel_t *arg1 = work_item->children->next; 1084251881Speter const char *local_relpath; 1085251881Speter const char *local_abspath; 1086251881Speter 1087251881Speter local_relpath = apr_pstrmemdup(scratch_pool, arg1->data, arg1->len); 1088251881Speter SVN_ERR(svn_wc__db_from_relpath(&local_abspath, db, wri_abspath, 1089251881Speter local_relpath, scratch_pool, scratch_pool)); 1090251881Speter 1091251881Speter return svn_error_trace(svn_wc__sync_flags_with_props(NULL, db, 1092251881Speter local_abspath, scratch_pool)); 1093251881Speter} 1094251881Speter 1095251881Speter 1096251881Spetersvn_error_t * 1097251881Spetersvn_wc__wq_build_sync_file_flags(svn_skel_t **work_item, 1098251881Speter svn_wc__db_t *db, 1099251881Speter const char *local_abspath, 1100251881Speter apr_pool_t *result_pool, 1101251881Speter apr_pool_t *scratch_pool) 1102251881Speter{ 1103251881Speter const char *local_relpath; 1104251881Speter *work_item = svn_skel__make_empty_list(result_pool); 1105251881Speter 1106251881Speter SVN_ERR(svn_wc__db_to_relpath(&local_relpath, db, local_abspath, 1107251881Speter local_abspath, result_pool, scratch_pool)); 1108251881Speter 1109251881Speter svn_skel__prepend_str(local_relpath, *work_item, result_pool); 1110251881Speter svn_skel__prepend_str(OP_SYNC_FILE_FLAGS, *work_item, result_pool); 1111251881Speter 1112251881Speter return SVN_NO_ERROR; 1113251881Speter} 1114251881Speter 1115251881Speter 1116251881Speter/* ------------------------------------------------------------------------ */ 1117251881Speter 1118251881Speter/* OP_PREJ_INSTALL */ 1119251881Speter 1120251881Speterstatic svn_error_t * 1121251881Speterrun_prej_install(work_item_baton_t *wqb, 1122251881Speter svn_wc__db_t *db, 1123251881Speter const svn_skel_t *work_item, 1124251881Speter const char *wri_abspath, 1125251881Speter svn_cancel_func_t cancel_func, 1126251881Speter void *cancel_baton, 1127251881Speter apr_pool_t *scratch_pool) 1128251881Speter{ 1129251881Speter const svn_skel_t *arg1 = work_item->children->next; 1130251881Speter const char *local_relpath; 1131251881Speter const char *local_abspath; 1132251881Speter svn_skel_t *conflicts; 1133251881Speter const svn_skel_t *prop_conflict_skel; 1134251881Speter const char *tmp_prejfile_abspath; 1135251881Speter const char *prejfile_abspath; 1136251881Speter 1137251881Speter local_relpath = apr_pstrmemdup(scratch_pool, arg1->data, arg1->len); 1138251881Speter SVN_ERR(svn_wc__db_from_relpath(&local_abspath, db, wri_abspath, 1139251881Speter local_relpath, scratch_pool, scratch_pool)); 1140251881Speter 1141251881Speter SVN_ERR(svn_wc__db_read_conflict(&conflicts, db, local_abspath, 1142251881Speter scratch_pool, scratch_pool)); 1143251881Speter 1144251881Speter SVN_ERR(svn_wc__conflict_read_prop_conflict(&prejfile_abspath, 1145251881Speter NULL, NULL, NULL, NULL, 1146251881Speter db, local_abspath, conflicts, 1147251881Speter scratch_pool, scratch_pool)); 1148251881Speter 1149251881Speter if (arg1->next != NULL) 1150251881Speter prop_conflict_skel = arg1->next; 1151251881Speter else 1152251881Speter SVN_ERR_MALFUNCTION(); /* ### wc_db can't provide it ... yet. */ 1153251881Speter 1154251881Speter /* Construct a property reject file in the temporary area. */ 1155251881Speter SVN_ERR(svn_wc__create_prejfile(&tmp_prejfile_abspath, 1156251881Speter db, local_abspath, 1157251881Speter prop_conflict_skel, 1158251881Speter scratch_pool, scratch_pool)); 1159251881Speter 1160251881Speter /* ... and atomically move it into place. */ 1161251881Speter SVN_ERR(svn_io_file_rename(tmp_prejfile_abspath, 1162251881Speter prejfile_abspath, 1163251881Speter scratch_pool)); 1164251881Speter 1165251881Speter return SVN_NO_ERROR; 1166251881Speter} 1167251881Speter 1168251881Speter 1169251881Spetersvn_error_t * 1170251881Spetersvn_wc__wq_build_prej_install(svn_skel_t **work_item, 1171251881Speter svn_wc__db_t *db, 1172251881Speter const char *local_abspath, 1173251881Speter svn_skel_t *conflict_skel, 1174251881Speter apr_pool_t *result_pool, 1175251881Speter apr_pool_t *scratch_pool) 1176251881Speter{ 1177251881Speter const char *local_relpath; 1178251881Speter *work_item = svn_skel__make_empty_list(result_pool); 1179251881Speter 1180251881Speter /* ### gotta have this, today */ 1181251881Speter SVN_ERR_ASSERT(conflict_skel != NULL); 1182251881Speter 1183251881Speter SVN_ERR(svn_wc__db_to_relpath(&local_relpath, db, local_abspath, 1184251881Speter local_abspath, result_pool, scratch_pool)); 1185251881Speter 1186251881Speter if (conflict_skel != NULL) 1187251881Speter svn_skel__prepend(conflict_skel, *work_item); 1188251881Speter svn_skel__prepend_str(local_relpath, *work_item, result_pool); 1189251881Speter svn_skel__prepend_str(OP_PREJ_INSTALL, *work_item, result_pool); 1190251881Speter 1191251881Speter return SVN_NO_ERROR; 1192251881Speter} 1193251881Speter 1194251881Speter 1195251881Speter/* ------------------------------------------------------------------------ */ 1196251881Speter 1197251881Speter/* OP_RECORD_FILEINFO */ 1198251881Speter 1199251881Speter 1200251881Speterstatic svn_error_t * 1201251881Speterrun_record_fileinfo(work_item_baton_t *wqb, 1202251881Speter svn_wc__db_t *db, 1203251881Speter const svn_skel_t *work_item, 1204251881Speter const char *wri_abspath, 1205251881Speter svn_cancel_func_t cancel_func, 1206251881Speter void *cancel_baton, 1207251881Speter apr_pool_t *scratch_pool) 1208251881Speter{ 1209251881Speter const svn_skel_t *arg1 = work_item->children->next; 1210251881Speter const char *local_relpath; 1211251881Speter const char *local_abspath; 1212251881Speter apr_time_t set_time = 0; 1213251881Speter 1214251881Speter local_relpath = apr_pstrmemdup(scratch_pool, arg1->data, arg1->len); 1215251881Speter 1216251881Speter SVN_ERR(svn_wc__db_from_relpath(&local_abspath, db, wri_abspath, 1217251881Speter local_relpath, scratch_pool, scratch_pool)); 1218251881Speter 1219251881Speter if (arg1->next) 1220251881Speter { 1221251881Speter apr_int64_t val; 1222251881Speter 1223251881Speter SVN_ERR(svn_skel__parse_int(&val, arg1->next, scratch_pool)); 1224251881Speter set_time = (apr_time_t)val; 1225251881Speter } 1226251881Speter 1227251881Speter if (set_time != 0) 1228251881Speter { 1229251881Speter svn_node_kind_t kind; 1230251881Speter svn_boolean_t is_special; 1231251881Speter 1232251881Speter /* Do not set the timestamp on special files. */ 1233251881Speter SVN_ERR(svn_io_check_special_path(local_abspath, &kind, &is_special, 1234251881Speter scratch_pool)); 1235251881Speter 1236251881Speter /* Don't set affected time when local_abspath does not exist or is 1237251881Speter a special file */ 1238251881Speter if (kind == svn_node_file && !is_special) 1239251881Speter SVN_ERR(svn_io_set_file_affected_time(set_time, local_abspath, 1240251881Speter scratch_pool)); 1241251881Speter 1242251881Speter /* Note that we can't use the value we get here for recording as the 1243251881Speter filesystem might have a different timestamp granularity */ 1244251881Speter } 1245251881Speter 1246251881Speter 1247251881Speter return svn_error_trace(get_and_record_fileinfo(wqb, local_abspath, 1248251881Speter TRUE /* ignore_enoent */, 1249251881Speter scratch_pool)); 1250251881Speter} 1251251881Speter 1252251881Speter/* ------------------------------------------------------------------------ */ 1253251881Speter 1254251881Speter/* OP_TMP_SET_TEXT_CONFLICT_MARKERS */ 1255251881Speter 1256251881Speter 1257251881Speterstatic svn_error_t * 1258251881Speterrun_set_text_conflict_markers(work_item_baton_t *wqb, 1259251881Speter svn_wc__db_t *db, 1260251881Speter const svn_skel_t *work_item, 1261251881Speter const char *wri_abspath, 1262251881Speter svn_cancel_func_t cancel_func, 1263251881Speter void *cancel_baton, 1264251881Speter apr_pool_t *scratch_pool) 1265251881Speter{ 1266251881Speter const svn_skel_t *arg = work_item->children->next; 1267251881Speter const char *local_relpath; 1268251881Speter const char *local_abspath; 1269251881Speter const char *old_abspath = NULL; 1270251881Speter const char *new_abspath = NULL; 1271251881Speter const char *wrk_abspath = NULL; 1272251881Speter 1273251881Speter local_relpath = apr_pstrmemdup(scratch_pool, arg->data, arg->len); 1274251881Speter SVN_ERR(svn_wc__db_from_relpath(&local_abspath, db, wri_abspath, 1275251881Speter local_relpath, scratch_pool, scratch_pool)); 1276251881Speter 1277251881Speter arg = arg->next; 1278251881Speter local_relpath = arg->len ? apr_pstrmemdup(scratch_pool, arg->data, arg->len) 1279251881Speter : NULL; 1280251881Speter 1281251881Speter if (local_relpath) 1282251881Speter { 1283251881Speter SVN_ERR(svn_wc__db_from_relpath(&old_abspath, db, wri_abspath, 1284251881Speter local_relpath, 1285251881Speter scratch_pool, scratch_pool)); 1286251881Speter } 1287251881Speter 1288251881Speter arg = arg->next; 1289251881Speter local_relpath = arg->len ? apr_pstrmemdup(scratch_pool, arg->data, arg->len) 1290251881Speter : NULL; 1291251881Speter if (local_relpath) 1292251881Speter { 1293251881Speter SVN_ERR(svn_wc__db_from_relpath(&new_abspath, db, wri_abspath, 1294251881Speter local_relpath, 1295251881Speter scratch_pool, scratch_pool)); 1296251881Speter } 1297251881Speter 1298251881Speter arg = arg->next; 1299251881Speter local_relpath = arg->len ? apr_pstrmemdup(scratch_pool, arg->data, arg->len) 1300251881Speter : NULL; 1301251881Speter 1302251881Speter if (local_relpath) 1303251881Speter { 1304251881Speter SVN_ERR(svn_wc__db_from_relpath(&wrk_abspath, db, wri_abspath, 1305251881Speter local_relpath, 1306251881Speter scratch_pool, scratch_pool)); 1307251881Speter } 1308251881Speter 1309251881Speter /* Upgrade scenario: We have a workqueue item that describes how to install a 1310251881Speter non skel conflict. Fetch all the information we can to create a new style 1311251881Speter conflict. */ 1312251881Speter /* ### Before format 30 this is/was a common code path as we didn't install 1313251881Speter ### the conflict directly in the db. It just calls the wc_db code 1314251881Speter ### to set the right fields. */ 1315251881Speter 1316251881Speter { 1317251881Speter /* Check if we should combine with a property conflict... */ 1318251881Speter svn_skel_t *conflicts; 1319251881Speter 1320251881Speter SVN_ERR(svn_wc__db_read_conflict(&conflicts, db, local_abspath, 1321251881Speter scratch_pool, scratch_pool)); 1322251881Speter 1323251881Speter if (! conflicts) 1324251881Speter { 1325251881Speter /* No conflict exists, create a basic skel */ 1326251881Speter conflicts = svn_wc__conflict_skel_create(scratch_pool); 1327251881Speter 1328251881Speter SVN_ERR(svn_wc__conflict_skel_set_op_update(conflicts, NULL, NULL, 1329251881Speter scratch_pool, 1330251881Speter scratch_pool)); 1331251881Speter } 1332251881Speter 1333251881Speter /* Add the text conflict to the existing onflict */ 1334251881Speter SVN_ERR(svn_wc__conflict_skel_add_text_conflict(conflicts, db, 1335251881Speter local_abspath, 1336251881Speter wrk_abspath, 1337251881Speter old_abspath, 1338251881Speter new_abspath, 1339251881Speter scratch_pool, 1340251881Speter scratch_pool)); 1341251881Speter 1342251881Speter SVN_ERR(svn_wc__db_op_mark_conflict(db, local_abspath, conflicts, 1343251881Speter NULL, scratch_pool)); 1344251881Speter } 1345251881Speter return SVN_NO_ERROR; 1346251881Speter} 1347251881Speter 1348251881Speter/* ------------------------------------------------------------------------ */ 1349251881Speter 1350251881Speter/* OP_TMP_SET_PROPERTY_CONFLICT_MARKER */ 1351251881Speter 1352251881Speterstatic svn_error_t * 1353251881Speterrun_set_property_conflict_marker(work_item_baton_t *wqb, 1354251881Speter svn_wc__db_t *db, 1355251881Speter const svn_skel_t *work_item, 1356251881Speter const char *wri_abspath, 1357251881Speter svn_cancel_func_t cancel_func, 1358251881Speter void *cancel_baton, 1359251881Speter apr_pool_t *scratch_pool) 1360251881Speter{ 1361251881Speter const svn_skel_t *arg = work_item->children->next; 1362251881Speter const char *local_relpath; 1363251881Speter const char *local_abspath; 1364251881Speter const char *prej_abspath = NULL; 1365251881Speter 1366251881Speter local_relpath = apr_pstrmemdup(scratch_pool, arg->data, arg->len); 1367251881Speter 1368251881Speter SVN_ERR(svn_wc__db_from_relpath(&local_abspath, db, wri_abspath, 1369251881Speter local_relpath, scratch_pool, scratch_pool)); 1370251881Speter 1371251881Speter 1372251881Speter arg = arg->next; 1373251881Speter local_relpath = arg->len ? apr_pstrmemdup(scratch_pool, arg->data, arg->len) 1374251881Speter : NULL; 1375251881Speter 1376251881Speter if (local_relpath) 1377251881Speter SVN_ERR(svn_wc__db_from_relpath(&prej_abspath, db, wri_abspath, 1378251881Speter local_relpath, 1379251881Speter scratch_pool, scratch_pool)); 1380251881Speter 1381251881Speter { 1382251881Speter /* Check if we should combine with a text conflict... */ 1383251881Speter svn_skel_t *conflicts; 1384251881Speter apr_hash_t *prop_names; 1385251881Speter 1386251881Speter SVN_ERR(svn_wc__db_read_conflict(&conflicts, db, local_abspath, 1387251881Speter scratch_pool, scratch_pool)); 1388251881Speter 1389251881Speter if (! conflicts) 1390251881Speter { 1391251881Speter /* No conflict exists, create a basic skel */ 1392251881Speter conflicts = svn_wc__conflict_skel_create(scratch_pool); 1393251881Speter 1394251881Speter SVN_ERR(svn_wc__conflict_skel_set_op_update(conflicts, NULL, NULL, 1395251881Speter scratch_pool, 1396251881Speter scratch_pool)); 1397251881Speter } 1398251881Speter 1399251881Speter prop_names = apr_hash_make(scratch_pool); 1400251881Speter SVN_ERR(svn_wc__conflict_skel_add_prop_conflict(conflicts, db, 1401251881Speter local_abspath, 1402251881Speter prej_abspath, 1403251881Speter NULL, NULL, NULL, 1404251881Speter prop_names, 1405251881Speter scratch_pool, 1406251881Speter scratch_pool)); 1407251881Speter 1408251881Speter SVN_ERR(svn_wc__db_op_mark_conflict(db, local_abspath, conflicts, 1409251881Speter NULL, scratch_pool)); 1410251881Speter } 1411251881Speter return SVN_NO_ERROR; 1412251881Speter} 1413251881Speter 1414251881Speter/* ------------------------------------------------------------------------ */ 1415251881Speter 1416251881Speterstatic const struct work_item_dispatch dispatch_table[] = { 1417251881Speter { OP_FILE_COMMIT, run_file_commit }, 1418251881Speter { OP_FILE_INSTALL, run_file_install }, 1419251881Speter { OP_FILE_REMOVE, run_file_remove }, 1420251881Speter { OP_FILE_MOVE, run_file_move }, 1421251881Speter { OP_FILE_COPY_TRANSLATED, run_file_copy_translated }, 1422251881Speter { OP_SYNC_FILE_FLAGS, run_sync_file_flags }, 1423251881Speter { OP_PREJ_INSTALL, run_prej_install }, 1424251881Speter { OP_DIRECTORY_REMOVE, run_dir_remove }, 1425251881Speter { OP_DIRECTORY_INSTALL, run_dir_install }, 1426251881Speter 1427251881Speter /* Upgrade steps */ 1428251881Speter { OP_POSTUPGRADE, run_postupgrade }, 1429251881Speter 1430251881Speter /* Legacy workqueue items. No longer created */ 1431251881Speter { OP_BASE_REMOVE, run_base_remove }, 1432251881Speter { OP_RECORD_FILEINFO, run_record_fileinfo }, 1433251881Speter { OP_TMP_SET_TEXT_CONFLICT_MARKERS, run_set_text_conflict_markers }, 1434251881Speter { OP_TMP_SET_PROPERTY_CONFLICT_MARKER, run_set_property_conflict_marker }, 1435251881Speter 1436251881Speter /* Sentinel. */ 1437251881Speter { NULL } 1438251881Speter}; 1439251881Speter 1440251881Speterstruct work_item_baton_t 1441251881Speter{ 1442251881Speter apr_pool_t *result_pool; /* Pool to allocate result in */ 1443251881Speter 1444251881Speter svn_boolean_t used; /* needs reset */ 1445251881Speter 1446251881Speter apr_hash_t *record_map; /* const char * -> svn_io_dirent2_t map */ 1447251881Speter}; 1448251881Speter 1449251881Speter 1450251881Speterstatic svn_error_t * 1451251881Speterdispatch_work_item(work_item_baton_t *wqb, 1452251881Speter svn_wc__db_t *db, 1453251881Speter const char *wri_abspath, 1454251881Speter const svn_skel_t *work_item, 1455251881Speter svn_cancel_func_t cancel_func, 1456251881Speter void *cancel_baton, 1457251881Speter apr_pool_t *scratch_pool) 1458251881Speter{ 1459251881Speter const struct work_item_dispatch *scan; 1460251881Speter 1461251881Speter /* Scan the dispatch table for a function to handle this work item. */ 1462251881Speter for (scan = &dispatch_table[0]; scan->name != NULL; ++scan) 1463251881Speter { 1464251881Speter if (svn_skel__matches_atom(work_item->children, scan->name)) 1465251881Speter { 1466251881Speter 1467251881Speter#ifdef SVN_DEBUG_WORK_QUEUE 1468251881Speter SVN_DBG(("dispatch: operation='%s'\n", scan->name)); 1469251881Speter#endif 1470251881Speter SVN_ERR((*scan->func)(wqb, db, work_item, wri_abspath, 1471251881Speter cancel_func, cancel_baton, 1472251881Speter scratch_pool)); 1473251881Speter 1474251881Speter#ifdef SVN_RUN_WORK_QUEUE_TWICE 1475251881Speter#ifdef SVN_DEBUG_WORK_QUEUE 1476251881Speter SVN_DBG(("dispatch: operation='%s'\n", scan->name)); 1477251881Speter#endif 1478251881Speter /* Being able to run every workqueue item twice is one 1479251881Speter requirement for workqueues to be restartable. */ 1480251881Speter SVN_ERR((*scan->func)(db, work_item, wri_abspath, 1481251881Speter cancel_func, cancel_baton, 1482251881Speter scratch_pool)); 1483251881Speter#endif 1484251881Speter 1485251881Speter break; 1486251881Speter } 1487251881Speter } 1488251881Speter 1489251881Speter if (scan->name == NULL) 1490251881Speter { 1491251881Speter /* We should know about ALL possible work items here. If we do not, 1492251881Speter then something is wrong. Most likely, some kind of format/code 1493251881Speter skew. There is nothing more we can do. Erasing or ignoring this 1494251881Speter work item could leave the WC in an even more broken state. 1495251881Speter 1496251881Speter Contrary to issue #1581, we cannot simply remove work items and 1497251881Speter continue, so bail out with an error. */ 1498251881Speter return svn_error_createf(SVN_ERR_WC_BAD_ADM_LOG, NULL, 1499251881Speter _("Unrecognized work item in the queue")); 1500251881Speter } 1501251881Speter 1502251881Speter return SVN_NO_ERROR; 1503251881Speter} 1504251881Speter 1505251881Speter 1506251881Spetersvn_error_t * 1507251881Spetersvn_wc__wq_run(svn_wc__db_t *db, 1508251881Speter const char *wri_abspath, 1509251881Speter svn_cancel_func_t cancel_func, 1510251881Speter void *cancel_baton, 1511251881Speter apr_pool_t *scratch_pool) 1512251881Speter{ 1513251881Speter apr_pool_t *iterpool = svn_pool_create(scratch_pool); 1514251881Speter apr_uint64_t last_id = 0; 1515251881Speter work_item_baton_t wib = { 0 }; 1516251881Speter wib.result_pool = svn_pool_create(scratch_pool); 1517251881Speter 1518251881Speter#ifdef SVN_DEBUG_WORK_QUEUE 1519251881Speter SVN_DBG(("wq_run: wri='%s'\n", wri_abspath)); 1520251881Speter { 1521251881Speter static int count = 0; 1522251881Speter const char *count_env_var = getenv("SVN_DEBUG_WORK_QUEUE"); 1523251881Speter 1524251881Speter if (count_env_var && ++count == atoi(count_env_var)) 1525251881Speter return svn_error_create(SVN_ERR_CANCELLED, NULL, "fake cancel"); 1526251881Speter } 1527251881Speter#endif 1528251881Speter 1529251881Speter while (TRUE) 1530251881Speter { 1531251881Speter apr_uint64_t id; 1532251881Speter svn_skel_t *work_item; 1533251881Speter svn_error_t *err; 1534251881Speter 1535251881Speter svn_pool_clear(iterpool); 1536251881Speter 1537251881Speter if (! wib.used) 1538251881Speter { 1539251881Speter /* Make sure to do this *early* in the loop iteration. There may 1540251881Speter be a LAST_ID that needs to be marked as completed, *before* we 1541251881Speter start worrying about anything else. */ 1542251881Speter SVN_ERR(svn_wc__db_wq_fetch_next(&id, &work_item, db, wri_abspath, 1543251881Speter last_id, iterpool, iterpool)); 1544251881Speter } 1545251881Speter else 1546251881Speter { 1547251881Speter /* Make sure to do this *early* in the loop iteration. There may 1548251881Speter be a LAST_ID that needs to be marked as completed, *before* we 1549251881Speter start worrying about anything else. */ 1550251881Speter SVN_ERR(svn_wc__db_wq_record_and_fetch_next(&id, &work_item, 1551251881Speter db, wri_abspath, 1552251881Speter last_id, wib.record_map, 1553251881Speter iterpool, 1554251881Speter wib.result_pool)); 1555251881Speter 1556251881Speter svn_pool_clear(wib.result_pool); 1557251881Speter wib.record_map = NULL; 1558251881Speter wib.used = FALSE; 1559251881Speter } 1560251881Speter 1561251881Speter /* Stop work queue processing, if requested. A future 'svn cleanup' 1562251881Speter should be able to continue the processing. Note that we may 1563251881Speter have WORK_ITEM, but we'll just skip its processing for now. */ 1564251881Speter if (cancel_func) 1565251881Speter SVN_ERR(cancel_func(cancel_baton)); 1566251881Speter 1567251881Speter /* If we have a WORK_ITEM, then process the sucker. Otherwise, 1568251881Speter we're done. */ 1569251881Speter if (work_item == NULL) 1570251881Speter break; 1571251881Speter 1572251881Speter err = dispatch_work_item(&wib, db, wri_abspath, work_item, 1573251881Speter cancel_func, cancel_baton, iterpool); 1574251881Speter if (err) 1575251881Speter { 1576251881Speter const char *skel = svn_skel__unparse(work_item, scratch_pool)->data; 1577251881Speter 1578251881Speter return svn_error_createf(SVN_ERR_WC_BAD_ADM_LOG, err, 1579251881Speter _("Failed to run the WC DB work queue " 1580251881Speter "associated with '%s', work item %d %s"), 1581251881Speter svn_dirent_local_style(wri_abspath, 1582251881Speter scratch_pool), 1583251881Speter (int)id, skel); 1584251881Speter } 1585251881Speter 1586251881Speter /* The work item finished without error. Mark it completed 1587251881Speter in the next loop. */ 1588251881Speter last_id = id; 1589251881Speter } 1590251881Speter 1591251881Speter svn_pool_destroy(iterpool); 1592251881Speter return SVN_NO_ERROR; 1593251881Speter} 1594251881Speter 1595251881Speter 1596251881Spetersvn_skel_t * 1597251881Spetersvn_wc__wq_merge(svn_skel_t *work_item1, 1598251881Speter svn_skel_t *work_item2, 1599251881Speter apr_pool_t *result_pool) 1600251881Speter{ 1601251881Speter /* If either argument is NULL, then just return the other. */ 1602251881Speter if (work_item1 == NULL) 1603251881Speter return work_item2; 1604251881Speter if (work_item2 == NULL) 1605251881Speter return work_item1; 1606251881Speter 1607251881Speter /* We have two items. Figure out how to join them. */ 1608251881Speter if (SVN_WC__SINGLE_WORK_ITEM(work_item1)) 1609251881Speter { 1610251881Speter if (SVN_WC__SINGLE_WORK_ITEM(work_item2)) 1611251881Speter { 1612251881Speter /* Both are singular work items. Construct a list, then put 1613251881Speter both work items into it (in the proper order). */ 1614251881Speter 1615251881Speter svn_skel_t *result = svn_skel__make_empty_list(result_pool); 1616251881Speter 1617251881Speter svn_skel__prepend(work_item2, result); 1618251881Speter svn_skel__prepend(work_item1, result); 1619251881Speter return result; 1620251881Speter } 1621251881Speter 1622251881Speter /* WORK_ITEM2 is a list of work items. We can simply shove WORK_ITEM1 1623251881Speter in the front to keep the ordering. */ 1624251881Speter svn_skel__prepend(work_item1, work_item2); 1625251881Speter return work_item2; 1626251881Speter } 1627251881Speter /* WORK_ITEM1 is a list of work items. */ 1628251881Speter 1629251881Speter if (SVN_WC__SINGLE_WORK_ITEM(work_item2)) 1630251881Speter { 1631251881Speter /* Put WORK_ITEM2 onto the end of the WORK_ITEM1 list. */ 1632251881Speter svn_skel__append(work_item1, work_item2); 1633251881Speter return work_item1; 1634251881Speter } 1635251881Speter 1636251881Speter /* We have two lists of work items. We need to chain all of the work 1637251881Speter items into one big list. We will leave behind the WORK_ITEM2 skel, 1638251881Speter as we only want its children. */ 1639251881Speter svn_skel__append(work_item1, work_item2->children); 1640251881Speter return work_item1; 1641251881Speter} 1642251881Speter 1643251881Speter 1644251881Speterstatic svn_error_t * 1645251881Speterget_and_record_fileinfo(work_item_baton_t *wqb, 1646251881Speter const char *local_abspath, 1647251881Speter svn_boolean_t ignore_enoent, 1648251881Speter apr_pool_t *scratch_pool) 1649251881Speter{ 1650251881Speter const svn_io_dirent2_t *dirent; 1651251881Speter 1652251881Speter SVN_ERR(svn_io_stat_dirent2(&dirent, local_abspath, FALSE, ignore_enoent, 1653251881Speter wqb->result_pool, scratch_pool)); 1654251881Speter 1655251881Speter if (dirent->kind != svn_node_file) 1656251881Speter return SVN_NO_ERROR; 1657251881Speter 1658251881Speter wqb->used = TRUE; 1659251881Speter 1660251881Speter if (! wqb->record_map) 1661251881Speter wqb->record_map = apr_hash_make(wqb->result_pool); 1662251881Speter 1663251881Speter svn_hash_sets(wqb->record_map, apr_pstrdup(wqb->result_pool, local_abspath), 1664251881Speter dirent); 1665251881Speter 1666251881Speter return SVN_NO_ERROR; 1667251881Speter} 1668