170
193
svn_stream_t *dst_stream;
171
194
const char *dst_tmp;
172
195
svn_error_t *err;
173
svn_boolean_t is_deleted;
174
svn_wc_context_t *wc_ctx = ctx->wc_ctx;
176
SVN_ERR(svn_wc__node_is_status_deleted(&is_deleted, wc_ctx, from_abspath,
197
const char *to_abspath = svn_dirent_join(
199
svn_dirent_skip_ancestor(eib->origin_abspath,
203
eib->exported = TRUE;
179
205
/* Don't export 'deleted' files and directories unless it's a
180
206
revision other than WORKING. These files and directories
181
207
don't really exist in WORKING. */
182
if (revision->kind == svn_opt_revision_working && is_deleted)
185
if (revision->kind != svn_opt_revision_working)
208
if (eib->revision->kind == svn_opt_revision_working
209
&& status->node_status == svn_wc_status_deleted)
212
if (status->kind == svn_node_dir)
214
apr_fileperms_t perm = APR_OS_DEFAULT;
216
/* Try to make the new directory. If this fails because the
217
directory already exists, check our FORCE flag to see if we
220
/* Keep the source directory's permissions if applicable.
221
Skip retrieving the umask on windows. Apr does not implement setting
222
filesystem privileges on Windows.
223
Retrieving the file permissions with APR_FINFO_PROT | APR_FINFO_OWNER
224
is documented to be 'incredibly expensive' */
226
if (eib->revision->kind == svn_opt_revision_working)
229
SVN_ERR(svn_io_stat(&finfo, local_abspath, APR_FINFO_PROT,
231
perm = finfo.protection;
234
err = svn_io_dir_make(to_abspath, perm, scratch_pool);
237
if (! APR_STATUS_IS_EEXIST(err->apr_err))
238
return svn_error_trace(err);
239
if (! eib->overwrite)
240
SVN_ERR_W(err, _("Destination directory exists, and will not be "
241
"overwritten unless forced"));
243
svn_error_clear(err);
247
&& (strcmp(eib->origin_abspath, local_abspath) != 0))
249
svn_wc_notify_t *notify =
250
svn_wc_create_notify(to_abspath,
251
svn_wc_notify_update_add, scratch_pool);
253
notify->kind = svn_node_dir;
254
(eib->notify_func)(eib->notify_baton, notify, scratch_pool);
259
else if (status->kind != svn_node_file)
261
if (strcmp(eib->origin_abspath, local_abspath) != 0)
264
return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
265
_("The node '%s' was not found."),
266
svn_dirent_local_style(local_abspath,
270
if (status->file_external)
273
/* Produce overwrite errors for the export root */
274
if (strcmp(local_abspath, eib->origin_abspath) == 0)
276
svn_node_kind_t to_kind;
278
SVN_ERR(svn_io_check_path(to_abspath, &to_kind, scratch_pool));
280
if ((to_kind == svn_node_file || to_kind == svn_node_unknown)
282
return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
283
_("Destination file '%s' exists, and "
284
"will not be overwritten unless forced"),
285
svn_dirent_local_style(to_abspath,
287
else if (to_kind == svn_node_dir)
288
return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
289
_("Destination '%s' exists. Cannot "
290
"overwrite directory with non-directory"),
291
svn_dirent_local_style(to_abspath,
295
if (eib->revision->kind != svn_opt_revision_working)
187
297
/* Only export 'added' files when the revision is WORKING. This is not
188
298
WORKING, so skip the 'added' files, since they didn't exist
336
432
/* Now that dst_tmp contains the translated data, do the atomic rename. */
337
433
SVN_ERR(svn_io_file_rename(dst_tmp, to_abspath, scratch_pool));
339
if (ctx->notify_func2)
435
if (eib->notify_func)
341
437
svn_wc_notify_t *notify = svn_wc_create_notify(to_abspath,
342
438
svn_wc_notify_update_add, scratch_pool);
343
439
notify->kind = svn_node_file;
344
(*ctx->notify_func2)(ctx->notify_baton2, notify, scratch_pool);
350
/* Make an unversioned copy of the versioned file or directory tree at the
351
* source path FROM_ABSPATH. Copy it to the destination path TO_ABSPATH.
353
* If REVISION is svn_opt_revision_working, copy the working version,
354
* otherwise copy the base version.
356
* See copy_one_versioned_file() for details of file copying behaviour,
357
* including IGNORE_KEYWORDS and NATIVE_EOL.
359
* Include externals unless IGNORE_EXTERNALS is true.
361
* Recurse according to DEPTH.
366
copy_versioned_files(const char *from_abspath,
367
const char *to_abspath,
368
const svn_opt_revision_t *revision,
370
svn_boolean_t ignore_externals,
371
svn_boolean_t ignore_keywords,
373
const char *native_eol,
374
svn_client_ctx_t *ctx,
378
apr_pool_t *iterpool;
379
const apr_array_header_t *children;
380
svn_node_kind_t from_kind;
381
svn_depth_t node_depth;
383
SVN_ERR_ASSERT(svn_dirent_is_absolute(from_abspath));
384
SVN_ERR_ASSERT(svn_dirent_is_absolute(to_abspath));
386
/* Only export 'added' and 'replaced' files when the revision is WORKING;
387
when the revision is BASE (i.e. != WORKING), only export 'added' and
388
'replaced' files when they are part of a copy-/move-here. Otherwise, skip
389
them, since they don't have an associated text-base. This condition for
390
added/replaced simply is an optimization. Added and replaced files would
391
be handled similarly by svn_wc_get_pristine_contents2(), which would
392
return NULL if they have no base associated.
393
TODO: We may prefer not to duplicate this condition and rather use
394
svn_wc_get_pristine_contents2() or a dedicated new function instead.
396
Don't export 'deleted' files and directories unless it's a
397
revision other than WORKING. These files and directories
398
don't really exist in WORKING. */
399
if (revision->kind != svn_opt_revision_working)
401
svn_boolean_t is_added;
402
const char *repos_relpath;
404
SVN_ERR(svn_wc__node_get_origin(&is_added, NULL, &repos_relpath,
406
ctx->wc_ctx, from_abspath, FALSE,
409
if (is_added && !repos_relpath)
410
return SVN_NO_ERROR; /* Local addition */
414
svn_boolean_t is_deleted;
416
SVN_ERR(svn_wc__node_is_status_deleted(&is_deleted, ctx->wc_ctx,
417
from_abspath, pool));
422
SVN_ERR(svn_wc_read_kind(&from_kind, ctx->wc_ctx, from_abspath, FALSE,
425
if (from_kind == svn_node_dir)
427
apr_fileperms_t perm = APR_OS_DEFAULT;
430
/* Try to make the new directory. If this fails because the
431
directory already exists, check our FORCE flag to see if we
434
/* Keep the source directory's permissions if applicable.
435
Skip retrieving the umask on windows. Apr does not implement setting
436
filesystem privileges on Windows.
437
Retrieving the file permissions with APR_FINFO_PROT | APR_FINFO_OWNER
438
is documented to be 'incredibly expensive' */
440
if (revision->kind == svn_opt_revision_working)
443
SVN_ERR(svn_io_stat(&finfo, from_abspath, APR_FINFO_PROT, pool));
444
perm = finfo.protection;
447
err = svn_io_dir_make(to_abspath, perm, pool);
450
if (! APR_STATUS_IS_EEXIST(err->apr_err))
451
return svn_error_trace(err);
453
SVN_ERR_W(err, _("Destination directory exists, and will not be "
454
"overwritten unless forced"));
456
svn_error_clear(err);
459
SVN_ERR(svn_wc__node_get_children(&children, ctx->wc_ctx, from_abspath,
462
iterpool = svn_pool_create(pool);
463
for (j = 0; j < children->nelts; j++)
465
const char *child_abspath = APR_ARRAY_IDX(children, j, const char *);
466
const char *child_name = svn_dirent_basename(child_abspath, NULL);
467
const char *target_abspath;
468
svn_node_kind_t child_kind;
470
svn_pool_clear(iterpool);
472
if (ctx->cancel_func)
473
SVN_ERR(ctx->cancel_func(ctx->cancel_baton));
475
target_abspath = svn_dirent_join(to_abspath, child_name, iterpool);
477
SVN_ERR(svn_wc_read_kind(&child_kind, ctx->wc_ctx, child_abspath,
480
if (child_kind == svn_node_dir)
482
if (depth == svn_depth_infinity
483
|| depth == svn_depth_immediates)
485
if (ctx->notify_func2)
487
svn_wc_notify_t *notify =
488
svn_wc_create_notify(target_abspath,
489
svn_wc_notify_update_add, pool);
490
notify->kind = svn_node_dir;
491
(*ctx->notify_func2)(ctx->notify_baton2, notify, pool);
494
if (depth == svn_depth_infinity)
495
SVN_ERR(copy_versioned_files(child_abspath, target_abspath,
498
ignore_keywords, depth,
499
native_eol, ctx, iterpool));
501
SVN_ERR(svn_io_make_dir_recursively(target_abspath,
505
else if (child_kind == svn_node_file
506
&& depth >= svn_depth_files)
508
svn_node_kind_t external_kind;
510
SVN_ERR(svn_wc__read_external_info(&external_kind,
517
if (external_kind != svn_node_file)
518
SVN_ERR(copy_one_versioned_file(child_abspath, target_abspath,
520
native_eol, ignore_keywords,
525
SVN_ERR(svn_wc__node_get_depth(&node_depth, ctx->wc_ctx,
526
from_abspath, pool));
528
/* Handle externals. */
529
if (! ignore_externals && depth == svn_depth_infinity
530
&& node_depth == svn_depth_infinity)
532
apr_array_header_t *ext_items;
533
const svn_string_t *prop_val;
535
SVN_ERR(svn_wc_prop_get2(&prop_val, ctx->wc_ctx, from_abspath,
536
SVN_PROP_EXTERNALS, pool, pool));
537
if (prop_val != NULL)
541
SVN_ERR(svn_wc_parse_externals_description3(&ext_items,
545
for (i = 0; i < ext_items->nelts; ++i)
547
svn_wc_external_item2_t *ext_item;
548
const char *new_from, *new_to;
550
svn_pool_clear(iterpool);
552
ext_item = APR_ARRAY_IDX(ext_items, i,
553
svn_wc_external_item2_t *);
554
new_from = svn_dirent_join(from_abspath,
555
ext_item->target_dir,
557
new_to = svn_dirent_join(to_abspath, ext_item->target_dir,
560
/* The target dir might have parents that don't exist.
561
Guarantee the path upto the last component. */
562
if (!svn_dirent_is_root(ext_item->target_dir,
563
strlen(ext_item->target_dir)))
565
const char *parent = svn_dirent_dirname(new_to, iterpool);
566
SVN_ERR(svn_io_make_dir_recursively(parent, iterpool));
569
SVN_ERR(copy_versioned_files(new_from, new_to,
570
revision, force, FALSE,
572
svn_depth_infinity, native_eol,
578
svn_pool_destroy(iterpool);
580
else if (from_kind == svn_node_file)
582
svn_node_kind_t to_kind;
584
SVN_ERR(svn_io_check_path(to_abspath, &to_kind, pool));
586
if ((to_kind == svn_node_file || to_kind == svn_node_unknown) && ! force)
587
return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
588
_("Destination file '%s' exists, and "
589
"will not be overwritten unless forced"),
590
svn_dirent_local_style(to_abspath, pool));
591
else if (to_kind == svn_node_dir)
592
return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
593
_("Destination '%s' exists. Cannot "
594
"overwrite directory with non-directory"),
595
svn_dirent_local_style(to_abspath, pool));
597
SVN_ERR(copy_one_versioned_file(from_abspath, to_abspath, ctx,
598
revision, native_eol, ignore_keywords,
440
(eib->notify_func)(eib->notify_baton, notify, scratch_pool);
606
446
/* Abstraction of open_root.
1020
865
return SVN_NO_ERROR;
869
fetch_props_func(apr_hash_t **props,
872
svn_revnum_t base_revision,
873
apr_pool_t *result_pool,
874
apr_pool_t *scratch_pool)
876
/* Always use empty props, since the node won't have pre-existing props
877
(This is an export, remember?) */
878
*props = apr_hash_make(result_pool);
884
fetch_base_func(const char **filename,
887
svn_revnum_t base_revision,
888
apr_pool_t *result_pool,
889
apr_pool_t *scratch_pool)
891
/* An export always gets text against the empty stream (i.e, full texts). */
898
get_editor_ev1(const svn_delta_editor_t **export_editor,
900
struct edit_baton *eb,
901
svn_client_ctx_t *ctx,
902
apr_pool_t *result_pool,
903
apr_pool_t *scratch_pool)
905
svn_delta_editor_t *editor = svn_delta_default_editor(result_pool);
907
editor->set_target_revision = set_target_revision;
908
editor->open_root = open_root;
909
editor->add_directory = add_directory;
910
editor->add_file = add_file;
911
editor->apply_textdelta = apply_textdelta;
912
editor->close_file = close_file;
913
editor->change_file_prop = change_file_prop;
914
editor->change_dir_prop = change_dir_prop;
916
SVN_ERR(svn_delta_get_cancellation_editor(ctx->cancel_func,
928
/*** The Ev2 Implementation ***/
931
add_file_ev2(void *baton,
933
const svn_checksum_t *checksum,
934
svn_stream_t *contents,
936
svn_revnum_t replaces_rev,
937
apr_pool_t *scratch_pool)
939
struct edit_baton *eb = baton;
940
const char *full_path = svn_dirent_join(eb->root_path, relpath,
942
/* RELPATH is not canonicalized, i.e. it may still contain spaces etc.
943
* but EB->root_url is. */
944
const char *full_url = svn_path_url_add_component2(eb->root_url,
947
const svn_string_t *val;
948
/* The four svn: properties we might actually care about. */
949
const svn_string_t *eol_style_val = NULL;
950
const svn_string_t *keywords_val = NULL;
951
const svn_string_t *executable_val = NULL;
952
svn_boolean_t special = FALSE;
953
/* Any keyword vals to be substituted */
954
const char *revision = NULL;
955
const char *author = NULL;
958
/* Look at any properties for additional information. */
959
if ( (val = svn_hash_gets(props, SVN_PROP_EOL_STYLE)) )
962
if ( !eb->ignore_keywords && (val = svn_hash_gets(props, SVN_PROP_KEYWORDS)) )
965
if ( (val = svn_hash_gets(props, SVN_PROP_EXECUTABLE)) )
966
executable_val = val;
968
/* Try to fill out the baton's keywords-structure too. */
969
if ( (val = svn_hash_gets(props, SVN_PROP_ENTRY_COMMITTED_REV)) )
970
revision = val->data;
972
if ( (val = svn_hash_gets(props, SVN_PROP_ENTRY_COMMITTED_DATE)) )
973
SVN_ERR(svn_time_from_cstring(&date, val->data, scratch_pool));
975
if ( (val = svn_hash_gets(props, SVN_PROP_ENTRY_LAST_AUTHOR)) )
978
if ( (val = svn_hash_gets(props, SVN_PROP_SPECIAL)) )
983
svn_stream_t *tmp_stream;
985
SVN_ERR(svn_subst_create_specialfile(&tmp_stream, full_path,
986
scratch_pool, scratch_pool));
987
SVN_ERR(svn_stream_copy3(contents, tmp_stream, eb->cancel_func,
988
eb->cancel_baton, scratch_pool));
992
svn_stream_t *tmp_stream;
995
/* Create a temporary file in the same directory as the file. We're going
996
to rename the thing into place when we're done. */
997
SVN_ERR(svn_stream_open_unique(&tmp_stream, &tmppath,
998
svn_dirent_dirname(full_path,
1000
svn_io_file_del_none,
1001
scratch_pool, scratch_pool));
1003
/* Possibly wrap the stream to be translated, as dictated by
1005
if (eol_style_val || keywords_val)
1007
svn_subst_eol_style_t style;
1008
const char *eol = NULL;
1009
svn_boolean_t repair = FALSE;
1010
apr_hash_t *final_kw = NULL;
1014
SVN_ERR(get_eol_style(&style, &eol, eol_style_val->data,
1020
SVN_ERR(svn_subst_build_keywords3(&final_kw, keywords_val->data,
1023
date, author, scratch_pool));
1025
/* Writing through a translated stream is more efficient than
1026
reading through one, so we wrap TMP_STREAM and not CONTENTS. */
1027
tmp_stream = svn_subst_stream_translated(tmp_stream, eol, repair,
1028
final_kw, TRUE, /* expand */
1032
SVN_ERR(svn_stream_copy3(contents, tmp_stream, eb->cancel_func,
1033
eb->cancel_baton, scratch_pool));
1035
/* Move the file into place. */
1036
SVN_ERR(svn_io_file_rename(tmppath, full_path, scratch_pool));
1040
SVN_ERR(svn_io_set_file_executable(full_path, TRUE, FALSE, scratch_pool));
1042
if (date && (! special))
1043
SVN_ERR(svn_io_set_file_affected_time(date, full_path, scratch_pool));
1045
if (eb->notify_func)
1047
svn_wc_notify_t *notify = svn_wc_create_notify(full_path,
1048
svn_wc_notify_update_add,
1050
notify->kind = svn_node_file;
1051
(*eb->notify_func)(eb->notify_baton, notify, scratch_pool);
1054
return SVN_NO_ERROR;
1057
static svn_error_t *
1058
add_directory_ev2(void *baton,
1059
const char *relpath,
1060
const apr_array_header_t *children,
1062
svn_revnum_t replaces_rev,
1063
apr_pool_t *scratch_pool)
1065
struct edit_baton *eb = baton;
1066
svn_node_kind_t kind;
1067
const char *full_path = svn_dirent_join(eb->root_path, relpath,
1071
SVN_ERR(svn_io_check_path(full_path, &kind, scratch_pool));
1072
if (kind == svn_node_none)
1073
SVN_ERR(svn_io_dir_make(full_path, APR_OS_DEFAULT, scratch_pool));
1074
else if (kind == svn_node_file)
1075
return svn_error_createf(SVN_ERR_WC_NOT_WORKING_COPY, NULL,
1076
_("'%s' exists and is not a directory"),
1077
svn_dirent_local_style(full_path, scratch_pool));
1078
else if (! (kind == svn_node_dir && eb->force))
1079
return svn_error_createf(SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL,
1080
_("'%s' already exists"),
1081
svn_dirent_local_style(full_path, scratch_pool));
1083
if ( (val = svn_hash_gets(props, SVN_PROP_EXTERNALS)) )
1084
SVN_ERR(add_externals(eb->externals, full_path, val));
1086
if (eb->notify_func)
1088
svn_wc_notify_t *notify = svn_wc_create_notify(full_path,
1089
svn_wc_notify_update_add,
1091
notify->kind = svn_node_dir;
1092
(*eb->notify_func)(eb->notify_baton, notify, scratch_pool);
1095
return SVN_NO_ERROR;
1098
static svn_error_t *
1099
target_revision_func(void *baton,
1100
svn_revnum_t target_revision,
1101
apr_pool_t *scratch_pool)
1103
struct edit_baton *eb = baton;
1105
*eb->target_revision = target_revision;
1107
return SVN_NO_ERROR;
1110
static svn_error_t *
1111
get_editor_ev2(const svn_delta_editor_t **export_editor,
1113
struct edit_baton *eb,
1114
svn_client_ctx_t *ctx,
1115
apr_pool_t *result_pool,
1116
apr_pool_t *scratch_pool)
1118
svn_editor_t *editor;
1119
struct svn_delta__extra_baton *exb = apr_pcalloc(result_pool, sizeof(*exb));
1120
svn_boolean_t *found_abs_paths = apr_palloc(result_pool,
1121
sizeof(*found_abs_paths));
1124
exb->target_revision = target_revision_func;
1126
SVN_ERR(svn_editor_create(&editor, eb, ctx->cancel_func, ctx->cancel_baton,
1127
result_pool, scratch_pool));
1128
SVN_ERR(svn_editor_setcb_add_directory(editor, add_directory_ev2,
1130
SVN_ERR(svn_editor_setcb_add_file(editor, add_file_ev2, scratch_pool));
1132
*found_abs_paths = TRUE;
1134
SVN_ERR(svn_delta__delta_from_editor(export_editor, edit_baton,
1135
editor, NULL, NULL, found_abs_paths,
1137
fetch_props_func, eb,
1138
fetch_base_func, eb,
1141
/* Create the root of the export. */
1142
SVN_ERR(open_root_internal(eb->root_path, eb->force, eb->notify_func,
1143
eb->notify_baton, scratch_pool));
1145
return SVN_NO_ERROR;
1148
static svn_error_t *
1149
export_file_ev2(const char *from_path_or_url,
1150
const char *to_path,
1151
struct edit_baton *eb,
1152
svn_client__pathrev_t *loc,
1153
svn_ra_session_t *ra_session,
1154
svn_boolean_t overwrite,
1155
apr_pool_t *scratch_pool)
1157
svn_boolean_t from_is_url = svn_path_is_url(from_path_or_url);
1159
svn_stream_t *tmp_stream;
1160
svn_node_kind_t to_kind;
1162
if (svn_path_is_empty(to_path))
1165
to_path = svn_uri_basename(from_path_or_url, scratch_pool);
1167
to_path = svn_dirent_basename(from_path_or_url, NULL);
1168
eb->root_path = to_path;
1172
SVN_ERR(append_basename_if_dir(&to_path, from_path_or_url,
1173
from_is_url, scratch_pool));
1174
eb->root_path = to_path;
1177
SVN_ERR(svn_io_check_path(to_path, &to_kind, scratch_pool));
1179
if ((to_kind == svn_node_file || to_kind == svn_node_unknown) &&
1181
return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
1182
_("Destination file '%s' exists, and "
1183
"will not be overwritten unless forced"),
1184
svn_dirent_local_style(to_path, scratch_pool));
1185
else if (to_kind == svn_node_dir)
1186
return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
1187
_("Destination '%s' exists. Cannot "
1188
"overwrite directory with non-directory"),
1189
svn_dirent_local_style(to_path, scratch_pool));
1191
tmp_stream = svn_stream_buffered(scratch_pool);
1193
SVN_ERR(svn_ra_get_file(ra_session, "", loc->rev,
1194
tmp_stream, NULL, &props, scratch_pool));
1196
/* Since you cannot actually root an editor at a file, we manually drive
1197
* a function of our editor. */
1198
SVN_ERR(add_file_ev2(eb, "", NULL, tmp_stream, props, SVN_INVALID_REVNUM,
1201
return SVN_NO_ERROR;
1204
static svn_error_t *
1205
export_file(const char *from_path_or_url,
1206
const char *to_path,
1207
struct edit_baton *eb,
1208
svn_client__pathrev_t *loc,
1209
svn_ra_session_t *ra_session,
1210
svn_boolean_t overwrite,
1211
apr_pool_t *scratch_pool)
1214
apr_hash_index_t *hi;
1215
struct file_baton *fb = apr_pcalloc(scratch_pool, sizeof(*fb));
1216
svn_node_kind_t to_kind;
1217
svn_boolean_t from_is_url = svn_path_is_url(from_path_or_url);
1219
if (svn_path_is_empty(to_path))
1222
to_path = svn_uri_basename(from_path_or_url, scratch_pool);
1224
to_path = svn_dirent_basename(from_path_or_url, NULL);
1225
eb->root_path = to_path;
1229
SVN_ERR(append_basename_if_dir(&to_path, from_path_or_url,
1230
from_is_url, scratch_pool));
1231
eb->root_path = to_path;
1234
SVN_ERR(svn_io_check_path(to_path, &to_kind, scratch_pool));
1236
if ((to_kind == svn_node_file || to_kind == svn_node_unknown) &&
1238
return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
1239
_("Destination file '%s' exists, and "
1240
"will not be overwritten unless forced"),
1241
svn_dirent_local_style(to_path, scratch_pool));
1242
else if (to_kind == svn_node_dir)
1243
return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
1244
_("Destination '%s' exists. Cannot "
1245
"overwrite directory with non-directory"),
1246
svn_dirent_local_style(to_path, scratch_pool));
1248
/* Since you cannot actually root an editor at a file, we
1249
* manually drive a few functions of our editor. */
1251
/* This is the equivalent of a parentless add_file(). */
1252
fb->edit_baton = eb;
1253
fb->path = eb->root_path;
1254
fb->url = eb->root_url;
1255
fb->pool = scratch_pool;
1256
fb->repos_root_url = eb->repos_root_url;
1258
/* Copied from apply_textdelta(). */
1259
SVN_ERR(svn_stream_open_unique(&fb->tmp_stream, &fb->tmppath,
1260
svn_dirent_dirname(fb->path, scratch_pool),
1261
svn_io_file_del_none,
1262
fb->pool, fb->pool));
1264
/* Step outside the editor-likeness for a moment, to actually talk
1265
* to the repository. */
1266
/* ### note: the stream will not be closed */
1267
SVN_ERR(svn_ra_get_file(ra_session, "", loc->rev,
1269
NULL, &props, scratch_pool));
1271
/* Push the props into change_file_prop(), to update the file_baton
1272
* with information. */
1273
for (hi = apr_hash_first(scratch_pool, props); hi; hi = apr_hash_next(hi))
1275
const char *propname = svn__apr_hash_index_key(hi);
1276
const svn_string_t *propval = svn__apr_hash_index_val(hi);
1278
SVN_ERR(change_file_prop(fb, propname, propval, scratch_pool));
1281
/* And now just use close_file() to do all the keyword and EOL
1282
* work, and put the file into place. */
1283
SVN_ERR(close_file(fb, NULL, scratch_pool));
1285
return SVN_NO_ERROR;
1288
static svn_error_t *
1289
export_directory(const char *from_path_or_url,
1290
const char *to_path,
1291
struct edit_baton *eb,
1292
svn_client__pathrev_t *loc,
1293
svn_ra_session_t *ra_session,
1294
svn_boolean_t overwrite,
1295
svn_boolean_t ignore_externals,
1296
svn_boolean_t ignore_keywords,
1298
const char *native_eol,
1299
svn_client_ctx_t *ctx,
1300
apr_pool_t *scratch_pool)
1303
const svn_delta_editor_t *export_editor;
1304
const svn_ra_reporter3_t *reporter;
1306
svn_node_kind_t kind;
1308
if (!ENABLE_EV2_IMPL)
1309
SVN_ERR(get_editor_ev1(&export_editor, &edit_baton, eb, ctx,
1310
scratch_pool, scratch_pool));
1312
SVN_ERR(get_editor_ev2(&export_editor, &edit_baton, eb, ctx,
1313
scratch_pool, scratch_pool));
1315
/* Manufacture a basic 'report' to the update reporter. */
1316
SVN_ERR(svn_ra_do_update3(ra_session,
1317
&reporter, &report_baton,
1319
"", /* no sub-target */
1321
FALSE, /* don't want copyfrom-args */
1322
FALSE, /* don't want ignore_ancestry */
1323
export_editor, edit_baton,
1324
scratch_pool, scratch_pool));
1326
SVN_ERR(reporter->set_path(report_baton, "", loc->rev,
1327
/* Depth is irrelevant, as we're
1328
passing start_empty=TRUE anyway. */
1330
TRUE, /* "help, my dir is empty!" */
1331
NULL, scratch_pool));
1333
SVN_ERR(reporter->finish_report(report_baton, scratch_pool));
1335
/* Special case: Due to our sly export/checkout method of updating an
1336
* empty directory, no target will have been created if the exported
1337
* item is itself an empty directory (export_editor->open_root never
1338
* gets called, because there are no "changes" to make to the empty
1339
* dir we reported to the repository).
1341
* So we just create the empty dir manually; but we do it via
1342
* open_root_internal(), in order to get proper notification.
1344
SVN_ERR(svn_io_check_path(to_path, &kind, scratch_pool));
1345
if (kind == svn_node_none)
1346
SVN_ERR(open_root_internal
1347
(to_path, overwrite, ctx->notify_func2,
1348
ctx->notify_baton2, scratch_pool));
1350
if (! ignore_externals && depth == svn_depth_infinity)
1352
const char *to_abspath;
1354
SVN_ERR(svn_dirent_get_absolute(&to_abspath, to_path, scratch_pool));
1355
SVN_ERR(svn_client__export_externals(eb->externals,
1357
to_abspath, eb->repos_root_url,
1360
ctx, scratch_pool));
1363
return SVN_NO_ERROR;
1025
1368
/*** Public Interfaces ***/
1082
1421
eb->notify_func = ctx->notify_func2;
1083
1422
eb->notify_baton = ctx->notify_baton2;
1085
SVN_ERR(svn_ra_check_path(ra_session, "", revnum, &kind, pool));
1424
SVN_ERR(svn_ra_check_path(ra_session, "", loc->rev, &kind, pool));
1087
1426
if (kind == svn_node_file)
1090
apr_hash_index_t *hi;
1091
struct file_baton *fb = apr_pcalloc(pool, sizeof(*fb));
1092
svn_node_kind_t to_kind;
1094
if (svn_path_is_empty(to_path))
1097
to_path = svn_uri_basename(from_path_or_url, pool);
1099
to_path = svn_dirent_basename(from_path_or_url, NULL);
1100
eb->root_path = to_path;
1428
if (!ENABLE_EV2_IMPL)
1429
SVN_ERR(export_file(from_path_or_url, to_path, eb, loc, ra_session,
1104
SVN_ERR(append_basename_if_dir(&to_path, from_path_or_url,
1105
from_is_url, pool));
1106
eb->root_path = to_path;
1109
SVN_ERR(svn_io_check_path(to_path, &to_kind, pool));
1111
if ((to_kind == svn_node_file || to_kind == svn_node_unknown) &&
1113
return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
1114
_("Destination file '%s' exists, and "
1115
"will not be overwritten unless forced"),
1116
svn_dirent_local_style(to_path, pool));
1117
else if (to_kind == svn_node_dir)
1118
return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
1119
_("Destination '%s' exists. Cannot "
1120
"overwrite directory with non-directory"),
1121
svn_dirent_local_style(to_path, pool));
1123
/* Since you cannot actually root an editor at a file, we
1124
* manually drive a few functions of our editor. */
1126
/* This is the equivalent of a parentless add_file(). */
1127
fb->edit_baton = eb;
1128
fb->path = eb->root_path;
1129
fb->url = eb->root_url;
1132
/* Copied from apply_textdelta(). */
1133
SVN_ERR(svn_stream_open_unique(&fb->tmp_stream, &fb->tmppath,
1134
svn_dirent_dirname(fb->path, pool),
1135
svn_io_file_del_none,
1136
fb->pool, fb->pool));
1138
/* Step outside the editor-likeness for a moment, to actually talk
1139
* to the repository. */
1140
/* ### note: the stream will not be closed */
1141
SVN_ERR(svn_ra_get_file(ra_session, "", revnum,
1143
NULL, &props, pool));
1145
/* Push the props into change_file_prop(), to update the file_baton
1146
* with information. */
1147
for (hi = apr_hash_first(pool, props); hi; hi = apr_hash_next(hi))
1149
const char *propname = svn__apr_hash_index_key(hi);
1150
const svn_string_t *propval = svn__apr_hash_index_val(hi);
1152
SVN_ERR(change_file_prop(fb, propname, propval, pool));
1155
/* And now just use close_file() to do all the keyword and EOL
1156
* work, and put the file into place. */
1157
SVN_ERR(close_file(fb, NULL, pool));
1432
SVN_ERR(export_file_ev2(from_path_or_url, to_path, eb, loc,
1433
ra_session, overwrite, pool));
1159
1435
else if (kind == svn_node_dir)
1162
const svn_delta_editor_t *export_editor;
1163
const svn_ra_reporter3_t *reporter;
1165
svn_delta_editor_t *editor = svn_delta_default_editor(pool);
1166
svn_boolean_t use_sleep = FALSE;
1168
editor->set_target_revision = set_target_revision;
1169
editor->open_root = open_root;
1170
editor->add_directory = add_directory;
1171
editor->add_file = add_file;
1172
editor->apply_textdelta = apply_textdelta;
1173
editor->close_file = close_file;
1174
editor->change_file_prop = change_file_prop;
1175
editor->change_dir_prop = change_dir_prop;
1177
SVN_ERR(svn_delta_get_cancellation_editor(ctx->cancel_func,
1186
/* Manufacture a basic 'report' to the update reporter. */
1187
SVN_ERR(svn_ra_do_update2(ra_session,
1188
&reporter, &report_baton,
1190
"", /* no sub-target */
1192
FALSE, /* don't want copyfrom-args */
1193
export_editor, edit_baton, pool));
1195
SVN_ERR(reporter->set_path(report_baton, "", revnum,
1196
/* Depth is irrelevant, as we're
1197
passing start_empty=TRUE anyway. */
1199
TRUE, /* "help, my dir is empty!" */
1202
SVN_ERR(reporter->finish_report(report_baton, pool));
1204
/* Special case: Due to our sly export/checkout method of
1205
* updating an empty directory, no target will have been created
1206
* if the exported item is itself an empty directory
1207
* (export_editor->open_root never gets called, because there
1208
* are no "changes" to make to the empty dir we reported to the
1211
* So we just create the empty dir manually; but we do it via
1212
* open_root_internal(), in order to get proper notification.
1214
SVN_ERR(svn_io_check_path(to_path, &kind, pool));
1215
if (kind == svn_node_none)
1216
SVN_ERR(open_root_internal
1217
(to_path, overwrite, ctx->notify_func2,
1218
ctx->notify_baton2, pool));
1220
if (! ignore_externals && depth == svn_depth_infinity)
1222
const char *to_abspath;
1224
SVN_ERR(svn_dirent_get_absolute(&to_abspath, to_path, pool));
1225
SVN_ERR(svn_client__export_externals(eb->externals,
1227
to_abspath, repos_root_url,
1229
ignore_keywords, &use_sleep,
1437
SVN_ERR(export_directory(from_path_or_url, to_path,
1438
eb, loc, ra_session, overwrite,
1439
ignore_externals, ignore_keywords, depth,
1440
native_eol, ctx, pool));
1233
1442
else if (kind == svn_node_none)