11
votes

Comment obtenir la cible d'un lien symbolique (ou de point de reparse) en utilisant .NET?

in .NET, je pense que je peux déterminer si un fichier est un lien symbolique en appelant system.io.file.getattributes () et vérifiant le bit de repères. Comme: xxx

Comment puis-je obtenir la cible du lien symbolique, dans ce cas?


PS: Je sais comment Créer Un lien symbolique. Il nécessite p / invoke: xxx


0 commentaires

3 Réponses :


10
votes

Vous devez utiliser DeviceIocontrol () et envoyer le code de contrôle FSCTL_GET_RePARSE_POPPOWER. Les détails de l'utilisation de P / invoke et d'API sont assez grains, mais il Googles vraiment bien .


1 commentaires

Cela m'a conduit au code source des extensions de la communauté PowerShell (PSCX), qui a un bon code permettant de manipuler des points de reparse.



4
votes

Ouvrir le fichier Utilisation de Createfile , puis transmettez la poignée sur GetFinalPathNameByhandle .


6 commentaires

@Cheeso: Symlinks aux fichiers débutés à Vista, Afaik. Ainsi, toutes les fonctions de symboles basées sur le fichier auront la même restriction.


Les points reparés ont été autour depuis Win2k; Ce ne sont que des liens symboliques vers des fichiers qui ont débuté à Vista.


Pour une raison quelconque, je reçois toujours une violation d'accès lors de l'appel de cette méthode ... Je ne sais pas pourquoi


En ce qui concerne Vista, tout est meilleur.


9 ans plus tard, le premier lien est cassé.


@Gault - Vous ne trouvez pas (et ne vous souvenez pas) Le commentaire de Raymond Chen, ainsi mis à jour sur la fonction Createefile nécessaire pour ouvrir



14
votes

Basé sur la réponse mentionnée getfinpharnamebyhandle code> Voici le code C # qui le fait (puisque toutes les autres réponses n'étaient que des pointeurs):

Utilisation p>

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);
        }
    }
}


4 commentaires

Je pense (mais je n'ai pas testé) mais vous pourrez peut-être simplifier votre code à l'aide d'un objet .NET FileStream, puis à l'aide de Var H = YourStream.safefilehandle.dangèreGetethandle () , lorsque vous fermez le flux Relâchez également la poignée afin que vous n'ayez pas besoin d'appeler étroitehandle (h) sur cette variable. Vous pouvez même rendre la fonction prendre dans un filtream au lieu d'une chaîne.


@Scottchamberlain - Les raisons pour lesquelles je n'ai pas utilisé de filtream est a) je ne suis pas sûr de passer par les attributs qui ne sont pas définis dans .NET et B) Je ne sais pas si cela fonctionnerait aussi pour les annuaires (Createfile travail). De plus, cela devrait être plus rapide (bien que je ne l'ai pas mesuré).


Si vous êtes comme moi, la prochaine chose que vous voudrez savoir est la suivante: @DATGUY Savez-vous que les chemins achètent avec \\? \\ sont réellement valides et utilisables? Il présente également des avantages (dire à Windows d'utiliser les extensions Unicode dans la mesure du possible, en contournant la limite max_path_length ) par tous les moyens, de la bande pour des raisons esthétiques, mais c'est une responsabilité parfaitement valide.