premake-core
premake-core copied to clipboard
os.reparse(path) or/and path.getfinal(path, recursive) to solve symbolic files or directories
ex:
os.reparse(path)
or/and
path.getfinal(path, /*recursive = */true)
What problem will this solve? It will ensure paths are unified when source files are located into symbolic directories (at least on Windows). In my case source files are different from generated PDB which makes Visual Studio to open multiple version of the same file as itself doesn't solve that symbolic link.
What might be a solution? On windows you can use internally something like this : (code not tested as is but inspired from the code I use myself in my library to solve reparsing)
HANDLE hFile;
std::string finalPath;
char lnk[256];
memset(lnk, 0, 256);
for (auto part : path_parts) // every part separated by / or \\
{
finalPath = finalPath.empty() ? part : finalPath + '\\' + part;
DWORD dwAttrib = GetFileAttributesA(finalPath.c_str());
if ((dwAttrib == INVALID_FILE_ATTRIBUTES))
return originalPath;
if (((dwAttrib & FILE_ATTRIBUTE_REPARSE_POINT) == FILE_ATTRIBUTE_REPARSE_POINT))
{
// reparse point :
hFile = CreateFileA(finalPath .c_str(), // file to open
GENERIC_READ, // open for reading
FILE_SHARE_READ, // share for reading
NULL, // default security
OPEN_EXISTING, // existing file only
(dwAttrib & FILE_ATTRIBUTE_DIRECTORY) ? FILE_FLAG_BACKUP_SEMANTICS
: FILE_ATTRIBUTE_NORMAL, // normal file
NULL);
if (hFile == INVALID_HANDLE_VALUE)
return originalPath;
GetFinalPathNameByHandleA(hFile, lnk, 256, VOLUME_NAME_DOS);
::CloseHandle(hFile);
if (*lnk)
{
finalPath = std::string(lnk + 4); // reparse adds extra unwanted chars
}
}
}
What other alternatives have you already considered? Tried everything existing (I expected realpath to do the job, but it does not)
Anything else we should know? That would save me some very hard headaches inside Visual Studio ! And it will make your API more complete on the path side !
(You can now support Premake on our OpenCollective. Your contributions help us spend more time responding to requests like these!)
I think your first inclination was correct: this should be handled by os.realpath(), rather than adding an entirely new API. Any chance you can integrate this fix with the existing os.realpath() code?
Here's an untested implementation I wrote up.
char* os_realpath_windows(char* result, const char* path)
{
char pathCopy[PATH_MAX];
strcpy(pathCopy, path);
HANDLE hFile;
memset(result, 0, PATH_MAX);
char lnk[PATH_MAX];
memset(lnk, 0, PATH_MAX);
char* token = strtok(pathCopy, "/\\");
while (token != NULL) {
if (*result != '\0')
{
strcat(result, "\\");
strcat(result, token);
}
DWORD dwAttrib = GetFileAttributesA(result);
if ((dwAttrib == INVALID_FILE_ATTRIBUTES))
{
return NULL;
}
if (((dwAttrib & FILE_ATTRIBUTE_REPARSE_POINT) == FILE_ATTRIBUTE_REPARSE_POINT))
{
// reparse point :
hFile = CreateFileA(result, // file to open
GENERIC_READ, // open for reading
FILE_SHARE_READ, // share for reading
NULL, // default security
OPEN_EXISTING, // existing file only
(dwAttrib & FILE_ATTRIBUTE_DIRECTORY) ? FILE_FLAG_BACKUP_SEMANTICS
: FILE_ATTRIBUTE_NORMAL, // normal file
NULL);
if (hFile == INVALID_HANDLE_VALUE)
return NULL;
GetFinalPathNameByHandleA(hFile, lnk, PATH_MAX, VOLUME_NAME_DOS);
CloseHandle(hFile);
if (*lnk)
{
strcpy(result, lnk + 4);
}
}
// get next token
token = strtok(NULL, "/\\");
}
return result;
}
@vlmillet Would you be willing to see if that works for your case? Just replace _realpath in os_realpath.c with that function.