Author Topic: Detecting a Symbolic Link  (Read 436 times)

td

  • Tech Support
  • *****
  • Posts: 2538
    • WinBatch
Detecting a Symbolic Link
« on: January 23, 2018, 03:04:45 pm »
A user recently asked about how a WinBatch script could detect a symbolic link.  Happened to stumble across this lightly documented technique on  MSFT's website.   Don't know how much if any interest there is but thought I would share it anyway.  Error handling is not included for brevity.

Code: Winbatch
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; IsSymLink
;;
;; Determines if a file or directory is
;; a sybolic link.
;;   _strFile - full path-name of file or
;;              directory.
;;
;; Returns true if input is a symbolic link.
#DefineFunction IsSymLink(_strFile)
   WIN32_FIND_DATA = $"
   DWORD::dwFileAttributes;
   DWORD::ftCreationTimeHigh;
   DWORD::ftCreationTimeLow;
   DWORD::ftLastAccessTimeHigh;
   DWORD::ftLastAccessTimeLow;
   DWORD::ftLastWriteTimeHigh;
   DWORD::ftLastWriteTimeLow;
   DWORD::nFileSizeHigh;
   DWORD::nFileSizeLow;
   DWORD::dwReserved0;
   DWORD::dwReserved1;
   CHAR::cFileName[260];
   CHAR::cAlternateFileName[14];
   $"

   FILE_ATTRIBUTE_REPARSE_POINT = 1024
   IO_REPARSE_TAG_SYMLINK = 2684354572 ; = -1610612724
   pFindData = DllStructAlloc(WIN32_FIND_DATA)

   hSearch = DllCall('kernel32.dll', long:'FindFirstFileA', lpstr:_strFile, lpstruct:pFindData)
   if hSearch > -1
      DllCall('kernel32.dll', long:'FindClose', long:hSearch)
      FileAttribute = DllStructPeek(pFindData, 'dwFileAttributes')
      Reserved0      = DllStructPeek(pFindData, 'dwReserved0')
      DllStructFree(pFindData)

      return FileAttribute&FILE_ATTRIBUTE_REPARSE_POINT && Reserved0==IO_REPARSE_TAG_SYMLINK
   Endif
 
   return 0
#EndFunction


; Test
strFile = 'c:\temp\Link.txt'

bResult = IsSymLink( strFile )
if bResult then strText = 'is a symbolic link'
else strText = ' is NOT a symbolic link'
Message(strFile, strText)
   
"Success is a lousy teacher. It seduces smart people into thinking they can't lose."
  - Bill Gates


ChuckC

  • Full Member
  • ***
  • Posts: 149
Re: Detecting a Symbolic Link
« Reply #1 on: January 24, 2018, 05:55:47 am »
That looks to essentially be correct.  The standard attributes bit mask contains the FILE_ATTRIBUTE_REPARSE_POINT flag bit if the directory or file is actually a reparse point of some type.  What I found thru some testing across a variety of versions of Windows and various NAS devices is that ferreting out the Reparse Point ID Tag value from the Reserved0 field in the structure wasn't always a 100% reliable method.

To avoid any issues of that type, there is a further call that you can make to DeviceIoControl() with an open handle to a directory or file, using the control code FSCTL_GET_REPARSE_POINT [need to have the handle open with read extended attributes access], which will return a REPARSE_DATA_BUFFER structure [declared in the Windows DDK, not the Platform SDK], which reliably contains the Reparse Point ID Tag as well as all of the other data requires to fully decode reparse point so that the target directory/file can be identified for a Junction, Directory Symbolic Link, File Symbolic Link, Volume Mount Point and DFS Link, as well as target data for other less commonly used types of reparse points [SIS stubs, HSM stubs, DeDup stubs, etc...] that may or may not be at least partially decoded into something meaningful.

td

  • Tech Support
  • *****
  • Posts: 2538
    • WinBatch
Re: Detecting a Symbolic Link
« Reply #2 on: January 24, 2018, 07:10:00 am »
I am aware of the  DeviceIoControl() approach but your feedback is appreciated.   In use, the method above has proven to be very reliable with respect to symbolic links on local system NTFS file systems on newer versions of Windows for both file and directory symbolic links.     
"Success is a lousy teacher. It seduces smart people into thinking they can't lose."
  - Bill Gates