25
25
#include "../write-or-die.h"
26
26
#include "../repository.h"
27
27
#include "win32/fscache.h"
28
+ #include "../attr.h"
28
29
29
30
#define HCAST (type , handle ) ((type)(intptr_t)handle)
30
31
@@ -461,6 +462,54 @@ static void process_phantom_symlinks(void)
461
462
LeaveCriticalSection (& phantom_symlinks_cs );
462
463
}
463
464
465
+ static int create_phantom_symlink (wchar_t * wtarget , wchar_t * wlink )
466
+ {
467
+ int len ;
468
+
469
+ /* create file symlink */
470
+ if (!CreateSymbolicLinkW (wlink , wtarget , symlink_file_flags )) {
471
+ errno = err_win_to_posix (GetLastError ());
472
+ return -1 ;
473
+ }
474
+
475
+ /* convert to directory symlink if target exists */
476
+ switch (process_phantom_symlink (wtarget , wlink )) {
477
+ case PHANTOM_SYMLINK_RETRY : {
478
+ /* if target doesn't exist, add to phantom symlinks list */
479
+ wchar_t wfullpath [MAX_LONG_PATH ];
480
+ struct phantom_symlink_info * psi ;
481
+
482
+ /* convert to absolute path to be independent of cwd */
483
+ len = GetFullPathNameW (wlink , MAX_LONG_PATH , wfullpath , NULL );
484
+ if (!len || len >= MAX_LONG_PATH ) {
485
+ errno = err_win_to_posix (GetLastError ());
486
+ return -1 ;
487
+ }
488
+
489
+ /* over-allocate and fill phantom_symlink_info structure */
490
+ psi = xmalloc (sizeof (struct phantom_symlink_info ) +
491
+ sizeof (wchar_t ) * (len + wcslen (wtarget ) + 2 ));
492
+ psi -> wlink = (wchar_t * )(psi + 1 );
493
+ wcscpy (psi -> wlink , wfullpath );
494
+ psi -> wtarget = psi -> wlink + len + 1 ;
495
+ wcscpy (psi -> wtarget , wtarget );
496
+
497
+ EnterCriticalSection (& phantom_symlinks_cs );
498
+ psi -> next = phantom_symlinks ;
499
+ phantom_symlinks = psi ;
500
+ LeaveCriticalSection (& phantom_symlinks_cs );
501
+ break ;
502
+ }
503
+ case PHANTOM_SYMLINK_DIRECTORY :
504
+ /* if we created a dir symlink, process other phantom symlinks */
505
+ process_phantom_symlinks ();
506
+ break ;
507
+ default :
508
+ break ;
509
+ }
510
+ return 0 ;
511
+ }
512
+
464
513
/* Normalizes NT paths as returned by some low-level APIs. */
465
514
static wchar_t * normalize_ntpath (wchar_t * wbuf )
466
515
{
@@ -3153,7 +3202,38 @@ int link(const char *oldpath, const char *newpath)
3153
3202
return 0 ;
3154
3203
}
3155
3204
3156
- int symlink (const char * target , const char * link )
3205
+ enum symlink_type {
3206
+ SYMLINK_TYPE_UNSPECIFIED = 0 ,
3207
+ SYMLINK_TYPE_FILE ,
3208
+ SYMLINK_TYPE_DIRECTORY ,
3209
+ };
3210
+
3211
+ static enum symlink_type check_symlink_attr (struct index_state * index , const char * link )
3212
+ {
3213
+ static struct attr_check * check ;
3214
+ const char * value ;
3215
+
3216
+ if (!index )
3217
+ return SYMLINK_TYPE_UNSPECIFIED ;
3218
+
3219
+ if (!check )
3220
+ check = attr_check_initl ("symlink" , NULL );
3221
+
3222
+ git_check_attr (index , link , check );
3223
+
3224
+ value = check -> items [0 ].value ;
3225
+ if (ATTR_UNSET (value ))
3226
+ return SYMLINK_TYPE_UNSPECIFIED ;
3227
+ if (!strcmp (value , "file" ))
3228
+ return SYMLINK_TYPE_FILE ;
3229
+ if (!strcmp (value , "dir" ) || !strcmp (value , "directory" ))
3230
+ return SYMLINK_TYPE_DIRECTORY ;
3231
+
3232
+ warning (_ ("ignoring invalid symlink type '%s' for '%s'" ), value , link );
3233
+ return SYMLINK_TYPE_UNSPECIFIED ;
3234
+ }
3235
+
3236
+ int mingw_create_symlink (struct index_state * index , const char * target , const char * link )
3157
3237
{
3158
3238
wchar_t wtarget [MAX_LONG_PATH ], wlink [MAX_LONG_PATH ];
3159
3239
int len ;
@@ -3173,48 +3253,31 @@ int symlink(const char *target, const char *link)
3173
3253
if (wtarget [len ] == '/' )
3174
3254
wtarget [len ] = '\\' ;
3175
3255
3176
- /* create file symlink */
3177
- if (!CreateSymbolicLinkW (wlink , wtarget , symlink_file_flags )) {
3178
- errno = err_win_to_posix (GetLastError ());
3179
- return -1 ;
3180
- }
3181
-
3182
- /* convert to directory symlink if target exists */
3183
- switch (process_phantom_symlink (wtarget , wlink )) {
3184
- case PHANTOM_SYMLINK_RETRY : {
3185
- /* if target doesn't exist, add to phantom symlinks list */
3186
- wchar_t wfullpath [MAX_LONG_PATH ];
3187
- struct phantom_symlink_info * psi ;
3188
-
3189
- /* convert to absolute path to be independent of cwd */
3190
- len = GetFullPathNameW (wlink , MAX_LONG_PATH , wfullpath , NULL );
3191
- if (!len || len >= MAX_LONG_PATH ) {
3192
- errno = err_win_to_posix (GetLastError ());
3193
- return -1 ;
3194
- }
3195
-
3196
- /* over-allocate and fill phantom_symlink_info structure */
3197
- psi = xmalloc (sizeof (struct phantom_symlink_info )
3198
- + sizeof (wchar_t ) * (len + wcslen (wtarget ) + 2 ));
3199
- psi -> wlink = (wchar_t * )(psi + 1 );
3200
- wcscpy (psi -> wlink , wfullpath );
3201
- psi -> wtarget = psi -> wlink + len + 1 ;
3202
- wcscpy (psi -> wtarget , wtarget );
3203
-
3204
- EnterCriticalSection (& phantom_symlinks_cs );
3205
- psi -> next = phantom_symlinks ;
3206
- phantom_symlinks = psi ;
3207
- LeaveCriticalSection (& phantom_symlinks_cs );
3208
- break ;
3209
- }
3210
- case PHANTOM_SYMLINK_DIRECTORY :
3211
- /* if we created a dir symlink, process other phantom symlinks */
3256
+ switch (check_symlink_attr (index , link )) {
3257
+ case SYMLINK_TYPE_UNSPECIFIED :
3258
+ /* Create a phantom symlink: it is initially created as a file
3259
+ * symlink, but may change to a directory symlink later if/when
3260
+ * the target exists. */
3261
+ return create_phantom_symlink (wtarget , wlink );
3262
+ case SYMLINK_TYPE_FILE :
3263
+ if (!CreateSymbolicLinkW (wlink , wtarget , symlink_file_flags ))
3264
+ break ;
3265
+ return 0 ;
3266
+ case SYMLINK_TYPE_DIRECTORY :
3267
+ if (!CreateSymbolicLinkW (wlink , wtarget ,
3268
+ symlink_directory_flags ))
3269
+ break ;
3270
+ /* There may be dangling phantom symlinks that point at this
3271
+ * one, which should now morph into directory symlinks. */
3212
3272
process_phantom_symlinks ();
3213
- break ;
3273
+ return 0 ;
3214
3274
default :
3215
- break ;
3275
+ BUG ( "unhandled symlink type" ) ;
3216
3276
}
3217
- return 0 ;
3277
+
3278
+ /* CreateSymbolicLinkW failed. */
3279
+ errno = err_win_to_posix (GetLastError ());
3280
+ return -1 ;
3218
3281
}
3219
3282
3220
3283
#ifndef _WINNT_H
0 commit comments