2010-12-14 43 views
5

Je travaille sur le rapport de certaines informations glanées à partir des API du système natif. (Je sais que c'est mauvais ... mais je reçois des informations que je ne peux pas obtenir autrement, et je n'ai pas besoin de mettre à jour mon application si/quand ce temps vient.)Comment puis-je convertir un chemin d'accès natif (NT) en nom de chemin Win32?

L'API renvoie des chemins d'accès natifs, comme vu par ob, c'est-à-dire \SystemRoot\System32\Ntoskrnl.exe, ou \??\C:\Program Files\VMWare Workstation\vstor-ws60.sys.

Je peux remplacer les préfixes communs, à savoir

std::wstring NtPathToWin32Path(std::wstring ntPath) 
{ 
    if (boost::starts_with(ntPath, L"\\\\?\\")) 
    { 
     ntPath.erase(ntPath.begin(), ntPath.begin() + 4); 
     return ntPath; 
    } 
    if (boost::starts_with(ntPath, L"\\??\\")) 
    { 
     ntPath.erase(ntPath.begin(), ntPath.begin() + 4); 
    } 
    if (boost::starts_with(ntPath, L"\\")) 
    { 
     ntPath.erase(ntPath.begin(), ntPath.begin() + 1); 
    } 
    if (boost::istarts_with(ntPath, L"globalroot\\")) 
    { 
     ntPath.erase(ntPath.begin(), ntPath.begin() + 11); 
    } 
    if (boost::istarts_with(ntPath, L"systemroot")) 
    { 
     ntPath.replace(ntPath.begin(), ntPath.begin() + 10, GetWindowsPath()); 
    } 
    if (boost::istarts_with(ntPath, L"windows")) 
    { 
     ntPath.replace(ntPath.begin(), ntPath.begin() + 7, GetWindowsPath()); 
    } 
    return ntPath; 
} 

TEST(Win32Path, NtPathDoubleQuestions) 
{ 
    ASSERT_EQ(L"C:\\Example", NtPathToWin32Path(L"\\??\\C:\\Example")); 
} 

TEST(Win32Path, NtPathUncBegin) 
{ 
    ASSERT_EQ(L"C:\\Example", NtPathToWin32Path(L"\\\\?\\C:\\Example")); 
} 

TEST(Win32Path, NtPathWindowsStart) 
{ 
    ASSERT_EQ(GetCombinedPath(GetWindowsPath(), L"Hello\\World"), NtPathToWin32Path(L"\\Windows\\Hello\\World")); 
} 

TEST(Win32Path, NtPathSystemrootStart) 
{ 
    ASSERT_EQ(GetCombinedPath(GetWindowsPath(), L"Hello\\World"), NtPathToWin32Path(L"\\SystemRoot\\Hello\\World")); 
} 

TEST(Win32Path, NtPathGlobalRootSystemRoot) 
{ 
    ASSERT_EQ(GetCombinedPath(GetWindowsPath(), L"Hello\\World"), NtPathToWin32Path(L"\\globalroot\\SystemRoot\\Hello\\World")); 
} 

mais je serais fort surpris s'il n'y a pas une API, natif ou autre, qui les convertir en noms de chemin Win32. Est-ce qu'une telle API existe?

+0

Est-ce que la fonction API shell 'PathCanonicalize' faire l'affaire? http://msdn.microsoft.com/en-us/library/bb773569%28v=vs.85%29.aspx – Praetorian

+0

@Praetorian: Non, PathCanonicalize accepte les chemins d'accès Win32. J'essaie d'obtenir un chemin win32. –

+1

Je ne connais pas une telle fonction, et ce n'est pas toujours possible: NT peut utiliser des chemins que Win32 ne peut pas du tout. Bonne chance de toute façon ... – ephemient

Répondre

6

Nous faisons cela dans le code de production. Autant que je sache, il n'y a pas d'API (publique ou privée) qui gère cela. Nous faisons juste quelques comparaisons de chaînes avec quelques préfixes et cela fonctionne pour nous.

Apparemment, il existe une fonction nommée RtlNtPathNameToDosPathName() dans ntdll.dll (introduite avec XP?), Mais je n'ai aucune idée de ce qu'elle fait; Je suppose que cela a plus à voir avec des choses comme \ Device \ Harddisk0, cependant.

Je ne suis pas sûr qu'il y ait vraiment besoin d'une telle fonction, cependant. Win32 transmet les chemins (dans le sens de CreateFile, etc) à NT; NT ne transmet pas de chemins à Win32. Donc ntdll.dll n'a pas vraiment besoin de passer des chemins NT aux chemins Win32. Dans le cas rare où une fonction de requête NT renvoie un chemin d'accès complet, toute fonction de conversion peut être interne à la DLL Win32 (par exemple, non exportée). Je ne sais même pas si elles dérangent, comme des choses comme GetModuleFileName() retournera juste le chemin utilisé pour charger l'image. Je suppose que c'est juste une abstraction qui fuit.

+0

+1. Edité ma question - que quelque chose comme ce que vous faites? –

+0

À peu près. Les seuls que j'ai vus sur une base régulière sont \\ ?? \\ et \\ SystemRoot, et même alors c'est plutôt rare (typiquement avec des processus de bas niveau lancés au début de la séquence de démarrage. – Luke

+0

Je suis en train de déblatérer avec des choses non documentées et tous ces préfixes semblent être communs ici. Je suppose qu'il y a une raison pour laquelle ils ne sont pas documentés: P –

4

Voici quelque chose que vous pourriez essayer. D'abord, utilisez NtCreateFile pour ouvrir le fichier, le volume etc. pour la lecture. Utilisez ensuite le HANDLE retourné pour obtenir le chemin complet comme décrit here.

+1

+1 :) Notez que l'on peut probablement passer l'étape de mappage de fichier en appelant 'NtQueryFileInformation' et en demandant la classe d'information' FileNameInformation'. (Bien que je ne l'ai pas testé ce encore, et bien sûr ce qui se passe dans les choses sans papier ...) –

+0

GetFinalPathNameByHandle pourrait aider à nettoyer cette place! – Gbps

1

Voir my answer to this question.

Vous devez d'abord obtenir un handle pour le fichier à ce chemin, puis obtenir le chemin d'accès Win32 pour le handle.

+0

Cela fonctionne - mais le problème est que vous avez besoin d'accéder à l'emplacement du fichier pour l'exécuter (parce que vous devez être en mesure d'ouvrir une poignée) - souvent je n'ai pas cela. –

+0

@Billy: Tout ce dont vous avez besoin est un accès 'FILE_READ_ATTRIBUTES', que vous pouvez presque toujours obtenir. Si vous ne pouvez pas l'obtenir, essayez-le sur le répertoire parent, puis concaténez le nom du fichier à la fin. (Vous ne pouvez pas convertir sans poignée, car il est pas toujours une correspondance biunivoque.) – Mehrdad

+0

@Mehrdad: Cela doit être possible de convertir sans poignée. FindFirstFile/FindNextFile/FindClose n'ouvre pas les handles. Vous pouvez les utiliser pour lister une structure de répertoire même si vous ne pouvez lire aucun attribut sur le fichier. Cette solution fonctionne, donc +1, mais cela ne m'aide vraiment pas :( –

0

J'ai écrit une fonction qui convertit différents types de noms de périphériques NT (noms de fichiers, ports COM, chemins réseau, etc.) en un chemin DOS.

Il y a deux fonctions. L'un convertit un handle en un chemin NT et l'autre convertit ce chemin NT en un chemin DOS.

Jetez un oeil ici: How to get name associated with open HANDLE

// "\Device\HarddiskVolume3"        (Harddisk Drive) 
// "\Device\HarddiskVolume3\Temp"       (Harddisk Directory) 
// "\Device\HarddiskVolume3\Temp\transparent.jpeg"   (Harddisk File) 
// "\Device\Harddisk1\DP(1)0-0+6\foto.jpg"     (USB stick) 
// "\Device\TrueCryptVolumeP\Data\Passwords.txt"   (Truecrypt Volume) 
// "\Device\Floppy0\Autoexec.bat"       (Floppy disk) 
// "\Device\CdRom1\VIDEO_TS\VTS_01_0.VOB"     (DVD drive) 
// "\Device\Serial1"          (real COM port) 
// "\Device\USBSER000"          (virtual COM port) 
// "\Device\Mup\ComputerName\C$\Boot.ini"     (network drive share, Windows 7) 
// "\Device\LanmanRedirector\ComputerName\C$\Boot.ini"  (network drive share, Windwos XP) 
// "\Device\LanmanRedirector\ComputerName\Shares\Dance.m3u" (network folder share, Windwos XP) 
// "\Device\Afd"           (internet socket) 
// "\Device\Console000F"         (unique name for any Console handle) 
// "\Device\NamedPipe\Pipename"        (named pipe) 
// "\BaseNamedObjects\Objectname"       (named mutex, named event, named semaphore) 
// "\REGISTRY\MACHINE\SOFTWARE\Classes\.txt"    (HKEY_CLASSES_ROOT\.txt)