@@ -1069,6 +1069,67 @@ static struct cache_entry *create_ce_entry(const struct traverse_info *info,
1069
1069
return ce ;
1070
1070
}
1071
1071
1072
+ /*
1073
+ * Determine whether the path specified by 'p' should be unpacked as a new
1074
+ * sparse directory in a sparse index. A new sparse directory 'A/':
1075
+ * - must be outside the sparse cone.
1076
+ * - must not already be in the index (i.e., no index entry with name 'A/'
1077
+ * exists).
1078
+ * - must not have any child entries in the index (i.e., no index entry
1079
+ * 'A/<something>' exists).
1080
+ * If 'p' meets the above requirements, return 1; otherwise, return 0.
1081
+ */
1082
+ static int entry_is_new_sparse_dir (const struct traverse_info * info ,
1083
+ const struct name_entry * p )
1084
+ {
1085
+ int res , pos ;
1086
+ struct strbuf dirpath = STRBUF_INIT ;
1087
+ struct unpack_trees_options * o = info -> data ;
1088
+
1089
+ if (!S_ISDIR (p -> mode ))
1090
+ return 0 ;
1091
+
1092
+ /*
1093
+ * If the path is inside the sparse cone, it can't be a sparse directory.
1094
+ */
1095
+ strbuf_add (& dirpath , info -> traverse_path , info -> pathlen );
1096
+ strbuf_add (& dirpath , p -> path , p -> pathlen );
1097
+ strbuf_addch (& dirpath , '/' );
1098
+ if (path_in_cone_mode_sparse_checkout (dirpath .buf , o -> src_index )) {
1099
+ res = 0 ;
1100
+ goto cleanup ;
1101
+ }
1102
+
1103
+ pos = index_name_pos_sparse (o -> src_index , dirpath .buf , dirpath .len );
1104
+ if (pos >= 0 ) {
1105
+ /* Path is already in the index, not a new sparse dir */
1106
+ res = 0 ;
1107
+ goto cleanup ;
1108
+ }
1109
+
1110
+ /* Where would this sparse dir be inserted into the index? */
1111
+ pos = - pos - 1 ;
1112
+ if (pos >= o -> src_index -> cache_nr ) {
1113
+ /*
1114
+ * Sparse dir would be inserted at the end of the index, so we
1115
+ * know it has no child entries.
1116
+ */
1117
+ res = 1 ;
1118
+ goto cleanup ;
1119
+ }
1120
+
1121
+ /*
1122
+ * If the dir has child entries in the index, the first would be at the
1123
+ * position the sparse directory would be inserted. If the entry at this
1124
+ * position is inside the dir, not a new sparse dir.
1125
+ */
1126
+ res = strncmp (o -> src_index -> cache [pos ]-> name , dirpath .buf , dirpath .len );
1127
+
1128
+ cleanup :
1129
+ strbuf_release (& dirpath );
1130
+ return res ;
1131
+ }
1132
+
1072
1133
/*
1073
1134
* Note that traverse_by_cache_tree() duplicates some logic in this function
1074
1135
* without actually calling it. If you change the logic here you may need to
@@ -1078,21 +1139,44 @@ static int unpack_single_entry(int n, unsigned long mask,
1078
1139
unsigned long dirmask ,
1079
1140
struct cache_entry * * src ,
1080
1141
const struct name_entry * names ,
1081
- const struct traverse_info * info )
1142
+ const struct traverse_info * info ,
1143
+ int * is_new_sparse_dir )
1082
1144
{
1083
1145
int i ;
1084
1146
struct unpack_trees_options * o = info -> data ;
1085
1147
unsigned long conflicts = info -> df_conflicts | dirmask ;
1148
+ const struct name_entry * p = names ;
1086
1149
1087
- if (mask == dirmask && !src [0 ])
1088
- return 0 ;
1150
+ * is_new_sparse_dir = 0 ;
1151
+ if (mask == dirmask && !src [0 ]) {
1152
+ /*
1153
+ * If we're not in a sparse index, we can't unpack a directory
1154
+ * without recursing into it, so we return.
1155
+ */
1156
+ if (!o -> src_index -> sparse_index )
1157
+ return 0 ;
1158
+
1159
+ /* Find first entry with a real name (we could use "mask" too) */
1160
+ while (!p -> mode )
1161
+ p ++ ;
1162
+
1163
+ /*
1164
+ * If the directory is completely missing from the index but
1165
+ * would otherwise be a sparse directory, we should unpack it.
1166
+ * If not, we'll return and continue recursively traversing the
1167
+ * tree.
1168
+ */
1169
+ * is_new_sparse_dir = entry_is_new_sparse_dir (info , p );
1170
+ if (!* is_new_sparse_dir )
1171
+ return 0 ;
1172
+ }
1089
1173
1090
1174
/*
1091
- * When we have a sparse directory entry for src[0],
1092
- * then this isn't necessarily a directory-file conflict.
1175
+ * When we are unpacking a sparse directory, then this isn't necessarily
1176
+ * a directory-file conflict.
1093
1177
*/
1094
- if (mask == dirmask && src [ 0 ] &&
1095
- S_ISSPARSEDIR (src [0 ]-> ce_mode ))
1178
+ if (mask == dirmask &&
1179
+ ( * is_new_sparse_dir || ( src [ 0 ] && S_ISSPARSEDIR (src [0 ]-> ce_mode )) ))
1096
1180
conflicts = 0 ;
1097
1181
1098
1182
/*
@@ -1352,7 +1436,7 @@ static int unpack_sparse_callback(int n, unsigned long mask, unsigned long dirma
1352
1436
{
1353
1437
struct cache_entry * src [MAX_UNPACK_TREES + 1 ] = { NULL , };
1354
1438
struct unpack_trees_options * o = info -> data ;
1355
- int ret ;
1439
+ int ret , is_new_sparse_dir ;
1356
1440
1357
1441
assert (o -> merge );
1358
1442
@@ -1376,7 +1460,7 @@ static int unpack_sparse_callback(int n, unsigned long mask, unsigned long dirma
1376
1460
* "index" tree (i.e., names[0]) and adjust 'names', 'n', 'mask', and
1377
1461
* 'dirmask' accordingly.
1378
1462
*/
1379
- ret = unpack_single_entry (n - 1 , mask >> 1 , dirmask >> 1 , src , names + 1 , info );
1463
+ ret = unpack_single_entry (n - 1 , mask >> 1 , dirmask >> 1 , src , names + 1 , info , & is_new_sparse_dir );
1380
1464
1381
1465
if (src [0 ])
1382
1466
discard_cache_entry (src [0 ]);
@@ -1394,6 +1478,7 @@ static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, str
1394
1478
struct cache_entry * src [MAX_UNPACK_TREES + 1 ] = { NULL , };
1395
1479
struct unpack_trees_options * o = info -> data ;
1396
1480
const struct name_entry * p = names ;
1481
+ int is_new_sparse_dir ;
1397
1482
1398
1483
/* Find first entry with a real name (we could use "mask" too) */
1399
1484
while (!p -> mode )
@@ -1440,7 +1525,7 @@ static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, str
1440
1525
}
1441
1526
}
1442
1527
1443
- if (unpack_single_entry (n , mask , dirmask , src , names , info ) < 0 )
1528
+ if (unpack_single_entry (n , mask , dirmask , src , names , info , & is_new_sparse_dir ) )
1444
1529
return -1 ;
1445
1530
1446
1531
if (o -> merge && src [0 ]) {
@@ -1478,6 +1563,7 @@ static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, str
1478
1563
}
1479
1564
1480
1565
if (!is_sparse_directory_entry (src [0 ], names , info ) &&
1566
+ !is_new_sparse_dir &&
1481
1567
traverse_trees_recursive (n , dirmask , mask & ~dirmask ,
1482
1568
names , info ) < 0 ) {
1483
1569
return -1 ;
0 commit comments