Read write Reparse point

Everything else that doesn't fall into one of the other PB categories.
jpd
Enthusiast
Enthusiast
Posts: 167
Joined: Fri May 21, 2004 3:31 pm

Read write Reparse point

Post by jpd »

Hi @All with the attached code example

is possible to view if a file or folder is a junction or a symbolic link

and show the reparse_point information path,typ





Read:

Code: Select all

; Author: jpd
; Date: 30.11.2007

;Read junction and symbolic link
;PureBasic-Port 2007  by jpd
;Info-Source and Description: http://www.flexhex.com/docs/articles/hard-links.phtml#junctions and one link to mklink http://www.zdnet.de/downloads/prg/l/e/de3NLE-wc.html
; with c++ source code from Christoph@Hochstaetter.org

;
Procedure.l IsReparsePoint(Attr.l) 
 reparse.l 
  
  If Attr & #FILE_ATTRIBUTE_REPARSE_POINT 
    reparse=1 
  Else 
    reparse=0 
  EndIf 
  ProcedureReturn reparse 
EndProcedure 
Declare.l CTL_CODE(DeviceType, Function, Method, Access)
#FILE_DEVICE_FILE_SYSTEM = 9
#METHOD_BUFFERED = 0
#FILE_ANY_ACCESS = 0
#MAXIMUM_REPARSE_DATA_BUFFER_SIZE = 2 * 1024; orig 16* problem with procedure ...

;-ReparseTag values...

#IO_REPARSE_TAG_MOUNT_POINT = 2684354563
#IO_REPARSE_TAG_SYMLINK	= 2684354572



Structure 	REPARSE_DATA_BUFFER;private struct REPARSE_DATA_BUFFER
		;{
			ReparseTag.l;public uint ReparseTag;
			ReparseDataLength.w;public short ReparseDataLength;
			Reserved.w;public short Reserved;
		 
EndStructure 			

 Structure SymbolicLinkReparseBuffer Extends REPARSE_DATA_BUFFER
 
			  SubsNameOffset.w;public short SubsNameOffset;
			  SubsNameLength.w;public short SubsNameLength;
			  PrintNameOffset.w;public short PrintNameOffset;
			  PrintNameLength.w;public short PrintNameLength;
			  Type.l;  //Vermute ich mal, ist nicht dokumentiert (1=relativer Link)
			  PathBuffer.w[#MAXIMUM_REPARSE_DATA_BUFFER_SIZE-20] ; PathBuffer.l[1]
  
  EndStructure
 
 Structure MountPointReparseBuffer Extends REPARSE_DATA_BUFFER
 
			  SubsNameOffset.w;public short SubsNameOffset;
			  SubsNameLength.w;public short SubsNameLength;
			  PrintNameOffset.w;public short PrintNameOffset;
			  PrintNameLength.w;public short PrintNameLength;
			   PathBuffer.w[#MAXIMUM_REPARSE_DATA_BUFFER_SIZE-16];PathBuffer.l[1]
  
  EndStructure
 
 ;Structure  GenericReparseBuffer Extends REPARSE_DATA_BUFFER
 ; DataBuffer.w[#MAXIMUM_REPARSE_DATA_BUFFER_SIZE-8]
;EndStructure 

Structure 	_REPARSE_DATA_BUFFER;private struct REPARSE_DATA_BUFFER
		;{
			ReparseTag.l;public uint ReparseTag;
			ReparseDataLength.w;public short ReparseDataLength;
			Reserved.w;public short Reserved;
			StructureUnion 
			  SubsNameOffset.w;public short SubsNameOffset;
			  SubsNameLength.w;public short SubsNameLength;
			  PrintNameOffset.w;public short PrintNameOffset;
			  PrintNameLength.w;public short PrintNameLength;
			  PathBuffer.w[#MAXIMUM_REPARSE_DATA_BUFFER_SIZE]
			EndStructureUnion 
	
EndStructure 			

	
#GetFileExInfoStandard = 0 ;used by GetFileAttributesEx_ 
Declare.s GetFinalPathNameByHandle(Handle.l) 
Structure _WIN32_FIND_DATA ;used by GetFileAttributesEx_ 
  dwFileAttributes.l 
  ftCreationTime.FILETIME 
  ftLastAccessTime.FILETIME 
  ftLastWriteTime.FILETIME 
  nFileSizeLow.l 
  nFileSizeHigh.l 
  dwReserved0.l 
  dwReserved1.l 
  cFileName.s{#MAX_PATH} 
  cAlternate.s{14} 
  dummy.w 
EndStructure 

Structure Atrrib_Ex
  FileIn.b
  FileOut.b
  type.l
  valid.l
EndStructure   


;------ used by GetFinalPathNameByHandleW 
#FILE_NAME_NORMALIZED =0 
#VOLUME_NAME_DOS = 0 
#VOLUME_NAME_GUID =1 
#VOLUME_NAME_NT=2 

#VOLUME_NAME_NONE =4 
#FILE_NAME_OPENED = 8 


Procedure ReparseType(FileIn.s,FileOut.s,checkfile.l,typ.l)
Debug "---------------------------------"
Debug FileIn
Debug FileOut
Debug checkfile 
Debug typ

pos= FindString(filein,":\",1)
driveletter.s= Mid(filein,pos-1,3)
Select GetDriveType_(driveletter) 
  Case 4
  ;  Debug "Network Drive: " +driveletter
  Default 
  ;  Debug "Local Drive: "+driveletter
EndSelect 

;GetDriveType_(Parameter) 

If checkfile <> -2 ;And typ=1 Or typ=0
  pos= FindString(FileOut,"\??\",1)
  reparse_path.s= Mid(FileOut,1,pos-1)
  If typ=0
    Debug "Reparse type: File --> ReparsePoint: "  +reparse_path
    
  EndIf 
  If typ=1
    Debug "Reparse type: File --> symbolic Link: "  +reparse_path
   
  EndIf  
EndIf
If checkfile = -2 ;And typ=1 Or typ=0
  pos= FindString(FileOut,"\??\",1)
  reparse_path.s= Mid(FileOut,pos+4,Len(fileOut)-4)
  search_unc= FindString(FileOut,"\??\UNC\",1)

  If search_unc  >0
  reparse_path=Mid(FileOut,1, search_unc-1)
  EndIf
  search_vol= FindString(FileOut,"\??\VOLUME",1)

  If search_vol  >0
  reparse_path=Mid(FileOut,1, search_vol-1)
  EndIf
  
  ;reparse_path.s=
  If typ=0
    Debug "Reparse type: Directory --> ReparsePoint: "  +reparse_path
  
  EndIf 
  If typ=1
    Debug "Reparse type: Directory --> junction: "  +reparse_path;value 4
  
  EndIf  
EndIf


EndProcedure





 
Procedure Dir_file_Handle(file_in.s,typ.l) 

;-----  used by createfile 
#FILE_LIST_DIRECTORY = 1 
#FILE_SHARE_READ = 1 
#FILE_SHARE_DELETE = 4 
#OPEN_EXISTING = 3 
#FILE_FLAG_BACKUP_SEMANTICS = 33554432; $02000000 
#FILE_SHARE_DELETE = 4 
#FILE_FLAG_OPEN_REPARSE_POINT=2097152 

 Protected flag.l 
  
  If typ=-2 
    flag=#FILE_LIST_DIRECTORY 
  Else 
    flag=#GENERIC_READ    
  EndIf 
  
  hDir = CreateFile_(file_in, flag,#FILE_SHARE_READ, #Null, #OPEN_EXISTING, #FILE_FLAG_BACKUP_SEMANTICS|#FILE_FLAG_OPEN_REPARSE_POINT, #Null) 

  ret=  GetLastError_()
 ; GetLastError(ret ) 
  ProcedureReturn hDir 
EndProcedure 




Procedure.l CTL_CODE(DeviceType, Function, Method, Access) 

  ProcedureReturn ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) 
EndProcedure 

Procedure.b IncreasePrivileges() 
    Protected hToken, Buff 
    Protected mLUID.LUID 
    Protected mPriv.TOKEN_PRIVILEGES 
    Protected mNewPriv.TOKEN_PRIVILEGES 
    Protected CurrentProcess = GetCurrentProcess_() 
    #TOKEN_ADJUST_PRIVILEGES = $20 
   #TOKEN_QUERY = $8 
    mPriv\PrivilegeCount = 1 
    mPriv\Privileges[0]\Attributes = #SE_PRIVILEGE_ENABLED 
    
    If CurrentProcess = 0 
       ProcedureReturn #False 
    EndIf 
    
    If OpenProcessToken_(CurrentProcess, #TOKEN_ADJUST_PRIVILEGES | #TOKEN_QUERY, @hToken) = 0 
       ProcedureReturn #False 
    EndIf 
    
    If LookupPrivilegeValue_(#Null, "SeBackupPrivilege", @mLUID) = 0 
       CloseHandle_(hToken) 
       ProcedureReturn #False 
    EndIf 
        
    If IsBadWritePtr_(@mPriv\Privileges[0]\Luid, SizeOf(LUID)) <> 0 
       CloseHandle_(hToken) 
       ProcedureReturn #False 
    EndIf 
    
    CopyMemory(@mLUID, @mPriv\Privileges[0]\Luid, SizeOf(LUID)) 
                  
    If AdjustTokenPrivileges_(hToken, #False, @mPriv, SizeOf(TOKEN_PRIVILEGES), @mNewPriv, @Buff) = 0 
       CloseHandle_(hToken) 
       ProcedureReturn #False 
    EndIf 
    
    If GetLastError_() <> #ERROR_SUCCESS 
       CloseHandle_(hToken) 
       ProcedureReturn #False 
    EndIf 
    
    ; If we get here, then it worked. Returns TRUE 
    CloseHandle_(hToken) 
    ProcedureReturn #True 
EndProcedure 
  
;EndProcedure 



Procedure GetReparse_Point(filein.s)
  Protected FSCTL_GET_REPARSE_POINT.l
  checkfile.l = FileSize(filein) 
  If checkfile  <> -1 
    attribute.WIN32_FIND_DATA 
    GetFileAttributesEx_(filein ,#GetFileExInfoStandard,@attribute) 
    If IsReparsePoint(attribute\dwFileAttributes) ;check if the file or dir containing a 
      handle.l=Dir_file_Handle(filein,checkfile) 
      ;Debug "handle: "+Str(handle)
      FSCTL_GET_REPARSE_POINT =CTL_CODE(#FILE_DEVICE_FILE_SYSTEM, 42, #METHOD_BUFFERED, #FILE_ANY_ACCESS)
      Protected rdb._REPARSE_DATA_BUFFER
      DeviceIoControl_(handle, FSCTL_GET_REPARSE_POINT,0,0,@rdb,SizeOf(_REPARSE_DATA_BUFFER),@retbytes,0) 
      val= rdb\ReparseTag
      If Hex(val)=Hex(#IO_REPARSE_TAG_MOUNT_POINT) ;And checkfile= -2
        Protected  trs_2.MountPointReparseBuffer
        CopyMemory(@rdb,@trs_2,SizeOf(MountPointReparseBuffer))
        junctionname.s=PeekS(@trs_2\PathBuffer,SizeOf(MountPointReparseBuffer),#PB_Unicode)
        ReparseType( filein,junctionname,checkfile,0)
        ;CloseHandle_(handle)
        trs_2\PathBuffer=0
      EndIf
      If Hex(val)=Hex(#IO_REPARSE_TAG_SYMLINK);	= 2684354572
        Protected trs_1.SymbolicLinkReparseBuffer
        CopyMemory(@rdb,@trs_1,SizeOf(SymbolicLinkReparseBuffer))
        junctionname.s= PeekS(@trs_1\PathBuffer,SizeOf(MountPointReparseBuffer),#PB_Unicode)
        ReparseType(filein, junctionname,checkfile,1)
        ;CloseHandle_(handle)
        trs_1\PathBuffer=0
      EndIf
    Else 
      Debug "next file" 
    EndIf  
  Else 
    Debug "file not found" 
  EndIf 
  CloseHandle_(handle)
EndProcedure 

;-start

Select OSVersion()

  Case  #PB_OS_Windows_Vista
  
  Default 
    Debug "Link Manager running only on Vista!"
    
    End
 EndSelect 

If IncreasePrivileges() = #False 
    MessageBox_(0, "Could not retrieve all privileges.", "Error :", #MB_ICONEXCLAMATION) 
    End
EndIf 


GetReparse_Point("c:\programme")
the big problem coming on write/create a new junction this is really hard and I dont have no more ideas for solve this.

the write code can generate the junction but write this not properly on disk,

my opinion is that I give false info to structure.

I hope that someone can give me the right hint.

Thanks
jpd

Write

Code: Select all

#FILE_DEVICE_FILE_SYSTEM = 9
#METHOD_BUFFERED = 0
#FILE_ANY_ACCESS = 0
#MAXIMUM_REPARSE_DATA_BUFFER_SIZE = 16 * 1024; orig 16* problem with procedure ...

;-ReparseTag values...

#IO_REPARSE_TAG_MOUNT_POINT = 2684354563
#IO_REPARSE_TAG_SYMLINK	= 2684354572
#GetFileExInfoStandard=0

Structure 	REPARSE_DATA_BUFFER;private struct REPARSE_DATA_BUFFER
		;{
			ReparseTag.l;public uint ReparseTag;
			ReparseDataLength.w;public short ReparseDataLength;
			Reserved.w;public short Reserved;
			StructureUnion 
			  SubstituteNameOffset.w;
      SubstituteNameLength.w;
      PrintNameOffset.w;
      PrintNameLength.w;
 
			  PathBuffer.b[#MAXIMUM_REPARSE_DATA_BUFFER_SIZE]
			EndStructureUnion 
	
EndStructure 			

Structure 	_REPARSE_DATA_BUFFER;private struct REPARSE_DATA_BUFFER
		;{
			ReparseTag.l;public uint ReparseTag;
			ReparseDataLength.w;public short ReparseDataLength;
			Reserved.w;public short Reserved;
		 
EndStructure 			

;Structure AllLinks Extends REPARSE_DATA_BUFFER
 
;      SubstituteNameOffset.w;
;      SubstituteNameLength.w;
;      PrintNameOffset.w;
;      PrintNameLength.w;
 
; EndStructure 
    
 Structure SymbolicLinkReparseBuffer Extends _REPARSE_DATA_BUFFER
 
			  SubstituteNameOffset.w;
        SubstituteNameLength.w;
        PrintNameOffset.w;
        PrintNameLength.w;
			  Type.l;  //Vermute ich mal, ist nicht dokumentiert (1=relativer Link)
			  PathBuffer.b[#MAXIMUM_REPARSE_DATA_BUFFER_SIZE-20] ; PathBuffer.l[1]
        
  EndStructure
        
 Structure MountPointReparseBuffer Extends _REPARSE_DATA_BUFFER
        
  	    SubstituteNameOffset.w;
        SubstituteNameLength.w;
        PrintNameOffset.w;
        PrintNameLength.w;
			  PathBuffer.b[#MAXIMUM_REPARSE_DATA_BUFFER_SIZE-16];PathBuffer.l[1]
  
  EndStructure
 
 Structure  GenericReparseBuffer Extends _REPARSE_DATA_BUFFER
  DataBuffer.b[#MAXIMUM_REPARSE_DATA_BUFFER_SIZE-8]
EndStructure 

#REPARSE_DATA_BUFFER_HEADER_SIZE = OffsetOf(GenericReparseBuffer\DataBuffer)
;#REPARSE_DATA_BUFFER_HEADER_SIZE = OffsetOf(MountPointReparseBuffer\PathBuffer)
;#MAXIMUM_REPARSE_DATA_BUFFER_SIZE = 16 * 1024 

Procedure.l CTL_CODE(DeviceType, Function, Method, Access) 
  ProcedureReturn ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) 
EndProcedure 
	
	Procedure.l IsReparsePoint(Attr.l) 
 reparse.l 
  
  If Attr & #FILE_ATTRIBUTE_REPARSE_POINT 
    reparse=1 
  Else 
    reparse=0 
  EndIf 
  ProcedureReturn reparse 
EndProcedure 

	
	Procedure Dir_Handle(DirIn.s) 

;-----  used by createfile 
#FILE_LIST_DIRECTORY = 1 
#FILE_SHARE_READ = 1 
#FILE_SHARE_DELETE = 4 
#OPEN_EXISTING = 3 
#FILE_FLAG_BACKUP_SEMANTICS = 33554432; $02000000 
#FILE_SHARE_DELETE = 4 
#FILE_FLAG_OPEN_REPARSE_POINT=2097152 

 ;Protected flag.l 
  
   ; flag=
 
  
  hDir = CreateFile_(DirIn, #GENERIC_WRITE | #GENERIC_READ ,#FILE_SHARE_READ, #Null, #OPEN_EXISTING, #FILE_FLAG_BACKUP_SEMANTICS|#FILE_FLAG_OPEN_REPARSE_POINT, #Null) 

  ret=  GetLastError_()
  Debug "hDir: "+Str(ret)
  ;If err=1
  ;GetLastError(ret,file_in ) 
  ;EndIf 
  ProcedureReturn hDir 
EndProcedure 

Procedure.b IncreasePrivileges() 
    Protected hToken, Buff 
    Protected mLUID.LUID 
    Protected mPriv.TOKEN_PRIVILEGES 
    Protected mNewPriv.TOKEN_PRIVILEGES 
    Protected CurrentProcess = GetCurrentProcess_() 
    #TOKEN_ADJUST_PRIVILEGES = $20 
   #TOKEN_QUERY = $8 
    mPriv\PrivilegeCount = 1 
    mPriv\Privileges[0]\Attributes = #SE_PRIVILEGE_ENABLED 
    #SE_RESTORE_NAME = "SeRestorePrivilege"
    #SE_BACKUP_NAME="SeBackupPrivilege"
    #SE_PRIVILEGE_ENABLED1="SeCreateSymbolicLinkPrivilege"

    If CurrentProcess = 0 
       ProcedureReturn #False 
    EndIf 
    
    If OpenProcessToken_(CurrentProcess, #TOKEN_ADJUST_PRIVILEGES | #TOKEN_QUERY, @hToken) = 0 
       ProcedureReturn #False 
    EndIf 
    
    If LookupPrivilegeValue_(#Null,#SE_PRIVILEGE_ENABLED1, @mLUID) = 0 
       CloseHandle_(hToken) 
       ProcedureReturn #False 
    EndIf 
        
    If IsBadWritePtr_(@mPriv\Privileges[0]\Luid, SizeOf(LUID)) <> 0 
       CloseHandle_(hToken) 
       ProcedureReturn #False 
    EndIf 
    
    CopyMemory(@mLUID, @mPriv\Privileges[0]\Luid, SizeOf(LUID)) 
                  
    If AdjustTokenPrivileges_(hToken, #False, @mPriv, SizeOf(TOKEN_PRIVILEGES), @mNewPriv, @Buff) = 0 
       CloseHandle_(hToken) 
       ProcedureReturn #False 
    EndIf 
    
    If GetLastError_() <> #ERROR_SUCCESS 
       CloseHandle_(hToken) 
       ProcedureReturn #False 
    EndIf 
    
    ; If we get here, then it worked. Returns TRUE 
    CloseHandle_(hToken) 
    ProcedureReturn #True 
EndProcedure 
;-start

If IncreasePrivileges() = #False 
    MessageBox_(0, "Could not retrieve all privileges.", "Error :", #MB_ICONEXCLAMATION) 
    End
EndIf 

;-start

DirIn.s="c:\test113"
DirOut.s="\\\??\c:\empty"; right is normaly \??\c:\empty...but will be troncated using \\\??\c:\empty the generate parsepoint is right but cannot access on it.
size.w=Len(DirIn)
sizePN.w=Len(DirOut)*SizeOf(character)
  
  checkDir.l = FileSize(DirIn) 
  If checkDir=-1
    Ergebnis = CreateDirectory(DirIn)
    checkDir.l = FileSize(DirIn)
  EndIf
  If checkDir   = -2
    Debug "IsDir: " +DirIn
    If PathIsDirectoryEmpty_(DirIn)
      Debug "IsEmpty"
      attribute.WIN32_FIND_DATA 
      GetFileAttributesEx_(DirIn ,#GetFileExInfoStandard,@attribute) 
      If Not IsReparsePoint(attribute\dwFileAttributes) ;check if the file or dir containing a 
        handle.l=Dir_Handle(DirIn) 
        FSCTL_SET_REPARSE_POINT =CTL_CODE(#FILE_DEVICE_FILE_SYSTEM, 41, #METHOD_BUFFERED, #FILE_ANY_ACCESS)
      
        junction.MountPointReparseBuffer
        With junction
          \ReparseTag=#IO_REPARSE_TAG_MOUNT_POINT
          \Reserved=0
          \SubstituteNameOffset=0
          \SubstituteNameLength=size
          \PrintNameOffset=size+SizeOf(character)
          \PrintNameLength=sizePN 
         EndWith
      ;  gen.GenericReparseBuffer 
   
       PokeS(@junction\PathBuffer,DirOut,Len(DirOut),#PB_Unicode)
  
    dummy.w=0
    junction\ReparseDataLength =size+sizePN+12
    Debug #REPARSE_DATA_BUFFER_HEADER_SIZE 
    ret=DeviceIoControl_(handle, FSCTL_SET_REPARSE_POINT,@junction,junction\ReparseDataLength+#REPARSE_DATA_BUFFER_HEADER_SIZE ,#Null,0,@dummy,#Null) 
        ret= GetLastError_()
        Debug ret
     EndIf
    EndIf
 EndIf        
PB 5.10 Windows 7 x64 SP1