1 /* fs-util.c : internal utility functions used by both FSFS and BDB back
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
13 * http://www.apache.org/licenses/LICENSE-2.0
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
21 * ====================================================================
26 #include <apr_pools.h>
27 #include <apr_strings.h>
31 #include "svn_dirent_uri.h"
33 #include "svn_private_config.h"
35 #include "private/svn_fs_util.h"
36 #include "private/svn_fspath.h"
37 #include "../libsvn_fs/fs-loader.h"
39 /* Return TRUE, if PATH of PATH_LEN > 0 chars starts with a '/' and does
40 * not end with a '/' and does not contain duplicate '/'.
43 is_canonical_abspath(const char *path, size_t path_len)
47 /* check for leading '/' */
51 /* check for trailing '/' */
54 if (path[path_len - 1] == '/')
58 end = path + path_len - 1;
59 for (; path != end; ++path)
60 if ((path[0] == '/') && (path[1] == '/'))
67 svn_fs__is_canonical_abspath(const char *path)
69 /* No PATH? No problem. */
73 /* Empty PATH? That's just "/". */
78 return is_canonical_abspath(path, strlen(path));
82 svn_fs__canonicalize_abspath(const char *path, apr_pool_t *pool)
86 size_t path_i = 0, newpath_i = 0;
87 svn_boolean_t eating_slashes = FALSE;
89 /* No PATH? No problem. */
93 /* Empty PATH? That's just "/". */
97 /* Non-trivial cases. Maybe, the path already is canonical after all? */
98 path_len = strlen(path);
99 if (is_canonical_abspath(path, path_len))
100 return apr_pstrmemdup(pool, path, path_len);
102 /* Now, the fun begins. Alloc enough room to hold PATH with an
103 added leading '/'. */
104 newpath = apr_palloc(pool, path_len + 2);
106 /* No leading slash? Fix that. */
109 newpath[newpath_i++] = '/';
112 for (path_i = 0; path_i < path_len; path_i++)
114 if (path[path_i] == '/')
116 /* The current character is a '/'. If we are eating up
117 extra '/' characters, skip this character. Else, note
118 that we are now eating slashes. */
121 eating_slashes = TRUE;
125 /* The current character is NOT a '/'. If we were eating
126 slashes, we need not do that any more. */
128 eating_slashes = FALSE;
131 /* Copy the current character into our new buffer. */
132 newpath[newpath_i++] = path[path_i];
135 /* Did we leave a '/' attached to the end of NEWPATH (other than in
136 the root directory case)? */
137 if ((newpath[newpath_i - 1] == '/') && (newpath_i > 1))
138 newpath[newpath_i - 1] = '\0';
140 newpath[newpath_i] = '\0';
146 svn_fs__check_fs(svn_fs_t *fs,
147 svn_boolean_t expect_open)
149 if ((expect_open && fs->fsap_data)
150 || ((! expect_open) && (! fs->fsap_data)))
153 return svn_error_create(SVN_ERR_FS_NOT_OPEN, 0,
154 _("Filesystem object has not been opened yet"));
156 return svn_error_create(SVN_ERR_FS_ALREADY_OPEN, 0,
157 _("Filesystem object already open"));
161 svn_fs__next_entry_name(const char **next_p,
167 /* Find the end of the current component. */
168 end = strchr(path, '/');
172 /* The path contains only one component, with no trailing
175 return apr_pstrdup(pool, path);
179 /* There's a slash after the first component. Skip over an arbitrary
180 number of slashes to find the next one. */
181 const char *next = end;
185 return apr_pstrndup(pool, path, end - path);
189 svn_fs_path_change2_t *
190 svn_fs__path_change_create_internal(const svn_fs_id_t *node_rev_id,
191 svn_fs_path_change_kind_t change_kind,
194 svn_fs_path_change2_t *change;
196 change = apr_pcalloc(pool, sizeof(*change));
197 change->node_rev_id = node_rev_id;
198 change->change_kind = change_kind;
204 svn_fs__append_to_merged_froms(svn_mergeinfo_t *output,
205 svn_mergeinfo_t input,
206 const char *rel_path,
209 apr_hash_index_t *hi;
211 *output = apr_hash_make(pool);
212 for (hi = apr_hash_first(pool, input); hi; hi = apr_hash_next(hi))
214 const char *path = svn__apr_hash_index_key(hi);
215 svn_rangelist_t *rangelist = svn__apr_hash_index_val(hi);
217 svn_hash_sets(*output,
218 svn_fspath__join(path, rel_path, pool),
219 svn_rangelist_dup(rangelist, pool));