44#include "git-compat-util.h"
55#include "abspath.h"
66#include "alloc.h"
7+ #include "attr.h"
78#include "config.h"
89#include "dir.h"
910#include "environment.h"
@@ -424,6 +425,54 @@ static void process_phantom_symlinks(void)
424425 LeaveCriticalSection (& phantom_symlinks_cs );
425426}
426427
428+ static int create_phantom_symlink (wchar_t * wtarget , wchar_t * wlink )
429+ {
430+ int len ;
431+
432+ /* create file symlink */
433+ if (!CreateSymbolicLinkW (wlink , wtarget , symlink_file_flags )) {
434+ errno = err_win_to_posix (GetLastError ());
435+ return -1 ;
436+ }
437+
438+ /* convert to directory symlink if target exists */
439+ switch (process_phantom_symlink (wtarget , wlink )) {
440+ case PHANTOM_SYMLINK_RETRY : {
441+ /* if target doesn't exist, add to phantom symlinks list */
442+ wchar_t wfullpath [MAX_PATH ];
443+ struct phantom_symlink_info * psi ;
444+
445+ /* convert to absolute path to be independent of cwd */
446+ len = GetFullPathNameW (wlink , MAX_PATH , wfullpath , NULL );
447+ if (!len || len >= MAX_PATH ) {
448+ errno = err_win_to_posix (GetLastError ());
449+ return -1 ;
450+ }
451+
452+ /* over-allocate and fill phantom_symlink_info structure */
453+ psi = xmalloc (sizeof (struct phantom_symlink_info ) +
454+ sizeof (wchar_t ) * (len + wcslen (wtarget ) + 2 ));
455+ psi -> wlink = (wchar_t * )(psi + 1 );
456+ wcscpy (psi -> wlink , wfullpath );
457+ psi -> wtarget = psi -> wlink + len + 1 ;
458+ wcscpy (psi -> wtarget , wtarget );
459+
460+ EnterCriticalSection (& phantom_symlinks_cs );
461+ psi -> next = phantom_symlinks ;
462+ phantom_symlinks = psi ;
463+ LeaveCriticalSection (& phantom_symlinks_cs );
464+ break ;
465+ }
466+ case PHANTOM_SYMLINK_DIRECTORY :
467+ /* if we created a dir symlink, process other phantom symlinks */
468+ process_phantom_symlinks ();
469+ break ;
470+ default :
471+ break ;
472+ }
473+ return 0 ;
474+ }
475+
427476/* Normalizes NT paths as returned by some low-level APIs. */
428477static wchar_t * normalize_ntpath (wchar_t * wbuf )
429478{
@@ -2763,7 +2812,38 @@ int link(const char *oldpath, const char *newpath)
27632812 return 0 ;
27642813}
27652814
2766- int symlink (const char * target , const char * link )
2815+ enum symlink_type {
2816+ SYMLINK_TYPE_UNSPECIFIED = 0 ,
2817+ SYMLINK_TYPE_FILE ,
2818+ SYMLINK_TYPE_DIRECTORY ,
2819+ };
2820+
2821+ static enum symlink_type check_symlink_attr (struct index_state * index , const char * link )
2822+ {
2823+ static struct attr_check * check ;
2824+ const char * value ;
2825+
2826+ if (!index )
2827+ return SYMLINK_TYPE_UNSPECIFIED ;
2828+
2829+ if (!check )
2830+ check = attr_check_initl ("symlink" , NULL );
2831+
2832+ git_check_attr (index , link , check );
2833+
2834+ value = check -> items [0 ].value ;
2835+ if (ATTR_UNSET (value ))
2836+ return SYMLINK_TYPE_UNSPECIFIED ;
2837+ if (!strcmp (value , "file" ))
2838+ return SYMLINK_TYPE_FILE ;
2839+ if (!strcmp (value , "dir" ) || !strcmp (value , "directory" ))
2840+ return SYMLINK_TYPE_DIRECTORY ;
2841+
2842+ warning (_ ("ignoring invalid symlink type '%s' for '%s'" ), value , link );
2843+ return SYMLINK_TYPE_UNSPECIFIED ;
2844+ }
2845+
2846+ int mingw_create_symlink (struct index_state * index , const char * target , const char * link )
27672847{
27682848 wchar_t wtarget [MAX_PATH ], wlink [MAX_PATH ];
27692849 int len ;
@@ -2783,48 +2863,31 @@ int symlink(const char *target, const char *link)
27832863 if (wtarget [len ] == '/' )
27842864 wtarget [len ] = '\\' ;
27852865
2786- /* create file symlink */
2787- if (!CreateSymbolicLinkW (wlink , wtarget , symlink_file_flags )) {
2788- errno = err_win_to_posix (GetLastError ());
2789- return -1 ;
2790- }
2791-
2792- /* convert to directory symlink if target exists */
2793- switch (process_phantom_symlink (wtarget , wlink )) {
2794- case PHANTOM_SYMLINK_RETRY : {
2795- /* if target doesn't exist, add to phantom symlinks list */
2796- wchar_t wfullpath [MAX_PATH ];
2797- struct phantom_symlink_info * psi ;
2798-
2799- /* convert to absolute path to be independent of cwd */
2800- len = GetFullPathNameW (wlink , MAX_PATH , wfullpath , NULL );
2801- if (!len || len >= MAX_PATH ) {
2802- errno = err_win_to_posix (GetLastError ());
2803- return -1 ;
2804- }
2805-
2806- /* over-allocate and fill phantom_symlink_info structure */
2807- psi = xmalloc (sizeof (struct phantom_symlink_info )
2808- + sizeof (wchar_t ) * (len + wcslen (wtarget ) + 2 ));
2809- psi -> wlink = (wchar_t * )(psi + 1 );
2810- wcscpy (psi -> wlink , wfullpath );
2811- psi -> wtarget = psi -> wlink + len + 1 ;
2812- wcscpy (psi -> wtarget , wtarget );
2813-
2814- EnterCriticalSection (& phantom_symlinks_cs );
2815- psi -> next = phantom_symlinks ;
2816- phantom_symlinks = psi ;
2817- LeaveCriticalSection (& phantom_symlinks_cs );
2818- break ;
2819- }
2820- case PHANTOM_SYMLINK_DIRECTORY :
2821- /* if we created a dir symlink, process other phantom symlinks */
2866+ switch (check_symlink_attr (index , link )) {
2867+ case SYMLINK_TYPE_UNSPECIFIED :
2868+ /* Create a phantom symlink: it is initially created as a file
2869+ * symlink, but may change to a directory symlink later if/when
2870+ * the target exists. */
2871+ return create_phantom_symlink (wtarget , wlink );
2872+ case SYMLINK_TYPE_FILE :
2873+ if (!CreateSymbolicLinkW (wlink , wtarget , symlink_file_flags ))
2874+ break ;
2875+ return 0 ;
2876+ case SYMLINK_TYPE_DIRECTORY :
2877+ if (!CreateSymbolicLinkW (wlink , wtarget ,
2878+ symlink_directory_flags ))
2879+ break ;
2880+ /* There may be dangling phantom symlinks that point at this
2881+ * one, which should now morph into directory symlinks. */
28222882 process_phantom_symlinks ();
2823- break ;
2883+ return 0 ;
28242884 default :
2825- break ;
2885+ BUG ( "unhandled symlink type" ) ;
28262886 }
2827- return 0 ;
2887+
2888+ /* CreateSymbolicLinkW failed. */
2889+ errno = err_win_to_posix (GetLastError ());
2890+ return -1 ;
28282891}
28292892
28302893#ifndef _WINNT_H
0 commit comments