From d6f4c0887ad5bc608a1d470c4ca00a4b1c9d936c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Herm=C3=A8s=20B=C3=A9lusca-Ma=C3=AFto?= Date: Mon, 27 Apr 2026 20:24:24 +0200 Subject: [PATCH] [MKSHELLLINK] Fix a bug in the special shell folder handling code (#8936) Addendum to commit 7b081be46d (PR #7158). CORE-15156, CORE-19691, CORE-19692 Since commit 7b081be46d (PR #7158), one can create shell links that point to a file in a subdirectory of SystemRoot (e.g. X:\reactos) or SystemRoot\system32 using a shell "special shell folder" syntax, for example: `shell:windows\Readme.txt` (--> X:\reactos\Readme.txt) , `shell:windows\system32\cmd.exe` , or: `shell:system\cmd.exe` (--> X:\reactos\system32\cmd.exe) . An `EXP_SPECIAL_FOLDER` data block allows parts of a shortcuts pidl to be overridden by such a special folder. - In these cases, try to build the shortcut pidl such that it faithfully mirrors the intended path. For example, when using `shell:system\cmd.exe`, resolve the `shell:system` part to `X:\reactos\system32` instead of just `X:\reactos` ; this helps understanding what happens when spelunking into such a shell link. This also helps when converting such a path to one containing unexpanded environment variables, for the purposes of making the Windows explorer shell show the correct shortcut target path, or resolve it independently of the SystemRoot being used; and, to be able to use the path for the shortcut icon. - Get rid of the `index`/`specialindex` variables. These were used for making the `EXP_SPECIAL_FOLDER` data block point to the correct path suffix part that follows the special path prefix in the ID list. Hardcoding its value caused problems when the special path prefix is made to contain more path elements than just "X:\reactos". For example, "X:\reactos\system32" in the case of the `shell:system` prefix. Instead, retrieve the length of the special path prefix, then, compare it with the length of the path elements being parsed in the loop. ---- This problem was made explicit when the the following code path is run: ``` shell32!CShellLink.cpp:CShellLink::Load(IStream *stm) --> ILCombine(folder, m_pPidl + pSpecial->cbOffset) ``` --- sdk/tools/mkshelllink/mkshelllink.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/sdk/tools/mkshelllink/mkshelllink.c b/sdk/tools/mkshelllink/mkshelllink.c index 770ab751ef7..ed22c1878c1 100644 --- a/sdk/tools/mkshelllink/mkshelllink.c +++ b/sdk/tools/mkshelllink/mkshelllink.c @@ -194,10 +194,11 @@ static const struct SPECIALFOLDER { unsigned char csidl; const char* name; + const char* dummyPath; } g_specialfolders[] = { - { CSIDL_WINDOWS, "windows" }, - { CSIDL_SYSTEM, "system" }, - { 0, NULL} + { CSIDL_WINDOWS, "windows", "X:\\reactos" }, + { CSIDL_SYSTEM, "system", "X:\\reactos\\system32" }, + { 0, NULL, NULL } }; @@ -338,7 +339,7 @@ int main(int argc, const char *argv[]) ID_LIST_DRIVE IdListDrive; unsigned cbListSize = sizeof(IdListGuid) + sizeof(uint16_t), cchName; const char *pszName = pszTarget; - int index = 1, specialindex = -1; + size_t specialPathLen = 0; const struct SPECIALFOLDER *special = get_special_folder(pszTarget); /* ID list. It appears explorer does not accept links @@ -349,14 +350,13 @@ int main(int argc, const char *argv[]) CsidlBlock.cbSize = sizeof(CsidlBlock); CsidlBlock.dwSignature = EXP_SPECIAL_FOLDER_SIG; CsidlBlock.idSpecialFolder = special->csidl; - specialindex = 3; // Skip GUID, drive and fake windows/reactos folder - sprintf(targetpath, "x:\\reactos\\%s", pszTarget + sizeof("shell:") + strlen(special->name)); + specialPathLen = strlen(special->dummyPath); + sprintf(targetpath, "%s\\%s", special->dummyPath, pszTarget + sizeof("shell:") + strlen(special->name)); pszName = pszTarget = targetpath; } if (pszName[0] && pszName[0] != ':' && pszName[1] == ':') { - ++index; cbListSize += sizeof(IdListDrive); pszName += 2; while (is_path_separator(*pszName)) @@ -372,8 +372,9 @@ int main(int argc, const char *argv[]) if (cchName != 1 || pszName[0] != '.') cbListSize += sizeof(IdListFile) + 2 * (cchName + 1); - if (++index == specialindex) + if (special && ((pszName+cchName)-pszTarget == specialPathLen)) { + /* Point the special folder block to the rest of the path in the ID list */ CsidlBlock.cbOffset = cbListSize - sizeof(uint16_t); pCsidlBlock = &CsidlBlock; }