@@ -43,6 +43,7 @@ interface
4343 IO_REPARSE_TAG_LX_SYMLINK = $A000001D;
4444
4545const
46+ LX_SYMLINK_HEADER_SIZE = 4 ;
4647 REPARSE_DATA_HEADER_SIZE = 8 ;
4748 MOUNT_POINT_HEADER_SIZE = 8 ;
4849 FILE_DOES_NOT_EXIST = DWORD(-1 );
@@ -119,6 +120,13 @@ function CreateHardLink(const AFileName, ALinkName: UnicodeString): Boolean;
119120 @returns(The function returns @true if successful, @false otherwise)
120121}
121122function ReadSymLink (const aSymlinkFileName: UnicodeString; out aTargetFileName: UnicodeString): Boolean;
123+ { en
124+ Creates a WSL/Cygwin symbolic link.
125+ @param(aTargetFileName The name of the existing file)
126+ @param(aSymlinkFileName The name of the symbolic link)
127+ @returns(The function returns @true if successful, @false otherwise)
128+ }
129+ function CreateSymLinkUnix (const aTargetFileName: String; const aSymlinkFileName: UnicodeString): Boolean;
122130
123131implementation
124132
@@ -357,6 +365,55 @@ function CreateSymLink(const ATargetName, ALinkName: UnicodeString; Attr: UInt32
357365 end ;
358366end ;
359367
368+ function CreateSymLinkUnix (const aTargetFileName: String; const aSymlinkFileName: UnicodeString): Boolean;
369+ var
370+ hDevice: THandle;
371+ dwLastError: DWORD;
372+ nInBufferSize: DWORD;
373+ dwPathBufferSize: DWORD;
374+ lpBytesReturned: DWORD = 0 ;
375+ lpInBuffer: PReparseDataBuffer;
376+ begin
377+ hDevice:= CreateFileW(PWideChar(aSymlinkFileName),
378+ GENERIC_WRITE, 0 , nil , CREATE_NEW,
379+ FILE_FLAG_OPEN_REPARSE_POINT, 0 );
380+ if hDevice = INVALID_HANDLE_VALUE then Exit(False);
381+ dwPathBufferSize:= Length(aTargetFileName);
382+ nInBufferSize:= REPARSE_DATA_HEADER_SIZE + LX_SYMLINK_HEADER_SIZE + dwPathBufferSize;
383+ lpInBuffer:= GetMem(nInBufferSize);
384+ ZeroMemory(lpInBuffer, nInBufferSize);
385+ with lpInBuffer^, lpInBuffer^.LxSymlinkReparseBuffer do
386+ begin
387+ FileType:= 2 ; // symbolic link
388+ ReparseTag:= IO_REPARSE_TAG_LX_SYMLINK;
389+ ReparseDataLength:= LX_SYMLINK_HEADER_SIZE + dwPathBufferSize;
390+ CopyMemory(@PathBuffer[0 ], @aTargetFileName[1 ], Length(aTargetFileName));
391+ end ;
392+ Result:= DeviceIoControl(hDevice, // handle to file or directory
393+ FSCTL_SET_REPARSE_POINT, // dwIoControlCode
394+ lpInBuffer, // input buffer
395+ nInBufferSize, // size of input buffer
396+ nil , // lpOutBuffer
397+ 0 , // nOutBufferSize
398+ lpBytesReturned, // lpBytesReturned
399+ nil ); // OVERLAPPED structure
400+ // File system does not support reparse points
401+ // Create a normal file with the link target inside
402+ if (not Result) and (GetLastError = ERROR_INVALID_FUNCTION) then
403+ begin
404+ Result:= (FileWrite(hDevice, aTargetFileName[1 ], dwPathBufferSize) = dwPathBufferSize);
405+ if Result then SetFileAttributesW(PWideChar(aSymlinkFileName), FILE_ATTRIBUTE_SYSTEM);
406+ end ;
407+ if not Result then dwLastError:= GetLastError;
408+ FreeMem(lpInBuffer);
409+ CloseHandle(hDevice);
410+ if not Result then
411+ begin
412+ DeleteFileW(PWideChar(aSymlinkFileName));
413+ SetLastError(dwLastError);
414+ end ;
415+ end ;
416+
360417function ReadSymLink (const aSymlinkFileName: UnicodeString; out aTargetFileName: UnicodeString): Boolean;
361418var
362419 L: Integer;
0 commit comments