2 * list.c: list local and remote directory entries.
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 * ====================================================================
24 #include "svn_client.h"
25 #include "svn_dirent_uri.h"
28 #include "svn_pools.h"
30 #include "svn_sorts.h"
31 #include "svn_props.h"
35 #include "private/svn_fspath.h"
36 #include "private/svn_ra_private.h"
37 #include "private/svn_sorts_private.h"
38 #include "private/svn_wc_private.h"
39 #include "svn_private_config.h"
41 /* Prototypes for referencing before declaration */
43 list_externals(apr_hash_t *externals,
45 apr_uint32_t dirent_fields,
46 svn_boolean_t fetch_locks,
47 svn_client_list_func2_t list_func,
49 svn_client_ctx_t *ctx,
50 apr_pool_t *scratch_pool);
53 list_internal(const char *path_or_url,
54 const svn_opt_revision_t *peg_revision,
55 const svn_opt_revision_t *revision,
57 apr_uint32_t dirent_fields,
58 svn_boolean_t fetch_locks,
59 svn_boolean_t include_externals,
60 const char *external_parent_url,
61 const char *external_target,
62 svn_client_list_func2_t list_func,
64 svn_client_ctx_t *ctx,
68 /* Get the directory entries of DIR at REV (relative to the root of
69 RA_SESSION), getting at least the fields specified by DIRENT_FIELDS.
70 Use the cancellation function/baton of CTX to check for cancellation.
72 If DEPTH is svn_depth_empty, return immediately. If DEPTH is
73 svn_depth_files, invoke LIST_FUNC on the file entries with BATON;
74 if svn_depth_immediates, invoke it on file and directory entries;
75 if svn_depth_infinity, invoke it on file and directory entries and
76 recurse into the directory entries with the same depth.
78 LOCKS, if non-NULL, is a hash mapping const char * paths to svn_lock_t
79 objects and FS_PATH is the absolute filesystem path of the RA session.
80 Use SCRATCH_POOL for temporary allocations.
82 If the caller passes EXTERNALS as non-NULL, populate the EXTERNALS
83 hash table whose keys are URLs of the directory which has externals
84 definitions, and whose values are the externals description text.
85 Allocate the hash's keys and values in RESULT_POOL.
87 EXTERNAL_PARENT_URL and EXTERNAL_TARGET are set when external items
88 are listed, otherwise both are set to NULL by the caller.
91 get_dir_contents(apr_uint32_t dirent_fields,
94 svn_ra_session_t *ra_session,
98 svn_client_ctx_t *ctx,
99 apr_hash_t *externals,
100 const char *external_parent_url,
101 const char *external_target,
102 svn_client_list_func2_t list_func,
104 apr_pool_t *result_pool,
105 apr_pool_t *scratch_pool)
107 apr_hash_t *tmpdirents;
108 apr_pool_t *iterpool = svn_pool_create(scratch_pool);
109 apr_array_header_t *array;
111 apr_hash_t *prop_hash = NULL;
112 const svn_string_t *prop_val = NULL;
115 if (depth == svn_depth_empty)
118 /* Get the directory's entries. If externals hash is non-NULL, get its
119 properties also. Ignore any not-authorized errors. */
120 err = svn_ra_get_dir2(ra_session, &tmpdirents, NULL,
121 externals ? &prop_hash : NULL,
122 dir, rev, dirent_fields, scratch_pool);
124 if (err && ((err->apr_err == SVN_ERR_RA_NOT_AUTHORIZED) ||
125 (err->apr_err == SVN_ERR_RA_DAV_FORBIDDEN)))
127 svn_error_clear(err);
132 /* Locks will often be empty. Prevent pointless lookups in that case. */
133 if (locks && apr_hash_count(locks) == 0)
136 /* Filter out svn:externals from all properties hash. */
138 prop_val = svn_hash_gets(prop_hash, SVN_PROP_EXTERNALS);
143 SVN_ERR(svn_ra_get_session_url(ra_session, &url, scratch_pool));
145 svn_hash_sets(externals,
146 svn_path_url_add_component2(url, dir, result_pool),
147 svn_string_dup(prop_val, result_pool));
150 if (ctx->cancel_func)
151 SVN_ERR(ctx->cancel_func(ctx->cancel_baton));
153 /* Sort the hash, so we can call the callback in a "deterministic" order. */
154 array = svn_sort__hash(tmpdirents, svn_sort_compare_items_lexically,
156 for (i = 0; i < array->nelts; ++i)
158 svn_sort__item_t *item = &APR_ARRAY_IDX(array, i, svn_sort__item_t);
160 svn_dirent_t *the_ent = item->value;
163 svn_pool_clear(iterpool);
165 path = svn_relpath_join(dir, item->key, iterpool);
169 const char *abs_path = svn_fspath__join(fs_path, path, iterpool);
170 lock = svn_hash_gets(locks, abs_path);
175 if (the_ent->kind == svn_node_file
176 || depth == svn_depth_immediates
177 || depth == svn_depth_infinity)
178 SVN_ERR(list_func(baton, path, the_ent, lock, fs_path,
179 external_parent_url, external_target, iterpool));
181 /* If externals is non-NULL, populate the externals hash table
182 recursively for all directory entries. */
183 if (depth == svn_depth_infinity && the_ent->kind == svn_node_dir)
184 SVN_ERR(get_dir_contents(dirent_fields, path, rev,
185 ra_session, locks, fs_path, depth, ctx,
186 externals, external_parent_url,
187 external_target, list_func, baton,
188 result_pool, iterpool));
191 svn_pool_destroy(iterpool);
196 /* List the file/directory entries for PATH_OR_URL at REVISION.
197 The actual node revision selected is determined by the path as
198 it exists in PEG_REVISION.
200 If DEPTH is svn_depth_infinity, then list all file and directory entries
201 recursively. Else if DEPTH is svn_depth_files, list all files under
202 PATH_OR_URL (if any), but not subdirectories. Else if DEPTH is
203 svn_depth_immediates, list all files and include immediate
204 subdirectories (at svn_depth_empty). Else if DEPTH is
205 svn_depth_empty, just list PATH_OR_URL with none of its entries.
207 DIRENT_FIELDS controls which fields in the svn_dirent_t's are
208 filled in. To have them totally filled in use SVN_DIRENT_ALL,
209 otherwise simply bitwise OR together the combination of SVN_DIRENT_*
210 fields you care about.
212 If FETCH_LOCKS is TRUE, include locks when reporting directory entries.
214 If INCLUDE_EXTERNALS is TRUE, also list all external items
215 reached by recursion. DEPTH value passed to the original list target
216 applies for the externals also. EXTERNAL_PARENT_URL is url of the
217 directory which has the externals definitions. EXTERNAL_TARGET is the
218 target subdirectory of externals definitions.
220 Report directory entries by invoking LIST_FUNC/BATON.
221 Pass EXTERNAL_PARENT_URL and EXTERNAL_TARGET to LIST_FUNC when external
222 items are listed, otherwise both are set to NULL.
224 Use authentication baton cached in CTX to authenticate against the
227 Use POOL for all allocations.
230 list_internal(const char *path_or_url,
231 const svn_opt_revision_t *peg_revision,
232 const svn_opt_revision_t *revision,
234 apr_uint32_t dirent_fields,
235 svn_boolean_t fetch_locks,
236 svn_boolean_t include_externals,
237 const char *external_parent_url,
238 const char *external_target,
239 svn_client_list_func2_t list_func,
241 svn_client_ctx_t *ctx,
244 svn_ra_session_t *ra_session;
245 svn_client__pathrev_t *loc;
246 svn_dirent_t *dirent;
250 apr_hash_t *externals;
252 if (include_externals)
253 externals = apr_hash_make(pool);
257 /* We use the kind field to determine if we should recurse, so we
259 dirent_fields |= SVN_DIRENT_KIND;
261 /* Get an RA plugin for this filesystem object. */
262 SVN_ERR(svn_client__ra_session_from_path2(&ra_session, &loc,
265 revision, ctx, pool));
267 fs_path = svn_client__pathrev_fspath(loc, pool);
269 SVN_ERR(svn_ra_stat(ra_session, "", loc->rev, &dirent, pool));
271 return svn_error_createf(SVN_ERR_FS_NOT_FOUND, NULL,
272 _("URL '%s' non-existent in revision %ld"),
275 /* Maybe get all locks under url. */
278 /* IMPORTANT: If locks are stored in a more temporary pool, we need
279 to fix store_dirent below to duplicate the locks. */
280 err = svn_ra_get_locks2(ra_session, &locks, "", depth, pool);
282 if (err && err->apr_err == SVN_ERR_RA_NOT_IMPLEMENTED)
284 svn_error_clear(err);
288 return svn_error_trace(err);
293 /* Report the dirent for the target. */
294 SVN_ERR(list_func(baton, "", dirent, locks
295 ? (svn_hash_gets(locks, fs_path))
296 : NULL, fs_path, external_parent_url,
297 external_target, pool));
299 if (dirent->kind == svn_node_dir
300 && (depth == svn_depth_files
301 || depth == svn_depth_immediates
302 || depth == svn_depth_infinity))
303 SVN_ERR(get_dir_contents(dirent_fields, "", loc->rev, ra_session, locks,
304 fs_path, depth, ctx, externals,
305 external_parent_url, external_target, list_func,
308 /* We handle externals after listing entries under path_or_url, so that
309 handling external items (and any errors therefrom) doesn't delay
310 the primary operation. */
311 if (include_externals && apr_hash_count(externals))
313 /* The 'externals' hash populated by get_dir_contents() is processed
315 SVN_ERR(list_externals(externals, depth, dirent_fields,
316 fetch_locks, list_func, baton,
324 wrap_list_error(const svn_client_ctx_t *ctx,
325 const char *target_abspath,
327 apr_pool_t *scratch_pool)
329 if (err && err->apr_err != SVN_ERR_CANCELLED)
331 if (ctx->notify_func2)
333 svn_wc_notify_t *notifier = svn_wc_create_notify(
335 svn_wc_notify_failed_external,
338 ctx->notify_func2(ctx->notify_baton2, notifier, scratch_pool);
340 svn_error_clear(err);
348 /* Walk through all the external items and list them. */
350 list_external_items(apr_array_header_t *external_items,
351 const char *externals_parent_url,
353 apr_uint32_t dirent_fields,
354 svn_boolean_t fetch_locks,
355 svn_client_list_func2_t list_func,
357 svn_client_ctx_t *ctx,
358 apr_pool_t *scratch_pool)
360 const char *externals_parent_repos_root_url;
361 apr_pool_t *iterpool;
364 SVN_ERR(svn_client_get_repos_root(&externals_parent_repos_root_url,
366 externals_parent_url, ctx,
367 scratch_pool, scratch_pool));
369 iterpool = svn_pool_create(scratch_pool);
371 for (i = 0; i < external_items->nelts; i++)
373 const char *resolved_url;
375 svn_wc_external_item2_t *item =
376 APR_ARRAY_IDX(external_items, i, svn_wc_external_item2_t *);
378 svn_pool_clear(iterpool);
380 SVN_ERR(svn_wc__resolve_relative_external_url(
383 externals_parent_repos_root_url,
384 externals_parent_url,
385 iterpool, iterpool));
387 /* List the external */
388 SVN_ERR(wrap_list_error(ctx, item->target_dir,
389 list_internal(resolved_url,
392 depth, dirent_fields,
395 externals_parent_url,
397 list_func, baton, ctx,
402 svn_pool_destroy(iterpool);
407 /* List external items defined on each external in EXTERNALS, a const char *
408 externals_parent_url(url of the directory which has the externals
409 definitions) of all externals mapping to the svn_string_t * externals_desc
410 (externals description text). All other options are the same as those
411 passed to svn_client_list(). */
413 list_externals(apr_hash_t *externals,
415 apr_uint32_t dirent_fields,
416 svn_boolean_t fetch_locks,
417 svn_client_list_func2_t list_func,
419 svn_client_ctx_t *ctx,
420 apr_pool_t *scratch_pool)
422 apr_pool_t *iterpool = svn_pool_create(scratch_pool);
423 apr_hash_index_t *hi;
425 for (hi = apr_hash_first(scratch_pool, externals);
427 hi = apr_hash_next(hi))
429 const char *externals_parent_url = apr_hash_this_key(hi);
430 svn_string_t *externals_desc = apr_hash_this_val(hi);
431 apr_array_header_t *external_items;
433 svn_pool_clear(iterpool);
435 SVN_ERR(svn_wc_parse_externals_description3(&external_items,
436 externals_parent_url,
437 externals_desc->data,
440 if (! external_items->nelts)
443 SVN_ERR(list_external_items(external_items, externals_parent_url, depth,
444 dirent_fields, fetch_locks, list_func,
445 baton, ctx, iterpool));
448 svn_pool_destroy(iterpool);
455 svn_client_list3(const char *path_or_url,
456 const svn_opt_revision_t *peg_revision,
457 const svn_opt_revision_t *revision,
459 apr_uint32_t dirent_fields,
460 svn_boolean_t fetch_locks,
461 svn_boolean_t include_externals,
462 svn_client_list_func2_t list_func,
464 svn_client_ctx_t *ctx,
468 return svn_error_trace(list_internal(path_or_url, peg_revision,
470 depth, dirent_fields,
473 NULL, NULL, list_func,