Komfortabler Dateimanager mit vielen Funktionen

Langsame Laufwerke

By Sven on 06.01.2005 - 22:45 in Entwicklung

Bei der Optimierung der Dateianzeige für VPN-Laufwerke bin ich über die Funktion PathIsSlow gestolpert. Die Dokumentation im Platform SDK ist nicht gerade aussagekräftig, eine Eigenschaft, die leider für viele Funktionen zutrifft, welche erst 2002 im Zuge des Antitrust-Prozesses gegen Microsoft dokumentiert wurden. In der Funktionsbeschreibung zu PathIsSlow steht

Determines whether a file path is a high-latency network connection.

Doch nach welchen Kriterien legt Windows fest, ob es sich für den angegebenen Dateinamen um eine langsame oder um eine schnelle Verbindung handelt?

Um dies herauszufinden, habe ich mir die Funktion im Debugger mal etwas näher angeschaut. Mit Hilfe der von Microsoft angebotenen Symboldateien lässt sich mit ein wenig Assembler-Kenntnis einiges herausfinden. PathIsSlow ist eine recht kurze Funktion und sieht wie folgt aus:

PathIsSlowW@8:
773DA350 push esi
773DA351 mov esi,dword ptr [esp+8]
773DA355 push esi
773DA356 call dword ptr [__imp__PathIsUNCW@4 (773a20a8)]
773DA35C test eax,eax
773DA35E push esi
773DA35F jne _PathIsSlowW@8+11h (774478bc)
773DA365 call dword ptr [__imp__PathGetDriveNumberW@4 (773a20e4)]
773DA36B push eax
773DA36C call _CMtPt_IsSlow@4 (773da388)
773DA371 test eax,eax
773DA373 jne _PathIsSlowW@8+21h (773da383)
773DA375 push dword ptr [esp+0Ch]
773DA379 push esi
773DA37A call _PathIsHighLatency@8 (773da3b8)
773DA37F pop esi
773DA380 ret 8
773DA383 xor eax,eax
773DA385 inc eax
773DA386 jmp _PathIsSlowW@8+40h (773da37f)

Zuerst wird mit Hilfe der Funktion PathIsUNC geprüft, ob der Dateiname in der UNC-Konvention (\\Server\Freigabe) vorliegt. Wenn ja, verzweigt PathIsSlow zur Adresse 0x774478bc. Befindet sich der Dateiname dagegen auf einem gemappten Laufwerk, dann wird über PathGetDriveNumber der Laufwerksbuchstabe ermittelt und mit diesem die Funktion CMtPt_IsSlow aufgerufen:

_CMtPt_IsSlow@4:
773DA388 push esi
773DA389 push edi
773DA38A push 1
773DA38C xor edi,edi
773DA38E push edi
773DA38F push dword ptr [esp+14h]
773DA393 call CMountPoint::GetMountPoint (773cb43b)
773DA398 mov esi,eax
773DA39A cmp esi,edi
773DA39C je _CMtPt_IsSlow@4+29h (773da3b1)
773DA39E mov eax,dword ptr [esi]
773DA3A0 mov ecx,esi
773DA3A2 call dword ptr [eax+0CCh]
773DA3A8 mov ecx,esi
773DA3AA mov edi,eax
773DA3AC call CMountPoint::Release (773cb385)
773DA3B1 mov eax,edi
773DA3B3 pop edi
773DA3B4 pop esi
773DA3B5 ret 4

In dieser Funktion wird geprüft, ob es für den gewünschten Laufwerksbuchstaben ein CMountPoint-Objekt gibt. Im Erfolgsfall wird CMtPtRemote::IsSlow (0x773DA3A2) aufgerufen:

_IsSlow@CMtPtRemote@@EAEHXZ:
77521018 push esi
77521019 xor esi,esi
7752101B call CMtPtRemote::_GetPathSpeed (77517e98)
77521020 test eax,eax
77521022 je CMtPtRemote::_IsSlow+14h (7752102c)
77521024 cmp eax,190h
77521029 ja CMtPtRemote::_IsSlow+14h (7752102c)
7752102B inc esi
7752102C mov eax,esi
7752102E pop esi
7752102F ret

Windows verzweigt weiter zur Funktion CMtPtRemote::GetPathSpeed:

_GetPathSpeed@CMtPtRemote@@AAEKXZ:
77517E98 push esi
77517E99 lea esi,[ecx+25Ch]
77517E9F cmp dword ptr [esi],0
77517EA2 jne CMtPtRemote::_GetPathSpeed+11h (77517ea9)
77517EA4 call CMtPtRemote::_CalcPathSpeed (77517cbb)
77517EA9 mov eax,dword ptr [esi]
77517EAB pop esi
77517EAC ret

und prüft, ob die Geschwindigkeit für das MountPoint-Objekt bereits berechnet und gespeichert wurde. Wenn ja, dann wird dieser Wert zurückgegeben. Ansonsten verzweigt Windows zur Funktion CMtPtRemote::CalcPathSpeed und berechnet mit Hilfe von MultinetGetConnectionPerformance die Geschwindigkeit. Diese wird in einer NETCONNECTINFOSTRUCT-Struktur zurückgeben und besitzt folgende Bedeutung:

Speed of the media to the network resource, in 100 bits-per-second (bps).

For example, a 1200 baud point-to-point link returns 12. A value of zero indicates that no information is available. A value of one indicates that the actual value is greater than the maximum that can be represented by the member.

In der Funktion CMtPtRemote::IsSlow sieht man an der Adresse 0x77521024, dass die ermittelte Geschwindigkeit mit 0x190 (400) verglichen wird. Ist sie größer als 400, dann gilt das Laufwerk als schnell; ist sie kleiner oder gleich 400, dann ist das Laufwerk langsam. 40000 bps ist also die Grenze für ein langsames Laufwerk. Nach meinem Verständnis ist dies eine normale Modemverbindung, anhand der gemessenen Werten ist für mich die Bedeutung dieses Wertes allerdings nicht ganz klar:

Verbindung Geschwindigkeit
1 MBit (VPN DSL)    104
10 MBit 948
54 MBit (WLAN) 2044
100 MBit 2115
1 GBit 7972

Die VPN-Verbindung fällt noch eindeutig in den langsamen Bereich, während die 10 MBit-Netzwerkanbindung schon deutlich zu schnell ist, um noch als langsam zu gelten.

Doch nun wieder zurück zu PathIsSlow. Die Ermittlung der Geschwindigkeit für UNC-Namen in der Funktion GetPathSpeed erfolgt ebenfalls über MultinetGetConnectionPerformance, den Abdruck der Funktion habe ich mir jetzt erspart. Sollte die Geschwindigkeitsprüfung für den Dateinamen ergeben, dass er sich nicht auf einem langsamen Laufwerk befindet, ruft Windows noch die Funktion PathIsHighLatency auf. Diese ist leider nicht dokumentiert und sieht wie folgt aus:

_PathIsHighLatency@8:
773DA3B8 mov eax,dword ptr [esp+8]
773DA3BC push esi
773DA3BD xor esi,esi
773DA3BF cmp eax,0FFFFFFFFh
773DA3C2 jne _PathIsHighLatency@8+26h (773da3d9)
773DA3C4 cmp dword ptr [esp+8],esi
773DA3C8 je _PathIsHighLatency@8+1Eh (773da3e8)
773DA3CA push dword ptr [esp+8]
773DA3CE call dword ptr [__imp__GetFileAttributesW@4 (773a1a38)]
773DA3D4 cmp eax,0FFFFFFFFh
773DA3D7 je _PathIsHighLatency@8+2Eh (773da3e2)
773DA3D9 test ah,10h
773DA3DC jne _PathIsHighLatency@8+2Bh (774478b4)
773DA3E2 mov eax,esi
773DA3E4 pop esi
773DA3E5 ret 8
773DA3E8 or eax,0FFFFFFFFh
773DA3EB jmp _PathIsHighLatency@8+21h (773da3d4)

Anhand der Dateiattribute, die der Funktion PathIsSlow übergeben worden sind, wird geprüft, ob das Attribut FILE_ATTRIBUTE_OFFLINE gesetzt ist. Dieses Flag wird von Remote Storage Systemen verwendet und gibt an, dass die Daten im Moment ausgelagert sind. Werden an PathIsSlow keine Dateiattribute übergeben, so ermittelt PathIsHighLatency die Attribute über GetFileAttributes selbst.

Das Rätsel um langsame Laufwerke ist nun (fast) gelüftet. PathIsSlow nutzt die Funktion MultinetGetConnectionPerformance, um die Geschwindigkeit zu bestimmen. Zusätzlich wird noch geprüft, ob sich die Datei auf einem Remote Storage System befindet und dort im Moment ausgelagert ist. Unklar ist bisher leider noch, wie sich die von MultinetGetConnectionPerformance zurückgegebene Geschwindigkeit einordnen lässt.

Es gibt einen Kommentar zu diesem Beitrag

Trackback URL | RSS-Feed für Kommentare

  1. Uwe Keim sagt:

    Das nenne ich mal gut beschrieben. Weiter so! 🙂

Top