Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to obtain the target of a symbolic link (or Reparse Point) using .Net?

In .NET, I think I can determine if a file is a symbolic link by calling System.IO.File.GetAttributes(), and checking for the ReparsePoint bit. like so:

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

How can I obtain the target of the symbolic link, in this case?


ps: I know how to create a symbolic link. It requires P/Invoke:

[Interop.DllImport("kernel32.dll", EntryPoint="CreateSymbolicLinkW", CharSet=Interop.CharSet.Unicode)] 
public static extern int CreateSymbolicLink(string lpSymlinkFileName, string lpTargetFileName, int dwFlags); 
like image 925
Cheeso Avatar asked Feb 20 '10 13:02

Cheeso


People also ask

How do I find symbolic links in files?

You can use grep with ls command to list all the symbolic links present in the current directory. This will list all the links present in the current directory.

What is symlink target?

A symbolic link contains a text string that is automatically interpreted and followed by the operating system as a path to another file or directory. This other file or directory is called the "target". The symbolic link is a second file that exists independently of its target.

Can a symbolic link point to a directory?

A symbolic link, also known as a soft link or symlink, is a special file pointing to another file or directory using an absolute or relative path. Symbolic links are similar to shortcuts in Windows and are useful when you need quick access to files or folders with long paths.


2 Answers

In .NET 6 you can use the property LinkTarget

bool IsLink(string path)
{
    var fi = new FileInfo(path);
    return fi.LinkTarget != null
}
like image 101
Marin Avatar answered Oct 16 '22 12:10

Marin


Based on the answer that mentioned GetFinalPathNameByHandle here is the C# code that does this (since all other answers were just pointers):

Usage

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

Code:

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);
        }
    }
}
like image 38
Knaģis Avatar answered Oct 16 '22 11:10

Knaģis