1010#include "../config.h"
1111#include "dir.h"
1212#include "win32/fscache.h"
13+ #include "../attr.h"
1314
1415#define HCAST (type , handle ) ((type)(intptr_t)handle)
1516
@@ -425,6 +426,54 @@ static void process_phantom_symlinks(void)
425426 LeaveCriticalSection (& phantom_symlinks_cs );
426427}
427428
429+ static int create_phantom_symlink (wchar_t * wtarget , wchar_t * wlink )
430+ {
431+ int len ;
432+
433+ /* create file symlink */
434+ if (!CreateSymbolicLinkW (wlink , wtarget , symlink_file_flags )) {
435+ errno = err_win_to_posix (GetLastError ());
436+ return -1 ;
437+ }
438+
439+ /* convert to directory symlink if target exists */
440+ switch (process_phantom_symlink (wtarget , wlink )) {
441+ case PHANTOM_SYMLINK_RETRY : {
442+ /* if target doesn't exist, add to phantom symlinks list */
443+ wchar_t wfullpath [MAX_LONG_PATH ];
444+ struct phantom_symlink_info * psi ;
445+
446+ /* convert to absolute path to be independent of cwd */
447+ len = GetFullPathNameW (wlink , MAX_LONG_PATH , wfullpath , NULL );
448+ if (!len || len >= MAX_LONG_PATH ) {
449+ errno = err_win_to_posix (GetLastError ());
450+ return -1 ;
451+ }
452+
453+ /* over-allocate and fill phantom_symlink_info structure */
454+ psi = xmalloc (sizeof (struct phantom_symlink_info ) +
455+ sizeof (wchar_t ) * (len + wcslen (wtarget ) + 2 ));
456+ psi -> wlink = (wchar_t * )(psi + 1 );
457+ wcscpy (psi -> wlink , wfullpath );
458+ psi -> wtarget = psi -> wlink + len + 1 ;
459+ wcscpy (psi -> wtarget , wtarget );
460+
461+ EnterCriticalSection (& phantom_symlinks_cs );
462+ psi -> next = phantom_symlinks ;
463+ phantom_symlinks = psi ;
464+ LeaveCriticalSection (& phantom_symlinks_cs );
465+ break ;
466+ }
467+ case PHANTOM_SYMLINK_DIRECTORY :
468+ /* if we created a dir symlink, process other phantom symlinks */
469+ process_phantom_symlinks ();
470+ break ;
471+ default :
472+ break ;
473+ }
474+ return 0 ;
475+ }
476+
428477/* Normalizes NT paths as returned by some low-level APIs. */
429478static wchar_t * normalize_ntpath (wchar_t * wbuf )
430479{
@@ -2770,7 +2819,38 @@ int link(const char *oldpath, const char *newpath)
27702819 return 0 ;
27712820}
27722821
2773- int symlink (const char * target , const char * link )
2822+ enum symlink_type {
2823+ SYMLINK_TYPE_UNSPECIFIED = 0 ,
2824+ SYMLINK_TYPE_FILE ,
2825+ SYMLINK_TYPE_DIRECTORY ,
2826+ };
2827+
2828+ static enum symlink_type check_symlink_attr (struct index_state * index , const char * link )
2829+ {
2830+ static struct attr_check * check ;
2831+ const char * value ;
2832+
2833+ if (!index )
2834+ return SYMLINK_TYPE_UNSPECIFIED ;
2835+
2836+ if (!check )
2837+ check = attr_check_initl ("symlink" , NULL );
2838+
2839+ git_check_attr (index , link , check );
2840+
2841+ value = check -> items [0 ].value ;
2842+ if (ATTR_UNSET (value ))
2843+ return SYMLINK_TYPE_UNSPECIFIED ;
2844+ if (!strcmp (value , "file" ))
2845+ return SYMLINK_TYPE_FILE ;
2846+ if (!strcmp (value , "dir" ) || !strcmp (value , "directory" ))
2847+ return SYMLINK_TYPE_DIRECTORY ;
2848+
2849+ warning (_ ("ignoring invalid symlink type '%s' for '%s'" ), value , link );
2850+ return SYMLINK_TYPE_UNSPECIFIED ;
2851+ }
2852+
2853+ int mingw_create_symlink (struct index_state * index , const char * target , const char * link )
27742854{
27752855 wchar_t wtarget [MAX_LONG_PATH ], wlink [MAX_LONG_PATH ];
27762856 int len ;
@@ -2790,48 +2870,31 @@ int symlink(const char *target, const char *link)
27902870 if (wtarget [len ] == '/' )
27912871 wtarget [len ] = '\\' ;
27922872
2793- /* create file symlink */
2794- if (!CreateSymbolicLinkW (wlink , wtarget , symlink_file_flags )) {
2795- errno = err_win_to_posix (GetLastError ());
2796- return -1 ;
2797- }
2798-
2799- /* convert to directory symlink if target exists */
2800- switch (process_phantom_symlink (wtarget , wlink )) {
2801- case PHANTOM_SYMLINK_RETRY : {
2802- /* if target doesn't exist, add to phantom symlinks list */
2803- wchar_t wfullpath [MAX_LONG_PATH ];
2804- struct phantom_symlink_info * psi ;
2805-
2806- /* convert to absolute path to be independent of cwd */
2807- len = GetFullPathNameW (wlink , MAX_LONG_PATH , wfullpath , NULL );
2808- if (!len || len >= MAX_LONG_PATH ) {
2809- errno = err_win_to_posix (GetLastError ());
2810- return -1 ;
2811- }
2812-
2813- /* over-allocate and fill phantom_symlink_info structure */
2814- psi = xmalloc (sizeof (struct phantom_symlink_info )
2815- + sizeof (wchar_t ) * (len + wcslen (wtarget ) + 2 ));
2816- psi -> wlink = (wchar_t * )(psi + 1 );
2817- wcscpy (psi -> wlink , wfullpath );
2818- psi -> wtarget = psi -> wlink + len + 1 ;
2819- wcscpy (psi -> wtarget , wtarget );
2820-
2821- EnterCriticalSection (& phantom_symlinks_cs );
2822- psi -> next = phantom_symlinks ;
2823- phantom_symlinks = psi ;
2824- LeaveCriticalSection (& phantom_symlinks_cs );
2825- break ;
2826- }
2827- case PHANTOM_SYMLINK_DIRECTORY :
2828- /* if we created a dir symlink, process other phantom symlinks */
2873+ switch (check_symlink_attr (index , link )) {
2874+ case SYMLINK_TYPE_UNSPECIFIED :
2875+ /* Create a phantom symlink: it is initially created as a file
2876+ * symlink, but may change to a directory symlink later if/when
2877+ * the target exists. */
2878+ return create_phantom_symlink (wtarget , wlink );
2879+ case SYMLINK_TYPE_FILE :
2880+ if (!CreateSymbolicLinkW (wlink , wtarget , symlink_file_flags ))
2881+ break ;
2882+ return 0 ;
2883+ case SYMLINK_TYPE_DIRECTORY :
2884+ if (!CreateSymbolicLinkW (wlink , wtarget ,
2885+ symlink_directory_flags ))
2886+ break ;
2887+ /* There may be dangling phantom symlinks that point at this
2888+ * one, which should now morph into directory symlinks. */
28292889 process_phantom_symlinks ();
2830- break ;
2890+ return 0 ;
28312891 default :
2832- break ;
2892+ BUG ( "unhandled symlink type" ) ;
28332893 }
2834- return 0 ;
2894+
2895+ /* CreateSymbolicLinkW failed. */
2896+ errno = err_win_to_posix (GetLastError ());
2897+ return -1 ;
28352898}
28362899
28372900#ifndef _WINNT_H
0 commit comments