From 7fdd58ffe2bc08a956ea791461fe421f3acc440a Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Tue, 19 Jan 2010 12:51:06 +0100 Subject: [PATCH] Installer: Use Vista's Symbolic Links for built-ins, if possible Unfortunately, Windows Explorer does not report the correct directory size if hardlinks are used inside that directory, which caused user complaints in the past, stating an installed msysGit would be as large as 150 MB (whereas it is more about 60 MB). This is why we prefer to use Symbolic Links now, if they are available, as those are handled correctly by Windows Explorer. Other advantages of Symblic Links are that they can be relative, and point to a different volume. Disadvantages are that they become invalid if the target is deleted, they cannot be easily enumerated (a target does not know its links), and creating them requires administrator rights / user elevation. If built-ins cannot be created using Symbolic Links for some reason, Hardlinks are tried next, and if that also fails, a copy is created. Credits go to Michael Lukashov for the suggestion and initial patch. Signed-off-by: Sebastian Schuberth --- share/WinGit/install.iss | 71 ++++++++++++++++++++++++------------------------ 1 file changed, 35 insertions(+), 36 deletions(-) diff --git a/share/WinGit/install.iss b/share/WinGit/install.iss index dd28b64e..0dfb20ef 100644 --- a/share/WinGit/install.iss +++ b/share/WinGit/install.iss @@ -91,6 +91,13 @@ external 'CreateHardLinkW@Kernel32.dll stdcall delayload setuponly'; external 'CreateHardLinkA@Kernel32.dll stdcall delayload setuponly'; #endif +function CreateSymbolicLink(lpSymlinkFileName,lpTargetFileName:String;dwFlags:DWORD):Boolean; +#ifdef UNICODE +external 'CreateSymbolicLinkW@Kernel32.dll stdcall delayload setuponly'; +#else +external 'CreateSymbolicLinkA@Kernel32.dll stdcall delayload setuponly'; +#endif + const // Git Path options. GP_BashOnly = 1; @@ -476,7 +483,7 @@ var AppDir,FileName,Cmd,Msg:String; BuiltIns,EnvPath,EnvHome,EnvSSH:TArrayOfString; Count,i:Longint; - IsNTFS:Boolean; + LinkCreated:Boolean; FindRec:TFindRec; RootKey:Integer; begin @@ -493,12 +500,6 @@ begin // Load the built-ins from a text file. FileName:=ExpandConstant('{app}\{#emit APP_BUILTINS}'); if LoadStringsFromFile(FileName,BuiltIns) then begin - // Check if we are running on NTFS. - IsNTFS:=False; - if SetNTFSCompression(AppDir+'\bin\git.exe',true) then begin - IsNTFS:=SetNTFSCompression(AppDir+'\bin\git.exe',false); - end; - Count:=GetArrayLength(BuiltIns)-1; // Delete those scripts from "bin" which have been replaced by built-ins in "libexec\git-core". @@ -509,43 +510,41 @@ begin end; end; - // Map the built-ins to git.exe. - if IsNTFS then begin - Log('Line {#emit __LINE__}: Partition seems to be NTFS, trying to create built-in aliases as hard links.'); + // Create built-ins as aliases for git.exe. + for i:=0 to Count do begin + FileName:=AppDir+'\'+BuiltIns[i]; - for i:=0 to Count do begin - FileName:=AppDir+'\'+BuiltIns[i]; + // Delete any existing built-in. + if FileExists(FileName) and (not DeleteFile(FileName)) then begin + Log('Line {#emit __LINE__}: Unable to delete existing built-in "'+FileName+'", skipping.'); + continue; + end; - // On non-NTFS partitions, create hard links. - if (FileExists(FileName) and (not DeleteFile(FileName))) or - (not CreateHardLink(FileName,AppDir+'\bin\git.exe',0)) then begin - Log('Line {#emit __LINE__}: Unable to create hard link "'+FileName+'", will try to copy files.'); - IsNTFS:=False; - Break; + try + // This will throw an exception on pre-WinVista systems. + LinkCreated:=CreateSymbolicLink(FileName,AppDir+'\bin\git.exe',0); + except + LinkCreated:=False; + Log('Line {#emit __LINE__}: Creating symbolic link "'+FileName+'" failed, will try a hard link.'); + end; + + if not LinkCreated then begin + try + // This will throw an exception on pre-Win2k systems. + LinkCreated:=CreateHardLink(FileName,AppDir+'\bin\git.exe',0); + except + LinkCreated:=False; + Log('Line {#emit __LINE__}: Creating hardlink "'+FileName+'" failed, will try a copy.'); end; end; - Log('Line {#emit __LINE__}: Successfully created built-in aliases as hard links.'); - end; - - // The fallback is to copy the files. - if not IsNTFS then begin - Log('Line {#emit __LINE__}: Trying to create built-in aliases as file copies.'); - - for i:=0 to Count do begin - FileName:=AppDir+'\'+BuiltIns[i]; - - // On non-NTFS partitions, copy simply the files (overwriting existing ones). - if not FileCopy(AppDir+'\bin\git.exe',FileName,false) then begin - Msg:='Line {#emit __LINE__}: Unable to create file copy "'+FileName+'".'; - MsgBox(Msg,mbError,MB_OK); - Log(Msg); + if not LinkCreated then begin + if not FileCopy(AppDir+'\bin\git.exe',FileName,False) then begin + Log('Line {#emit __LINE__}: Creating copy "'+FileName+'" failed, giving up.'); // This is not a critical error, Git could basically be used without the - // aliases for built-ins, so we continue. + // built-ins, so we continue. end; end; - - Log('Line {#emit __LINE__}: Successfully created built-in aliases as file copies.'); end; // Delete any duplicate files in case we are updating from a non-libexec to a libexec directory layout. -- 2.11.4.GIT