22
22
#include "../write-or-die.h"
23
23
#include "../repository.h"
24
24
#include "win32/fscache.h"
25
+ #include "../attr.h"
25
26
26
27
#define HCAST (type , handle ) ((type)(intptr_t)handle)
27
28
@@ -458,6 +459,54 @@ static void process_phantom_symlinks(void)
458
459
LeaveCriticalSection (& phantom_symlinks_cs );
459
460
}
460
461
462
+ static int create_phantom_symlink (wchar_t * wtarget , wchar_t * wlink )
463
+ {
464
+ int len ;
465
+
466
+ /* create file symlink */
467
+ if (!CreateSymbolicLinkW (wlink , wtarget , symlink_file_flags )) {
468
+ errno = err_win_to_posix (GetLastError ());
469
+ return -1 ;
470
+ }
471
+
472
+ /* convert to directory symlink if target exists */
473
+ switch (process_phantom_symlink (wtarget , wlink )) {
474
+ case PHANTOM_SYMLINK_RETRY : {
475
+ /* if target doesn't exist, add to phantom symlinks list */
476
+ wchar_t wfullpath [MAX_LONG_PATH ];
477
+ struct phantom_symlink_info * psi ;
478
+
479
+ /* convert to absolute path to be independent of cwd */
480
+ len = GetFullPathNameW (wlink , MAX_LONG_PATH , wfullpath , NULL );
481
+ if (!len || len >= MAX_LONG_PATH ) {
482
+ errno = err_win_to_posix (GetLastError ());
483
+ return -1 ;
484
+ }
485
+
486
+ /* over-allocate and fill phantom_symlink_info structure */
487
+ psi = xmalloc (sizeof (struct phantom_symlink_info ) +
488
+ sizeof (wchar_t ) * (len + wcslen (wtarget ) + 2 ));
489
+ psi -> wlink = (wchar_t * )(psi + 1 );
490
+ wcscpy (psi -> wlink , wfullpath );
491
+ psi -> wtarget = psi -> wlink + len + 1 ;
492
+ wcscpy (psi -> wtarget , wtarget );
493
+
494
+ EnterCriticalSection (& phantom_symlinks_cs );
495
+ psi -> next = phantom_symlinks ;
496
+ phantom_symlinks = psi ;
497
+ LeaveCriticalSection (& phantom_symlinks_cs );
498
+ break ;
499
+ }
500
+ case PHANTOM_SYMLINK_DIRECTORY :
501
+ /* if we created a dir symlink, process other phantom symlinks */
502
+ process_phantom_symlinks ();
503
+ break ;
504
+ default :
505
+ break ;
506
+ }
507
+ return 0 ;
508
+ }
509
+
461
510
/* Normalizes NT paths as returned by some low-level APIs. */
462
511
static wchar_t * normalize_ntpath (wchar_t * wbuf )
463
512
{
@@ -2911,7 +2960,38 @@ int link(const char *oldpath, const char *newpath)
2911
2960
return 0 ;
2912
2961
}
2913
2962
2914
- int symlink (const char * target , const char * link )
2963
+ enum symlink_type {
2964
+ SYMLINK_TYPE_UNSPECIFIED = 0 ,
2965
+ SYMLINK_TYPE_FILE ,
2966
+ SYMLINK_TYPE_DIRECTORY ,
2967
+ };
2968
+
2969
+ static enum symlink_type check_symlink_attr (struct index_state * index , const char * link )
2970
+ {
2971
+ static struct attr_check * check ;
2972
+ const char * value ;
2973
+
2974
+ if (!index )
2975
+ return SYMLINK_TYPE_UNSPECIFIED ;
2976
+
2977
+ if (!check )
2978
+ check = attr_check_initl ("symlink" , NULL );
2979
+
2980
+ git_check_attr (index , link , check );
2981
+
2982
+ value = check -> items [0 ].value ;
2983
+ if (ATTR_UNSET (value ))
2984
+ return SYMLINK_TYPE_UNSPECIFIED ;
2985
+ if (!strcmp (value , "file" ))
2986
+ return SYMLINK_TYPE_FILE ;
2987
+ if (!strcmp (value , "dir" ) || !strcmp (value , "directory" ))
2988
+ return SYMLINK_TYPE_DIRECTORY ;
2989
+
2990
+ warning (_ ("ignoring invalid symlink type '%s' for '%s'" ), value , link );
2991
+ return SYMLINK_TYPE_UNSPECIFIED ;
2992
+ }
2993
+
2994
+ int mingw_create_symlink (struct index_state * index , const char * target , const char * link )
2915
2995
{
2916
2996
wchar_t wtarget [MAX_LONG_PATH ], wlink [MAX_LONG_PATH ];
2917
2997
int len ;
@@ -2931,48 +3011,31 @@ int symlink(const char *target, const char *link)
2931
3011
if (wtarget [len ] == '/' )
2932
3012
wtarget [len ] = '\\' ;
2933
3013
2934
- /* create file symlink */
2935
- if (!CreateSymbolicLinkW (wlink , wtarget , symlink_file_flags )) {
2936
- errno = err_win_to_posix (GetLastError ());
2937
- return -1 ;
2938
- }
2939
-
2940
- /* convert to directory symlink if target exists */
2941
- switch (process_phantom_symlink (wtarget , wlink )) {
2942
- case PHANTOM_SYMLINK_RETRY : {
2943
- /* if target doesn't exist, add to phantom symlinks list */
2944
- wchar_t wfullpath [MAX_LONG_PATH ];
2945
- struct phantom_symlink_info * psi ;
2946
-
2947
- /* convert to absolute path to be independent of cwd */
2948
- len = GetFullPathNameW (wlink , MAX_LONG_PATH , wfullpath , NULL );
2949
- if (!len || len >= MAX_LONG_PATH ) {
2950
- errno = err_win_to_posix (GetLastError ());
2951
- return -1 ;
2952
- }
2953
-
2954
- /* over-allocate and fill phantom_symlink_info structure */
2955
- psi = xmalloc (sizeof (struct phantom_symlink_info )
2956
- + sizeof (wchar_t ) * (len + wcslen (wtarget ) + 2 ));
2957
- psi -> wlink = (wchar_t * )(psi + 1 );
2958
- wcscpy (psi -> wlink , wfullpath );
2959
- psi -> wtarget = psi -> wlink + len + 1 ;
2960
- wcscpy (psi -> wtarget , wtarget );
2961
-
2962
- EnterCriticalSection (& phantom_symlinks_cs );
2963
- psi -> next = phantom_symlinks ;
2964
- phantom_symlinks = psi ;
2965
- LeaveCriticalSection (& phantom_symlinks_cs );
2966
- break ;
2967
- }
2968
- case PHANTOM_SYMLINK_DIRECTORY :
2969
- /* if we created a dir symlink, process other phantom symlinks */
3014
+ switch (check_symlink_attr (index , link )) {
3015
+ case SYMLINK_TYPE_UNSPECIFIED :
3016
+ /* Create a phantom symlink: it is initially created as a file
3017
+ * symlink, but may change to a directory symlink later if/when
3018
+ * the target exists. */
3019
+ return create_phantom_symlink (wtarget , wlink );
3020
+ case SYMLINK_TYPE_FILE :
3021
+ if (!CreateSymbolicLinkW (wlink , wtarget , symlink_file_flags ))
3022
+ break ;
3023
+ return 0 ;
3024
+ case SYMLINK_TYPE_DIRECTORY :
3025
+ if (!CreateSymbolicLinkW (wlink , wtarget ,
3026
+ symlink_directory_flags ))
3027
+ break ;
3028
+ /* There may be dangling phantom symlinks that point at this
3029
+ * one, which should now morph into directory symlinks. */
2970
3030
process_phantom_symlinks ();
2971
- break ;
3031
+ return 0 ;
2972
3032
default :
2973
- break ;
3033
+ BUG ( "unhandled symlink type" ) ;
2974
3034
}
2975
- return 0 ;
3035
+
3036
+ /* CreateSymbolicLinkW failed. */
3037
+ errno = err_win_to_posix (GetLastError ());
3038
+ return -1 ;
2976
3039
}
2977
3040
2978
3041
#ifndef _WINNT_H
0 commit comments