svn_error_t * sbox_disk_mkdir(svn_test__sandbox_t *b, const char *path) { path = sbox_wc_path(b, path); SVN_ERR(svn_io_dir_make(path, APR_FPROT_OS_DEFAULT, b->pool)); return SVN_NO_ERROR; }
static svn_error_t * make_adm_subdir(const char *path, const char *subdir, svn_boolean_t tmp, apr_pool_t *pool) { const char *fullpath; fullpath = extend_with_adm_name(path, NULL, tmp, pool, subdir, NULL); return svn_io_dir_make(fullpath, APR_OS_DEFAULT, pool); }
static svn_error_t * make_adm_subdir(const char *path, const char *subdir, svn_boolean_t tmp, apr_pool_t *pool) { const char *fullpath; fullpath = simple_extend(path, tmp, NULL, subdir, NULL, pool); return svn_io_dir_make(fullpath, APR_OS_DEFAULT, pool); }
/* Make an unversioned copy of the versioned file or directory tree at the * source path FROM_ABSPATH. Copy it to the destination path TO_ABSPATH. * * If REVISION is svn_opt_revision_working, copy the working version, * otherwise copy the base version. * * See copy_one_versioned_file() for details of file copying behaviour, * including IGNORE_KEYWORDS and NATIVE_EOL. * * Include externals unless IGNORE_EXTERNALS is true. * * Recurse according to DEPTH. * */ static svn_error_t * copy_versioned_files(const char *from_abspath, const char *to_abspath, const svn_opt_revision_t *revision, svn_boolean_t force, svn_boolean_t ignore_externals, svn_boolean_t ignore_keywords, svn_depth_t depth, const char *native_eol, svn_client_ctx_t *ctx, apr_pool_t *pool) { svn_error_t *err; apr_pool_t *iterpool; const apr_array_header_t *children; svn_node_kind_t from_kind; svn_depth_t node_depth; SVN_ERR_ASSERT(svn_dirent_is_absolute(from_abspath)); SVN_ERR_ASSERT(svn_dirent_is_absolute(to_abspath)); /* Only export 'added' and 'replaced' files when the revision is WORKING; when the revision is BASE (i.e. != WORKING), only export 'added' and 'replaced' files when they are part of a copy-/move-here. Otherwise, skip them, since they don't have an associated text-base. This condition for added/replaced simply is an optimization. Added and replaced files would be handled similarly by svn_wc_get_pristine_contents2(), which would return NULL if they have no base associated. TODO: We may prefer not to duplicate this condition and rather use svn_wc_get_pristine_contents2() or a dedicated new function instead. Don't export 'deleted' files and directories unless it's a revision other than WORKING. These files and directories don't really exist in WORKING. */ if (revision->kind != svn_opt_revision_working) { svn_boolean_t is_added; const char *repos_relpath; SVN_ERR(svn_wc__node_get_origin(&is_added, NULL, &repos_relpath, NULL, NULL, NULL, ctx->wc_ctx, from_abspath, FALSE, pool, pool)); if (is_added && !repos_relpath) return SVN_NO_ERROR; /* Local addition */ } else { svn_boolean_t is_deleted; SVN_ERR(svn_wc__node_is_status_deleted(&is_deleted, ctx->wc_ctx, from_abspath, pool)); if (is_deleted) return SVN_NO_ERROR; } SVN_ERR(svn_wc_read_kind(&from_kind, ctx->wc_ctx, from_abspath, FALSE, pool)); if (from_kind == svn_node_dir) { apr_fileperms_t perm = APR_OS_DEFAULT; int j; /* Try to make the new directory. If this fails because the directory already exists, check our FORCE flag to see if we care. */ /* Keep the source directory's permissions if applicable. Skip retrieving the umask on windows. Apr does not implement setting filesystem privileges on Windows. Retrieving the file permissions with APR_FINFO_PROT | APR_FINFO_OWNER is documented to be 'incredibly expensive' */ #ifndef WIN32 if (revision->kind == svn_opt_revision_working) { apr_finfo_t finfo; SVN_ERR(svn_io_stat(&finfo, from_abspath, APR_FINFO_PROT, pool)); perm = finfo.protection; } #endif err = svn_io_dir_make(to_abspath, perm, pool); if (err) { if (! APR_STATUS_IS_EEXIST(err->apr_err)) return svn_error_trace(err); if (! force) SVN_ERR_W(err, _("Destination directory exists, and will not be " "overwritten unless forced")); else svn_error_clear(err); } SVN_ERR(svn_wc__node_get_children(&children, ctx->wc_ctx, from_abspath, FALSE, pool, pool)); iterpool = svn_pool_create(pool); for (j = 0; j < children->nelts; j++) { const char *child_abspath = APR_ARRAY_IDX(children, j, const char *); const char *child_name = svn_dirent_basename(child_abspath, NULL); const char *target_abspath; svn_node_kind_t child_kind; svn_pool_clear(iterpool); if (ctx->cancel_func) SVN_ERR(ctx->cancel_func(ctx->cancel_baton)); target_abspath = svn_dirent_join(to_abspath, child_name, iterpool); SVN_ERR(svn_wc_read_kind(&child_kind, ctx->wc_ctx, child_abspath, FALSE, iterpool)); if (child_kind == svn_node_dir) { if (depth == svn_depth_infinity || depth == svn_depth_immediates) { if (ctx->notify_func2) { svn_wc_notify_t *notify = svn_wc_create_notify(target_abspath, svn_wc_notify_update_add, pool); notify->kind = svn_node_dir; (*ctx->notify_func2)(ctx->notify_baton2, notify, pool); } if (depth == svn_depth_infinity) SVN_ERR(copy_versioned_files(child_abspath, target_abspath, revision, force, ignore_externals, ignore_keywords, depth, native_eol, ctx, iterpool)); else SVN_ERR(svn_io_make_dir_recursively(target_abspath, iterpool)); } } else if (child_kind == svn_node_file && depth >= svn_depth_files) { svn_node_kind_t external_kind; SVN_ERR(svn_wc__read_external_info(&external_kind, NULL, NULL, NULL, NULL, ctx->wc_ctx, child_abspath, child_abspath, TRUE, pool, pool)); if (external_kind != svn_node_file) SVN_ERR(copy_one_versioned_file(child_abspath, target_abspath, ctx, revision, native_eol, ignore_keywords, iterpool)); } } SVN_ERR(svn_wc__node_get_depth(&node_depth, ctx->wc_ctx, from_abspath, pool)); /* Handle externals. */ if (! ignore_externals && depth == svn_depth_infinity && node_depth == svn_depth_infinity) { apr_array_header_t *ext_items; const svn_string_t *prop_val; SVN_ERR(svn_wc_prop_get2(&prop_val, ctx->wc_ctx, from_abspath, SVN_PROP_EXTERNALS, pool, pool)); if (prop_val != NULL) { int i; SVN_ERR(svn_wc_parse_externals_description3(&ext_items, from_abspath, prop_val->data, FALSE, pool)); for (i = 0; i < ext_items->nelts; ++i) { svn_wc_external_item2_t *ext_item; const char *new_from, *new_to; svn_pool_clear(iterpool); ext_item = APR_ARRAY_IDX(ext_items, i, svn_wc_external_item2_t *); new_from = svn_dirent_join(from_abspath, ext_item->target_dir, iterpool); new_to = svn_dirent_join(to_abspath, ext_item->target_dir, iterpool); /* The target dir might have parents that don't exist. Guarantee the path upto the last component. */ if (!svn_dirent_is_root(ext_item->target_dir, strlen(ext_item->target_dir))) { const char *parent = svn_dirent_dirname(new_to, iterpool); SVN_ERR(svn_io_make_dir_recursively(parent, iterpool)); } SVN_ERR(copy_versioned_files(new_from, new_to, revision, force, FALSE, ignore_keywords, svn_depth_infinity, native_eol, ctx, iterpool)); } }
/* Handle the moving of a pristine from SRC_WCROOT to DST_WCROOT. The existing pristine in SRC_WCROOT is described by CHECKSUM, MD5_CHECKSUM and SIZE */ static svn_error_t * maybe_transfer_one_pristine(svn_wc__db_wcroot_t *src_wcroot, svn_wc__db_wcroot_t *dst_wcroot, const svn_checksum_t *checksum, const svn_checksum_t *md5_checksum, apr_int64_t size, svn_cancel_func_t cancel_func, void *cancel_baton, apr_pool_t *scratch_pool) { const char *pristine_abspath; svn_sqlite__stmt_t *stmt; svn_stream_t *src_stream; svn_stream_t *dst_stream; const char *tmp_abspath; const char *src_abspath; int affected_rows; svn_error_t *err; SVN_ERR(svn_sqlite__get_statement(&stmt, dst_wcroot->sdb, STMT_INSERT_OR_IGNORE_PRISTINE)); SVN_ERR(svn_sqlite__bind_checksum(stmt, 1, checksum, scratch_pool)); SVN_ERR(svn_sqlite__bind_checksum(stmt, 2, md5_checksum, scratch_pool)); SVN_ERR(svn_sqlite__bind_int64(stmt, 3, size)); SVN_ERR(svn_sqlite__update(&affected_rows, stmt)); if (affected_rows == 0) return SVN_NO_ERROR; SVN_ERR(svn_stream_open_unique(&dst_stream, &tmp_abspath, pristine_get_tempdir(dst_wcroot, scratch_pool, scratch_pool), svn_io_file_del_on_pool_cleanup, scratch_pool, scratch_pool)); SVN_ERR(get_pristine_fname(&src_abspath, src_wcroot->abspath, checksum, scratch_pool, scratch_pool)); SVN_ERR(svn_stream_open_readonly(&src_stream, src_abspath, scratch_pool, scratch_pool)); /* ### Should we verify the SHA1 or MD5 here, or is that too expensive? */ SVN_ERR(svn_stream_copy3(src_stream, dst_stream, cancel_func, cancel_baton, scratch_pool)); SVN_ERR(get_pristine_fname(&pristine_abspath, dst_wcroot->abspath, checksum, scratch_pool, scratch_pool)); /* Move the file to its target location. (If it is already there, it is * an orphan file and it doesn't matter if we overwrite it.) */ err = svn_io_file_rename2(tmp_abspath, pristine_abspath, FALSE, scratch_pool); /* Maybe the directory doesn't exist yet? */ if (err && APR_STATUS_IS_ENOENT(err->apr_err)) { svn_error_t *err2; err2 = svn_io_dir_make(svn_dirent_dirname(pristine_abspath, scratch_pool), APR_OS_DEFAULT, scratch_pool); if (err2) /* Creating directory didn't work: Return all errors */ return svn_error_trace(svn_error_compose_create(err, err2)); else /* We could create a directory: retry install */ svn_error_clear(err); SVN_ERR(svn_io_file_rename2(tmp_abspath, pristine_abspath, FALSE, scratch_pool)); } else SVN_ERR(err); return SVN_NO_ERROR; }
/* Make a copy of the filesystem node (or tree if RECURSIVE) at SRC_ABSPATH under a temporary name in the directory TMPDIR_ABSPATH and return the absolute path of the copy in *DST_ABSPATH. Return the node kind of SRC_ABSPATH in *KIND. If SRC_ABSPATH doesn't exist then set *DST_ABSPATH to NULL to indicate that no copy was made. */ static svn_error_t * copy_to_tmpdir(svn_skel_t **work_item, svn_node_kind_t *kind, svn_wc__db_t *db, const char *src_abspath, const char *dst_abspath, const char *tmpdir_abspath, svn_boolean_t file_copy, svn_boolean_t unversioned, svn_cancel_func_t cancel_func, void *cancel_baton, apr_pool_t *result_pool, apr_pool_t *scratch_pool) { svn_boolean_t is_special; svn_io_file_del_t delete_when; const char *dst_tmp_abspath; svn_node_kind_t dsk_kind; if (!kind) kind = &dsk_kind; *work_item = NULL; SVN_ERR(svn_io_check_special_path(src_abspath, kind, &is_special, scratch_pool)); if (*kind == svn_node_none) { return SVN_NO_ERROR; } else if (*kind == svn_node_unknown) { return svn_error_createf(SVN_ERR_NODE_UNEXPECTED_KIND, NULL, _("Source '%s' is unexpected kind"), svn_dirent_local_style(src_abspath, scratch_pool)); } else if (*kind == svn_node_dir || is_special) delete_when = svn_io_file_del_on_close; else /* the default case: (*kind == svn_node_file) */ delete_when = svn_io_file_del_none; /* ### Do we need a pool cleanup to remove the copy? We can't use ### svn_io_file_del_on_pool_cleanup above because a) it won't ### handle the directory case and b) we need to be able to remove ### the cleanup before queueing the move work item. */ if (file_copy && !unversioned) { svn_boolean_t modified; /* It's faster to look for mods on the source now, as the timestamp might match, than to examine the destination later as the destination timestamp will never match. */ SVN_ERR(svn_wc__internal_file_modified_p(&modified, db, src_abspath, FALSE, scratch_pool)); if (!modified) { /* Why create a temp copy if we can just reinstall from pristine? */ SVN_ERR(svn_wc__wq_build_file_install(work_item, db, dst_abspath, NULL, FALSE, TRUE, result_pool, scratch_pool)); return SVN_NO_ERROR; } } /* Set DST_TMP_ABSPATH to a temporary unique path. If *KIND is file, leave a file there and then overwrite it; otherwise leave no node on disk at that path. In the latter case, something else might use that path before we get around to using it a moment later, but never mind. */ SVN_ERR(svn_io_open_unique_file3(NULL, &dst_tmp_abspath, tmpdir_abspath, delete_when, scratch_pool, scratch_pool)); if (*kind == svn_node_dir) { if (file_copy) SVN_ERR(svn_io_copy_dir_recursively( src_abspath, tmpdir_abspath, svn_dirent_basename(dst_tmp_abspath, scratch_pool), TRUE, /* copy_perms */ cancel_func, cancel_baton, scratch_pool)); else SVN_ERR(svn_io_dir_make(dst_tmp_abspath, APR_OS_DEFAULT, scratch_pool)); } else if (!is_special) SVN_ERR(svn_io_copy_file(src_abspath, dst_tmp_abspath, TRUE /* copy_perms */, scratch_pool)); else SVN_ERR(svn_io_copy_link(src_abspath, dst_tmp_abspath, scratch_pool)); if (file_copy) { /* Remove 'read-only' from the destination file; it's a local add now. */ SVN_ERR(svn_io_set_file_read_write(dst_tmp_abspath, FALSE, scratch_pool)); } SVN_ERR(svn_wc__wq_build_file_move(work_item, db, dst_abspath, dst_tmp_abspath, dst_abspath, result_pool, scratch_pool)); return SVN_NO_ERROR; }