]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/subversion/subversion/libsvn_repos/node_tree.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / subversion / subversion / libsvn_repos / node_tree.c
1 /*
2  * node_tree.c:  an editor for tracking repository deltas changes
3  *
4  * ====================================================================
5  *    Licensed to the Apache Software Foundation (ASF) under one
6  *    or more contributor license agreements.  See the NOTICE file
7  *    distributed with this work for additional information
8  *    regarding copyright ownership.  The ASF licenses this file
9  *    to you under the Apache License, Version 2.0 (the
10  *    "License"); you may not use this file except in compliance
11  *    with the License.  You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  *    Unless required by applicable law or agreed to in writing,
16  *    software distributed under the License is distributed on an
17  *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18  *    KIND, either express or implied.  See the License for the
19  *    specific language governing permissions and limitations
20  *    under the License.
21  * ====================================================================
22  */
23
24 /* ==================================================================== */
25
26
27
28 \f
29 #include <stdio.h>
30
31 #define APR_WANT_STRFUNC
32 #include <apr_want.h>
33 #include <apr_pools.h>
34
35 #include "svn_types.h"
36 #include "svn_error.h"
37 #include "svn_dirent_uri.h"
38 #include "svn_path.h"
39 #include "svn_delta.h"
40 #include "svn_fs.h"
41 #include "svn_repos.h"
42 #include "repos.h"
43 #include "svn_private_config.h"
44 #include "private/svn_fspath.h"
45
46 /*** NOTE: This editor is unique in that it currently is hard-coded to
47      be anchored at the root directory of the filesystem.  This
48      affords us the ability to use the same paths for filesystem
49      locations and editor paths.  ***/
50
51
52 \f
53 /*** Node creation and assembly structures and routines. ***/
54 static svn_repos_node_t *
55 create_node(const char *name,
56             svn_repos_node_t *parent,
57             apr_pool_t *pool)
58 {
59   svn_repos_node_t *node = apr_pcalloc(pool, sizeof(*node));
60   node->action = 'R';
61   node->kind = svn_node_unknown;
62   node->name = apr_pstrdup(pool, name);
63   node->parent = parent;
64   return node;
65 }
66
67
68 static svn_repos_node_t *
69 create_sibling_node(svn_repos_node_t *elder,
70                     const char *name,
71                     apr_pool_t *pool)
72 {
73   svn_repos_node_t *tmp_node;
74
75   /* No ELDER sibling?  That's just not gonna work out. */
76   if (! elder)
77     return NULL;
78
79   /* Run to the end of the list of siblings of ELDER. */
80   tmp_node = elder;
81   while (tmp_node->sibling)
82     tmp_node = tmp_node->sibling;
83
84   /* Create a new youngest sibling and return that. */
85   return (tmp_node->sibling = create_node(name, elder->parent, pool));
86 }
87
88
89 static svn_repos_node_t *
90 create_child_node(svn_repos_node_t *parent,
91                   const char *name,
92                   apr_pool_t *pool)
93 {
94   /* No PARENT node?  That's just not gonna work out. */
95   if (! parent)
96     return NULL;
97
98   /* If PARENT has no children, create its first one and return that. */
99   if (! parent->child)
100     return (parent->child = create_node(name, parent, pool));
101
102   /* If PARENT already has a child, create a new sibling for its first
103      child and return that. */
104   return create_sibling_node(parent->child, name, pool);
105 }
106
107
108 static svn_repos_node_t *
109 find_child_by_name(svn_repos_node_t *parent,
110                    const char *name)
111 {
112   svn_repos_node_t *tmp_node;
113
114   /* No PARENT node, or a barren PARENT?  Nothing to find. */
115   if ((! parent) || (! parent->child))
116     return NULL;
117
118   /* Look through the children for a node with a matching name. */
119   tmp_node = parent->child;
120   while (1)
121     {
122       if (! strcmp(tmp_node->name, name))
123         {
124           return tmp_node;
125         }
126       else
127         {
128           if (tmp_node->sibling)
129             tmp_node = tmp_node->sibling;
130           else
131             break;
132         }
133     }
134
135   return NULL;
136 }
137
138
139 static void
140 find_real_base_location(const char **path_p,
141                         svn_revnum_t *rev_p,
142                         svn_repos_node_t *node,
143                         apr_pool_t *pool)
144 {
145   /* If NODE is an add-with-history, then its real base location is
146      the copy source. */
147   if ((node->action == 'A')
148       && node->copyfrom_path
149       && SVN_IS_VALID_REVNUM(node->copyfrom_rev))
150     {
151       *path_p = node->copyfrom_path;
152       *rev_p = node->copyfrom_rev;
153       return;
154     }
155
156   /* Otherwise, if NODE has a parent, we'll recurse, and add NODE's
157      name to whatever the parent's real base path turns out to be (and
158      pass the base revision on through). */
159   if (node->parent)
160     {
161       const char *path;
162       svn_revnum_t rev;
163
164       find_real_base_location(&path, &rev, node->parent, pool);
165       *path_p = svn_fspath__join(path, node->name, pool);
166       *rev_p = rev;
167       return;
168     }
169
170   /* Finally, if the node has no parent, then its name is "/", and it
171      has no interesting base revision.  */
172   *path_p = "/";
173   *rev_p = SVN_INVALID_REVNUM;
174   return;
175 }
176
177
178
179 \f
180 /*** Editor functions and batons. ***/
181
182 struct edit_baton
183 {
184   svn_fs_t *fs;
185   svn_fs_root_t *root;
186   svn_fs_root_t *base_root;
187   apr_pool_t *node_pool;
188   svn_repos_node_t *node;
189 };
190
191
192 struct node_baton
193 {
194   struct edit_baton *edit_baton;
195   struct node_baton *parent_baton;
196   svn_repos_node_t *node;
197 };
198
199
200 static svn_error_t *
201 delete_entry(const char *path,
202              svn_revnum_t revision,
203              void *parent_baton,
204              apr_pool_t *pool)
205 {
206   struct node_baton *d = parent_baton;
207   struct edit_baton *eb = d->edit_baton;
208   svn_repos_node_t *node;
209   const char *name;
210   const char *base_path;
211   svn_revnum_t base_rev;
212   svn_fs_root_t *base_root;
213   svn_node_kind_t kind;
214
215   /* Get (or create) the change node and update it. */
216   name = svn_relpath_basename(path, pool);
217   node = find_child_by_name(d->node, name);
218   if (! node)
219     node = create_child_node(d->node, name, eb->node_pool);
220   node->action = 'D';
221
222   /* We need to look up this node's parents to see what its original
223      path in the filesystem was.  Why?  Because if this deletion
224      occurred underneath a copied path, the thing that was deleted
225      probably lived at a different location (relative to the copy
226      source). */
227   find_real_base_location(&base_path, &base_rev, node, pool);
228   if (! SVN_IS_VALID_REVNUM(base_rev))
229     {
230       /* No interesting base revision?  We'll just look for the path
231          in our base root.  */
232       base_root = eb->base_root;
233     }
234   else
235     {
236       /* Oh.  Perhaps some copy goodness happened somewhere? */
237       SVN_ERR(svn_fs_revision_root(&base_root, eb->fs, base_rev, pool));
238     }
239
240   /* Now figure out if this thing was a file or a dir. */
241   SVN_ERR(svn_fs_check_path(&kind, base_root, base_path, pool));
242   if (kind == svn_node_none)
243     return svn_error_createf(SVN_ERR_FS_NOT_FOUND, NULL,
244                              _("'%s' not found in filesystem"), path);
245   node->kind = kind;
246
247   return SVN_NO_ERROR;
248 }
249
250
251
252 static svn_error_t *
253 add_open_helper(const char *path,
254                 char action,
255                 svn_node_kind_t kind,
256                 void *parent_baton,
257                 const char *copyfrom_path,
258                 svn_revnum_t copyfrom_rev,
259                 apr_pool_t *pool,
260                 void **child_baton)
261 {
262   struct node_baton *pb = parent_baton;
263   struct edit_baton *eb = pb->edit_baton;
264   struct node_baton *nb = apr_pcalloc(pool, sizeof(*nb));
265
266   SVN_ERR_ASSERT(parent_baton && path);
267
268   nb->edit_baton = eb;
269   nb->parent_baton = pb;
270
271   /* Create and populate the node. */
272   nb->node = create_child_node(pb->node, svn_relpath_basename(path, NULL),
273                                eb->node_pool);
274   nb->node->kind = kind;
275   nb->node->action = action;
276   nb->node->copyfrom_rev = copyfrom_rev;
277   nb->node->copyfrom_path =
278     copyfrom_path ? apr_pstrdup(eb->node_pool, copyfrom_path) : NULL;
279
280   *child_baton = nb;
281   return SVN_NO_ERROR;
282 }
283
284
285 static svn_error_t *
286 open_root(void *edit_baton,
287           svn_revnum_t base_revision,
288           apr_pool_t *pool,
289           void **root_baton)
290 {
291   struct edit_baton *eb = edit_baton;
292   struct node_baton *d = apr_pcalloc(pool, sizeof(*d));
293
294   d->edit_baton = eb;
295   d->parent_baton = NULL;
296   d->node = (eb->node = create_node("", NULL, eb->node_pool));
297   d->node->kind = svn_node_dir;
298   d->node->action = 'R';
299   *root_baton = d;
300
301   return SVN_NO_ERROR;
302 }
303
304
305 static svn_error_t *
306 open_directory(const char *path,
307                void *parent_baton,
308                svn_revnum_t base_revision,
309                apr_pool_t *pool,
310                void **child_baton)
311 {
312   return add_open_helper(path, 'R', svn_node_dir, parent_baton,
313                          NULL, SVN_INVALID_REVNUM,
314                          pool, child_baton);
315 }
316
317
318 static svn_error_t *
319 add_directory(const char *path,
320               void *parent_baton,
321               const char *copyfrom_path,
322               svn_revnum_t copyfrom_revision,
323               apr_pool_t *pool,
324               void **child_baton)
325 {
326   return add_open_helper(path, 'A', svn_node_dir, parent_baton,
327                          copyfrom_path, copyfrom_revision,
328                          pool, child_baton);
329 }
330
331
332 static svn_error_t *
333 open_file(const char *path,
334           void *parent_baton,
335           svn_revnum_t base_revision,
336           apr_pool_t *pool,
337           void **file_baton)
338 {
339   return add_open_helper(path, 'R', svn_node_file, parent_baton,
340                          NULL, SVN_INVALID_REVNUM,
341                          pool, file_baton);
342 }
343
344
345 static svn_error_t *
346 add_file(const char *path,
347          void *parent_baton,
348          const char *copyfrom_path,
349          svn_revnum_t copyfrom_revision,
350          apr_pool_t *pool,
351          void **file_baton)
352 {
353   return add_open_helper(path, 'A', svn_node_file, parent_baton,
354                          copyfrom_path, copyfrom_revision,
355                          pool, file_baton);
356 }
357
358
359 static svn_error_t *
360 apply_textdelta(void *file_baton,
361                 const char *base_checksum,
362                 apr_pool_t *pool,
363                 svn_txdelta_window_handler_t *handler,
364                 void **handler_baton)
365 {
366   struct node_baton *fb = file_baton;
367   fb->node->text_mod = TRUE;
368   *handler = svn_delta_noop_window_handler;
369   *handler_baton = NULL;
370   return SVN_NO_ERROR;
371 }
372
373
374
375 static svn_error_t *
376 change_node_prop(void *node_baton,
377                  const char *name,
378                  const svn_string_t *value,
379                  apr_pool_t *pool)
380 {
381   struct node_baton *nb = node_baton;
382   nb->node->prop_mod = TRUE;
383   return SVN_NO_ERROR;
384 }
385
386
387 svn_error_t *
388 svn_repos_node_editor(const svn_delta_editor_t **editor,
389                       void **edit_baton,
390                       svn_repos_t *repos,
391                       svn_fs_root_t *base_root,
392                       svn_fs_root_t *root,
393                       apr_pool_t *node_pool,
394                       apr_pool_t *pool)
395 {
396   svn_delta_editor_t *my_editor;
397   struct edit_baton *my_edit_baton;
398
399   /* Set up the editor. */
400   my_editor = svn_delta_default_editor(pool);
401   my_editor->open_root           = open_root;
402   my_editor->delete_entry        = delete_entry;
403   my_editor->add_directory       = add_directory;
404   my_editor->open_directory      = open_directory;
405   my_editor->add_file            = add_file;
406   my_editor->open_file           = open_file;
407   my_editor->apply_textdelta     = apply_textdelta;
408   my_editor->change_file_prop    = change_node_prop;
409   my_editor->change_dir_prop     = change_node_prop;
410
411   /* Set up the edit baton. */
412   my_edit_baton = apr_pcalloc(pool, sizeof(*my_edit_baton));
413   my_edit_baton->node_pool = node_pool;
414   my_edit_baton->fs = repos->fs;
415   my_edit_baton->root = root;
416   my_edit_baton->base_root = base_root;
417
418   *editor = my_editor;
419   *edit_baton = my_edit_baton;
420
421   return SVN_NO_ERROR;
422 }
423
424
425
426 svn_repos_node_t *
427 svn_repos_node_from_baton(void *edit_baton)
428 {
429   struct edit_baton *eb = edit_baton;
430   return eb->node;
431 }