在Windows中替代readlink()函数的方法

4

readLink() 函数在 Linux 中出现,并且在 unistd.h 中定义。请问在 Windows 中是否有类似的函数?如果没有,请提供一个类似功能的自定义函数。如果没有预定义的函数,则需要提供用于替换该函数的用户定义函数以使用与 readLink() 相同的功能。

以下是代码快照:

        char buffer[2048];

        readlink("/proc/self/exe", buffer, 2048);

        std::stringstream ss;
        ss << buffer;
        std::string exeFile = ss.str();
        std::string directory;

        const size_t last_slash_idx = exeFile.rfind('/');
        if (std::string::npos != last_slash_idx)
        {
            directory = exeFile.substr(0, last_slash_idx);
        }
        return directory;
    #endif 

我的应用程序可以检测机器的平台,并且可以根据情况自动工作,无需用户输入。 - Ankit Srivastava
可以形成一个函数,它可以像readLink()一样工作吗? - Ankit Srivastava
2
你没有理解重点。Readlink及其功能与Windows无关。你需要弄清楚Linux版本对readlink的处理方式,而不仅仅是看readlink本身。 - kaylum
@kaylum,Node.js在Windows上支持此功能,因此这是可能的。 - Qwertiy
@AnkitSrivastava,你找到解决方法了吗? - Qwertiy
显示剩余6条评论
3个回答

1

Windows系统没有类似于readlink(2)的功能,但它却有一个realpath(3)的等效功能:GetFinalPathNameByHandleW()

参见:由Ramond Chen所撰写的"如何获取符号链接目标信息"。

伪代码如下,省略错误检查:

HANDLE hPath = CreateFileW(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
DWORD len = GetFinalPathNameByHandleW(hPath, NULL, 0, FILE_NAME_OPENED);
WCHAR* realPathBuf = new WCHAR[len+1];
GetFinalPathNameByHandleW(hPath, realPathBuf, len, FILE_NAME_OPENED);

请注意,realPathBuf 可能是以 \\?\ 开头的“本地 UNC”路径。

0

好的,正如评论中所述,Windows没有一个readlink()链式API。尽管如此,示例中给出的代码正在处理程序无需直接处理的一些内容。Linux系统API为您处理链接。而且readlink不会空终止,它只返回原始数据。这样,QFile提供了一个平台无关的API来解析链接。QFile :: symLinkTarget提供了一种在Windows和Unix上获取链接目标的方法,而无需您的程序干扰此操作系统的特定部分。

Windows执行此操作的过程并不像Linux / Unix系统上那样简单。实际上,Windows上有两种不同类型的链接。我强烈建议在尝试进行跨平台I / O时使用Qt等框架。Windows是与典型的Linux / Unix系统非常不同的动物。首先,它不是POSIX系统,大多数Linux / Unix系统都是。


0

这段代码在Windows上的作用类似于Linux上的readlink。只需添加错误和不足大小缓冲处理:

int readlink(const char* pathname, char* link, size_t linksize)
{
    HANDLE h = CreateFileA(pathname, 0, 0, NULL, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT, NULL);
    char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
    DWORD dwBytesReturned = 0;
    DeviceIoControl(h, FSCTL_GET_REPARSE_POINT, NULL, 0, buffer, sizeof(buffer), &dwBytesReturned, 0);
    typedef struct
    {
        ULONG ReparseTag;
        USHORT ReparseDataLength;
        USHORT Reserved;
        union
        {
            struct
            {
                USHORT SubstituteNameOffset;
                USHORT SubstituteNameLength;
                USHORT PrintNameOffset;
                USHORT PrintNameLength;
                ULONG Flags;
                WCHAR PathBuffer[1];
            } SymbolicLinkReparseBuffer;
            struct
            {
                USHORT SubstituteNameOffset;
                USHORT SubstituteNameLength;
                USHORT PrintNameOffset;
                USHORT PrintNameLength;
                WCHAR PathBuffer[1];
            } MountPointReparseBuffer;
            struct
            {
                UCHAR  DataBuffer[1];
            } GenericReparseBuffer;
        };
    } REPARSE_DATA_BUFFER;
    REPARSE_DATA_BUFFER* pRDB = reinterpret_cast<REPARSE_DATA_BUFFER*>(buffer);
    if (pRDB->ReparseTag == IO_REPARSE_TAG_SYMLINK)
    {
        int nameLength = pRDB->SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof(wchar_t);
        wchar_t* pName = (wchar_t*)((char*)pRDB->SymbolicLinkReparseBuffer.PathBuffer + pRDB->SymbolicLinkReparseBuffer.SubstituteNameOffset);
        int bytesWritten = WideCharToMultiByte(CP_UTF8, 0, pName, nameLength, link, linksize, NULL, NULL);
        return bytesWritten;
    }
    CloseHandle(h);
    return -1;
}

你的回答可以通过提供更多支持信息来改进。请[编辑]以添加进一步的细节,例如引用或文档,以便他人可以确认你的答案是正确的。您可以在帮助中心中找到有关如何编写良好答案的更多信息。 - Community

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接