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
{
@@ -3064,7 +3113,38 @@ int link(const char *oldpath, const char *newpath)
3064
3113
return 0 ;
3065
3114
}
3066
3115
3067
- int symlink (const char * target , const char * link )
3116
+ enum symlink_type {
3117
+ SYMLINK_TYPE_UNSPECIFIED = 0 ,
3118
+ SYMLINK_TYPE_FILE ,
3119
+ SYMLINK_TYPE_DIRECTORY ,
3120
+ };
3121
+
3122
+ static enum symlink_type check_symlink_attr (struct index_state * index , const char * link )
3123
+ {
3124
+ static struct attr_check * check ;
3125
+ const char * value ;
3126
+
3127
+ if (!index )
3128
+ return SYMLINK_TYPE_UNSPECIFIED ;
3129
+
3130
+ if (!check )
3131
+ check = attr_check_initl ("symlink" , NULL );
3132
+
3133
+ git_check_attr (index , link , check );
3134
+
3135
+ value = check -> items [0 ].value ;
3136
+ if (ATTR_UNSET (value ))
3137
+ return SYMLINK_TYPE_UNSPECIFIED ;
3138
+ if (!strcmp (value , "file" ))
3139
+ return SYMLINK_TYPE_FILE ;
3140
+ if (!strcmp (value , "dir" ) || !strcmp (value , "directory" ))
3141
+ return SYMLINK_TYPE_DIRECTORY ;
3142
+
3143
+ warning (_ ("ignoring invalid symlink type '%s' for '%s'" ), value , link );
3144
+ return SYMLINK_TYPE_UNSPECIFIED ;
3145
+ }
3146
+
3147
+ int mingw_create_symlink (struct index_state * index , const char * target , const char * link )
3068
3148
{
3069
3149
wchar_t wtarget [MAX_LONG_PATH ], wlink [MAX_LONG_PATH ];
3070
3150
int len ;
@@ -3084,48 +3164,31 @@ int symlink(const char *target, const char *link)
3084
3164
if (wtarget [len ] == '/' )
3085
3165
wtarget [len ] = '\\' ;
3086
3166
3087
- /* create file symlink */
3088
- if (!CreateSymbolicLinkW (wlink , wtarget , symlink_file_flags )) {
3089
- errno = err_win_to_posix (GetLastError ());
3090
- return -1 ;
3091
- }
3092
-
3093
- /* convert to directory symlink if target exists */
3094
- switch (process_phantom_symlink (wtarget , wlink )) {
3095
- case PHANTOM_SYMLINK_RETRY : {
3096
- /* if target doesn't exist, add to phantom symlinks list */
3097
- wchar_t wfullpath [MAX_LONG_PATH ];
3098
- struct phantom_symlink_info * psi ;
3099
-
3100
- /* convert to absolute path to be independent of cwd */
3101
- len = GetFullPathNameW (wlink , MAX_LONG_PATH , wfullpath , NULL );
3102
- if (!len || len >= MAX_LONG_PATH ) {
3103
- errno = err_win_to_posix (GetLastError ());
3104
- return -1 ;
3105
- }
3106
-
3107
- /* over-allocate and fill phantom_symlink_info structure */
3108
- psi = xmalloc (sizeof (struct phantom_symlink_info )
3109
- + sizeof (wchar_t ) * (len + wcslen (wtarget ) + 2 ));
3110
- psi -> wlink = (wchar_t * )(psi + 1 );
3111
- wcscpy (psi -> wlink , wfullpath );
3112
- psi -> wtarget = psi -> wlink + len + 1 ;
3113
- wcscpy (psi -> wtarget , wtarget );
3114
-
3115
- EnterCriticalSection (& phantom_symlinks_cs );
3116
- psi -> next = phantom_symlinks ;
3117
- phantom_symlinks = psi ;
3118
- LeaveCriticalSection (& phantom_symlinks_cs );
3119
- break ;
3120
- }
3121
- case PHANTOM_SYMLINK_DIRECTORY :
3122
- /* if we created a dir symlink, process other phantom symlinks */
3167
+ switch (check_symlink_attr (index , link )) {
3168
+ case SYMLINK_TYPE_UNSPECIFIED :
3169
+ /* Create a phantom symlink: it is initially created as a file
3170
+ * symlink, but may change to a directory symlink later if/when
3171
+ * the target exists. */
3172
+ return create_phantom_symlink (wtarget , wlink );
3173
+ case SYMLINK_TYPE_FILE :
3174
+ if (!CreateSymbolicLinkW (wlink , wtarget , symlink_file_flags ))
3175
+ break ;
3176
+ return 0 ;
3177
+ case SYMLINK_TYPE_DIRECTORY :
3178
+ if (!CreateSymbolicLinkW (wlink , wtarget ,
3179
+ symlink_directory_flags ))
3180
+ break ;
3181
+ /* There may be dangling phantom symlinks that point at this
3182
+ * one, which should now morph into directory symlinks. */
3123
3183
process_phantom_symlinks ();
3124
- break ;
3184
+ return 0 ;
3125
3185
default :
3126
- break ;
3186
+ BUG ( "unhandled symlink type" ) ;
3127
3187
}
3128
- return 0 ;
3188
+
3189
+ /* CreateSymbolicLinkW failed. */
3190
+ errno = err_win_to_posix (GetLastError ());
3191
+ return -1 ;
3129
3192
}
3130
3193
3131
3194
#ifndef _WINNT_H
0 commit comments