Die Tiefen von Windows I/O (Teil 5) — NTFS-Interna: Das Dateisystem anhand des MFT verstehen

· · Windows, NTFS, I/O, Dateisystem, MFT, Kernel, .NET, Fehleranalyse

In den vier bisherigen Teilen haben wir verfolgt, wie eine I/O-Anforderung fließt (Teile 1–3) und wie der Cache-Manager sie entgegennimmt (Teil 4). Am Ende landet die Anforderung beim Dateisystem. Diesmal ist sein prominentester Vertreter an der Reihe: NTFS.

Der Blickwinkel wechselt hier. Bisher ging es um eine dynamische Geschichte — den Fluss einer Anforderung. Diesmal geht es um eine statische Geschichte darüber, wie Daten auf dem Datenträger abgelegt werden. Die wahre Identität des unsichtbaren „Zone.Identifier“, der an einer heruntergeladenen Datei hängt. Warum das Kopieren von zehntausend kleinen Dateien so viel langsamer ist als das Kopieren einer einzigen Datei gleicher Gesamtgröße. Wie weit „NTFS ist Journaling, also ist es sicher“ wirklich stimmt — all das lässt sich aus dieser Struktur erklären.

Dies ist Teil 5 der Serie „Die Tiefen von Windows I/O“.

Voraussetzung für diesen Teil: Es hilft, die Grundlagen zu IRPs und dem Gerätestapel aus Teil 1 bereits zu kennen. Damit dieser Artikel aber auch für sich allein steht, sind hier die Begriffe aus früheren Teilen definiert, die im Folgenden vorkommen.

Begriff In einem Satz Details
IRP (I/O Request Packet) Der „Laufzettel für eine I/O-Anforderung“, in den ein API-Aufruf wie ReadFile im Kernel umgewandelt wird. Treiber nehmen diesen Zettel entgegen und arbeiten ihn ab Teil 1
Der I/O-Manager und der Gerätestapel Die Kernel-Komponente, die das IRP erzeugt und der Reihe nach an den Stapel von Treibern weiterreicht, der bis zum Zielgerät aufgetürmt ist — sowie dieser Stapel selbst Teil 1
Der Cache-Manager Die Komponente, die den Inhalt einer Datei im Speicher hält und die gesammelten Inhalte von WriteFile-Aufrufen später auf den Datenträger schreibt. Die Ursache dafür, dass „geschrieben“ nicht bedeutet, dass es schon auf dem Datenträger angekommen ist Teil 4

Tabelle 1: Begriffe aus früheren Teilen, die in dieser Folge vorausgesetzt werden

Noch etwas: Die beiden Phasen aus Teil 1 — cleanup (wenn das letzte Handle geschlossen wird) und close (wenn jede Referenz im Kernel verschwunden ist) — werden auch in der Erklärung des Datei-Löschens in Abschnitt 4 verwendet.

1. Das Wichtigste zuerst

  • NTFS ist rund um die MFT (Master File Table) aufgebaut. Jede Datei wird als Datensatz in diesem Verzeichnis geführt, und alles, was zu einer Datei gehört, liegt entweder „innerhalb des MFT-Eintrags“ oder „in dem Bereich außerhalb der MFT, auf den der Eintrag verweist“ (Abschnitt 2).1
  • Das Wesen einer Datei ist „eine Sammlung von Attributen“. Eine kleine Datei passt mitsamt ihren Daten vollständig in ihren MFT-Datensatz (resident); eine große Datei besitzt nur einen Verweis auf eine Folge von Clustern (nicht resident). Das erklärt, warum die Verarbeitung riesiger Mengen kleiner Dateien so langsam ist (Abschnitt 2).1
  • Eine Datei kann mehr als einen Datenstrom besitzen (mehrere Datenströme). Die Daten, die man normalerweise sieht, sind der „unbenannte Stream“; mit datei.txt:name kann eine Datei zusätzliche Streams neben sich führen. Das ist die wahre Identität von Zone.Identifier (Mark of the Web) (Abschnitt 3).2
  • Auch Namen sind Attribute. Wenn ein und derselbe Datensatz mehr als einen Namen trägt, ist das ein Hardlink. Auch der 8.3-Kurzname liegt als „ein weiterer Name“ daneben (Abschnitt 4).34
  • Reparse-Points sind der offizielle Mechanismus für „hier öffnen, dort landen“. Symbolische Links, Junctions und OneDrive Files On-Demand sind allesamt Anwendungen dieser mit einem Tag versehenen Daten (Abschnitt 5).56
  • Es gibt zwei Journale. $LogFile dient der Wiederherstellung der Metadaten-Konsistenz (ein Write-Ahead-Log, damit das Volume nicht beschädigt wird), das USN-Journal dient der Aufzeichnung der Änderungshistorie (ein Verzeichnis dessen, was sich geändert hat). Ihre Rollen sind völlig unterschiedlich (Abschnitt 6).78
  • „Größe“ und „Größe auf dem Datenträger“ sind zwei verschiedene Dinge. Sparse-Dateien und Komprimierung treiben sie auseinander. Auch der Hintergrund von „eine komprimierte Datei wird nie asynchron“, den wir in Teil 2 gesehen haben, liegt hier begründet (Abschnitt 7).910

2. Alles ist ein Datensatz in der MFT

2.1. Das Verzeichnis des Volumes

Beim Formatieren eines NTFS-Volumes entstehen die MFT (master file table) sowie eine Reihe von Metadateien, deren Namen mit $ beginnen. Die MFT enthält mindestens einen Eintrag für jede Datei auf dem Volume, und das schließt einen Eintrag für die MFT selbst mit ein.1

NTFS-VolumeDatensätze verweisen auf den Ort$MFT — die Master File TableVerzeichnis aller Dateidatensätze, sich selbst eingeschlossenBenutzerdatenbereichOrt für nicht resident gespeicherte Daten$LogFile — Transaktionsprotokoll fürMetadatenoperationen, Abschnitt 6$Bitmap — Belegungsstatus der Cluster$Boot / $Secure / $UpCase und weitereMetadateien

Abbildung 1: Der Aufbau eines NTFS-Volumes. Das Designprinzip von NTFS ist, dass sogar die eigenen Verwaltungsinformationen des Dateisystems als Datei geführt werden

Informationen zu einer Datei — Größe, Zeitstempel, Zugriffsrechte und sogar der Dateninhalt selbst — werden entweder im MFT-Eintrag gespeichert oder in einem Bereich außerhalb der MFT, dessen Ort der MFT-Eintrag beschreibt.1 Wird eine Datei gelöscht, wird ihr Eintrag als „frei“ zur Wiederverwendung markiert, aber die MFT selbst schrumpft nie. Die offizielle Dokumentation beschreibt sogar den Lebenszyklus der MFT: Ein Bereich namens MFT-Zone wird reserviert, um die MFT zusammenhängend zu halten, und sobald sich das Volume zu füllen beginnt, setzt die Fragmentierung der MFT ein.1

2.2. Eine Datei ist eine Sammlung von Attributen: resident und nicht resident

Der Inhalt eines Dateidatensatzes ist eine Liste von Attributen: Standardinformationen (Zeitstempel und Ähnliches), der Dateiname, Sicherheitsinformationen und die Daten. Hier gibt es eine wichtige Weiche.

MFT-Dateidatensatz — der Verzeichniseintrag für eine Dateibis etwa ein paar hundert Bytedarüber hinausStandardinformationsattributZeitstempel und AttributflagsDateinamenattributkann mehrfach vorkommen — Abschnitt 4DatenattributSind die Daten klein?ResidentDie Daten selbst passen in den DatensatzZum Lesen genügt ein MFT-ZugriffNicht residentDer Datensatz enthält nur einen Verweis auf eine ClusterfolgeDie eigentlichen Daten liegen im Benutzerdatenbereich

Abbildung 2: Ein Dateidatensatz ist eine Sammlung von Attributen. Sind die Daten klein, „residieren“ sie im Datensatz

Es hilft, nebeneinanderzustellen, wie sich der Inhalt desselben Datensatzes zwischen resident und nicht resident unterscheidet.

Nicht resident — eine große Dateiverweist auf den Ortverweist auf den OrtMFT-Dateidatensatz, feste LängeStandardinfo / Dateiname / Sicherheit─────────────Datenattribut = eine Tabelle von DatenläufenEine Liste von 'ab wo, wie viele Cluster'BenutzerdatenbereichLauf 1 — zusammenhängende ClusterBenutzerdatenbereichLauf 2 — zusammenhängende Cluster an anderer StelleResident — eine kleine DateiMFT-Dateidatensatz, feste LängeStandardinfo / Dateiname / Sicherheit─────────────Datenattribut = der Inhalt selbstz. B. landet 'Einstellung=1' direkt hierEs gibt keinen separaten Ort auf dem DatenträgerZum Lesen genügt allein ein MFT-Zugriff

Abbildung 3: Resident und nicht resident im Vergleich. Bei einer nicht residenten Datei enthält der Datensatz nur eine Tabelle (die Datenläufe) darüber, wo die echten Daten liegen und wie viel es davon gibt

Je mehr Datenläufe es gibt, desto mehr verstreute Bereiche muss man durchlaufen, um eine einzelne Datei zu lesen. Das ist die wahre Identität der Fragmentierung, zu der wir als Nächstes kommen.

Aus dieser Struktur lassen sich mehrere Phänomene erklären, denen man in der Praxis begegnet.

  • Warum das Kopieren von zehntausend kleinen Dateien langsam ist. Jede einzelne Datei löst Metadatenoperationen aus — das Anlegen eines MFT-Datensatzes, das Registrieren eines Namens, das Setzen von Sicherheitseinstellungen —, und am Ende dominiert diese Verwaltungsarbeit gegenüber der eigentlichen Datenübertragung. (Und jede dieser Operationen ist zusätzlich etwas, das die Filter aus Teil 6 prüfen können.)
  • Die wahre Identität der Fragmentierung. Nicht resident gespeicherte Daten werden als „eine Folge zusammenhängender Clusterbereiche (Läufe)“ aufgezeichnet. Findet sich kein zusammenhängender Bereich, wächst die Anzahl der Läufe, und damit auch die Anzahl der Seeks, die ein Lesevorgang benötigt — das ist Fragmentierung. Die tatsächliche Anordnung der Läufe lässt sich mit fsutil file layout einsehen.
  • Auch „Ordner“ sind nichts Besonderes. Ein Verzeichnis ist „eine Datei, die einen Index von Dateinamen zu MFT-Datensatznummern enthält“. Im Verzeichnis der MFT steht letztlich alles auf demselben Mechanismus.

3. Daten sind nur einer der „Streams“

3.1. Eine Datei, mehrere Bytefolgen

In NTFS kann eine einzelne Datei mehr als einen Datenstrom besitzen. Was man normalerweise mit ReadFile/WriteFile liest und schreibt, ist der unbenannte Standardstream; mit der Syntax dateiname:streamname lässt sich ein alternativer Datenstrom (ADS) anlegen.2

Eine Datei namens bericht.docx — ein einzelner MFT-DatensatzStandardstream, unbenannt= der Inhalt, den man normalerweise sieht:Zone.IdentifierHerkunftsinformation, Mark of the Web:beliebiger NameZusatzdaten einer bestimmten Anwendung

Abbildung 4: Mehrere Datenströme. Nur der Standardstream erscheint in der Größenanzeige des Explorers

Der bekannteste ADS ist Zone.Identifier. Bei einer über den Browser heruntergeladenen Datei speichert dieser Stream ihre Herkunft (etwa, dass sie aus dem Internet stammt), und genau darauf stützen sich SmartScreens „Windows hat Ihren PC geschützt“ und die geschützte Ansicht von Office. Die sichtbare Seite dieses Mechanismus haben wir in „Warum Windows „Windows hat Ihren PC geschützt“ anzeigt“ behandelt — die Identität dahinter entpuppt sich als nichts anderes als ein NTFS-Stream.

3.2. Fallstricke, in die Entwickler tappen

  • Er ist unsichtbar. Er erscheint weder in der Größenangabe des Explorers noch in einer dir-Auflistung. Prüfen lässt er sich mit dir /r oder dem Sysinternals-Tool streams.11
  • Er reist nicht mit. Da ADS eine NTFS-Funktion ist, geht er beim Kopieren auf einen FAT-formatierten USB-Stick oder über Cloud-Speicher meist verloren. Genau daher stammt das Phänomen „die Download-Warnung war weg, nachdem ich die Datei kopiert hatte“.
  • Auch die eigene Anwendung kann ihn öffnen. Ein einfacher Doppelpunkt im Pfad, wie in CreateFile("data.txt:meta", ...), genügt zum Lesen und Schreiben.2 Das ist praktisch, aber man erbt dabei auch die im vorigen Punkt genannte Eigenschaft „reist nicht mit“ — es ist also nicht der richtige Ort, um den eigentlichen Inhalt geschäftskritischer Daten abzulegen.

In Abbildung 2 haben wir festgehalten, dass „eine Datei mehr als ein Dateinamenattribut besitzen kann“. Mehrere Pfade innerhalb desselben Volumes, die auf eine einzige Datei verweisen — das ist ein Hardlink (CreateHardLink / mklink /H).3

Der Index für C:\backup\Der Index für C:\app\config-link.json verweist auf Datensatz Nr. 1234config.json verweist auf Datensatz Nr. 1234MFT-Datensatz Nr. 1234Die Daten selbst oder ein Verweis auf ihre LäufeLinkanzahl: 2

Abbildung 5: Ein Hardlink. Beide Verzeichnisindizes verweisen schlicht auf denselben MFT-Datensatz, und beide sind gleichermaßen „das Original“

Da es sich unabhängig davon, über welchen Namen man sie ändert, immer um dieselbe Datei handelt, stimmt der Inhalt sofort überein.3 Und das verändert die Bedeutung von „Löschen“: DeleteFile bedeutet „einen Namen entfernen“, und das Dateiobjekt selbst verschwindet erst, wenn der letzte Name entfernt wurde, jedes offene Handle geschlossen ist und auch jede Referenz im Kernel — etwa ein Memory-Mapped-Abschnitt — verschwunden ist. Die beiden Phasen aus Teil 1, cleanup (das letzte Handle) und close (die letzte Referenz), bestimmen also auf genau dieselbe Weise, wie lange ein Löschen dauert. Zu beachten ist außerdem eine Eigenart bei der Attributanzeige: Die offizielle Dokumentation weist darauf hin, dass eine über einen Link geänderte Attributanzeige über einen anderen Link zunächst veraltet erscheinen kann.3

4.2. Der 8.3-Name — ein weiterer versteckter Name

Aus Gründen der historischen Kompatibilität kann NTFS für lange Dateinamen automatisch einen Kurznamen im 8.3-Format wie REPORT~1.DOC erzeugen. Auch dieser liegt als „ein weiterer Name“ neben dem Datensatz. In einem Ordner mit sehr vielen Dateien werden das Erzeugen von Kurznamen und das Vermeiden von Kollisionen zu einem echten Kostenfaktor, weshalb sich mit fsutil 8dot3name die Erzeugung deaktivieren oder vorhandene Kurznamen entfernen lassen (ein praktischer Hinweis: Da eine alte Anwendung, die einen Registry-Pfad über den Kurznamen referenziert, durch das Entfernen kaputtgehen kann, gibt es eine Prüffunktion, die man vor dem Entfernen laufen lassen kann).4

Wichtig ist hier, dass ob überhaupt ein Kurzname existiert, von der Umgebung abhängt. Das Standardverhalten wird über den Registry-Wert NtfsDisable8dot3NameCreation gesteuert, der vier Einstellungen kennt: 0 (auf jedem Volume erzeugen), 1 (auf keinem Volume erzeugen), 2 (pro Volume festlegen) und 3 (außerhalb des Systemvolumes nicht erzeugen).4 Da sich mit 2 die Einstellung pro Volume umschalten lässt, gilt eben nicht: „Unter Windows existiert immer ein Kurzname wie PROGRA~1“. Bevor man Code oder ein Verfahren schreibt, das von Kurznamen abhängt, sollte man den aktuellen Zustand mit fsutil 8dot3name query C: prüfen (ohne Angabe eines Volumes zeigt der Befehl die für alle Volumes gemeinsame Standardeinstellung).

Die Fallstricke rund um Pfade und Namen (MAX_PATH, reservierte Namen, abschließende Punkte) werden ausführlich in „MAX_PATH und die Fallstricke von Windows-Pfaden und Dateinamen“ behandelt. Zusammen mit der Namensauflösung (dem Objekt-Manager) aus Teil 1 ergibt dieser Abschnitt (Namen innerhalb des Dateisystems) das vollständige Bild von „Namen“ unter Windows.

5. Reparse-Points — der Mechanismus hinter „hier öffnen, dort landen“

Dateien und Verzeichnisse können einen Reparse-Point tragen. Dahinter steckt ein Attribut, das aus „einem Tag plus benutzerdefinierten Daten“ besteht. Öffnet das Dateisystem eine Datei mit einem Reparse-Point, wird die Verarbeitung je nach Tag übernommen — entweder von einem Filtertreiber, der das Tag versteht, oder, bei einem Tag zur Namensumleitung, indem die Auflösung mit dem Zielpfad neu beginnt.5

NTFSI/O-ManagerAnwendungNTFSI/O-ManagerAnwendungFindet einen Reparse-Point am Zielliefert Tag und Daten zurückEin Filter, der das Tag versteht,übernimmt die Verarbeitung (Teil 6)alt[Symbolischer Link / Junction (Namensumleitung)][Vom Filter verwaltetes Tag (z. B. Cloud-Dateien)]CreateFile("C:\data\link.txt")IRP_MJ_CREATE (die Welt aus Teil 1)„Der wahre Ort ist hier“Auflösung mit dem Zielpfad neu starten

Abbildung 6: Auflösung eines Reparse-Points. Er ist der offizielle Hook, der in die Operation „Öffnen“ eingreift

Auf diesem einen Mechanismus baut eine ganze Reihe vertrauter Funktionen auf.

  • Symbolische Links (mklink) — ein Wegweiser, der den Zielpfad hält. Er kann auch auf ein anderes Volume oder einen UNC-Pfad verweisen.6
  • Junctions/Mountpoints — ein altbewährter Mechanismus, der ein Verzeichnis mit einem Ort auf einem anderen lokalen Volume verbindet.3
  • OneDrive Files On-Demand — stellt eine Datei, deren eigentliche Daten lokal nicht vorhanden sind, über einen Reparse-Point dar, und in dem Moment, in dem sie geöffnet wird, lädt ein Filter sie herunter und liefert den Inhalt. Das ist die wahre Identität von „im Explorer sichtbar, aber beim Öffnen beginnt plötzlich Netzwerkverkehr“. (Der Mechanismus des Filters selbst wird in Teil 6 behandelt.)

Es gibt eine praktische Warnung: Das Ende eines Pfads ist nicht zwingend wirklich dieser lokale Ort. Ein Werkzeug, das einen Baum rekursiv durchläuft, kann sich durch eine Junction in einer Schleife verfangen; Größensummen können doppelt gezählt werden; ein Backup kann eine massenhafte Hydrierung von Cloud-Dateien auslösen — Code, der nichts von der Existenz von Reparse-Points weiß, tappt genau in diese Fallen. Das Prüfen des Attributs FILE_ATTRIBUTE_REPARSE_POINT, das FindFirstFile und verwandte Funktionen liefern, ist der Ausgangspunkt, um sich dagegen abzusichern.5

6. Zwei Journale — $LogFile und USN

Man hört oft, „NTFS sei ein Journaling-Dateisystem“, aber NTFS besitzt tatsächlich zwei Journale mit unterschiedlichen Aufgaben. Wer sie verwechselt, liest ihre eigentlichen Garantien falsch.

USN-Journal — Änderungshistorie, um zu erfahren, was sich geändert hatZeichnet bei jeder Änderung an einer Datei oder einem VerzeichnisArt der Änderung und Namen aufErmöglicht Backup-, Suchindex- und Synchronisierungstools,ohne vollständigen Scan zu erfahren, 'was sich seit dem letzten Mal geändert hat'$LogFile — ein Write-Ahead-Log, damit das Volume nicht beschädigt wirdZeichnet Metadatenoperationen — Datensatzänderungen, Umbenennungen usw. —vor ihrer Ausführung im Protokoll aufSpielt das Protokoll beim nächsten Start nach einem Systemausfall ab,um die strukturelle Konsistenz wiederherzustellen

Abbildung 7: Zwei Journale. $LogFile existiert, damit nichts kaputtgeht; das USN existiert, damit man erfährt, was sich geändert hat

Als Tabelle sieht der Unterschied so aus.

Aspekt $LogFile (Transaktionsprotokoll) USN-Journal (Änderungsjournal)
Zweck Stellt nach einem Ausfall die Struktur des Dateisystems wieder in einen konsistenten Zustand7 Erlaubt es, im Nachhinein zu erfahren, „was sich seit dem letzten Mal geändert hat“8
Was aufgezeichnet wird Ein Write-Ahead-Log der Metadatenoperationen (Datensatzänderungen, Umbenennungen usw.). Der Dateiinhalt bleibt außen vor Bei jeder Änderung die Art der Änderung sowie der Name der betroffenen Datei oder des Verzeichnisses8
Wer es nutzt NTFS selbst, für die automatische Wiederherstellung beim nächsten Mounten Anwendungen wie Backup-, Suchindex- und Synchronisierungstools
Wie weit es zurückreicht Nur so weit, wie es für die Wiederherstellung nötig ist. Es verwendet eine feste Größe im Umlauf, taugt also nicht dazu, historische Aufzeichnungen zu verfolgen Überschreitet es die Zielgröße (MaximumSize), werden ältere Einträge beim Checkpoint abgeschnitten. Wie weit man zurückreichen kann, hängt von der Größeneinstellung und der Änderungsrate des Volumes ab12
Wie man es einsieht Es gibt keinen offiziellen Weg, den Inhalt zu lesen (die Größe lässt sich mit chkdsk /L prüfen) Status über fsutil usn queryjournal, Inhalt über fsutil usn readjournal. Programmatisch über FSCTL_QUERY_USN_JOURNAL / FSCTL_READ_USN_JOURNAL12
Lässt es sich abschalten Nein, es ist Teil von NTFS Ein Administrator kann es löschen oder deaktivieren, was aber jeden Dienst, der es nutzt, zu einem vollständigen Scan zwingt — die Auswirkung ist also erheblich12

Tabelle 2: Die beiden Journale im Vergleich

  • $LogFile (das Transaktionsprotokoll) ist das Write-Ahead-Log der Metadatenoperationen. Auch nach einem Systemausfall nutzt NTFS dieses Protokoll zusammen mit Checkpoint-Informationen beim nächsten Start, um die Konsistenz des Dateisystems automatisch wiederherzustellen.7 Geschützt wird hier die Struktur. Wie wir in Teil 4 gesehen haben, können im Cache liegende, noch nicht geschriebene (dirty) Dateninhalte trotzdem durch einen Stromausfall verloren gehen — die richtige Lesart lautet: „Das Volume geht nicht kaputt, aber der letzte Schreibvorgang kann trotzdem verloren gehen.“
  • Das USN-Journal (Änderungsjournal) ist ein Verzeichnis, das bei jeder Änderung an einer Datei oder einem Verzeichnis innerhalb des Volumes die Art der Änderung und den Namen des Ziels aufzeichnet.8 Es ist der Mechanismus, der es Backup-Tools und Indexierern erlaubt, „nur das, was sich seit dem letzten Mal geändert hat“, ohne vollständigen Scan zu erfassen, und wird auch genutzt, um nach einem Ausfall den Neuaufbau eines Index zu vermeiden.8 In der Praxis lohnt es sich, sich zu merken, dass man fsutil usn readjournal zur Untersuchung als Abgleichsverzeichnis nutzen kann, um Lücken auszugleichen, die FileSystemWatcher hinterlässt (siehe „Praxisleitfaden zu FileSystemWatcher — Umgang mit verpassten und doppelten Ereignissen“).

7. Sparse-Dateien und Komprimierung — die Geschichte zweier „Größen“

In NTFS werden die logische Länge einer Datei und der ihr tatsächlich zugewiesene Bereich getrennt verwaltet — das sind „Größe“ und „Größe auf dem Datenträger“ im Eigenschaftendialog. Zwei Dinge sind vor allem dafür verantwortlich, dass sie auseinanderklaffen.

Eine Sparse-Datei weist Bereichen, die ausschließlich aus Nullen bestehen, keinen realen Speicherplatz zu — sie verwaltet sie als „Löcher“.9 Es ist völlig normal, dass eine virtuelle Festplattendatei mit einer logischen Größe von 42 GB auf dem Datenträger nur 500 MB belegt. Liest man ein Loch, erhält man Nullen zurück; schreibt man hinein, wird genau so viel Speicherplatz zugewiesen, wie man geschrieben hat.

Die Zuordnung auf dem Datenträger — 15 MB plus VerwaltungsinformationenDie logische Datei — Größe 1 GBLauf — der eigentliche Inhalt von R1Lauf — der eigentliche Inhalt von R2Daten 10 MBLoch, Nullen — 500 MBDaten 5 MBLoch, Nullen — der Rest

Abbildung 8: Eine Sparse-Datei. Ein „Loch“ hat keine Zuordnung, was logische Größe und Größe auf dem Datenträger auseinandertreibt

Die NTFS-Komprimierung komprimiert und speichert Daten in Einheiten, die Komprimierungseinheiten genannt werden.10 Sie ist transparent und praktisch, aber die Kosten sind es nicht — bei jedem Lese- und Schreibvorgang laufen Dekomprimierung und erneute Komprimierung, und auch die Fragmentierung schreitet tendenziell schneller voran. Und wie wir in Teil 2, Abschnitt 5 gesehen haben, wird der Zugriff auf eine komprimierte Datei nie asynchron (das Dateisystem wandelt ihn in synchronen Zugriff um). Das ist einer der Orte, an denen man suchen sollte, wenn „manche Dateien trotz Umstellung auf asynchrones I/O nicht schneller werden“.

Die tatsächliche, auf der Zuordnung basierende Größe lässt sich mit GetCompressedFileSize abrufen. Untersucht man eine Diskrepanz zwischen der „Summe der Dateigrößen“ und der „Belegung auf dem Datenträger“, lautet das Standardvorgehen, der Reihe nach vier Verdächtige zu prüfen: Sparse-Eigenschaft, Komprimierung, ADS (Abschnitt 3) und Rundung auf Cluster.

8. Selbst nachprüfen

Auch diesmal lässt sich alles auf dem eigenen Windows-Rechner beobachten (manches erfordert Administratorrechte). Damit Sie selbst beurteilen können, ob die Ergebnisse stimmen, ist jedem Befehl ein Hinweis beigefügt, worauf zu achten ist und was das aussagt.

:: Alternative Datenströme anzeigen
dir /r C:\Users\%USERNAME%\Downloads

Worauf achten: Unterhalb der normalen Dateizeile erscheint eine eingerückte Zeile der Form dateiname:Zone.Identifier:$DATA mit einer Längenangabe. Ist diese Zeile vorhanden, hat die Datei Mark of the Web (Abschnitt 3). Über den Browser heruntergeladene Dateien haben sie, selbst erstellte Dateien nicht. Führen Sie den Befehl an beiden Orten aus und vergleichen Sie — dann wird sofort deutlich, ob der ADS vorhanden ist.

:: Die Anordnung (Läufe) und Attribute einer Datei in der MFT anzeigen
fsutil file layout C:\pfad\zur\datei.dat

:: Nur die Extents anzeigen (ein in der offiziellen Dokumentation belegter Unterbefehl)
fsutil file queryextents C:\pfad\zur\datei.dat

Worauf achten: layout listet für jeden Stream Größe und zugewiesene Größe auf sowie — falls nicht resident — die Liste der Extents (jeweils ein Tripel aus VCN, LCN und Clusteranzahl). Eine sehr kleine Datei, die keine Extent-Zeilen zeigt, ist resident (Abschnitt 2.2); ist sie auf mehrere Zeilen verteilt, ist sie fragmentiert. Den Befehl gegen eine Textdatei mit wenigen Bytes und eine Datei mit mehreren hundert MB auszuführen und die Ausgabe zu vergleichen, ist der schnellste Weg, ein Gefühl für resident gegenüber nicht resident zu entwickeln.

:: Die Einstellung zur Erzeugung von 8.3-Kurznamen und vorhandene Kurznamen
fsutil 8dot3name query C:
dir /x

Worauf achten: query gibt zurück, ob die Erzeugung von Kurznamen für dieses Volume aktiviert oder deaktiviert ist (ohne Angabe eines Volumes wird die für alle Volumes gemeinsame Standardeinstellung angezeigt).4 dir /x zeigt neben dem langen Namen eine Spalte mit dem Kurznamen an, sodass eine leere Spalte bedeutet, dass kein Kurzname erzeugt wurde. Damit lässt sich auf dem eigenen Rechner nachprüfen, was Abschnitt 4.2 mit „man kann nicht davon ausgehen, dass ein Kurzname existiert“ meinte.

:: Der Status des USN-Journals
fsutil usn queryjournal C:

Worauf achten: Angezeigt werden die Journal-ID, der gültige Bereich der USNs (First USN / Next USN), die Zielgröße (MaximumSize) und die Zuordnungseinheit (AllocationDelta).12 Erstellen Sie eine Datei und führen Sie den Befehl erneut aus — Next USN sollte sich weiterbewegt haben, was bestätigt, dass „Änderungen aufgezeichnet werden“. MaximumSize ist ein grober Anhaltspunkt für „wie weit man zurückreichen kann“, wie in Abschnitt 6 angesprochen. Auf einem Volume, dessen Journal deaktiviert ist, liefert der Befehl einen Fehler.

:: Reparse-Points prüfen (Ziel und Tag)
dir /aL C:\Users\%USERNAME%
fsutil reparsepoint query "C:\Users\%USERNAME%\OneDrive"

Worauf achten: Alles, was dir /aL auflistet, ist ein Reparse-Point (einer, bei dem FILE_ATTRIBUTE_REPARSE_POINT gesetzt ist). Symbolische Links und Junctions erscheinen mit einer Typkennzeichnung wie <SYMLINKD> oder <JUNCTION>. fsutil reparsepoint query zeigt den Wert des Reparse-Tags und, bei einem Tag zur Namensumleitung, den Zielpfad an. Zielt der Befehl auf etwas, das kein Reparse-Point ist, liefert er einen Fehler — sodass ein Fehler selbst die Bestätigung ist, dass „hier ist nur ein gewöhnlicher Ordner“.

Verfolgt man Dateioperationen mit Procmon, ziehen die heutigen Hauptfiguren unter ihrem echten Namen vorbei (Schreibvorgänge in $LogFile, Pfade mit angehängtem Streamnamen, Reparse-Verarbeitung). Wie man das Tool einsetzt, steht in „Praxisleitfaden zu Process Monitor (ProcMon) — „Einstellungen werden nicht übernommen“ und „ACCESS DENIED“ in 10 Minuten eingrenzen“.

9. Zusammenfassung

  • NTFS ist rund um die MFT aufgebaut. Jede Datei ist ein Datensatz im Verzeichnis, und Informationen liegen entweder „im Datensatz“ oder „in dem externen Bereich, auf den der Datensatz verweist“. Kleine Daten sind resident, große Daten werden über Läufe referenziert, und sowohl die Langsamkeit bei der Verarbeitung riesiger Mengen kleiner Dateien als auch die Fragmentierung sind Folgen dieser Struktur.1
  • Eine Datei kann mehr als einen Datenstrom besitzen. Zone.Identifier (Mark of the Web) ist nichts anderes als ein ADS: sichtbar mit dir /r, und reist nicht über NTFS hinaus.211
  • Namen sind Attribute, und eine Datei kann mehrere davon haben. Ein Hardlink ist ein gleichrangiger Name, der auf denselben Datensatz verweist; der 8.3-Name ist ein weiterer, aus Kompatibilitätsgründen mitgeführter Name. „Löschen“ bedeutet „einen Namen entfernen“, und das Dateiobjekt selbst verschwindet erst, wenn der letzte Name, das letzte Handle und jede Referenz im Kernel (etwa ein gemapptes Segment) verschwunden sind.34
  • Reparse-Points sind der offizielle Hook in „Öffnen“, und symbolische Links, Junctions und Files On-Demand sind allesamt Anwendungen davon. Code, der einen Baum durchläuft, muss sich FILE_ATTRIBUTE_REPARSE_POINT bewusst sein.56
  • Es gibt zwei Journale. $LogFile dient der Wiederherstellung der strukturellen Konsistenz (damit nichts kaputtgeht), das USN ist die Änderungshistorie (was sich geändert hat). „Es ist Journaling, also ist auch die Daten sicher“ stimmt nicht — Datenhaltbarkeit baut man selbst mit den Werkzeugen aus Teil 4.78
  • Logische Größe und Zuordnung sind getrennte Dinge. Sparse-Eigenschaft, Komprimierung, ADS und Rundung auf Cluster sind die vier großen Ursachen für „die Größen stimmen nicht überein“. Zusammen mit der Tatsache, dass komprimierte Dateien nie asynchron werden, ist das ein nützliches Werkzeugset für Leistungsuntersuchungen.910

Die Serie endet beim nächsten Mal in Teil 6, „Filtertreiber und Minifilter — Warum Procmon und Virenscanner I/O abfangen können“. Wie fangen eigentlich die „Figuren, die dazwischenstehen“ — Virenschutz, Procmon, OneDrive, Verschlüsselung —, die seit Teil 1 immer wieder aufgetaucht sind, den I/O-Verkehr tatsächlich ab? Als Abschluss der Serie enthüllen wir die wahre Identität der Bewohner, die in den Lücken des Gerätestapels stehen.

Verwandte Artikel

Verwandte Beratungsleistungen

Die KomuraSoft LLC übernimmt Design und Untersuchung von Windows-Business-Anwendungen, die in der tatsächlichen Funktionsweise von NTFS wurzeln — rätselhaftes Verhalten bei Dateigröße und Kopierleistung, Störungen rund um Links und Streams, und mehr.

  1. Microsoft Learn, Master File Table. Dazu, dass jede Datei auf einem NTFS-Volume mindestens einen Eintrag in der MFT besitzt, einschließlich eines Eintrags für die MFT selbst; dazu, dass alle Informationen zu einer Datei — Größe, Zeitstempel, Zugriffsrechte und Dateninhalt — entweder im MFT-Eintrag gespeichert werden oder in einem Bereich außerhalb der MFT, dessen Ort der Eintrag beschreibt; dazu, dass das Löschen einer Datei ihren Eintrag als frei zur Wiederverwendung markiert, ohne dass die MFT selbst schrumpft; dazu, dass eine MFT-Zone reserviert wird, um die MFT zusammenhängend zu halten; sowie dazu, dass mit fortschreitender Zuordnung eine Fragmentierung der MFT auftritt.  2 3 4 5 6

  2. Microsoft Learn, File Streams. Dazu, dass NTFS-Dateidaten als ein oder mehrere Streams gespeichert werden, dass es sowohl einen Standard-(unbenannten) Datenstrom als auch benannte alternative Datenströme gibt, sowie dazu, dass sich ein Stream mit CreateFile über die Syntax „dateiname:streamname“ öffnen lässt.  2 3 4

  3. Microsoft Learn, fsutil 8dot3name. Dazu, dass NTFS für einen langen Dateinamen einen Kurznamen im 8.3-Format erzeugen kann, sowie dazu, dass sich mit fsutil 8dot3name abfragen und festlegen lässt, ob die Erzeugung von Kurznamen aktiviert oder deaktiviert ist, vorhandene Kurznamen entfernt (strip) werden können und sich nach der Entfernung betroffene Registry-Verweise durchsuchen lassen.  2 3 4 5

  4. Microsoft Learn, Reparse points. Dazu, dass ein Reparse-Point eine Sammlung benutzerdefinierter Daten zusammen mit einem Reparse-Tag ist, das das Format der Daten eindeutig identifiziert; dazu, dass das Dateisystem beim Öffnen einer Datei mit Reparse-Point die zu dem Tag gehörende Verarbeitung versucht (übernommen von einem Dateisystemfilter, der das Tag interpretiert); zu seiner Verwendung bei der Implementierung von NTFS-Dateisystemlinks und Remote-Speicher (hierarchischer Speicherung); sowie dazu, dass sich seine Existenz über das Attribut FILE_ATTRIBUTE_REPARSE_POINT bestätigen lässt.  2 3 4

  5. Microsoft Learn, NTFS overview. Dazu, dass NTFS eine Protokolldatei und Checkpoint-Informationen nutzt, um nach einem Systemausfall beim nächsten Start durch Abspielen des Transaktionsprotokolls automatisch die Konsistenz des Dateisystems wiederherzustellen, sowie zur dynamischen Neuzuordnung defekter Sektoren und zum selbstheilenden NTFS, das kleinere Beschädigungen im Hintergrund repariert.  2 3 4

  6. Microsoft Learn, Change Journals. Dazu, dass bei jeder Änderung an einer Datei oder einem Verzeichnis auf einem Volume die Art der Änderung sowie der Name der betroffenen Datei oder des Verzeichnisses im USN-Änderungsjournal dieses Volumes aufgezeichnet wird; dazu, dass pro Volume ein eigenes Journal geführt wird; sowie zu seiner Verwendung bei der Wiederherstellung des Dateisystemindex nach einem Ausfall, wodurch eine vollständige Neuindizierung des Volumes vermieden werden kann.  2 3 4 5 6

  7. Microsoft Learn, Sparse Files. Dazu, dass eine Sparse-Datei großen Bereichen, die aus Nullen bestehen, keinen physischen Speicherplatz zuweist, sondern nur den Bereichen mit Daten Speicherplatz zuweist, sowie dazu, dass das Lesen eines nicht zugewiesenen Bereichs Nullen zurückgibt.  2 3

  8. Microsoft Learn, File Compression and Decompression. Dazu, dass die NTFS-Dateikomprimierung transparent erfolgt, wobei Daten pro Komprimierungseinheit komprimiert und gespeichert werden; dazu, dass sich mit GetCompressedFileSize die komprimierte (tatsächlich zugewiesene) Größe abrufen lässt; sowie zu den Kosten durch Dekomprimierung und erneute Komprimierung beim Lesen und Schreiben einer komprimierten Datei.  2 3

  9. Microsoft Learn, Streams - Sysinternals. Dazu, dass das Sysinternals-Dienstprogramm streams alternative Datenströme von NTFS-Dateien auflisten und löschen kann.  2

  10. Microsoft Learn, Creating, Modifying, and Deleting a Change Journal und fsutil usn. Dazu, dass MaximumSize des Änderungsjournals ein Zielwert ist und das Journal beim NTFS-Checkpoint abgeschnitten wird, sobald seine Größe die Summe aus MaximumSize und AllocationDelta überschreitet; dazu, dass AllocationDelta die Einheit ist, in der am Ende angehängt und am Anfang entfernt wird; dazu, dass fsutil usn queryjournal den Status und die Kapazität des Journals anzeigt und readjournal seinen Inhalt; zum programmatischen Zugriff über FSCTL_CREATE_USN_JOURNAL / FSCTL_QUERY_USN_JOURNAL / FSCTL_READ_USN_JOURNAL / FSCTL_DELETE_USN_JOURNAL; sowie dazu, dass das Löschen oder Deaktivieren eines aktiven Journals einen vollständigen Scan der MFT erfordert und jeden Dienst, der das Journal nutzt, zu einem erneuten Scan des Volumes zwingt.  2 3 4

Aktuelle Artikel mit denselben Schlagwörtern führen zu verwandten Themen weiter.

Diese Seiten ordnen den Artikel in einen größeren Leistungs- und Entscheidungskontext ein.

Dieser Artikel ist direkt mit den folgenden Leistungen verbunden.

Häufige Fragen

Fragen, die in Beratungen zu diesem Artikelthema häufig gestellt werden.

Was ist die MFT (Master File Table)?
Es handelt sich um die Datenstruktur im Herzen eines NTFS-Volumes: ein Verzeichnis, das für jede Datei auf dem Volume mindestens einen Eintrag (einen Dateidatensatz) enthält — einschließlich eines Eintrags für die MFT selbst. Alles, was zu einer Datei gehört, von Größe, Zeitstempeln und Zugriffsrechten bis hin zum eigentlichen Dateninhalt, wird entweder innerhalb eines MFT-Eintrags gespeichert oder in einem Bereich außerhalb der MFT, auf den der Eintrag verweist. Eine kleine Datei passt vollständig, mitsamt ihren Daten, in ihren MFT-Eintrag (resident); eine große Datei besitzt im Eintrag nur einen Verweis auf die Lage ihrer Daten (eine Folge von Clustern) (nicht resident). Wird eine Datei gelöscht, wird ihr Eintrag als frei zur Wiederverwendung markiert, aber die Größe der MFT selbst schrumpft dadurch nie.
Was ist die unsichtbare „Zone.Identifier“-Information, die an Dateien hängt?
Sie ist einer der mehreren Datenströme (alternativen Datenströme) von NTFS. In NTFS kann eine einzelne Datei mehrere Bytefolgen (Streams) enthalten; normalerweise liest und schreibt man den unbenannten Standardstream. Windows speichert die Herkunft einer Datei — etwa dass sie aus dem Internet heruntergeladen wurde — in einem zusätzlichen Stream, den man mit einem Doppelpunkt angibt, wie in „file.txt:Zone.Identifier“. Das ist das sogenannte „Mark of the Web“, und genau darauf stützen sich SmartScreen und die geschützte Ansicht von Office bei ihrer Beurteilung. Alternative Streams erscheinen nicht in der Größenanzeige des Explorers; man kann sie mit dem Befehl dir /r oder dem Sysinternals-Tool streams prüfen. Zu beachten ist außerdem, dass sie beim Kopieren auf ein Nicht-NTFS-Dateisystem wie FAT nicht erhalten bleiben.
Was ist der Unterschied zwischen einem Hardlink und einem symbolischen Link?
Ein Hardlink ist „ein weiterer, gleichrangiger Name, der auf dasselbe Dateiobjekt — denselben MFT-Datensatz — verweist“. Er lässt sich nur innerhalb desselben Volumes erstellen, der Zugriff über jeden seiner Namen liefert dieselbe Datei, und das Löschen eines Namens entfernt die Datei nicht, solange ein anderer Name noch existiert. Ein symbolischer Link ist „ein Wegweiser, der auf einen anderen Pfad verweist“, implementiert als Reparse-Point. Da er nur den Zielpfad als Zeichenkette hält, kann er auf ein anderes Volume oder sogar einen entfernten Ort verweisen, wird aber zur Sackgasse, wenn das Ziel verschwindet. In der Praxis gilt als Faustregel: Ein Hardlink dient dazu, dasselbe Dateiobjekt zu teilen (was die Bedeutung von „Löschen“ verändert), ein symbolischer Link dazu, einen Pfad umzuleiten (für Umzüge oder Weiterleitungen).
NTFS ist ein Journaling-Dateisystem — bedeutet das, dass bei einem Stromausfall keine Daten verloren gehen?
Man muss genau verstehen, was hier tatsächlich geschützt wird. Was das Transaktionsprotokoll von NTFS ($LogFile) schützt, ist die Konsistenz der Struktur des Dateisystems (seiner Metadaten). Kommt es zu einem Systemausfall, stellt NTFS beim nächsten Start die Konsistenz mithilfe des Protokolls automatisch wieder her und verhindert so, dass das Volume beschädigt und unlesbar wird. Das bedeutet aber nicht, dass der tatsächliche Inhalt einer Datei, die gerade mitten im Schreiben war, wiederhergestellt wird. Wie wir in Teil 4 dieser Serie gesehen haben, gehen im Cache liegende, noch nicht geschriebene (dirty) Daten bei einem Stromausfall verloren. Das richtige Verständnis lautet also: „Das Volume geht nicht kaputt, aber der Inhalt des letzten Schreibvorgangs kann trotzdem verloren gehen“ — wer Haltbarkeit für die Daten selbst benötigt, muss sie selbst einbauen, etwa mit FlushFileBuffers, WRITE_THROUGH oder einem anwendungsseitigen Schreibdesign wie „erst in eine temporäre Datei schreiben, dann umbenennen“.
Warum unterscheiden sich „Größe“ und „Größe auf dem Datenträger“ bei einer Datei?
Weil NTFS die logische Länge einer Datei und den tatsächlich dafür reservierten Speicherplatz getrennt verwaltet. Selbst bei einer gewöhnlichen Datei entsteht ein gewisser Unterschied, weil die Zuordnung auf ganze Cluster (standardmäßig 4 KB) aufgerundet wird, aber richtig groß wird die Lücke bei Sparse-Dateien und komprimierten Dateien. Eine Sparse-Datei weist Bereichen, die durchgehend aus Nullen bestehen, keinen realen Speicherplatz zu — sie verwaltet sie als „Löcher“ —, sodass eine Datei mit mehreren Gigabyte logischer Größe durchaus nur wenige Megabyte auf dem Datenträger belegen kann. Bei einer komprimierten Datei wird nur die Größe nach der Komprimierung zugewiesen. Erscheint umgekehrt die „Größe auf dem Datenträger“ größer, liegt die Ursache oft in der Rundung auf Cluster oder in einem alternativen Datenstrom.

Autorenprofil

Profilseite des Artikelautors.

Go Komura

Geschäftsführer von KomuraSoft LLC

Spezialisiert auf Windows-Softwareentwicklung, technische Beratung und Fehleranalyse, insbesondere bei bestehenden Systemen und schwer reproduzierbaren Störungen.

Zurück zum Blog