⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tree.c

📁 subversion-1.4.3-1.tar.gz 配置svn的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* Determine if the properties of two path/root combinations are   different.  Set *CHANGED_P to TRUE if the properties at PATH1 under   ROOT1 differ from those at PATH2 under ROOT2, or FALSE otherwise.   Both roots must be in the same filesystem. */static svn_error_t *fs_props_changed(svn_boolean_t *changed_p,                 svn_fs_root_t *root1,                 const char *path1,                 svn_fs_root_t *root2,                 const char *path2,                 apr_pool_t *pool){  dag_node_t *node1, *node2;    /* Check that roots are in the same fs. */  if (root1->fs != root2->fs)    return svn_error_create      (SVN_ERR_FS_GENERAL, NULL,       _("Cannot compare property value between two different filesystems"));    SVN_ERR(get_dag(&node1, root1, path1, pool));  SVN_ERR(get_dag(&node2, root2, path2, pool));  SVN_ERR(svn_fs_fs__things_different(changed_p, NULL,                                       node1, node2, pool));    return SVN_NO_ERROR;}/* Merges and commits. *//* Set ARGS->node to the root node of ARGS->root.  */static svn_error_t *get_root(dag_node_t **node, svn_fs_root_t *root, apr_pool_t *pool){  SVN_ERR(get_dag(node, root, "", pool));  return SVN_NO_ERROR;}static svn_error_t *update_ancestry(svn_fs_t *fs,                const svn_fs_id_t *source_id,                const svn_fs_id_t *target_id,                const char *txn_id,                const char *target_path,                int source_pred_count,                apr_pool_t *pool){  node_revision_t *noderev;  if (svn_fs_fs__id_txn_id(target_id) == NULL)    return svn_error_createf      (SVN_ERR_FS_NOT_MUTABLE, NULL,       _("Unexpected immutable node at '%s'"), target_path);  SVN_ERR(svn_fs_fs__get_node_revision(&noderev, fs, target_id, pool));  noderev->predecessor_id = source_id;  noderev->predecessor_count = source_pred_count;  if (noderev->predecessor_count != -1)    noderev->predecessor_count++;  SVN_ERR(svn_fs_fs__put_node_revision(fs, target_id, noderev, pool));  return SVN_NO_ERROR;}/* Set the contents of CONFLICT_PATH to PATH, and return an   SVN_ERR_FS_CONFLICT error that indicates that there was a conflict   at PATH.  Perform all allocations in POOL (except the allocation of   CONFLICT_PATH, which should be handled outside this function).  */static svn_error_t *conflict_err(svn_stringbuf_t *conflict_path,             const char *path){  svn_stringbuf_set(conflict_path, path);  return svn_error_createf(SVN_ERR_FS_CONFLICT, NULL,                           _("Conflict at '%s'"), path);}/* Merge changes between ANCESTOR and SOURCE into TARGET.  ANCESTOR * and TARGET must be distinct node revisions.  TARGET_PATH should * correspond to TARGET's full path in its filesystem, and is used for * reporting conflict location. * * SOURCE, TARGET, and ANCESTOR are generally directories; this * function recursively merges the directories' contents.  If any are * files, this function simply returns an error whenever SOURCE, * TARGET, and ANCESTOR are all distinct node revisions. * * If there are differences between ANCESTOR and SOURCE that conflict * with changes between ANCESTOR and TARGET, this function returns an * SVN_ERR_FS_CONFLICT error, and updates CONFLICT_P to the name of the * conflicting node in TARGET, with TARGET_PATH prepended as a path. * * If there are no conflicting differences, CONFLICT_P is updated to * the empty string. * * CONFLICT_P must point to a valid svn_stringbuf_t. * * Do any necessary temporary allocation in POOL. */static svn_error_t *merge(svn_stringbuf_t *conflict_p,      const char *target_path,      dag_node_t *target,      dag_node_t *source,      dag_node_t *ancestor,      const char *txn_id,      apr_pool_t *pool){  const svn_fs_id_t *source_id, *target_id, *ancestor_id;  apr_hash_t *s_entries, *t_entries, *a_entries;  apr_hash_index_t *hi;  svn_fs_t *fs;  apr_pool_t *iterpool;  int pred_count;  /* Make sure everyone comes from the same filesystem. */  fs = svn_fs_fs__dag_get_fs(ancestor);  if ((fs != svn_fs_fs__dag_get_fs(source))      || (fs != svn_fs_fs__dag_get_fs(target)))    {      return svn_error_create        (SVN_ERR_FS_CORRUPT, NULL,         _("Bad merge; ancestor, source, and target not all in same fs"));    }  /* We have the same fs, now check it. */  SVN_ERR(svn_fs_fs__check_fs(fs));  source_id   = svn_fs_fs__dag_get_id(source);  target_id   = svn_fs_fs__dag_get_id(target);  ancestor_id = svn_fs_fs__dag_get_id(ancestor);  /* It's improper to call this function with ancestor == target. */  if (svn_fs_fs__id_eq(ancestor_id, target_id))    {      svn_string_t *id_str = svn_fs_fs__id_unparse(target_id, pool);      return svn_error_createf        (SVN_ERR_FS_GENERAL, NULL,         _("Bad merge; target '%s' has id '%s', same as ancestor"),         target_path, id_str->data);    }  svn_stringbuf_setempty(conflict_p);  /* Base cases:   * Either no change made in source, or same change as made in target.   * Both mean nothing to merge here.   */  if (svn_fs_fs__id_eq(ancestor_id, source_id)      || (svn_fs_fs__id_eq(source_id, target_id)))    return SVN_NO_ERROR;  /* Else proceed, knowing all three are distinct node revisions.   *   * How to merge from this point:    *   * if (not all 3 are directories)   *   {   *     early exit with conflict;   *   }   *   * // Property changes may only be made to up-to-date   * // directories, because once the client commits the prop   * // change, it bumps the directory's revision, and therefore   * // must be able to depend on there being no other changes to   * // that directory in the repository.   * if (target's property list differs from ancestor's)   *    conflict;   *   * For each entry NAME in the directory ANCESTOR:   *   *   Let ANCESTOR-ENTRY, SOURCE-ENTRY, and TARGET-ENTRY be the IDs of   *   the name within ANCESTOR, SOURCE, and TARGET respectively.   *   (Possibly null if NAME does not exist in SOURCE or TARGET.)   *   *   If ANCESTOR-ENTRY == SOURCE-ENTRY, then:   *     No changes were made to this entry while the transaction was in   *     progress, so do nothing to the target.   *   *   Else if ANCESTOR-ENTRY == TARGET-ENTRY, then:   *     A change was made to this entry while the transaction was in   *     process, but the transaction did not touch this entry.  Replace   *     TARGET-ENTRY with SOURCE-ENTRY.   *   *   Else:   *     Changes were made to this entry both within the transaction and   *     to the repository while the transaction was in progress.  They   *     must be merged or declared to be in conflict.   *   *     If SOURCE-ENTRY and TARGET-ENTRY are both null, that's a   *     double delete; flag a conflict.   *   *     If any of the three entries is of type file, declare a conflict.   *   *     If either SOURCE-ENTRY or TARGET-ENTRY is not a direct   *     modification of ANCESTOR-ENTRY (determine by comparing the   *     node-id fields), declare a conflict.  A replacement is   *     incompatible with a modification or other replacement--even   *     an identical replacement.   *   *     Direct modifications were made to the directory ANCESTOR-ENTRY   *     in both SOURCE and TARGET.  Recursively merge these   *     modifications.   *   * For each leftover entry NAME in the directory SOURCE:   *   *   If NAME exists in TARGET, declare a conflict.  Even if SOURCE and   *   TARGET are adding exactly the same thing, two additions are not   *   auto-mergeable with each other.   *   *   Add NAME to TARGET with the entry from SOURCE.   *   * Now that we are done merging the changes from SOURCE into the   * directory TARGET, update TARGET's predecessor to be SOURCE.   */  if ((svn_fs_fs__dag_node_kind(source) != svn_node_dir)      || (svn_fs_fs__dag_node_kind(target) != svn_node_dir)      || (svn_fs_fs__dag_node_kind(ancestor) != svn_node_dir))    {      return conflict_err(conflict_p, target_path);    }        /* Possible early merge failure: if target and ancestor have     different property lists, then the merge should fail.     Propchanges can *only* be committed on an up-to-date directory.     ### TODO: Please see issue #418 about the inelegance of this. */  {    node_revision_t *tgt_nr, *anc_nr;    /* Get node revisions for our id's. */        SVN_ERR(svn_fs_fs__get_node_revision(&tgt_nr, fs, target_id, pool));    SVN_ERR(svn_fs_fs__get_node_revision(&anc_nr, fs, ancestor_id, pool));        /* Now compare the prop-keys of the skels.  Note that just because       the keys are different -doesn't- mean the proplists have       different contents.  But merge() isn't concerned with contents;       it doesn't do a brute-force comparison on textual contents, so       it won't do that here either.  Checking to see if the propkey       atoms are `equal' is enough. */    if (! svn_fs_fs__noderev_same_rep_key(tgt_nr->prop_rep, anc_nr->prop_rep))      {        return conflict_err(conflict_p, target_path);      }  }  /* ### todo: it would be more efficient to simply check for a NULL     entries hash where necessary below than to allocate an empty hash     here, but another day, another day... */  SVN_ERR(svn_fs_fs__dag_dir_entries(&s_entries, source, pool));  s_entries = svn_fs_fs__copy_dir_entries(s_entries, pool);  SVN_ERR(svn_fs_fs__dag_dir_entries(&t_entries, target, pool));  t_entries = svn_fs_fs__copy_dir_entries(t_entries, pool);  SVN_ERR(svn_fs_fs__dag_dir_entries(&a_entries, ancestor, pool));  a_entries = svn_fs_fs__copy_dir_entries(a_entries, pool);  /* for each entry E in a_entries... */  iterpool = svn_pool_create(pool);  for (hi = apr_hash_first(pool, a_entries);        hi;        hi = apr_hash_next(hi))    {      svn_fs_dirent_t *s_entry, *t_entry, *a_entry;      const void *key;      void *val;      apr_ssize_t klen;                svn_pool_clear(iterpool);      /* KEY will be the entry name in ancestor, VAL the dirent */      apr_hash_this(hi, &key, &klen, &val);      a_entry = val;      s_entry = apr_hash_get(s_entries, key, klen);      t_entry = apr_hash_get(t_entries, key, klen);      /* No changes were made to this entry while the transaction was         in progress, so do nothing to the target. */      if (s_entry && svn_fs_fs__id_eq(a_entry->id, s_entry->id))        goto end;      /* A change was made to this entry while the transaction was in         process, but the transaction did not touch this entry. */      else if (t_entry && svn_fs_fs__id_eq(a_entry->id, t_entry->id))        {          if (s_entry)            {              SVN_ERR(svn_fs_fs__dag_set_entry(target, key,                                               s_entry->id,                                               s_entry->kind,                                               txn_id,                                               iterpool));            }          else            {              SVN_ERR(svn_fs_fs__dag_delete(target, key, txn_id, iterpool));            }        }      /* Changes were made to this entry both within the transaction         and to the repository while the transaction was in progress.         They must be merged or declared to be in conflict. */      else        {          dag_node_t *s_ent_node, *t_ent_node, *a_ent_node;          const char *new_tpath;          /* If SOURCE-ENTRY and TARGET-ENTRY are both null, that's a             double delete; flag a conflict. */          if (s_entry == NULL || t_entry == NULL)            return conflict_err(conflict_p,                                svn_path_join(target_path,                                              a_entry->name,                                              iterpool));          /* If any of the three entries is of type file, flag a conflict. */          if (s_entry->kind == svn_node_file              || t_entry->kind == svn_node_file              || a_entry->kind == svn_node_file)            return conflict_err(conflict_p,                                svn_path_join(target_path,                                              a_entry->name,                                              iterpool));          /* If either SOURCE-ENTRY or TARGET-ENTRY is not a direct             modification of ANCESTOR-ENTRY, declare a conflict. */          if (strcmp(svn_fs_fs__id_node_id(s_entry->id),                     svn_fs_fs__id_node_id(a_entry->id)) != 0              || strcmp(svn_fs_fs__id_copy_id(s_entry->id),                        svn_fs_fs__id_copy_id(a_entry->id)) != 0              || strcmp(svn_fs_fs__id_node_id(t_entry->id),                        svn_fs_fs__id_node_id(a_entry->id)) != 0              || strcmp(svn_fs_fs__id_copy_id(t_entry->id),                        svn_fs_fs__id_copy_id(a_entry->id)) != 0)            return conflict_err(conflict_p,                                svn_path_join(target_path,                                              a_entry->name,                                              iterpool));          /* Direct modifications were made to the directory             ANCESTOR-ENTRY in both SOURCE and TARGET.  Recursively             merge these modifications. */          SVN_ERR(svn_fs_fs__dag_get_node(&s_ent_node, fs,                                          s_entry->id, iterpool));          SVN_ERR(svn_fs_fs__dag_get_node(&t_ent_node, fs,                                          t_entry->id, iterpool));          SVN_ERR(svn_fs_fs__dag_get_node(&a_ent_node, fs,                                          a_entry->id, iterpool));          new_tpath = svn_path_join(target_path, t_entry->name, iterpool);          SVN_ERR(merge(conflict_p, new_tpath,                        t_ent_node, s_ent_node, a_ent_node,                        txn_id, iterpool));        }      /* We've taken care of any possible implications E could have.         Remove it from source_entries, so it's easy later to loop         over all the source entries that didn't exist in         ancestor_entries. */    end:      apr_hash_set(s_entries, key, klen, NULL);    }  /* For each entry E in source but not in ancestor */  for (hi = apr_hash_first(pool, s_entries);        hi;        hi = apr_hash_next(hi))    {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -