23
23
#include "../write-or-die.h"
24
24
#include "../repository.h"
25
25
#include "win32/fscache.h"
26
+ #include "../attr.h"
26
27
27
28
#define HCAST (type , handle ) ((type)(intptr_t)handle)
28
29
@@ -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
{
@@ -2915,7 +2964,38 @@ int link(const char *oldpath, const char *newpath)
2915
2964
return 0 ;
2916
2965
}
2917
2966
2918
- int symlink (const char * target , const char * link )
2967
+ enum symlink_type {
2968
+ SYMLINK_TYPE_UNSPECIFIED = 0 ,
2969
+ SYMLINK_TYPE_FILE ,
2970
+ SYMLINK_TYPE_DIRECTORY ,
2971
+ };
2972
+
2973
+ static enum symlink_type check_symlink_attr (struct index_state * index , const char * link )
2974
+ {
2975
+ static struct attr_check * check ;
2976
+ const char * value ;
2977
+
2978
+ if (!index )
2979
+ return SYMLINK_TYPE_UNSPECIFIED ;
2980
+
2981
+ if (!check )
2982
+ check = attr_check_initl ("symlink" , NULL );
2983
+
2984
+ git_check_attr (index , link , check );
2985
+
2986
+ value = check -> items [0 ].value ;
2987
+ if (ATTR_UNSET (value ))
2988
+ return SYMLINK_TYPE_UNSPECIFIED ;
2989
+ if (!strcmp (value , "file" ))
2990
+ return SYMLINK_TYPE_FILE ;
2991
+ if (!strcmp (value , "dir" ) || !strcmp (value , "directory" ))
2992
+ return SYMLINK_TYPE_DIRECTORY ;
2993
+
2994
+ warning (_ ("ignoring invalid symlink type '%s' for '%s'" ), value , link );
2995
+ return SYMLINK_TYPE_UNSPECIFIED ;
2996
+ }
2997
+
2998
+ int mingw_create_symlink (struct index_state * index , const char * target , const char * link )
2919
2999
{
2920
3000
wchar_t wtarget [MAX_LONG_PATH ], wlink [MAX_LONG_PATH ];
2921
3001
int len ;
@@ -2935,48 +3015,31 @@ int symlink(const char *target, const char *link)
2935
3015
if (wtarget [len ] == '/' )
2936
3016
wtarget [len ] = '\\' ;
2937
3017
2938
- /* create file symlink */
2939
- if (!CreateSymbolicLinkW (wlink , wtarget , symlink_file_flags )) {
2940
- errno = err_win_to_posix (GetLastError ());
2941
- return -1 ;
2942
- }
2943
-
2944
- /* convert to directory symlink if target exists */
2945
- switch (process_phantom_symlink (wtarget , wlink )) {
2946
- case PHANTOM_SYMLINK_RETRY : {
2947
- /* if target doesn't exist, add to phantom symlinks list */
2948
- wchar_t wfullpath [MAX_LONG_PATH ];
2949
- struct phantom_symlink_info * psi ;
2950
-
2951
- /* convert to absolute path to be independent of cwd */
2952
- len = GetFullPathNameW (wlink , MAX_LONG_PATH , wfullpath , NULL );
2953
- if (!len || len >= MAX_LONG_PATH ) {
2954
- errno = err_win_to_posix (GetLastError ());
2955
- return -1 ;
2956
- }
2957
-
2958
- /* over-allocate and fill phantom_symlink_info structure */
2959
- psi = xmalloc (sizeof (struct phantom_symlink_info )
2960
- + sizeof (wchar_t ) * (len + wcslen (wtarget ) + 2 ));
2961
- psi -> wlink = (wchar_t * )(psi + 1 );
2962
- wcscpy (psi -> wlink , wfullpath );
2963
- psi -> wtarget = psi -> wlink + len + 1 ;
2964
- wcscpy (psi -> wtarget , wtarget );
2965
-
2966
- EnterCriticalSection (& phantom_symlinks_cs );
2967
- psi -> next = phantom_symlinks ;
2968
- phantom_symlinks = psi ;
2969
- LeaveCriticalSection (& phantom_symlinks_cs );
2970
- break ;
2971
- }
2972
- case PHANTOM_SYMLINK_DIRECTORY :
2973
- /* if we created a dir symlink, process other phantom symlinks */
3018
+ switch (check_symlink_attr (index , link )) {
3019
+ case SYMLINK_TYPE_UNSPECIFIED :
3020
+ /* Create a phantom symlink: it is initially created as a file
3021
+ * symlink, but may change to a directory symlink later if/when
3022
+ * the target exists. */
3023
+ return create_phantom_symlink (wtarget , wlink );
3024
+ case SYMLINK_TYPE_FILE :
3025
+ if (!CreateSymbolicLinkW (wlink , wtarget , symlink_file_flags ))
3026
+ break ;
3027
+ return 0 ;
3028
+ case SYMLINK_TYPE_DIRECTORY :
3029
+ if (!CreateSymbolicLinkW (wlink , wtarget ,
3030
+ symlink_directory_flags ))
3031
+ break ;
3032
+ /* There may be dangling phantom symlinks that point at this
3033
+ * one, which should now morph into directory symlinks. */
2974
3034
process_phantom_symlinks ();
2975
- break ;
3035
+ return 0 ;
2976
3036
default :
2977
- break ;
3037
+ BUG ( "unhandled symlink type" ) ;
2978
3038
}
2979
- return 0 ;
3039
+
3040
+ /* CreateSymbolicLinkW failed. */
3041
+ errno = err_win_to_posix (GetLastError ());
3042
+ return -1 ;
2980
3043
}
2981
3044
2982
3045
#ifndef _WINNT_H
0 commit comments