在 Windows 系统下,获取软连接的真正文件地址

#if UNITY_EDITOR

using System;
using System.Runtime.InteropServices;

namespace UnityEngine.Rendering.Universal
{
    /// <summary>
    /// Windows 平台高级路径工具
    /// </summary>
    public class WindowsAdvancedPathTools
    {
        const int MAXIMUM_REPARSE_DATA_BUFFER_SIZE = 16 * 1024;
        
        const uint FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000;
        const uint FILE_FLAG_BACKUP_SEMANTICS = 0x02000000;
        const uint FILE_SHARE_READ = 0x00000001;
        const uint FILE_SHARE_WRITE = 0x00000002;
        const uint OPEN_EXISTING = 3;
        const uint GENERIC_READ = 0x80000000;
        const int FSCTL_GET_REPARSE_POINT = 0x000900A8;
        
        const uint IO_REPARSE_TAG_SYMLINK = 0xA000000C; // 软连接
        const uint IO_REPARSE_TAG_MOUNT_POINT = 0xA0000003; // 挂载点

        [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        static extern IntPtr CreateFile(
            string lpFileName,
            uint dwDesiredAccess,
            uint dwShareMode,
            IntPtr lpSecurityAttributes,
            uint dwCreationDisposition,
            uint dwFlagsAndAttributes,
            IntPtr hTemplateFile);

        [DllImport("kernel32.dll", SetLastError = true)]
        static extern bool DeviceIoControl(
            IntPtr hDevice,
            uint dwIoControlCode,
            IntPtr lpInBuffer,
            uint nInBufferSize,
            IntPtr lpOutBuffer,
            uint nOutBufferSize,
            out uint lpBytesReturned,
            IntPtr lpOverlapped);

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

        [StructLayout(LayoutKind.Sequential)]
        struct REPARSE_DATA_BUFFER
        {
            public uint ReparseTag;
            public ushort ReparseDataLength;
            public ushort Reserved;
            public ushort SubstituteNameOffset;
            public ushort SubstituteNameLength;
            public ushort PrintNameOffset;
            public ushort PrintNameLength;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAXIMUM_REPARSE_DATA_BUFFER_SIZE)]
            public byte[] PathBuffer;
        }
        
        public static string GetReparsePointTarget(string reparsePointPath)
        {
            IntPtr hFile = CreateFile(reparsePointPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, IntPtr.Zero);
            if (hFile == IntPtr.Zero || hFile == new IntPtr(-1))
            {
                throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
            }

            try
            {
                IntPtr outBuffer = Marshal.AllocHGlobal(MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
                try
                {
                    uint bytesReturned;
                    bool result = DeviceIoControl(hFile, FSCTL_GET_REPARSE_POINT, IntPtr.Zero, 0, outBuffer, (uint)MAXIMUM_REPARSE_DATA_BUFFER_SIZE, out bytesReturned, IntPtr.Zero);
                    if (!result)
                    {
                        throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
                    }

                    var reparseDataBuffer = Marshal.PtrToStructure<REPARSE_DATA_BUFFER>(outBuffer);
                    if (reparseDataBuffer.ReparseTag == IO_REPARSE_TAG_SYMLINK || reparseDataBuffer.ReparseTag == IO_REPARSE_TAG_MOUNT_POINT)
                    {
                        string targetPath = System.Text.Encoding.Unicode.GetString(reparseDataBuffer.PathBuffer, reparseDataBuffer.SubstituteNameOffset, reparseDataBuffer.SubstituteNameLength);
                        return targetPath;
                    }
                    else
                    {
                        throw new InvalidOperationException("指定的文件不是软连接或挂载点");
                    }
                }
                finally
                {
                    Marshal.FreeHGlobal(outBuffer);
                }
            }
            finally
            {
                CloseHandle(hFile);
            }
        }
        
    }
}

#endif // UNITY_EDITOR

工作中有时会碰到在不同项目中创建软连接的情况,所以就会有获取到软连接真实地址的需要,这里提供一个类,可以做到这一点。

但是一定要传入软连接的节点目录,就是被创建为软连接的那个文件夹才行,软连接内部的文件夹是无法被获取到真实地址的。

<think>好的,我现在需要回答用户关于如何在CentOS中查看链接目标路径的问题。首先,我得回忆一下Linux系统中处理链接的相关命令。记得链接,也就是符号链接,类似于Windows的快捷方式,它存储的是目标文件的路径。用户想知道如何查看这些链接指向的实际路径。 首先,想到的是常用的ls命令。通常,ls -l可以显示文件的详细信息,包括符号链接的目标。例如,当使用ls -l时,输出中的权限部分后面会显示链接指向的路径。比如,输出可能像这样:lrwxrwxrwx 1 user group 11 May 1 12:34 linkname -> targetpath。这里箭头后面的就是目标路径。所以,使用ls -l应该是一个直接的方法。但用户可能希望更简洁的方式,或者需要处理多个文件的情况。 接下来,有没有其他命令可以专门查看链接目标呢?记得readlink命令就是用来显示符号链接的目标的。例如,readlink linkname会直接输出目标路径。这可能在脚本中使用更方便,因为它只返回路径,没有其他信息。此外,如果链接是相对路径,可能需要用readlink -f来解析绝对路径,这样更准确。比如,readlink -f linkname会显示完整的绝对路径,即使链接本身是相对的。 另外,考虑到用户可能使用的是CentOS,这些命令应该是可用的。不过,可能需要确认系统是否安装了coreutils包,因为readlink是其中的一部分,但通常默认安装。如果用户遇到问题,可能需要检查是否安装了该件包。 还有,stat命令也可以显示链接的信息。例如,stat linkname会在输出中显示符号链接指向的路径。这可能对于需要更多文件详细信息的情况有用,但输出可能比较复杂,用户需要从中提取目标路径。 总结一下,主要有三个方法: 1. 使用ls -l命令,查看输出中的箭头指向。 2. 使用readlink命令,直接获取目标路径。 3. 使用stat命令,查看链接信息。 用户可能还需要处理多个链接或者批量查看的情况,这时候可以结合find命令或者循环来处理。例如,find /path -type l -exec ls -l {} \; 可以查找所有符号链接并显示其目标。 最后,要确保回答中提到的命令在CentOS环境下有效,并且语法正确。同时,引用之前提供的参考资料,比如引用[3]中提到ln命令用于创建符号链接,而用户的问题是关于查看,但相关的引用可能支持说明符号链接的特性。</think>在CentOS中查看链接(符号链接)的目标路径,可以使用以下命令: ### 1. **`ls -l` 命令** 通过`ls -l`查看文件详细信息,链接的指向路径会显示在箭头`->`后: ```bash ls -l /path/to/symbolic_link ``` 输出示例: `lrwxrwxrwx. 1 root root 15 Jul 16 10:00 mylink -> /target/file` 此处`mylink -> /target/file`表示链接指向`/target/file`[^3][^5]。 --- ### 2. **`readlink` 命令** 直接获取链接的目标路径(推荐脚本中使用): ```bash readlink /path/to/symbolic_link ``` 若需解析绝对路径(即使链接本身是相对路径): ```bash readlink -f /path/to/symbolic_link ``` --- ### 3. **`stat` 命令** 显示文件详细信息,包含链接目标: ```bash stat /path/to/symbolic_link ``` 输出中的`Links`字段显示指向的路径。 --- ### 示例操作 ```bash # 创建测试链接 ln -s /etc/hosts /tmp/mylink # 查看目标路径 ls -l /tmp/mylink # 显示 "mylink -> /etc/hosts" readlink /tmp/mylink # 输出 "/etc/hosts" ``` ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值