You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by sv...@apache.org on 2012/03/01 05:01:00 UTC

svn commit: r1295403 - in /subversion/branches/1.7.x: ./ subversion/libsvn_wc/ subversion/tests/cmdline/

Author: svn-role
Date: Thu Mar  1 04:00:59 2012
New Revision: 1295403

URL: http://svn.apache.org/viewvc?rev=1295403&view=rev
Log:
Reintegrate the 1.7.x-issue4102 branch:

 * r1233292, r1245711, r1245746, r1245764, r1245809, r1245929, r1245935, r1293577
   Fix various problems with symlinks pointing at externals (issue #4102).
   Justification:
     Regression from 1.6.x. Users complained:
     http://svn.haxx.se/users/archive-2012-02/0266.shtml
   Branch:
     ^/subversion/branches/1.7.x-issue4102
   Votes:
     +1: stsp, rhuijben, neels

Modified:
    subversion/branches/1.7.x/   (props changed)
    subversion/branches/1.7.x/STATUS
    subversion/branches/1.7.x/subversion/libsvn_wc/adm_ops.c
    subversion/branches/1.7.x/subversion/libsvn_wc/status.c
    subversion/branches/1.7.x/subversion/libsvn_wc/wc_db.c
    subversion/branches/1.7.x/subversion/libsvn_wc/wc_db_private.h
    subversion/branches/1.7.x/subversion/libsvn_wc/wc_db_wcroot.c
    subversion/branches/1.7.x/subversion/tests/cmdline/special_tests.py

Propchange: subversion/branches/1.7.x/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Thu Mar  1 04:00:59 2012
@@ -9,6 +9,7 @@
 /subversion/branches/1.7.x-issue4035-r1185738:1186316-1186778
 /subversion/branches/1.7.x-issue4059:1239745-1242661
 /subversion/branches/1.7.x-issue4093:1229839-1230236
+/subversion/branches/1.7.x-issue4102:1292401-1295402
 /subversion/branches/1.7.x-issue4123:1293358-1293812
 /subversion/branches/1.7.x-issue4k:1166502-1167193
 /subversion/branches/1.7.x-neon-default:1148803-1158680
@@ -78,4 +79,4 @@
 /subversion/branches/tree-conflicts:868291-873154
 /subversion/branches/tree-conflicts-notify:873926-874008
 /subversion/branches/uris-as-urls:1060426-1064427
-/subversion/trunk:1146013,1146121,1146219,1146222,1146274,1146492,1146555,1146606,1146620,1146684,1146762,1146781,1146832,1146834,1146870,1146899,1146904,1147293,1147299,1147309,1147882,1148071,1148083,1148094,1148131,1148374,1148424,1148566,1148588,1148652,1148662,1148699,1148853,1148877,1148882,1148936,1149103,1149105,1149135,1149141,1149160,1149228,1149240,1149343,1149371-1149372,1149377,1149398,1149401,1149539,1149572,1149627,1149675,1149701,1149713,1150242,1150254,1150260-1150261,1150266,1150302,1150327,1150344,1150368,1150372,1150441,1150506,1150812,1150853,1151036,1151177,1151610,1151854,1151906,1151911,1152129,1152140,1152189-1152190,1152267,1152282,1152286,1152726,1152809,1153138,1153141,1153416,1153540,1153566,1153799,1153807,1153968,1154009,1154023,1154115,1154119,1154121,1154144,1154155,1154159,1154165,1154215,1154225,1154273,1154278,1154379,1154382,1154461,1154717-1154718,1154733,1154908,1154982,1155015,1155044,1155124,1155131,1155160,1155313,1155334,1155391,115
 5404,1156085,1156098,1156216,1156218,1156312,1156527,1156717,1156721,1156750,1156827,1156838,1157416,1158187,1158193-1158194,1158196,1158201,1158207,1158209-1158210,1158217,1158285,1158288,1158303,1158309,1158407,1158419,1158421,1158436,1158455,1158616-1158617,1158634,1158854,1158875,1158886,1158893,1158896,1158919,1158923-1158924,1158929,1158963,1159093,1159098,1159101,1159132,1159136,1159148,1159230,1159275,1159400,1159686,1159760,1159772,1160605,1160671,1160682,1160704-1160705,1160756,1161063,1161080,1161185,1161210,1161683,1161721,1162024,1162033,1162201,1162516,1162880,1162974,1162995,1163243,1163372,1163383,1163557,1163792,1163953,1164027,1164386,1164426,1164517,1164535,1164554,1164580,1164614,1164645,1164760,1164765,1166267,1166500,1166555,1166678,1167062,1167173,1167209,1167269,1167503,1167659,1167681,1169524,1169531,1169650,1171708,1173111,1173425,1173639,1174051,1174060,1174652,1174761,1174797-1174798,1174806,1175888,1176915,1176949,1177001,1177492,1177732,1178280,
 1178282,1178942,1179680,1179767,1179776,1180154,1181090,1181110,1181155,1181215,1181609,1181666,1182115,1182527,1182771,1182904,1182909,1183054,1183263,1183347,1185222,1185242,1185280,1185282,1185730,1185738,1185746,1185763,1185768,1185886,1185911,1185918,1186059,1186092,1186101,1186107,1186109,1186121,1186231,1186240,1186422,1186434,1186732,1186755,1186784,1186815,1186928,1186944,1186981,1186983,1187311,1187676,1187695,1188609,1188652,1188677,1188762,1188774,1189190,1189261,1189395,1189580,1189665,1195480,1197135,1197998,1199876,1199950,1200837,1201002,1201072,1201419,1201824,1202132,1202135,1202187,1202333,1202630,1202807,1203546,1203651,1203653,1204167,1204478,1204610,1204673,1205188,1205193,1205209,1205726,1205839,1205848,1206523,1206533,1206576,1206718-1206719,1206724,1206741,1206748,1207555,1207656,1207663,1207808,1207823,1207858,1207949,1208840,1209631,1209654,1210147,1210195,1211483,1211859,1211885,1212476,1212482,1212484,1213331,1213673,1213681,1213690,1213711,12137
 16,1214139,1215260,1215288,1215374-1215375,1215379,1220740,1220742,1220750,1220861,1221178,1221303,1221767,1221780,1221793,1222521,1222628,1222644,1222693,1222699,1225491,1226597,1227146,1227237,1227250,1227352,1227372,1227384-1227385,1227900,1228340,1229252,1229303,1229677,1229833,1229980,1230212,1230714,1231029,1231944-1231945,1232202,1232207,1232221-1232222,1232413,1235264,1235296,1235302,1235736,1236163,1236173,1236283,1236343,1237720,1238121,1239382,1239596,1239631,1239655,1239747,1240314,1240485,1240619,1240752,1241530,1241553,1241599,1241626,1241713,1241726,1242116,1242537,1242607,1243976,1244303,1244317,1245284-1245285,1245738,1245817,1291429,1291446,1291520,1291680,1291685,1291700,1291704,1291726,1291729,1291941,1292090,1292255,1292507,1292516,1292768,1292827,1292926,1293229,1294470,1295303
+/subversion/trunk:1146013,1146121,1146219,1146222,1146274,1146492,1146555,1146606,1146620,1146684,1146762,1146781,1146832,1146834,1146870,1146899,1146904,1147293,1147299,1147309,1147882,1148071,1148083,1148094,1148131,1148374,1148424,1148566,1148588,1148652,1148662,1148699,1148853,1148877,1148882,1148936,1149103,1149105,1149135,1149141,1149160,1149228,1149240,1149343,1149371-1149372,1149377,1149398,1149401,1149539,1149572,1149627,1149675,1149701,1149713,1150242,1150254,1150260-1150261,1150266,1150302,1150327,1150344,1150368,1150372,1150441,1150506,1150812,1150853,1151036,1151177,1151610,1151854,1151906,1151911,1152129,1152140,1152189-1152190,1152267,1152282,1152286,1152726,1152809,1153138,1153141,1153416,1153540,1153566,1153799,1153807,1153968,1154009,1154023,1154115,1154119,1154121,1154144,1154155,1154159,1154165,1154215,1154225,1154273,1154278,1154379,1154382,1154461,1154717-1154718,1154733,1154908,1154982,1155015,1155044,1155124,1155131,1155160,1155313,1155334,1155391,115
 5404,1156085,1156098,1156216,1156218,1156312,1156527,1156717,1156721,1156750,1156827,1156838,1157416,1158187,1158193-1158194,1158196,1158201,1158207,1158209-1158210,1158217,1158285,1158288,1158303,1158309,1158407,1158419,1158421,1158436,1158455,1158616-1158617,1158634,1158854,1158875,1158886,1158893,1158896,1158919,1158923-1158924,1158929,1158963,1159093,1159098,1159101,1159132,1159136,1159148,1159230,1159275,1159400,1159686,1159760,1159772,1160605,1160671,1160682,1160704-1160705,1160756,1161063,1161080,1161185,1161210,1161683,1161721,1162024,1162033,1162201,1162516,1162880,1162974,1162995,1163243,1163372,1163383,1163557,1163792,1163953,1164027,1164386,1164426,1164517,1164535,1164554,1164580,1164614,1164645,1164760,1164765,1166267,1166500,1166555,1166678,1167062,1167173,1167209,1167269,1167503,1167659,1167681,1169524,1169531,1169650,1171708,1173111,1173425,1173639,1174051,1174060,1174652,1174761,1174797-1174798,1174806,1175888,1176915,1176949,1177001,1177492,1177732,1178280,
 1178282,1178942,1179680,1179767,1179776,1180154,1181090,1181110,1181155,1181215,1181609,1181666,1182115,1182527,1182771,1182904,1182909,1183054,1183263,1183347,1185222,1185242,1185280,1185282,1185730,1185738,1185746,1185763,1185768,1185886,1185911,1185918,1186059,1186092,1186101,1186107,1186109,1186121,1186231,1186240,1186422,1186434,1186732,1186755,1186784,1186815,1186928,1186944,1186981,1186983,1187311,1187676,1187695,1188609,1188652,1188677,1188762,1188774,1189190,1189261,1189395,1189580,1189665,1195480,1197135,1197998,1199876,1199950,1200837,1201002,1201072,1201419,1201824,1202132,1202135,1202187,1202333,1202630,1202807,1203546,1203651,1203653,1204167,1204478,1204610,1204673,1205188,1205193,1205209,1205726,1205839,1205848,1206523,1206533,1206576,1206718-1206719,1206724,1206741,1206748,1207555,1207656,1207663,1207808,1207823,1207858,1207949,1208840,1209631,1209654,1210147,1210195,1211483,1211859,1211885,1212476,1212482,1212484,1213331,1213673,1213681,1213690,1213711,12137
 16,1214139,1215260,1215288,1215374-1215375,1215379,1220740,1220742,1220750,1220861,1221178,1221303,1221767,1221780,1221793,1222521,1222628,1222644,1222693,1222699,1225491,1226597,1227146,1227237,1227250,1227352,1227372,1227384-1227385,1227900,1228340,1229252,1229303,1229677,1229833,1229980,1230212,1230714,1231029,1231944-1231945,1232202,1232207,1232221-1232222,1232413,1233292,1235264,1235296,1235302,1235736,1236163,1236173,1236283,1236343,1237720,1238121,1239382,1239596,1239631,1239655,1239747,1240314,1240485,1240619,1240752,1241530,1241553,1241599,1241626,1241713,1241726,1242116,1242537,1242607,1243976,1244303,1244317,1245284-1245285,1245711,1245738,1245746,1245764,1245809,1245817,1245929,1245935,1291429,1291446,1291520,1291680,1291685,1291700,1291704,1291726,1291729,1291941,1292090,1292255,1292507,1292516,1292768,1292827,1292926,1293229,1293577,1294470,1295303

Modified: subversion/branches/1.7.x/STATUS
URL: http://svn.apache.org/viewvc/subversion/branches/1.7.x/STATUS?rev=1295403&r1=1295402&r2=1295403&view=diff
==============================================================================
--- subversion/branches/1.7.x/STATUS (original)
+++ subversion/branches/1.7.x/STATUS Thu Mar  1 04:00:59 2012
@@ -87,13 +87,3 @@ Veto-blocked changes:
 
 Approved changes:
 =================
-
- * r1233292, r1245711, r1245746, r1245764, r1245809, r1245929, r1245935, r1293577
-   Fix various problems with symlinks pointing at externals (issue #4102).
-   Justification:
-     Regression from 1.6.x. Users complained:
-     http://svn.haxx.se/users/archive-2012-02/0266.shtml
-   Branch:
-     ^/subversion/branches/1.7.x-issue4102
-   Votes:
-     +1: stsp, rhuijben, neels

Modified: subversion/branches/1.7.x/subversion/libsvn_wc/adm_ops.c
URL: http://svn.apache.org/viewvc/subversion/branches/1.7.x/subversion/libsvn_wc/adm_ops.c?rev=1295403&r1=1295402&r2=1295403&view=diff
==============================================================================
--- subversion/branches/1.7.x/subversion/libsvn_wc/adm_ops.c (original)
+++ subversion/branches/1.7.x/subversion/libsvn_wc/adm_ops.c Thu Mar  1 04:00:59 2012
@@ -1553,8 +1553,15 @@ revert_restore(svn_wc__db_t *db,
         }
       else if (on_disk == svn_node_file && kind != svn_wc__db_kind_file)
         {
-          SVN_ERR(svn_io_remove_file2(local_abspath, FALSE, scratch_pool));
-          on_disk = svn_node_none;
+#ifdef HAVE_SYMLINK
+          /* Preserve symlinks pointing at directories. Changes on the
+           * directory node have been reverted. The symlink should remain. */
+          if (!(special && kind == svn_wc__db_kind_dir))
+#endif
+            {
+              SVN_ERR(svn_io_remove_file2(local_abspath, FALSE, scratch_pool));
+              on_disk = svn_node_none;
+            }
         }
       else if (on_disk == svn_node_file)
         {

Modified: subversion/branches/1.7.x/subversion/libsvn_wc/status.c
URL: http://svn.apache.org/viewvc/subversion/branches/1.7.x/subversion/libsvn_wc/status.c?rev=1295403&r1=1295402&r2=1295403&view=diff
==============================================================================
--- subversion/branches/1.7.x/subversion/libsvn_wc/status.c (original)
+++ subversion/branches/1.7.x/subversion/libsvn_wc/status.c Thu Mar  1 04:00:59 2012
@@ -2383,6 +2383,28 @@ svn_wc__internal_walk_status(svn_wc__db_
   SVN_ERR(svn_io_stat_dirent(&dirent, local_abspath, TRUE,
                              scratch_pool, scratch_pool));
 
+#ifdef HAVE_SYMLINK
+  if (dirent->special && !skip_root)
+    {
+      svn_io_dirent2_t *this_dirent = svn_io_dirent2_dup(dirent,
+                                                         scratch_pool);
+
+      /* We're being pointed to the status root via a symlink.
+       * Get the real node kind and pretend the path is not a symlink.
+       * This prevents send_status_structure() from treating the root
+       * as a directory obstructed by a file. */
+      SVN_ERR(svn_io_check_resolved_path(local_abspath,
+                                         &this_dirent->kind, scratch_pool));
+      this_dirent->special = FALSE;
+      SVN_ERR(send_status_structure(&wb, local_abspath,
+                                    NULL, NULL, NULL,
+                                    dir_info, this_dirent, get_all,
+                                    status_func, status_baton,
+                                    scratch_pool));
+      skip_root = TRUE;
+    }
+#endif
+
   SVN_ERR(get_dir_status(&wb,
                          anchor_abspath,
                          target_name,

Modified: subversion/branches/1.7.x/subversion/libsvn_wc/wc_db.c
URL: http://svn.apache.org/viewvc/subversion/branches/1.7.x/subversion/libsvn_wc/wc_db.c?rev=1295403&r1=1295402&r2=1295403&view=diff
==============================================================================
--- subversion/branches/1.7.x/subversion/libsvn_wc/wc_db.c (original)
+++ subversion/branches/1.7.x/subversion/libsvn_wc/wc_db.c Thu Mar  1 04:00:59 2012
@@ -6670,6 +6670,49 @@ read_info(svn_wc__db_status_t *status,
 
 
 svn_error_t *
+svn_wc__db_read_info_internal(svn_wc__db_status_t *status,
+                              svn_wc__db_kind_t *kind,
+                              svn_revnum_t *revision,
+                              const char **repos_relpath,
+                              apr_int64_t *repos_id,
+                              svn_revnum_t *changed_rev,
+                              apr_time_t *changed_date,
+                              const char **changed_author,
+                              svn_depth_t *depth,
+                              const svn_checksum_t **checksum,
+                              const char **target,
+                              const char **original_repos_relpath,
+                              apr_int64_t *original_repos_id,
+                              svn_revnum_t *original_revision,
+                              svn_wc__db_lock_t **lock,
+                              svn_filesize_t *recorded_size,
+                              apr_time_t *recorded_mod_time,
+                              const char **changelist,
+                              svn_boolean_t *conflicted,
+                              svn_boolean_t *op_root,
+                              svn_boolean_t *had_props,
+                              svn_boolean_t *props_mod,
+                              svn_boolean_t *have_base,
+                              svn_boolean_t *have_more_work,
+                              svn_boolean_t *have_work,
+                              svn_wc__db_wcroot_t *wcroot,
+                              const char *local_relpath,
+                              apr_pool_t *result_pool,
+                              apr_pool_t *scratch_pool)
+{
+  return svn_error_trace(
+           read_info(status, kind, revision, repos_relpath, repos_id,
+                     changed_rev, changed_date, changed_author,
+                     depth, checksum, target, original_repos_relpath,
+                     original_repos_id, original_revision, lock,
+                     recorded_size, recorded_mod_time, changelist, conflicted,
+                     op_root, had_props, props_mod,
+                     have_base, have_more_work, have_work,
+                     wcroot, local_relpath, result_pool, scratch_pool));
+}
+
+
+svn_error_t *
 svn_wc__db_read_info(svn_wc__db_status_t *status,
                      svn_wc__db_kind_t *kind,
                      svn_revnum_t *revision,

Modified: subversion/branches/1.7.x/subversion/libsvn_wc/wc_db_private.h
URL: http://svn.apache.org/viewvc/subversion/branches/1.7.x/subversion/libsvn_wc/wc_db_private.h?rev=1295403&r1=1295402&r2=1295403&view=diff
==============================================================================
--- subversion/branches/1.7.x/subversion/libsvn_wc/wc_db_private.h (original)
+++ subversion/branches/1.7.x/subversion/libsvn_wc/wc_db_private.h Thu Mar  1 04:00:59 2012
@@ -55,6 +55,7 @@ struct svn_wc__db_t {
   {
     svn_stringbuf_t *abspath;
     svn_node_kind_t kind;
+    svn_boolean_t is_symlink;
   } parse_cache;
 
   /* As we grow the state of this DB, allocate that state here. */
@@ -174,6 +175,39 @@ svn_wc__db_util_open_db(svn_sqlite__db_t
                         apr_pool_t *result_pool,
                         apr_pool_t *scratch_pool);
 
+/* Like svn_wc__db_read_info(), but taking WCROOT+LOCAL_RELPATH instead of
+   DB+LOCAL_ABSPATH, and outputting repos ids instead of URL+UUID. */
+svn_error_t *
+svn_wc__db_read_info_internal(svn_wc__db_status_t *status,
+                              svn_wc__db_kind_t *kind,
+                              svn_revnum_t *revision,
+                              const char **repos_relpath,
+                              apr_int64_t *repos_id,
+                              svn_revnum_t *changed_rev,
+                              apr_time_t *changed_date,
+                              const char **changed_author,
+                              svn_depth_t *depth,
+                              const svn_checksum_t **checksum,
+                              const char **target,
+                              const char **original_repos_relpath,
+                              apr_int64_t *original_repos_id,
+                              svn_revnum_t *original_revision,
+                              svn_wc__db_lock_t **lock,
+                              svn_filesize_t *recorded_size,
+                              apr_time_t *recorded_mod_time,
+                              const char **changelist,
+                              svn_boolean_t *conflicted,
+                              svn_boolean_t *op_root,
+                              svn_boolean_t *had_props,
+                              svn_boolean_t *props_mod,
+                              svn_boolean_t *have_base,
+                              svn_boolean_t *have_more_work,
+                              svn_boolean_t *have_work,
+                              svn_wc__db_wcroot_t *wcroot,
+                              const char *local_relpath,
+                              apr_pool_t *result_pool,
+                              apr_pool_t *scratch_pool);
+
 
 /* Transaction handling */
 

Modified: subversion/branches/1.7.x/subversion/libsvn_wc/wc_db_wcroot.c
URL: http://svn.apache.org/viewvc/subversion/branches/1.7.x/subversion/libsvn_wc/wc_db_wcroot.c?rev=1295403&r1=1295402&r2=1295403&view=diff
==============================================================================
--- subversion/branches/1.7.x/subversion/libsvn_wc/wc_db_wcroot.c (original)
+++ subversion/branches/1.7.x/subversion/libsvn_wc/wc_db_wcroot.c Thu Mar  1 04:00:59 2012
@@ -105,12 +105,11 @@ get_old_version(int *version,
    Sets *KIND to svn_node_dir for symlinks. */
 static svn_error_t *
 get_path_kind(svn_node_kind_t *kind,
+              svn_boolean_t *is_symlink,
               svn_wc__db_t *db,
               const char *local_abspath,
               apr_pool_t *scratch_pool)
 {
-  svn_boolean_t special;
-
   /* This implements a *really* simple LRU cache, where "simple" is defined
      as "only one element".  In other words, we remember the most recently
      queried path, and nothing else.  This gives >80% cache hits. */
@@ -120,6 +119,7 @@ get_path_kind(svn_node_kind_t *kind,
     {
       /* Cache hit! */
       *kind = db->parse_cache.kind;
+      *is_symlink = db->parse_cache.is_symlink;
       return SVN_NO_ERROR;
     }
 
@@ -133,13 +133,11 @@ get_path_kind(svn_node_kind_t *kind,
       svn_stringbuf_set(db->parse_cache.abspath, local_abspath);
     }
 
-  SVN_ERR(svn_io_check_special_path(local_abspath, &db->parse_cache.kind,
-                                    &special, scratch_pool));
+  SVN_ERR(svn_io_check_special_path(local_abspath, kind,
+                                    is_symlink, scratch_pool));
 
-  /* The wcroot could be a symlink to a directory. (Issue #2557, #3987) */
-  if (special)
-    db->parse_cache.kind = svn_node_dir;
-  *kind = db->parse_cache.kind;
+  db->parse_cache.kind = *kind;
+  db->parse_cache.is_symlink = *is_symlink;
 
   return SVN_NO_ERROR;
 }
@@ -374,6 +372,7 @@ svn_wc__db_wcroot_parse_local_abspath(sv
   svn_sqlite__db_t *sdb;
   svn_boolean_t moved_upwards = FALSE;
   svn_boolean_t always_check = FALSE;
+  svn_boolean_t is_symlink;
   int wc_format = 0;
 
   /* ### we need more logic for finding the database (if it is located
@@ -401,8 +400,8 @@ svn_wc__db_wcroot_parse_local_abspath(sv
      ### rid of this stat() call. it is going to happen for EVERY call
      ### into wc_db which references a file. calls for directories could
      ### get an early-exit in the hash lookup just above.  */
-  SVN_ERR(get_path_kind(&kind, db, local_abspath, scratch_pool));
-  if (kind != svn_node_dir)
+  SVN_ERR(get_path_kind(&kind, &is_symlink, db, local_abspath, scratch_pool));
+  if (kind != svn_node_dir || is_symlink)
     {
       /* If the node specified by the path is NOT present, then it cannot
          possibly be a directory containing ".svn/wc.db".
@@ -511,6 +510,39 @@ svn_wc__db_wcroot_parse_local_abspath(sv
       if (svn_dirent_is_root(local_abspath, strlen(local_abspath)))
         {
           /* Hit the root without finding a wcroot. */
+
+          /* The wcroot could be a symlink to a directory.
+           * (Issue #2557, #3987). If so, try again, this time scanning
+           * for a db within the directory the symlink points to,
+           * rather than within the symlink's parent directory. */
+          if (is_symlink)
+            {
+              svn_node_kind_t resolved_kind;
+
+              local_abspath = original_abspath;
+
+              SVN_ERR(svn_io_check_resolved_path(local_abspath,
+                                                 &resolved_kind,
+                                                 scratch_pool));
+              if (resolved_kind == svn_node_dir)
+                {
+                  /* Is this directory recorded in our hash?  */
+                  found_wcroot = apr_hash_get(db->dir_data, local_abspath,
+                                              APR_HASH_KEY_STRING);
+                  if (found_wcroot)
+                    break;
+
+try_symlink_as_dir:
+                  kind = svn_node_dir;
+                  is_symlink = FALSE;
+                  moved_upwards = FALSE;
+                  local_dir_abspath = local_abspath;
+                  build_relpath = "";
+
+                  continue;
+                }
+            }
+
           return svn_error_createf(SVN_ERR_WC_NOT_WORKING_COPY, NULL,
                                    _("'%s' is not a working copy"),
                                    svn_dirent_local_style(original_abspath,
@@ -584,6 +616,61 @@ svn_wc__db_wcroot_parse_local_abspath(sv
     *local_relpath = svn_relpath_join(dir_relpath, build_relpath, result_pool);
   }
 
+  if (is_symlink)
+    {
+      svn_boolean_t retry_if_dir = FALSE;
+      svn_wc__db_status_t status;
+      svn_boolean_t conflicted;
+      svn_error_t *err;
+
+      /* Check if the symlink is versioned or obstructs a versioned node
+       * in this DB -- in that case, use this wcroot. Else, if the symlink
+       * points to a directory, try to find a wcroot in that directory
+       * instead. */
+      
+      err = svn_wc__db_read_info_internal(&status, NULL, NULL, NULL, NULL,
+                                          NULL, NULL, NULL, NULL, NULL, NULL,
+                                          NULL, NULL, NULL, NULL, NULL, NULL,
+                                          NULL, &conflicted, NULL, NULL, NULL,
+                                          NULL, NULL, NULL,
+                                          *wcroot, *local_relpath,
+                                          scratch_pool, scratch_pool);
+      if (err)
+        {
+          if (err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND
+              && !SVN_WC__ERR_IS_NOT_CURRENT_WC(err))
+            return svn_error_trace(err);
+
+          svn_error_clear(err);
+          retry_if_dir = TRUE; /* The symlink is unversioned. */
+        }
+      else
+        {
+          /* The symlink is versioned, or obstructs a versioned node.
+           * Ignore non-conflicted not-present/excluded nodes.
+           * This allows the symlink to redirect the wcroot query to a
+           * directory, regardless of 'invisible' nodes in this WC. */
+          retry_if_dir = ((status == svn_wc__db_status_not_present ||
+                           status == svn_wc__db_status_excluded ||
+                           status == svn_wc__db_status_server_excluded)
+                          && !conflicted);
+        }
+
+      if (retry_if_dir)
+        {
+          svn_node_kind_t resolved_kind;
+
+          SVN_ERR(svn_io_check_resolved_path(original_abspath,
+                                             &resolved_kind,
+                                             scratch_pool));
+          if (resolved_kind == svn_node_dir)
+            {
+              local_abspath = original_abspath;
+              goto try_symlink_as_dir;
+            }
+        }
+    } 
+
   /* We've found the appropriate WCROOT for the requested path. Stash
      it into that path's directory.  */
   apr_hash_set(db->dir_data,

Modified: subversion/branches/1.7.x/subversion/tests/cmdline/special_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/1.7.x/subversion/tests/cmdline/special_tests.py?rev=1295403&r1=1295402&r2=1295403&view=diff
==============================================================================
--- subversion/branches/1.7.x/subversion/tests/cmdline/special_tests.py (original)
+++ subversion/branches/1.7.x/subversion/tests/cmdline/special_tests.py Thu Mar  1 04:00:59 2012
@@ -906,6 +906,37 @@ def update_symlink(sbox):
                                         None, None, None,
                                         None, None, 1)
 
+@Issue(4102)
+@SkipUnless(svntest.main.is_posix_os)
+def externals_as_symlink_targets(sbox):
+  "externals as symlink targets"
+  sbox.build()
+  wc = sbox.ospath
+
+  # Control: symlink to normal dir and file.
+  os.symlink('E', wc('sym_E'))
+  os.symlink('mu', wc('sym_mu'))
+
+  # Test case: symlink to external dir and file.
+  sbox.simple_propset("svn:externals",
+                      '^/A/B/E ext_E\n'
+                      '^/A/mu ext_mu',
+                      '')
+  sbox.simple_update()
+  os.symlink('ext_E', wc('sym_ext_E'))
+  os.symlink('ext_mu', wc('sym_ext_mu'))
+
+  # Adding symlinks to normal items and to a file external is OK.
+  sbox.simple_add('sym_E', 'sym_mu', 'sym_ext_mu')
+
+  ### Adding a symlink to an external dir failed with
+  ###   svn: E200009: Could not add all targets because some targets are
+  ###   already versioned
+  sbox.simple_add('sym_ext_E')
+
+  sbox.simple_commit()
+    
+
 ########################################################################
 # Run the tests
 
@@ -933,6 +964,7 @@ test_list = [ None,
               symlink_to_wc_basic,
               symlink_to_wc_svnversion,
               update_symlink,
+              externals_as_symlink_targets,
              ]
 
 if __name__ == '__main__':