2010-02-20 16 views
7

En .NET, creo que puedo determinar si un archivo es un enlace simbólico llamando a System.IO.File.GetAttributes() y buscando el bit ReparsePoint. como el siguiente:En .NET, ¿cómo obtener el destino de un enlace simbólico (o punto de análisis)?

var a = System.IO.File.GetAttributes(fileName); 
if ((a & FileAttributes.ReparsePoint) != 0) 
{ 
    // it's a symlink 
} 

¿Cómo puedo obtener el objetivo del enlace simbólico, en este caso?


PS: Sé cómo crear un enlace simbólico. Requiere P/Invoke:

[Interop.DllImport("kernel32.dll", EntryPoint="CreateSymbolicLinkW", CharSet=Interop.CharSet.Unicode)] 
public static extern int CreateSymbolicLink(string lpSymlinkFileName, string lpTargetFileName, int dwFlags); 

Respuesta

7

Usted tiene que usar Dispositivo() y enviar el código de control FSCTL_GET_REPARSE_POINT. Los detalles de uso de P/Invoke y API son bastante arenosos, pero es Googles really well.

+1

Este me llevó al código fuente de las Extensiones Comunitarias Powershell (PSCX), que tiene un buen código para manejar ReparsePoints. – Cheeso

4

Open the file, y luego pase el asa a GetFinalPathNameByHandle.

+0

funciona con Vista o mejor, o WS2008 o superior. – Cheeso

+1

@ Cheeso: los enlaces simbólicos a los archivos se debutaron en Vista, AFAIK. Por lo tanto, todas las funciones de enlace simbólico basadas en archivos tendrán la misma restricción. –

+2

Los puntos de análisis han estado presentes desde Win2k; solo son enlaces simbólicos a los archivos que aparecieron en Vista. – Gabe

8

Sobre la base de la respuesta que se menciona GetFinalPathNameByHandle Este es el código C# que hace esto (ya que todas las otras respuestas eran sólo punteros):

Uso

var path = NativeMethods.GetFinalPathName(@"c:\link"); 

Código:

public static class NativeMethods 
{ 
    private static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1); 

    private const uint FILE_READ_EA = 0x0008; 
    private const uint FILE_FLAG_BACKUP_SEMANTICS = 0x2000000; 

    [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] 
    static extern uint GetFinalPathNameByHandle(IntPtr hFile, [MarshalAs(UnmanagedType.LPTStr)] StringBuilder lpszFilePath, uint cchFilePath, uint dwFlags); 

    [DllImport("kernel32.dll", SetLastError = true)] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    static extern bool CloseHandle(IntPtr hObject); 

    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
    public static extern IntPtr CreateFile(
      [MarshalAs(UnmanagedType.LPTStr)] string filename, 
      [MarshalAs(UnmanagedType.U4)] uint access, 
      [MarshalAs(UnmanagedType.U4)] FileShare share, 
      IntPtr securityAttributes, // optional SECURITY_ATTRIBUTES struct or IntPtr.Zero 
      [MarshalAs(UnmanagedType.U4)] FileMode creationDisposition, 
      [MarshalAs(UnmanagedType.U4)] uint flagsAndAttributes, 
      IntPtr templateFile); 

    public static string GetFinalPathName(string path) 
    { 
     var h = CreateFile(path, 
      FILE_READ_EA, 
      FileShare.ReadWrite | FileShare.Delete, 
      IntPtr.Zero, 
      FileMode.Open, 
      FILE_FLAG_BACKUP_SEMANTICS, 
      IntPtr.Zero); 
     if (h == INVALID_HANDLE_VALUE) 
      throw new Win32Exception(); 

     try 
     { 
      var sb = new StringBuilder(1024); 
      var res = GetFinalPathNameByHandle(h, sb, 1024, 0); 
      if (res == 0) 
       throw new Win32Exception(); 

      return sb.ToString(); 
     } 
     finally 
     { 
      CloseHandle(h); 
     } 
    } 
} 
+0

Creo (pero no lo he probado) pero puede simplificar su código usando un objeto .NET FileStream y luego usando 'var h = yourStream.SafeFileHandle.DangerousGetHandle()', cuando cierra la secuencia también suelta el controlador por lo que no necesita llamar 'CloseHandle (h)' en esa variable. Incluso podría hacer que la función tome un 'FileStream' en lugar de una cadena. –

+1

@ScottChamberlain - las razones por las que no usé FileStream es a) No estoy seguro de si pasaría por los atributos que no están definidos en .NET yb) No estoy seguro de si también funcionaría para los directorios (CreateFile funciona). Además, esto debería ser más rápido (aunque no lo midí). –

+0

Si eres como yo, lo siguiente que querrás saber es esto: https://stackoverflow.com/questions/31439011/getfinalpathnamebyhandle-without-prepended – datguy

Cuestiones relacionadas