/* Schedule directory DIR_ABSPATH, and some of the tree under it, for * addition. DEPTH is the depth at this * point in the descent (it may be changed for recursive calls). * * If DIR_ABSPATH (or any item below DIR_ABSPATH) is already scheduled for * addition, add will fail and return an error unless FORCE is TRUE. * * Files and directories that match ignore patterns will not be added unless * NO_IGNORE is TRUE. * * Use MAGIC_COOKIE (which may be NULL) to detect the mime-type of files * if necessary. * * If CTX->CANCEL_FUNC is non-null, call it with CTX->CANCEL_BATON to allow * the user to cancel the operation */ static svn_error_t * add_dir_recursive(const char *dir_abspath, svn_depth_t depth, svn_boolean_t force, svn_boolean_t no_ignore, svn_magic__cookie_t *magic_cookie, svn_client_ctx_t *ctx, apr_pool_t *scratch_pool) { svn_error_t *err; apr_pool_t *iterpool; apr_array_header_t *ignores; apr_hash_t *dirents; apr_hash_index_t *hi; /* Check cancellation; note that this catches recursive calls too. */ if (ctx->cancel_func) SVN_ERR(ctx->cancel_func(ctx->cancel_baton)); iterpool = svn_pool_create(scratch_pool); /* Add this directory to revision control. */ err = svn_wc_add_from_disk(ctx->wc_ctx, dir_abspath, ctx->notify_func2, ctx->notify_baton2, iterpool); if (err && err->apr_err == SVN_ERR_ENTRY_EXISTS && force) svn_error_clear(err); else if (err) return svn_error_trace(err); if (!no_ignore) { SVN_ERR(svn_wc_get_ignores2(&ignores, ctx->wc_ctx, dir_abspath, ctx->config, scratch_pool, iterpool)); } SVN_ERR(svn_io_get_dirents3(&dirents, dir_abspath, TRUE, scratch_pool, iterpool)); /* Read the directory entries one by one and add those things to version control. */ for (hi = apr_hash_first(scratch_pool, dirents); hi; hi = apr_hash_next(hi)) { const char *name = svn__apr_hash_index_key(hi); svn_io_dirent2_t *dirent = svn__apr_hash_index_val(hi); const char *abspath; svn_pool_clear(iterpool); /* Check cancellation so you can cancel during an * add of a directory with lots of files. */ if (ctx->cancel_func) SVN_ERR(ctx->cancel_func(ctx->cancel_baton)); /* Skip over SVN admin directories. */ if (svn_wc_is_adm_dir(name, iterpool)) continue; if ((!no_ignore) && svn_wc_match_ignore_list(name, ignores, iterpool)) continue; /* Construct the full path of the entry. */ abspath = svn_dirent_join(dir_abspath, name, iterpool); /* Recurse on directories; add files; ignore the rest. */ if (dirent->kind == svn_node_dir && depth >= svn_depth_immediates) { svn_depth_t depth_below_here = depth; if (depth == svn_depth_immediates) depth_below_here = svn_depth_empty; SVN_ERR(add_dir_recursive(abspath, depth_below_here, force, no_ignore, magic_cookie, ctx, iterpool)); } else if ((dirent->kind == svn_node_file || dirent->special) && depth >= svn_depth_files) { err = add_file(abspath, magic_cookie, ctx, iterpool); if (err && err->apr_err == SVN_ERR_ENTRY_EXISTS && force) svn_error_clear(err); else SVN_ERR(err); } } /* Destroy the per-iteration pool. */ svn_pool_destroy(iterpool); return SVN_NO_ERROR; }
/* Schedule directory DIRNAME, and some of the tree under it, for * addition with access baton ADM_ACCESS. DEPTH is the depth at this * point in the descent (it may be changed for recursive calls). * * If DIRNAME (or any item below directory DIRNAME) is already scheduled for * addition, add will fail and return an error unless FORCE is TRUE. * * Files and directories that match ignore patterns will not be added unless * NO_IGNORE is TRUE. * * If CTX->CANCEL_FUNC is non-null, call it with CTX->CANCEL_BATON to allow * the user to cancel the operation */ static svn_error_t * add_dir_recursive(const char *dirname, svn_wc_adm_access_t *adm_access, svn_depth_t depth, svn_boolean_t force, svn_boolean_t no_ignore, svn_client_ctx_t *ctx, apr_pool_t *pool) { apr_dir_t *dir; apr_finfo_t this_entry; svn_error_t *err; apr_pool_t *subpool; apr_int32_t flags = APR_FINFO_TYPE | APR_FINFO_NAME; svn_wc_adm_access_t *dir_access; apr_array_header_t *ignores; /* Check cancellation; note that this catches recursive calls too. */ if (ctx->cancel_func) SVN_ERR(ctx->cancel_func(ctx->cancel_baton)); /* Add this directory to revision control. */ err = svn_wc_add2(dirname, adm_access, NULL, SVN_INVALID_REVNUM, ctx->cancel_func, ctx->cancel_baton, ctx->notify_func2, ctx->notify_baton2, pool); if (err && err->apr_err == SVN_ERR_ENTRY_EXISTS && force) svn_error_clear(err); else if (err) return err; SVN_ERR(svn_wc_adm_retrieve(&dir_access, adm_access, dirname, pool)); if (!no_ignore) SVN_ERR(svn_wc_get_ignores(&ignores, ctx->config, dir_access, pool)); subpool = svn_pool_create(pool); SVN_ERR(svn_io_dir_open(&dir, dirname, pool)); /* Read the directory entries one by one and add those things to version control. */ while (1) { const char *fullpath; svn_pool_clear(subpool); err = svn_io_dir_read(&this_entry, flags, dir, subpool); if (err) { /* Check if we're done reading the dir's entries. */ if (APR_STATUS_IS_ENOENT(err->apr_err)) { apr_status_t apr_err; svn_error_clear(err); apr_err = apr_dir_close(dir); if (apr_err) return svn_error_wrap_apr (apr_err, _("Can't close directory '%s'"), svn_path_local_style(dirname, subpool)); break; } else { return svn_error_createf (err->apr_err, err, _("Error during add of '%s'"), svn_path_local_style(dirname, subpool)); } } /* Skip entries for this dir and its parent. */ if (this_entry.name[0] == '.' && (this_entry.name[1] == '\0' || (this_entry.name[1] == '.' && this_entry.name[2] == '\0'))) continue; /* Check cancellation so you can cancel during an * add of a directory with lots of files. */ if (ctx->cancel_func) SVN_ERR(ctx->cancel_func(ctx->cancel_baton)); /* Skip over SVN admin directories. */ if (svn_wc_is_adm_dir(this_entry.name, subpool)) continue; if ((!no_ignore) && svn_wc_match_ignore_list(this_entry.name, ignores, subpool)) continue; /* Construct the full path of the entry. */ fullpath = svn_path_join(dirname, this_entry.name, subpool); /* Recurse on directories; add files; ignore the rest. */ if (this_entry.filetype == APR_DIR && depth >= svn_depth_immediates) { svn_depth_t depth_below_here = depth; if (depth == svn_depth_immediates) depth_below_here = svn_depth_empty; SVN_ERR(add_dir_recursive(fullpath, dir_access, depth_below_here, force, no_ignore, ctx, subpool)); } else if (this_entry.filetype != APR_UNKFILE && this_entry.filetype != APR_DIR && depth >= svn_depth_files) { err = add_file(fullpath, ctx, dir_access, subpool); if (err && err->apr_err == SVN_ERR_ENTRY_EXISTS && force) svn_error_clear(err); else if (err) return err; } } /* Opened by svn_wc_add */ SVN_ERR(svn_wc_adm_close(dir_access)); /* Destroy the per-iteration pool. */ svn_pool_destroy(subpool); return SVN_NO_ERROR; }