https://bugs.winehq.org/show_bug.cgi?id=56399
--- Comment #3 from tncgyp+uypezc35u0dyxed6tszn0wk59xjphxb2gcxycxno8mxg4od48@sharklasers.com --- The problematic code is in: wine/programs/cmd/batch.c, function WCMD_HandleTildeModifiers @ line 546
/* 4. Handle 's' : Use short paths (File doesn't have to exist) */ if (wmemchr(firstModifier, 's', modifierLen) != NULL) { if (finaloutput[0] != 0x00) lstrcatW(finaloutput, L" ");
/* Convert fullfilename's path to a short path - Save filename away as only path is valid, name may not exist which causes GetShortPathName to fail if it is provided */ if (filepart) { lstrcpyW(thisoutput, filepart); *filepart = 0x00; GetShortPathNameW(fullfilename, fullfilename, ARRAY_SIZE(fullfilename)); lstrcatW(fullfilename, thisoutput); } }
The first question is, why does the conversion always take place without the file at the end of the path? This is always wrong for file names with more than 8 characters.
The second question is why a directory at the end of the path is recognized as a file?
To solve the first question, my proposal would be the following change:
/* 4. Handle 's' : Use short paths (File doesn't have to exist) */ if (wmemchr(firstModifier, 's', modifierLen) != NULL) { if (finaloutput[0] != 0x00) lstrcatW(finaloutput, L" ");
if (exists) { GetShortPathNameW(fullfilename, fullfilename, ARRAY_SIZE(fullfilename)); } else { WIN32_FILE_ATTRIBUTE_DATA dirInfo; int i_end = lstrlenW(fullfilename); int i_cut = i_end; i = i_end; while (i-- > 0) { /* Cut the last element of the path chain until the path resolves to a existing directory */ if (fullfilename[i] == L'\' || fullfilename[i] == L'/') { /* Undo the previous cut */ if (i_cut < i_end) fullfilename[i_cut] = L'\'; fullfilename[i] = 0x00; i_cut = i; if (GetFileAttributesExW(fullfilename, GetFileExInfoStandard, &dirInfo) != FALSE) { /* Keep the non-existing end of the path chain and append it to the new short path */ lstrcpyW(&thisoutput[1], &fullfilename[i_cut + 1]); thisoutput[0] = L'\'; GetShortPathNameW(fullfilename, fullfilename, ARRAY_SIZE(fullfilename)); lstrcatW(fullfilename, thisoutput); break; } } } } }
Unfortunately I can't test this at the moment so I would be happy if someone could perhaps take this on.