Added function to a file's path from a handle (file descriptor).

This commit is contained in:
LoRd_MuldeR 2015-11-22 17:33:25 +01:00
parent b926f98ee7
commit ae605d9d1e
2 changed files with 144 additions and 0 deletions

View File

@ -181,6 +181,9 @@ namespace MUtils
//Shell notification
MUTILS_API void shell_change_notification(void);
//Get file path from descriptor
MUTILS_API QString get_file_path(const int &fd);
//WOW64 redirection
MUTILS_API bool wow64fsredir_disable(void *oldValue);
MUTILS_API bool wow64fsredir_revert (void *oldValue);

View File

@ -715,6 +715,147 @@ quint64 MUtils::OS::current_file_time(void)
return temp.QuadPart;
}
///////////////////////////////////////////////////////////////////////////////
// FILE PATH FROM FD
///////////////////////////////////////////////////////////////////////////////
typedef DWORD(_stdcall *GetPathNameByHandleFun)(HANDLE hFile, LPWSTR lpszFilePath, DWORD cchFilePath, DWORD dwFlags);
static QReadWriteLock g_getFilePath_lock;
static QScopedPointer<QLibrary> g_getFilePath_kernel32;
static GetPathNameByHandleFun g_getFilePath_prt = NULL;
static QString get_file_path_drive_list(void)
{
QString list;
const DWORD len = GetLogicalDriveStringsW(0, NULL);
if (len > 0)
{
if (wchar_t *const buffer = (wchar_t*) _malloca(sizeof(wchar_t) * len))
{
const DWORD ret = GetLogicalDriveStringsW(len, buffer);
if ((ret > 0) && (ret < len))
{
const wchar_t *ptr = buffer;
while (const size_t current_len = wcslen(ptr))
{
list.append(QChar(*reinterpret_cast<const ushort*>(ptr)));
ptr += (current_len + 1);
}
}
_freea(buffer);
}
}
return list;
}
static QString &get_file_path_translate(QString &path)
{
static const DWORD BUFSIZE = 4096;
wchar_t buffer[BUFSIZE], drive[3];
const QString driveList = get_file_path_drive_list();
wcscpy_s(drive, 3, L"?:");
for (const wchar_t *current = MUTILS_WCHR(driveList); *current; current++)
{
drive[0] = (*current);
if (QueryDosDeviceW(drive, buffer, MAX_PATH))
{
const QString prefix = MUTILS_QSTR(buffer);
if (path.startsWith(prefix, Qt::CaseInsensitive))
{
path.remove(0, prefix.length()).prepend(QLatin1Char(':')).prepend(QChar(*reinterpret_cast<const ushort*>(current)));
break;
}
}
}
return path;
}
static QString get_file_path_fallback(const HANDLE &hFile)
{
QString filePath;
const HANDLE hFileMap = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 1, NULL);
if (hFileMap)
{
void* pMem = MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 1);
if (pMem)
{
static const DWORD BUFSIZE = 4096;
wchar_t buffer[BUFSIZE];
if (GetMappedFileNameW(GetCurrentProcess(), pMem, buffer, BUFSIZE))
{
filePath = get_file_path_translate(MUTILS_QSTR(buffer));
}
UnmapViewOfFile(pMem);
}
CloseHandle(hFileMap);
}
return filePath;
}
static bool get_file_path_init()
{
QWriteLocker writeLock(&g_getFilePath_lock);
if (g_getFilePath_prt)
{
return true; /*already initialized*/
}
if (g_getFilePath_kernel32.isNull())
{
g_getFilePath_kernel32.reset(new QLibrary("kernel32.dll"));
}
if (!g_getFilePath_kernel32->isLoaded())
{
if (!g_getFilePath_kernel32->load())
{
return false; /*faild to load kernel32.dll*/
}
}
g_getFilePath_prt = (GetPathNameByHandleFun) g_getFilePath_kernel32->resolve("GetFinalPathNameByHandleW");
return (g_getFilePath_prt != NULL);
}
QString MUtils::OS::get_file_path(const int &fd)
{
if (fd >= 0)
{
QReadLocker readLock(&g_getFilePath_lock);
if (!g_getFilePath_prt)
{
readLock.unlock();
if (!get_file_path_init())
{
qWarning("MUtils::OS::get_file_path() --> fallback!");
return get_file_path_fallback((HANDLE)_get_osfhandle(fd));
}
readLock.relock();
}
const HANDLE handle = (HANDLE) _get_osfhandle(fd);
const DWORD len = g_getFilePath_prt(handle, NULL, 0, FILE_NAME_OPENED);
if (len > 0)
{
wchar_t *const buffer = (wchar_t*) _malloca(sizeof(wchar_t) * len);
const DWORD ret = g_getFilePath_prt(handle, buffer, len, FILE_NAME_OPENED);
if ((ret > 0) && (ret < len))
{
const QString path(MUTILS_QSTR(buffer));
return path.startsWith(QLatin1String("\\\\?\\")) ? path.mid(4) : path;
}
}
}
return QString();
}
///////////////////////////////////////////////////////////////////////////////
// PROCESS ELEVATION
///////////////////////////////////////////////////////////////////////////////