📄 props.c
字号:
SVN_ERR(svn_wc__prop_path(&working_prop_tmp_path, full_path, kind, TRUE, pool)); /* Write the working prop hash to path/.svn/tmp/props/name or path/.svn/tmp/dir-props */ SVN_ERR(svn_wc__save_prop_file(working_prop_tmp_path, working_props, pool)); /* Compute pathnames for the "mv" log entries. Notice that these paths are RELATIVE pathnames (each beginning with ".svn/"), so that each .svn subdir remains separable when executing run_log(). */ tmp_props = apr_pstrdup(pool, working_prop_tmp_path + access_len); /* Write log entry to move working tmp copy to real working area. */ SVN_ERR(svn_wc__loggy_move(log_accum, NULL, adm_access, tmp_props, real_props, FALSE, pool)); /* Make props read-only */ SVN_ERR(svn_wc__loggy_set_readonly(log_accum, adm_access, real_props, pool)); } else { /* No property modifications, remove the file instead. */ SVN_ERR(svn_wc__loggy_remove(log_accum, adm_access, real_props, pool)); } /* Repeat the above steps for the base properties if required. */ if (write_base_props) { const char *base_propfile_path, *base_prop_tmp_path; const char *tmp_prop_base, *real_prop_base; SVN_ERR(svn_wc__prop_base_path(&base_propfile_path, full_path, kind, FALSE, pool)); real_prop_base = apr_pstrdup(pool, base_propfile_path + access_len); if (apr_hash_count(base_props) > 0) { SVN_ERR(svn_wc__prop_base_path(&base_prop_tmp_path, full_path, kind, TRUE, pool)); SVN_ERR(svn_wc__save_prop_file(base_prop_tmp_path, base_props, pool)); tmp_prop_base = apr_pstrdup(pool, base_prop_tmp_path + access_len); SVN_ERR(svn_wc__loggy_move(log_accum, NULL, adm_access, tmp_prop_base, real_prop_base, FALSE, pool)); SVN_ERR(svn_wc__loggy_set_readonly(log_accum, adm_access, real_prop_base, pool)); } else SVN_ERR(svn_wc__loggy_remove(log_accum, adm_access, real_prop_base, pool)); } return SVN_NO_ERROR;}/*---------------------------------------------------------------------*//*** Merging propchanges into the working copy ***/svn_error_t *svn_wc_merge_props(svn_wc_notify_state_t *state, const char *path, svn_wc_adm_access_t *adm_access, apr_hash_t *baseprops, const apr_array_header_t *propchanges, svn_boolean_t base_merge, svn_boolean_t dry_run, apr_pool_t *pool){ const svn_wc_entry_t *entry; const char *parent, *base_name; svn_stringbuf_t *log_accum; /* IMPORTANT: svn_wc_merge_prop_diffs relies on the fact that baseprops may be NULL. */ SVN_ERR(svn_wc_entry(&entry, path, adm_access, FALSE, pool)); if (entry == NULL) return svn_error_createf(SVN_ERR_UNVERSIONED_RESOURCE, NULL, _("'%s' is not under version control"), svn_path_local_style(path, pool)); /* Notice that we're not using svn_path_split_if_file(), because that looks at the actual working file. Its existence shouldn't matter, so we're looking at entry->kind instead. */ switch (entry->kind) { case svn_node_dir: parent = path; base_name = NULL; break; case svn_node_file: svn_path_split(path, &parent, &base_name, pool); break; default: return SVN_NO_ERROR; /* ### svn_node_none or svn_node_unknown */ } if (! dry_run) log_accum = svn_stringbuf_create("", pool); /* Note that while this routine does the "real" work, it's only prepping tempfiles and writing log commands. */ SVN_ERR(svn_wc__merge_props(state, adm_access, base_name, baseprops, propchanges, base_merge, dry_run, pool, &log_accum)); if (! dry_run) { SVN_ERR(svn_wc__write_log(adm_access, 0, log_accum, pool)); SVN_ERR(svn_wc__run_log(adm_access, NULL, pool)); } return SVN_NO_ERROR;}svn_error_t *svn_wc__merge_props(svn_wc_notify_state_t *state, svn_wc_adm_access_t *adm_access, const char *name, apr_hash_t *server_baseprops, const apr_array_header_t *propchanges, svn_boolean_t base_merge, svn_boolean_t dry_run, apr_pool_t *pool, svn_stringbuf_t **entry_accum){ int i; svn_boolean_t is_dir; const char *entryname; const char *full_path; apr_hash_t *working_props; /* all `working' properties */ apr_hash_t *base_props; /* all `pristine' properties */ const char *access_path = svn_wc_adm_access_path(adm_access); int access_len = strlen(access_path); const char *reject_path = NULL; apr_file_t *reject_tmp_fp = NULL; /* the temporary conflicts file */ const char *reject_tmp_path = NULL; /* Non-empty path without trailing slash need an extra slash removed */ if (access_len != 0 && access_path[access_len - 1] != '/') access_len++; if (name == NULL) { /* We must be merging props on the directory PATH */ entryname = SVN_WC_ENTRY_THIS_DIR; full_path = access_path; is_dir = TRUE; } else { /* We must be merging props on the file PATH/NAME */ entryname = name; full_path = svn_path_join(access_path, name, pool); is_dir = FALSE; } /* Load the base & working property files into hashes */ SVN_ERR(svn_wc__load_props(&base_props, &working_props, adm_access, entryname, pool)); if (!server_baseprops) server_baseprops = base_props; if (state) { /* Start out assuming no conflicts. Don't bother to examine propchanges->nelts yet; even if we knew there were propchanges, we wouldn't yet know if they are "normal" props, as opposed wc or entry props. */ if (propchanges->nelts > 0) *state = svn_wc_notify_state_changed; else *state = svn_wc_notify_state_unchanged; } /* Looping over the array of incoming propchanges we want to apply: */ for (i = 0; i < propchanges->nelts; i++) { const char *propname; svn_string_t *conflict = NULL; const svn_prop_t *incoming_change; const svn_string_t *from_val, *to_val, *working_val; svn_boolean_t is_normal; /* For the incoming propchange, figure out the TO and FROM values. */ incoming_change = &APR_ARRAY_IDX(propchanges, i, svn_prop_t); propname = incoming_change->name; is_normal = svn_wc_is_normal_prop(propname); to_val = incoming_change->value ? svn_string_dup(incoming_change->value, pool) : NULL; from_val = apr_hash_get(server_baseprops, propname, APR_HASH_KEY_STRING); working_val = apr_hash_get(working_props, propname, APR_HASH_KEY_STRING); if (base_merge) apr_hash_set(base_props, propname, APR_HASH_KEY_STRING, to_val); /* We already know that state is at least `modified', so mark that, but remember that we may later upgrade to `merged' or even `conflicted'. */ if (state && is_normal) *state = svn_wc_notify_state_changed; if (! from_val) /* adding a new property */ { if (working_val) { /* the property already exists in working_props... */ if (svn_string_compare(working_val, to_val)) { /* The value we want is already there, so it's a 'clean merge'. */ if (state && is_normal && (*state != svn_wc_notify_state_conflicted)) *state = svn_wc_notify_state_merged; } else { conflict = svn_string_createf (pool, _("Trying to add new property '%s' with value '%s',\n" "but property already exists with value '%s'."), propname, to_val->data, working_val->data); } } else /* property dosen't yet exist in working_props... */ { /* so just set it */ apr_hash_set(working_props, propname, APR_HASH_KEY_STRING, to_val); } } else /* changing or deleting an existing property */ { if (! working_val) /* ... but it's not in the working_props */ { if (to_val) { conflict = svn_string_createf (pool, _("Trying to change property '%s' from '%s' to '%s',\n" "but the property does not exist."), propname, from_val->data, to_val->data); } else { /* The property to be deleted doesn't exist, so it's a 'clean merge'. */ if (state && is_normal && (*state != svn_wc_notify_state_conflicted)) *state = svn_wc_notify_state_merged; } } else /* property already exists */ { if (svn_string_compare(working_val, from_val)) { /* property has the expected 'from' value, so it's fine to set it to the 'to' value. */ apr_hash_set(working_props, propname, APR_HASH_KEY_STRING, to_val); } else if (!to_val && !svn_string_compare(from_val, working_val)) { conflict = svn_string_createf (pool, _("Trying to delete property '%s' but value" " has been modified from '%s' to '%s'."), propname, from_val->data, working_val->data); } else if (svn_string_compare(working_val, to_val)) { /* The value we want is already there, so it's a 'clean merge'. */ if (state && is_normal && (*state != svn_wc_notify_state_conflicted)) *state = svn_wc_notify_state_merged; } else /* property has some random value */ { conflict = svn_string_createf (pool, _("Trying to change property '%s' from '%s' to '%s',\n" "but property already exists with value '%s'."), propname, from_val->data, to_val->data, working_val->data); } } } /* merging logic complete, now we need to possibly log conflict data to tmpfiles. */ if (conflict) { if (state && is_normal) *state = svn_wc_notify_state_conflicted; if (dry_run) continue; /* skip to next incoming change */ if (! reject_tmp_fp) /* This is the very first prop conflict found on this item. */ SVN_ERR(open_reject_tmp_file(&reject_tmp_fp, &reject_tmp_path, full_path, adm_access, is_dir, pool)); /* Append the conflict to the open tmp/PROPS/---.prej file */ SVN_ERR(append_prop_conflict(reject_tmp_fp, conflict, pool)); } } /* foreach propchange ... */ /* Finished applying all incoming propchanges to our hashes! */ if (dry_run) return SVN_NO_ERROR; SVN_ERR(svn_wc__install_props(entry_accum, adm_access, entryname, base_props, working_props, base_merge, pool)); if (reject_tmp_fp) { /* There's a .prej file sitting in .svn/tmp/ somewhere. Deal with the conflicts. */ /* First, _close_ this temporary conflicts file. We've been appending to it all along. */ SVN_ERR(svn_io_file_close(reject_tmp_fp, pool)); /* Now try to get the name of a pre-existing .prej file from the entries file */ SVN_ERR(get_existing_prop_reject_file(&reject_path, adm_access, entryname, pool)); if (! reject_path) { /* Reserve a new .prej file *above* the .svn/ directory by opening and closing it. */ const char *reserved_path; const char *full_reject_path; full_reject_path = svn_path_join (access_path, is_dir ? SVN_WC__THIS_DIR_PREJ : name, pool); SVN_ERR(svn_io_open_unique_file2(NULL, &reserved_path, full_reject_path, SVN_WC__PROP_REJ_EXT, svn_io_file_del_none, pool)); /* This file will be overwritten when the log is run; that's ok, because at least now we have a reservation on disk. */ /* Now just get the name of the reserved file. This is the "relative" path we will use in the log entry. */ reject_path = svn_path_basename(reserved_path, pool); } /* We've now guaranteed that some kind of .prej file exists above the .svn/ dir. We write log entries to append our conflicts to it. */ SVN_ERR(svn_wc__loggy_append(entry_accum, adm_access, reject_tmp_path, reject_path, pool));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -