1251881Speter/* 2251881Speter * wcroot_anchor.c : wcroot and anchor functions 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 25251881Speter 26251881Speter#include <stdlib.h> 27251881Speter#include <string.h> 28251881Speter 29251881Speter#include "svn_types.h" 30251881Speter#include "svn_pools.h" 31251881Speter#include "svn_string.h" 32251881Speter#include "svn_dirent_uri.h" 33251881Speter#include "svn_error.h" 34251881Speter#include "svn_io.h" 35251881Speter#include "svn_private_config.h" 36251881Speter 37251881Speter#include "wc.h" 38251881Speter 39251881Speter#include "private/svn_wc_private.h" 40251881Speter 41251881Speter/* ABOUT ANCHOR AND TARGET, AND svn_wc_get_actual_target2() 42251881Speter 43251881Speter THE GOAL 44251881Speter 45251881Speter Note the following actions, where X is the thing we wish to update, 46251881Speter P is a directory whose repository URL is the parent of 47251881Speter X's repository URL, N is directory whose repository URL is *not* 48251881Speter the parent directory of X (including the case where N is not a 49251881Speter versioned resource at all): 50251881Speter 51251881Speter 1. `svn up .' from inside X. 52251881Speter 2. `svn up ...P/X' from anywhere. 53251881Speter 3. `svn up ...N/X' from anywhere. 54251881Speter 55251881Speter For the purposes of the discussion, in the '...N/X' situation, X is 56251881Speter said to be a "working copy (WC) root" directory. 57251881Speter 58251881Speter Now consider the four cases for X's type (file/dir) in the working 59251881Speter copy vs. the repository: 60251881Speter 61251881Speter A. dir in working copy, dir in repos. 62251881Speter B. dir in working copy, file in repos. 63251881Speter C. file in working copy, dir in repos. 64251881Speter D. file in working copy, file in repos. 65251881Speter 66251881Speter Here are the results we expect for each combination of the above: 67251881Speter 68251881Speter 1A. Successfully update X. 69251881Speter 1B. Error (you don't want to remove your current working 70251881Speter directory out from underneath the application). 71251881Speter 1C. N/A (you can't be "inside X" if X is a file). 72251881Speter 1D. N/A (you can't be "inside X" if X is a file). 73251881Speter 74251881Speter 2A. Successfully update X. 75251881Speter 2B. Successfully update X. 76251881Speter 2C. Successfully update X. 77251881Speter 2D. Successfully update X. 78251881Speter 79251881Speter 3A. Successfully update X. 80251881Speter 3B. Error (you can't create a versioned file X inside a 81251881Speter non-versioned directory). 82251881Speter 3C. N/A (you can't have a versioned file X in directory that is 83251881Speter not its repository parent). 84251881Speter 3D. N/A (you can't have a versioned file X in directory that is 85251881Speter not its repository parent). 86251881Speter 87251881Speter To summarize, case 2 always succeeds, and cases 1 and 3 always fail 88251881Speter (or can't occur) *except* when the target is a dir that remains a 89251881Speter dir after the update. 90251881Speter 91251881Speter ACCOMPLISHING THE GOAL 92251881Speter 93251881Speter Updates are accomplished by driving an editor, and an editor is 94251881Speter "rooted" on a directory. So, in order to update a file, we need to 95251881Speter break off the basename of the file, rooting the editor in that 96251881Speter file's parent directory, and then updating only that file, not the 97251881Speter other stuff in its parent directory. 98251881Speter 99251881Speter Secondly, we look at the case where we wish to update a directory. 100251881Speter This is typically trivial. However, one problematic case, exists 101251881Speter when we wish to update a directory that has been removed from the 102251881Speter repository and replaced with a file of the same name. If we root 103251881Speter our edit at the initial directory, there is no editor mechanism for 104251881Speter deleting that directory and replacing it with a file (this would be 105251881Speter like having an editor now anchored on a file, which is disallowed). 106251881Speter 107251881Speter All that remains is to have a function with the knowledge required 108251881Speter to properly decide where to root our editor, and what to act upon 109251881Speter with that now-rooted editor. Given a path to be updated, this 110251881Speter function should conditionally split that path into an "anchor" and 111251881Speter a "target", where the "anchor" is the directory at which the update 112251881Speter editor is rooted (meaning, editor->open_root() is called with 113251881Speter this directory in mind), and the "target" is the actual intended 114251881Speter subject of the update. 115251881Speter 116251881Speter svn_wc_get_actual_target2() is that function. 117251881Speter 118251881Speter So, what are the conditions? 119251881Speter 120251881Speter Case I: Any time X is '.' (implying it is a directory), we won't 121251881Speter lop off a basename. So we'll root our editor at X, and update all 122251881Speter of X. 123251881Speter 124251881Speter Cases II & III: Any time we are trying to update some path ...N/X, 125251881Speter we again will not lop off a basename. We can't root an editor at 126251881Speter ...N with X as a target, either because ...N isn't a versioned 127251881Speter resource at all (Case II) or because X is X is not a child of ...N 128251881Speter in the repository (Case III). We root at X, and update X. 129251881Speter 130251881Speter Cases IV-???: We lop off a basename when we are updating a 131251881Speter path ...P/X, rooting our editor at ...P and updating X, or when X 132251881Speter is missing from disk. 133251881Speter 134251881Speter These conditions apply whether X is a file or directory. 135251881Speter 136251881Speter --- 137251881Speter 138251881Speter As it turns out, commits need to have a similar check in place, 139251881Speter too, specifically for the case where a single directory is being 140251881Speter committed (we have to anchor at that directory's parent in case the 141251881Speter directory itself needs to be modified). 142251881Speter*/ 143251881Speter 144251881Speter 145251881Spetersvn_error_t * 146251881Spetersvn_wc_check_root(svn_boolean_t *is_wcroot, 147251881Speter svn_boolean_t *is_switched, 148251881Speter svn_node_kind_t *kind, 149251881Speter svn_wc_context_t *wc_ctx, 150251881Speter const char *local_abspath, 151251881Speter apr_pool_t *scratch_pool) 152251881Speter{ 153251881Speter SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath)); 154251881Speter 155251881Speter return svn_error_trace(svn_wc__db_is_switched(is_wcroot,is_switched, kind, 156251881Speter wc_ctx->db, local_abspath, 157251881Speter scratch_pool)); 158251881Speter} 159251881Speter 160251881Spetersvn_error_t * 161251881Spetersvn_wc__is_wcroot(svn_boolean_t *is_wcroot, 162251881Speter svn_wc_context_t *wc_ctx, 163251881Speter const char *local_abspath, 164251881Speter apr_pool_t *scratch_pool) 165251881Speter{ 166251881Speter return svn_error_trace(svn_wc__db_is_wcroot(is_wcroot, 167251881Speter wc_ctx->db, 168251881Speter local_abspath, 169251881Speter scratch_pool)); 170251881Speter} 171251881Speter 172251881Speter 173251881Spetersvn_error_t * 174251881Spetersvn_wc__get_wcroot(const char **wcroot_abspath, 175251881Speter svn_wc_context_t *wc_ctx, 176251881Speter const char *local_abspath, 177251881Speter apr_pool_t *result_pool, 178251881Speter apr_pool_t *scratch_pool) 179251881Speter{ 180251881Speter return svn_wc__db_get_wcroot(wcroot_abspath, wc_ctx->db, 181251881Speter local_abspath, result_pool, scratch_pool); 182251881Speter} 183251881Speter 184251881Speter 185251881Spetersvn_error_t * 186251881Spetersvn_wc_get_actual_target2(const char **anchor, 187251881Speter const char **target, 188251881Speter svn_wc_context_t *wc_ctx, 189251881Speter const char *path, 190251881Speter apr_pool_t *result_pool, 191251881Speter apr_pool_t *scratch_pool) 192251881Speter{ 193251881Speter svn_boolean_t is_wc_root, is_switched; 194251881Speter svn_node_kind_t kind; 195251881Speter const char *local_abspath; 196251881Speter svn_error_t *err; 197251881Speter 198251881Speter SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, scratch_pool)); 199251881Speter 200251881Speter err = svn_wc__db_is_switched(&is_wc_root, &is_switched, &kind, 201251881Speter wc_ctx->db, local_abspath, 202251881Speter scratch_pool); 203251881Speter 204251881Speter if (err) 205251881Speter { 206251881Speter if (err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND && 207251881Speter err->apr_err != SVN_ERR_WC_NOT_WORKING_COPY) 208251881Speter return svn_error_trace(err); 209251881Speter 210251881Speter svn_error_clear(err); 211251881Speter is_wc_root = FALSE; 212251881Speter is_switched = FALSE; 213251881Speter } 214251881Speter 215251881Speter /* If PATH is not a WC root, or if it is a file, lop off a basename. */ 216251881Speter if (!(is_wc_root || is_switched) || (kind != svn_node_dir)) 217251881Speter { 218251881Speter svn_dirent_split(anchor, target, path, result_pool); 219251881Speter } 220251881Speter else 221251881Speter { 222251881Speter *anchor = apr_pstrdup(result_pool, path); 223251881Speter *target = ""; 224251881Speter } 225251881Speter 226251881Speter return SVN_NO_ERROR; 227251881Speter} 228