See the question and my original answer on StackOverflow

Here is how I do it. Originally, I used to depend on GetFinalPathNameByHandle which is very good, but unfortunately, some custom file systems don't support it (of course NTFS does). I also tried NtQueryObject with ObjectNameInformation but again, they don't necessarily report the original file name.

So here is another "manual" way:

public static string GetRealPath(string fullPath)
{
    if (fullPath == null)
        return null; // invalid

    var pos = fullPath.LastIndexOf(Path.DirectorySeparatorChar);
    if (pos < 0 || pos == (fullPath.Length - 1))
        return fullPath.ToUpperInvariant(); // drive letter

    var dirPath = fullPath.Substring(0, pos);
    var realPath = GetRealPath(dirPath); // go recursive, we want the final full path
    if (realPath == null)
        return null; // doesn't exist

    var dir = new DirectoryInfo(realPath);
    if (!dir.Exists)
        return null; // doesn't exist
    
    var fileName = fullPath.Substring(pos + 1);
    if (fileName.IndexOfAny(Path.GetInvalidFileNameChars()) >= 0) // avoid wildcard calls
        return null;

    return dir.EnumerateFileSystemInfos(fileName).FirstOrDefault()?.FullName; // may return null
}