1414#define SECURITY_WIN32
1515#include <sspi.h>
1616#include "win32/fscache.h"
17+ #include "../attr.h"
1718
1819#define HCAST (type , handle ) ((type)(intptr_t)handle)
1920
@@ -429,6 +430,54 @@ static void process_phantom_symlinks(void)
429430 LeaveCriticalSection (& phantom_symlinks_cs );
430431}
431432
433+ static int create_phantom_symlink (wchar_t * wtarget , wchar_t * wlink )
434+ {
435+ int len ;
436+
437+ /* create file symlink */
438+ if (!CreateSymbolicLinkW (wlink , wtarget , symlink_file_flags )) {
439+ errno = err_win_to_posix (GetLastError ());
440+ return -1 ;
441+ }
442+
443+ /* convert to directory symlink if target exists */
444+ switch (process_phantom_symlink (wtarget , wlink )) {
445+ case PHANTOM_SYMLINK_RETRY : {
446+ /* if target doesn't exist, add to phantom symlinks list */
447+ wchar_t wfullpath [MAX_LONG_PATH ];
448+ struct phantom_symlink_info * psi ;
449+
450+ /* convert to absolute path to be independent of cwd */
451+ len = GetFullPathNameW (wlink , MAX_LONG_PATH , wfullpath , NULL );
452+ if (!len || len >= MAX_LONG_PATH ) {
453+ errno = err_win_to_posix (GetLastError ());
454+ return -1 ;
455+ }
456+
457+ /* over-allocate and fill phantom_symlink_info structure */
458+ psi = xmalloc (sizeof (struct phantom_symlink_info ) +
459+ sizeof (wchar_t ) * (len + wcslen (wtarget ) + 2 ));
460+ psi -> wlink = (wchar_t * )(psi + 1 );
461+ wcscpy (psi -> wlink , wfullpath );
462+ psi -> wtarget = psi -> wlink + len + 1 ;
463+ wcscpy (psi -> wtarget , wtarget );
464+
465+ EnterCriticalSection (& phantom_symlinks_cs );
466+ psi -> next = phantom_symlinks ;
467+ phantom_symlinks = psi ;
468+ LeaveCriticalSection (& phantom_symlinks_cs );
469+ break ;
470+ }
471+ case PHANTOM_SYMLINK_DIRECTORY :
472+ /* if we created a dir symlink, process other phantom symlinks */
473+ process_phantom_symlinks ();
474+ break ;
475+ default :
476+ break ;
477+ }
478+ return 0 ;
479+ }
480+
432481/* Normalizes NT paths as returned by some low-level APIs. */
433482static wchar_t * normalize_ntpath (wchar_t * wbuf )
434483{
@@ -2818,7 +2867,38 @@ int link(const char *oldpath, const char *newpath)
28182867 return 0 ;
28192868}
28202869
2821- int symlink (const char * target , const char * link )
2870+ enum symlink_type {
2871+ SYMLINK_TYPE_UNSPECIFIED = 0 ,
2872+ SYMLINK_TYPE_FILE ,
2873+ SYMLINK_TYPE_DIRECTORY ,
2874+ };
2875+
2876+ static enum symlink_type check_symlink_attr (struct index_state * index , const char * link )
2877+ {
2878+ static struct attr_check * check ;
2879+ const char * value ;
2880+
2881+ if (!index )
2882+ return SYMLINK_TYPE_UNSPECIFIED ;
2883+
2884+ if (!check )
2885+ check = attr_check_initl ("symlink" , NULL );
2886+
2887+ git_check_attr (index , link , check );
2888+
2889+ value = check -> items [0 ].value ;
2890+ if (ATTR_UNSET (value ))
2891+ return SYMLINK_TYPE_UNSPECIFIED ;
2892+ if (!strcmp (value , "file" ))
2893+ return SYMLINK_TYPE_FILE ;
2894+ if (!strcmp (value , "dir" ) || !strcmp (value , "directory" ))
2895+ return SYMLINK_TYPE_DIRECTORY ;
2896+
2897+ warning (_ ("ignoring invalid symlink type '%s' for '%s'" ), value , link );
2898+ return SYMLINK_TYPE_UNSPECIFIED ;
2899+ }
2900+
2901+ int mingw_create_symlink (struct index_state * index , const char * target , const char * link )
28222902{
28232903 wchar_t wtarget [MAX_LONG_PATH ], wlink [MAX_LONG_PATH ];
28242904 int len ;
@@ -2838,48 +2918,31 @@ int symlink(const char *target, const char *link)
28382918 if (wtarget [len ] == '/' )
28392919 wtarget [len ] = '\\' ;
28402920
2841- /* create file symlink */
2842- if (!CreateSymbolicLinkW (wlink , wtarget , symlink_file_flags )) {
2843- errno = err_win_to_posix (GetLastError ());
2844- return -1 ;
2845- }
2846-
2847- /* convert to directory symlink if target exists */
2848- switch (process_phantom_symlink (wtarget , wlink )) {
2849- case PHANTOM_SYMLINK_RETRY : {
2850- /* if target doesn't exist, add to phantom symlinks list */
2851- wchar_t wfullpath [MAX_LONG_PATH ];
2852- struct phantom_symlink_info * psi ;
2853-
2854- /* convert to absolute path to be independent of cwd */
2855- len = GetFullPathNameW (wlink , MAX_LONG_PATH , wfullpath , NULL );
2856- if (!len || len >= MAX_LONG_PATH ) {
2857- errno = err_win_to_posix (GetLastError ());
2858- return -1 ;
2859- }
2860-
2861- /* over-allocate and fill phantom_symlink_info structure */
2862- psi = xmalloc (sizeof (struct phantom_symlink_info )
2863- + sizeof (wchar_t ) * (len + wcslen (wtarget ) + 2 ));
2864- psi -> wlink = (wchar_t * )(psi + 1 );
2865- wcscpy (psi -> wlink , wfullpath );
2866- psi -> wtarget = psi -> wlink + len + 1 ;
2867- wcscpy (psi -> wtarget , wtarget );
2868-
2869- EnterCriticalSection (& phantom_symlinks_cs );
2870- psi -> next = phantom_symlinks ;
2871- phantom_symlinks = psi ;
2872- LeaveCriticalSection (& phantom_symlinks_cs );
2873- break ;
2874- }
2875- case PHANTOM_SYMLINK_DIRECTORY :
2876- /* if we created a dir symlink, process other phantom symlinks */
2921+ switch (check_symlink_attr (index , link )) {
2922+ case SYMLINK_TYPE_UNSPECIFIED :
2923+ /* Create a phantom symlink: it is initially created as a file
2924+ * symlink, but may change to a directory symlink later if/when
2925+ * the target exists. */
2926+ return create_phantom_symlink (wtarget , wlink );
2927+ case SYMLINK_TYPE_FILE :
2928+ if (!CreateSymbolicLinkW (wlink , wtarget , symlink_file_flags ))
2929+ break ;
2930+ return 0 ;
2931+ case SYMLINK_TYPE_DIRECTORY :
2932+ if (!CreateSymbolicLinkW (wlink , wtarget ,
2933+ symlink_directory_flags ))
2934+ break ;
2935+ /* There may be dangling phantom symlinks that point at this
2936+ * one, which should now morph into directory symlinks. */
28772937 process_phantom_symlinks ();
2878- break ;
2938+ return 0 ;
28792939 default :
2880- break ;
2940+ BUG ( "unhandled symlink type" ) ;
28812941 }
2882- return 0 ;
2942+
2943+ /* CreateSymbolicLinkW failed. */
2944+ errno = err_win_to_posix (GetLastError ());
2945+ return -1 ;
28832946}
28842947
28852948#ifndef _WINNT_H
0 commit comments