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
@@ -451,6 +452,54 @@ static void process_phantom_symlinks(void)
451
452
LeaveCriticalSection (& phantom_symlinks_cs );
452
453
}
453
454
455
+ static int create_phantom_symlink (wchar_t * wtarget , wchar_t * wlink )
456
+ {
457
+ int len ;
458
+
459
+ /* create file symlink */
460
+ if (!CreateSymbolicLinkW (wlink , wtarget , symlink_file_flags )) {
461
+ errno = err_win_to_posix (GetLastError ());
462
+ return -1 ;
463
+ }
464
+
465
+ /* convert to directory symlink if target exists */
466
+ switch (process_phantom_symlink (wtarget , wlink )) {
467
+ case PHANTOM_SYMLINK_RETRY : {
468
+ /* if target doesn't exist, add to phantom symlinks list */
469
+ wchar_t wfullpath [MAX_LONG_PATH ];
470
+ struct phantom_symlink_info * psi ;
471
+
472
+ /* convert to absolute path to be independent of cwd */
473
+ len = GetFullPathNameW (wlink , MAX_LONG_PATH , wfullpath , NULL );
474
+ if (!len || len >= MAX_LONG_PATH ) {
475
+ errno = err_win_to_posix (GetLastError ());
476
+ return -1 ;
477
+ }
478
+
479
+ /* over-allocate and fill phantom_symlink_info structure */
480
+ psi = xmalloc (sizeof (struct phantom_symlink_info ) +
481
+ sizeof (wchar_t ) * (len + wcslen (wtarget ) + 2 ));
482
+ psi -> wlink = (wchar_t * )(psi + 1 );
483
+ wcscpy (psi -> wlink , wfullpath );
484
+ psi -> wtarget = psi -> wlink + len + 1 ;
485
+ wcscpy (psi -> wtarget , wtarget );
486
+
487
+ EnterCriticalSection (& phantom_symlinks_cs );
488
+ psi -> next = phantom_symlinks ;
489
+ phantom_symlinks = psi ;
490
+ LeaveCriticalSection (& phantom_symlinks_cs );
491
+ break ;
492
+ }
493
+ case PHANTOM_SYMLINK_DIRECTORY :
494
+ /* if we created a dir symlink, process other phantom symlinks */
495
+ process_phantom_symlinks ();
496
+ break ;
497
+ default :
498
+ break ;
499
+ }
500
+ return 0 ;
501
+ }
502
+
454
503
/* Normalizes NT paths as returned by some low-level APIs. */
455
504
static wchar_t * normalize_ntpath (wchar_t * wbuf )
456
505
{
@@ -3093,7 +3142,38 @@ int link(const char *oldpath, const char *newpath)
3093
3142
return 0 ;
3094
3143
}
3095
3144
3096
- int symlink (const char * target , const char * link )
3145
+ enum symlink_type {
3146
+ SYMLINK_TYPE_UNSPECIFIED = 0 ,
3147
+ SYMLINK_TYPE_FILE ,
3148
+ SYMLINK_TYPE_DIRECTORY ,
3149
+ };
3150
+
3151
+ static enum symlink_type check_symlink_attr (struct index_state * index , const char * link )
3152
+ {
3153
+ static struct attr_check * check ;
3154
+ const char * value ;
3155
+
3156
+ if (!index )
3157
+ return SYMLINK_TYPE_UNSPECIFIED ;
3158
+
3159
+ if (!check )
3160
+ check = attr_check_initl ("symlink" , NULL );
3161
+
3162
+ git_check_attr (index , link , check );
3163
+
3164
+ value = check -> items [0 ].value ;
3165
+ if (ATTR_UNSET (value ))
3166
+ return SYMLINK_TYPE_UNSPECIFIED ;
3167
+ if (!strcmp (value , "file" ))
3168
+ return SYMLINK_TYPE_FILE ;
3169
+ if (!strcmp (value , "dir" ) || !strcmp (value , "directory" ))
3170
+ return SYMLINK_TYPE_DIRECTORY ;
3171
+
3172
+ warning (_ ("ignoring invalid symlink type '%s' for '%s'" ), value , link );
3173
+ return SYMLINK_TYPE_UNSPECIFIED ;
3174
+ }
3175
+
3176
+ int mingw_create_symlink (struct index_state * index , const char * target , const char * link )
3097
3177
{
3098
3178
wchar_t wtarget [MAX_LONG_PATH ], wlink [MAX_LONG_PATH ];
3099
3179
int len ;
@@ -3113,48 +3193,31 @@ int symlink(const char *target, const char *link)
3113
3193
if (wtarget [len ] == '/' )
3114
3194
wtarget [len ] = '\\' ;
3115
3195
3116
- /* create file symlink */
3117
- if (!CreateSymbolicLinkW (wlink , wtarget , symlink_file_flags )) {
3118
- errno = err_win_to_posix (GetLastError ());
3119
- return -1 ;
3120
- }
3121
-
3122
- /* convert to directory symlink if target exists */
3123
- switch (process_phantom_symlink (wtarget , wlink )) {
3124
- case PHANTOM_SYMLINK_RETRY : {
3125
- /* if target doesn't exist, add to phantom symlinks list */
3126
- wchar_t wfullpath [MAX_LONG_PATH ];
3127
- struct phantom_symlink_info * psi ;
3128
-
3129
- /* convert to absolute path to be independent of cwd */
3130
- len = GetFullPathNameW (wlink , MAX_LONG_PATH , wfullpath , NULL );
3131
- if (!len || len >= MAX_LONG_PATH ) {
3132
- errno = err_win_to_posix (GetLastError ());
3133
- return -1 ;
3134
- }
3135
-
3136
- /* over-allocate and fill phantom_symlink_info structure */
3137
- psi = xmalloc (sizeof (struct phantom_symlink_info )
3138
- + sizeof (wchar_t ) * (len + wcslen (wtarget ) + 2 ));
3139
- psi -> wlink = (wchar_t * )(psi + 1 );
3140
- wcscpy (psi -> wlink , wfullpath );
3141
- psi -> wtarget = psi -> wlink + len + 1 ;
3142
- wcscpy (psi -> wtarget , wtarget );
3143
-
3144
- EnterCriticalSection (& phantom_symlinks_cs );
3145
- psi -> next = phantom_symlinks ;
3146
- phantom_symlinks = psi ;
3147
- LeaveCriticalSection (& phantom_symlinks_cs );
3148
- break ;
3149
- }
3150
- case PHANTOM_SYMLINK_DIRECTORY :
3151
- /* if we created a dir symlink, process other phantom symlinks */
3196
+ switch (check_symlink_attr (index , link )) {
3197
+ case SYMLINK_TYPE_UNSPECIFIED :
3198
+ /* Create a phantom symlink: it is initially created as a file
3199
+ * symlink, but may change to a directory symlink later if/when
3200
+ * the target exists. */
3201
+ return create_phantom_symlink (wtarget , wlink );
3202
+ case SYMLINK_TYPE_FILE :
3203
+ if (!CreateSymbolicLinkW (wlink , wtarget , symlink_file_flags ))
3204
+ break ;
3205
+ return 0 ;
3206
+ case SYMLINK_TYPE_DIRECTORY :
3207
+ if (!CreateSymbolicLinkW (wlink , wtarget ,
3208
+ symlink_directory_flags ))
3209
+ break ;
3210
+ /* There may be dangling phantom symlinks that point at this
3211
+ * one, which should now morph into directory symlinks. */
3152
3212
process_phantom_symlinks ();
3153
- break ;
3213
+ return 0 ;
3154
3214
default :
3155
- break ;
3215
+ BUG ( "unhandled symlink type" ) ;
3156
3216
}
3157
- return 0 ;
3217
+
3218
+ /* CreateSymbolicLinkW failed. */
3219
+ errno = err_win_to_posix (GetLastError ());
3220
+ return -1 ;
3158
3221
}
3159
3222
3160
3223
#ifndef _WINNT_H
0 commit comments