@@ -136,6 +136,126 @@ static int streaming_write_entry(const struct cache_entry *ce, char *path,
136
136
return result ;
137
137
}
138
138
139
+ /*
140
+ * Does 'match' match the given name?
141
+ * A match is found if
142
+ *
143
+ * (1) the 'match' string is leading directory of 'name', or
144
+ * (2) the 'match' string is exactly the same as 'name'.
145
+ *
146
+ * and the return value tells which case it was.
147
+ *
148
+ * It returns 0 when there is no match.
149
+ *
150
+ * Preserved and simplified from dir.c for use here (without glob special matching)
151
+ */
152
+ static int match_one (const char * match , const char * name , int namelen )
153
+ {
154
+ int matchlen ;
155
+
156
+ /* If the match was just the prefix, we matched */
157
+ if (!* match )
158
+ return MATCHED_RECURSIVELY ;
159
+
160
+ if (ignore_case ) {
161
+ for (;;) {
162
+ unsigned char c1 = tolower (* match );
163
+ unsigned char c2 = tolower (* name );
164
+ if (c1 == '\0' )
165
+ break ;
166
+ if (c1 != c2 )
167
+ return 0 ;
168
+ match ++ ;
169
+ name ++ ;
170
+ namelen -- ;
171
+ }
172
+ /* We don't match the matchstring exactly, */
173
+ matchlen = strlen (match );
174
+ if (strncmp_icase (match , name , matchlen ))
175
+ return 0 ;
176
+ } else {
177
+ for (;;) {
178
+ unsigned char c1 = * match ;
179
+ unsigned char c2 = * name ;
180
+ if (c1 == '\0' )
181
+ break ;
182
+ if (c1 != c2 )
183
+ return 0 ;
184
+ match ++ ;
185
+ name ++ ;
186
+ namelen -- ;
187
+ }
188
+ /* We don't match the matchstring exactly, */
189
+ matchlen = strlen (match );
190
+ if (strncmp (match , name , matchlen ))
191
+ return 0 ;
192
+ }
193
+
194
+ if (namelen == matchlen )
195
+ return MATCHED_EXACTLY ;
196
+ if (match [matchlen - 1 ] == '/' || name [matchlen ] == '/' )
197
+ return MATCHED_RECURSIVELY ;
198
+ return 0 ;
199
+ }
200
+
201
+ static enum git_target_type get_symlink_type (const char * filepath , const char * symlinkpath )
202
+ {
203
+ /* For certain O/S and file-systems, symlinks need to know before-hand whether it
204
+ * is a directory or a file being pointed to.
205
+ *
206
+ * This allows us to use index information for relative paths that lie
207
+ * within the working directory.
208
+ *
209
+ * This function is not interested in interrogating the file-system.
210
+ */
211
+ char * sanitized ;
212
+ const char * fpos , * last ;
213
+ enum git_target_type ret ;
214
+ int len , pos ;
215
+
216
+ /* This is an absolute path, so git doesn't know.
217
+ */
218
+ if (is_absolute_path (symlinkpath ))
219
+ return GIT_TARGET_UNKNOWN ;
220
+
221
+ /* Work on a sanitized version of the path that can be
222
+ * matched against the index.
223
+ */
224
+ last = NULL ;
225
+ for (fpos = filepath ; * fpos ; ++ fpos )
226
+ if (is_dir_sep (* fpos ))
227
+ last = fpos ;
228
+
229
+ if (last ) {
230
+ len = (1 + last - filepath );
231
+ sanitized = xmalloc (len + strlen (symlinkpath )+ 1 );
232
+ memcpy (sanitized , filepath , 1 + last - filepath );
233
+ } else {
234
+ len = 0 ;
235
+ sanitized = xmalloc (strlen (symlinkpath )+ 1 );
236
+ }
237
+ strcpy (sanitized + len , symlinkpath );
238
+
239
+ ret = GIT_TARGET_UNKNOWN ;
240
+ if (!normalize_path_copy (sanitized , sanitized )) {
241
+ for (pos = 0 ; pos < active_nr ; pos ++ ) {
242
+ struct cache_entry * ce = active_cache [pos ];
243
+ switch (match_one (sanitized , ce -> name , ce_namelen (ce ))) {
244
+ case MATCHED_EXACTLY :
245
+ case MATCHED_FNMATCH :
246
+ ret = GIT_TARGET_ISFILE ;
247
+ break ;
248
+ case MATCHED_RECURSIVELY :
249
+ ret = GIT_TARGET_ISDIR ;
250
+ break ;
251
+ }
252
+ }
253
+ }
254
+
255
+ free (sanitized );
256
+ return ret ;
257
+ }
258
+
139
259
static int write_entry (struct cache_entry * ce ,
140
260
char * path , const struct checkout * state , int to_tempfile )
141
261
{
@@ -165,7 +285,10 @@ static int write_entry(struct cache_entry *ce,
165
285
path , sha1_to_hex (ce -> sha1 ));
166
286
167
287
if (ce_mode_s_ifmt == S_IFLNK && has_symlinks && !to_tempfile ) {
168
- ret = symlink (new , path );
288
+ /* Note that symlink_with_type is a macro, and that for filesystems that
289
+ * don't care, get_symlink_type will not be called.
290
+ */
291
+ ret = symlink_with_type (new , path , get_symlink_type (path , new ));
169
292
free (new );
170
293
if (ret )
171
294
return error ("unable to create symlink %s (%s)" ,
0 commit comments