1/*
2 *  dump_editor.c: The svn_delta_editor_t editor used by svnrdump to
3 *  dump revisions.
4 *
5 * ====================================================================
6 *    Licensed to the Apache Software Foundation (ASF) under one
7 *    or more contributor license agreements.  See the NOTICE file
8 *    distributed with this work for additional information
9 *    regarding copyright ownership.  The ASF licenses this file
10 *    to you under the Apache License, Version 2.0 (the
11 *    "License"); you may not use this file except in compliance
12 *    with the License.  You may obtain a copy of the License at
13 *
14 *      http://www.apache.org/licenses/LICENSE-2.0
15 *
16 *    Unless required by applicable law or agreed to in writing,
17 *    software distributed under the License is distributed on an
18 *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
19 *    KIND, either express or implied.  See the License for the
20 *    specific language governing permissions and limitations
21 *    under the License.
22 * ====================================================================
23 */
24
25#include "svn_types.h"
26#include "svn_props.h"
27#include "svn_ra.h"
28#include "svn_io.h"
29#include "svn_delta.h"
30
31#include "private/svn_repos_private.h"
32#include "private/svn_editor.h"
33
34#include "svnrdump.h"
35#include <assert.h>
36
37
38/* The baton used by the dump editor. */
39struct dump_edit_baton {
40  /* A backdoor ra session to fetch additional information during the edit. */
41  svn_ra_session_t *ra_session;
42
43  /* The revision we're currently dumping. */
44  svn_revnum_t current_revision;
45};
46
47static svn_error_t *
48fetch_base_func(const char **filename,
49                void *baton,
50                const char *path,
51                svn_revnum_t base_revision,
52                apr_pool_t *result_pool,
53                apr_pool_t *scratch_pool)
54{
55  struct dump_edit_baton *eb = baton;
56  svn_stream_t *fstream;
57  svn_error_t *err;
58
59  if (path[0] == '/')
60    path += 1;
61
62  if (! SVN_IS_VALID_REVNUM(base_revision))
63    base_revision = eb->current_revision - 1;
64
65  SVN_ERR(svn_stream_open_unique(&fstream, filename, NULL,
66                                 svn_io_file_del_on_pool_cleanup,
67                                 result_pool, scratch_pool));
68
69  err = svn_ra_get_file(eb->ra_session, path, base_revision,
70                        fstream, NULL, NULL, scratch_pool);
71  if (err && err->apr_err == SVN_ERR_FS_NOT_FOUND)
72    {
73      svn_error_clear(err);
74      SVN_ERR(svn_stream_close(fstream));
75
76      *filename = NULL;
77      return SVN_NO_ERROR;
78    }
79  else if (err)
80    return svn_error_trace(err);
81
82  SVN_ERR(svn_stream_close(fstream));
83
84  return SVN_NO_ERROR;
85}
86
87static svn_error_t *
88fetch_props_func(apr_hash_t **props,
89                 void *baton,
90                 const char *path,
91                 svn_revnum_t base_revision,
92                 apr_pool_t *result_pool,
93                 apr_pool_t *scratch_pool)
94{
95  struct dump_edit_baton *eb = baton;
96  svn_node_kind_t node_kind;
97
98  if (path[0] == '/')
99    path += 1;
100
101  if (! SVN_IS_VALID_REVNUM(base_revision))
102    base_revision = eb->current_revision - 1;
103
104  SVN_ERR(svn_ra_check_path(eb->ra_session, path, base_revision, &node_kind,
105                            scratch_pool));
106
107  if (node_kind == svn_node_file)
108    {
109      SVN_ERR(svn_ra_get_file(eb->ra_session, path, base_revision,
110                              NULL, NULL, props, result_pool));
111    }
112  else if (node_kind == svn_node_dir)
113    {
114      apr_array_header_t *tmp_props;
115
116      SVN_ERR(svn_ra_get_dir2(eb->ra_session, NULL, NULL, props, path,
117                              base_revision, 0 /* Dirent fields */,
118                              result_pool));
119      tmp_props = svn_prop_hash_to_array(*props, result_pool);
120      SVN_ERR(svn_categorize_props(tmp_props, NULL, NULL, &tmp_props,
121                                   result_pool));
122      *props = svn_prop_array_to_hash(tmp_props, result_pool);
123    }
124  else
125    {
126      *props = apr_hash_make(result_pool);
127    }
128
129  return SVN_NO_ERROR;
130}
131
132static svn_error_t *
133fetch_kind_func(svn_node_kind_t *kind,
134                void *baton,
135                const char *path,
136                svn_revnum_t base_revision,
137                apr_pool_t *scratch_pool)
138{
139  struct dump_edit_baton *eb = baton;
140
141  if (path[0] == '/')
142    path += 1;
143
144  if (! SVN_IS_VALID_REVNUM(base_revision))
145    base_revision = eb->current_revision - 1;
146
147  SVN_ERR(svn_ra_check_path(eb->ra_session, path, base_revision, kind,
148                            scratch_pool));
149
150  return SVN_NO_ERROR;
151}
152
153svn_error_t *
154svn_rdump__get_dump_editor(const svn_delta_editor_t **editor,
155                           void **edit_baton,
156                           svn_revnum_t revision,
157                           svn_stream_t *stream,
158                           svn_ra_session_t *ra_session,
159                           const char *update_anchor_relpath,
160                           svn_cancel_func_t cancel_func,
161                           void *cancel_baton,
162                           apr_pool_t *pool)
163{
164  struct dump_edit_baton *eb;
165  svn_delta_shim_callbacks_t *shim_callbacks =
166                                        svn_delta_shim_callbacks_default(pool);
167
168  eb = apr_pcalloc(pool, sizeof(struct dump_edit_baton));
169  eb->ra_session = ra_session;
170  eb->current_revision = revision;
171
172  SVN_ERR(svn_repos__get_dump_editor(editor, edit_baton,
173                                     stream, update_anchor_relpath, pool));
174
175  /* Wrap this editor in a cancellation editor. */
176  SVN_ERR(svn_delta_get_cancellation_editor(cancel_func, cancel_baton,
177                                            *editor, *edit_baton,
178                                            editor, edit_baton,
179                                            pool));
180
181  shim_callbacks->fetch_base_func = fetch_base_func;
182  shim_callbacks->fetch_props_func = fetch_props_func;
183  shim_callbacks->fetch_kind_func = fetch_kind_func;
184  shim_callbacks->fetch_baton = eb;
185
186  SVN_ERR(svn_editor__insert_shims(editor, edit_baton, *editor, *edit_baton,
187                                   NULL, NULL, shim_callbacks, pool, pool));
188
189  return SVN_NO_ERROR;
190}
191