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. */
39 struct 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 
47 static svn_error_t *
fetch_base_func(const char ** filename,void * baton,const char * path,svn_revnum_t base_revision,apr_pool_t * result_pool,apr_pool_t * scratch_pool)48 fetch_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 
87 static svn_error_t *
fetch_props_func(apr_hash_t ** props,void * baton,const char * path,svn_revnum_t base_revision,apr_pool_t * result_pool,apr_pool_t * scratch_pool)88 fetch_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 
132 static svn_error_t *
fetch_kind_func(svn_node_kind_t * kind,void * baton,const char * path,svn_revnum_t base_revision,apr_pool_t * scratch_pool)133 fetch_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 
153 svn_error_t *
svn_rdump__get_dump_editor(const svn_delta_editor_t ** editor,void ** edit_baton,svn_revnum_t revision,svn_stream_t * stream,svn_ra_session_t * ra_session,const char * update_anchor_relpath,svn_cancel_func_t cancel_func,void * cancel_baton,apr_pool_t * pool)154 svn_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