Nelle 4 puntate fin qui si è visto come scorre una richiesta I/O (1ª–3ª puntata) e come la cache la riceve (4ª puntata). La richiesta, alla fine, arriva al file system. Questa volta è il turno del suo rappresentante, NTFS.
Il punto di vista cambia. Finora era un discorso dinamico, «il flusso della richiesta». Questa volta è un discorso statico su come i dati sono messi sul disco. L’identità del «Zone.Identifier» invisibile attaccato a un file scaricato. Perché copiare 10.000 file piccoli è molto più lento di copiare un file della stessa dimensione totale. Fino a che punto è vero «NTFS ha il journal, quindi si sta tranquilli» — tutto si spiega da questa struttura.
È la 5ª puntata della serie «Le profondità dell’I/O di Windows».
Premessa per leggere questa puntata: avere fermi i fondamenti di IRP e stack di dispositivi della 1ª puntata rende la lettura più facile. Detto questo, perché si possa leggere anche da sola, si definiscono prima i termini delle puntate precedenti che escono nel corpo.
| Termine | In una riga | Per i dettagli |
|---|---|---|
| IRP (I/O Request Packet) | La «bolla della richiesta I/O» in cui una chiamata API come ReadFile viene convertita nel kernel. I driver ricevono questa bolla e la trattano |
1ª puntata |
| I/O Manager e stack di dispositivi | Il pezzo del kernel che crea l’IRP e lo passa in ordine ai driver impilati fino al dispositivo di destinazione, e quell’impilamento | 1ª puntata |
| Cache Manager | Il pezzo che tiene il contenuto del file in memoria e in seguito scrive in blocco sul disco il contenuto di WriteFile. La causa di «appena scritto non è detto che sia arrivato sul disco» |
4ª puntata |
Tabella 1: I termini delle puntate precedenti presupposti in questa puntata
Un’altra cosa: i due stadi trattati nella 1ª puntata — cleanup (quando si chiude l’ultimo handle) e close (quando spariscono tutti i riferimenti nel kernel) — si usano anche nella spiegazione dell’eliminazione dei file del capitolo 4.
1. Prima di tutto, la conclusione
- Il centro di NTFS è l’MFT (Master File Table). Tutti i file sono gestiti come record nel registro dell’MFT, e tutte le informazioni sul file stanno «dentro la voce MFT» o «nell’area fuori dall’MFT che la voce indica» (capitolo 2).1
- L’entità di un file è un «insieme di attributi». Un file piccolo entra, dati compresi, nel record MFT (residente); un file grande ha solo un riferimento alla sequenza di cluster (non residente). La lentezza nel trattare tanti file piccoli si spiega da qui (capitolo 2).1
- I dati si possono avere in più (flussi di dati multipli). I dati di tutti i giorni sono il «flusso senza nome», e con
file.txt:nomesi può avere un flusso aggiuntivo. È l’identità di Zone.Identifier (Mark of the Web) (capitolo 3).2 - Anche il nome è un attributo. Aver messo più nomi sullo stesso record è l’hard link. Anche il nome breve 8.3 coabita come «un altro nome» (capitolo 4).34
- Il reparse point è il meccanismo ufficiale di «se si apre, un altro posto». Collegamenti simbolici, junction, file su richiesta di OneDrive sono tutti applicazioni di questi dati con tag (capitolo 5).56
- I journal sono due.
$LogFileè per il ripristino della coerenza dei metadati (log anticipato per non rompersi), il journal USN è per registrare la cronologia delle modifiche (il registro di che cosa è cambiato). I ruoli sono del tutto diversi (capitolo 6).78 - «Dimensione» e «dimensione su disco» sono cose distinte. File sparsi e compressione generano lo scostamento. Anche lo sfondo di «un file compresso non diventa asincrono» visto nella 2ª puntata sta qui (capitolo 7).910
Mappa della conoscenza di questo articolo
Il centro di NTFS è l’MFT (Master File Table), e tutti i file sono gestiti come record nel registro dell’MFT. I dati piccoli risiedono nel record (residenti); i dati grandi diventano non residenti e tengono solo un riferimento alla sequenza di cluster (data run): questa è l’identità della lentezza nel trattare tanti file piccoli e della frammentazione. Flussi di dati multipli, hard link e nomi brevi 8.3 sono tutti applicazioni dello stesso meccanismo, «insieme di attributi»; i reparse point sono l’hook ufficiale sull’«aprire» che sostiene dai collegamenti simbolici fino ai file su richiesta di OneDrive. Ciò che $LogFile protegge è la coerenza della struttura; la durabilità del contenuto dei dati va costruita a parte con gli strumenti di controllo della cache della 4ª puntata.
flowchart LR
accTitle: Mappa della conoscenza della struttura interna di NTFS e dell'MFT
accDescr: Diagramma che mostra le relazioni tra NTFS, MFT, record di file, attributi residenti e non residenti, data run, frammentazione, flussi di dati multipli, Zone.Identifier, hard link, nomi brevi 8.3, reparse point (collegamenti simbolici, junction, file su richiesta di OneDrive), $LogFile e journal USN, file sparsi e compressione NTFS
ntfs["NTFS"]
mft["MFT (Master File Table)"]
mft_record["Record di file MFT"]
mft_zone["Zona MFT"]
fragmentation["Frammentazione (NTFS)"]
resident_attribute["Attributo residente (resident)"]
non_resident_attribute["Attributo non residente (non-resident)"]
data_run["Data run"]
fsutil["fsutil"]
alternate_data_stream["Flusso di dati alternativo (ADS)"]
zone_identifier["Zone.Identifier (Mark of the Web)"]
streams_tool["streams (Sysinternals)"]
size_disk_usage_mismatch["Scostamento tra dimensione logica e uso del disco"]
hard_link["Hard link"]
eight_dot_three_name["Nome breve 8.3"]
reparse_point["Reparse point"]
symbolic_link["Collegamento simbolico"]
junction["Junction (punto di montaggio)"]
onedrive_files_on_demand["File su richiesta di OneDrive"]
ntfs_logfile["$LogFile (log delle transazioni NTFS)"]
volume_corruption["Danneggiamento del volume"]
cache_manager["Cache Manager"]
usn_journal["Journal USN (journal delle modifiche)"]
sparse_file["File sparso"]
ntfs_compression["Compressione NTFS"]
asynchronous_io["I/O asincrono"]
procmon["Process Monitor (procmon.exe)"]
ntfs -->|"usa"| mft
mft -->|"usa"| mft_record
mft -->|"richiede"| mft_zone
mft_zone -.->|"mitiga"| fragmentation
mft_record -->|"usa"| resident_attribute
mft_record -->|"usa"| non_resident_attribute
resident_attribute -->|"incompatibile con"| non_resident_attribute
non_resident_attribute -->|"usa"| data_run
data_run -.->|"può causare"| fragmentation
fragmentation -->|"verificato da"| fsutil
ntfs -->|"usa"| alternate_data_stream
zone_identifier -->|"salvato in"| alternate_data_stream
zone_identifier -->|"verificato da"| streams_tool
alternate_data_stream -->|"verificato da"| streams_tool
alternate_data_stream -.->|"può causare"| size_disk_usage_mismatch
ntfs -->|"usa"| hard_link
hard_link -->|"richiede"| mft_record
ntfs -.->|"usa"| eight_dot_three_name
eight_dot_three_name -->|"configurato da"| fsutil
ntfs -->|"usa"| reparse_point
reparse_point -->|"verificato da"| fsutil
symbolic_link -->|"implementa"| reparse_point
junction -->|"implementa"| reparse_point
onedrive_files_on_demand -->|"implementa"| reparse_point
ntfs -->|"usa"| ntfs_logfile
ntfs_logfile -->|"mitiga"| volume_corruption
ntfs -->|"usa"| cache_manager
ntfs -->|"usa"| usn_journal
usn_journal -->|"verificato da"| fsutil
ntfs -->|"usa"| sparse_file
sparse_file -->|"può causare"| size_disk_usage_mismatch
ntfs -->|"usa"| ntfs_compression
ntfs_compression -->|"può causare"| size_disk_usage_mismatch
ntfs_compression -->|"incompatibile con"| asynchronous_io
ntfs -->|"verificato da"| procmon
Nel diagramma, una linea continua indica una relazione che vale sempre e una linea tratteggiata indica una relazione condizionale (le condizioni sono nella spiegazione di ciascuna relazione nella pagina di dettaglio). L’elenco completo delle relazioni (in totale 35, con evidenza e livello di certezza) e le definizioni dei concetti principali sono raccolti nella pagina di dettaglio della mappa della conoscenza (in giapponese). Dati: JSON-LD / Turtle
2. Tutto è un record dell’MFT
2.1. Il registro del volume
Quando si formatta un volume NTFS, vengono creati l’MFT (master file table) e una serie di file di metadati che iniziano per $. Nell’MFT c’è almeno una voce per ogni file sul volume, e include anche la voce dell’MFT stesso.1
flowchart TB
subgraph VOL["Volume NTFS"]
MFT["$MFT ── Master File Table<br/>Registro dei record di tutti i file (c'è anche sé stesso)"]
LOG["$LogFile ── Log delle transazioni<br/>delle operazioni sui metadati (capitolo 6)"]
BITMAP["$Bitmap ── Stato d'uso dei cluster"]
OTH["$Boot / $Secure / $UpCase ecc.<br/>Altri file di metadati"]
DATA["Area dati utente<br/>(posto dei dati non residenti)"]
end
MFT -->|"il record indica la posizione"| DATA
Figura 1: Struttura di un volume NTFS. «Anche le informazioni di gestione del file system in sé le ha come file» è il progetto di NTFS
Le informazioni sul file — dimensione, timestamp, permessi di accesso, e fino al contenuto dei dati — sono conservate dentro la voce MFT, oppure in un’area fuori dall’MFT di cui la voce MFT descrive la posizione.1 Eliminando un file la voce viene marcata come «libera» e riutilizzata, ma l’MFT in sé non si restringe. Inoltre, per tenere l’MFT continuo è riservata un’area chiamata zona MFT, e quando il volume si riempie inizia la frammentazione dell’MFT — fino a questo discorso di vita, è scritto nella documentazione ufficiale.1
2.2. File = insieme di attributi, residenti e non residenti
Il contenuto di un record di file è una lista di attributi. Informazioni standard (timestamp ecc.), nome del file, sicurezza, e i dati. Qui c’è una biforcazione importante.
flowchart TB
subgraph REC["Record di file MFT (il registro di un file)"]
STD["Attributo informazioni standard<br/>Timestamp, flag di attributo"]
FN["Attributo nome file<br/>(se ne possono avere più d'uno ── capitolo 4)"]
DATA["Attributo dati"]
end
Q{"I dati sono piccoli?"}
RES["Residente (resident)<br/>il contenuto dei dati entra nel record<br/>la lettura si chiude col solo accesso all'MFT"]
NONRES["Non residente (non-resident)<br/>nel record c'è solo un «riferimento alla sequenza di cluster»<br/>i dati veri stanno nell'area dati utente"]
DATA --> Q
Q -->|"fino a qualche centinaio di byte"| RES
Q -->|"oltre"| NONRES
Figura 2: Il record di file è un insieme di attributi. Se i dati sono piccoli, «risiedono» nel record
Allineando come cambia il contenuto dello stesso record tra residente e non residente, si capisce meglio.
flowchart LR
subgraph RES2["Residente (resident) ── file piccolo"]
RA["Record di file MFT (lunghezza fissa)<br/>informazioni standard / nome file / sicurezza<br/>─────────────<br/>attributo dati = il contenuto in sé<br/>«valore di impostazione=1» entra qui direttamente"]
RB["Sul disco non c'è un altro posto<br/>la lettura si chiude col solo accesso all'MFT"]
RA --> RB
end
subgraph NON2["Non residente (non-resident) ── file grande"]
NA["Record di file MFT (lunghezza fissa)<br/>informazioni standard / nome file / sicurezza<br/>─────────────<br/>attributo dati = tabella dei data run<br/>la sequenza di «da dove, quanti cluster»"]
NB["Area dati utente<br/>run 1: cluster consecutivi"]
NC["Area dati utente<br/>run 2: cluster consecutivi in un altro posto"]
NA -->|"indica la posizione"| NB
NA -->|"indica la posizione"| NC
end
Figura 3: Confronto tra residente e non residente. Nel non residente, ciò che il record ha è solo la tabella di «dove e quanti sono i dati veri» (data run)
Più aumenta il numero di data run, più per leggere un file si deve passeggiare tra aree sparse. Questa è l’identità della frammentazione che segue.
Da questa struttura si spiegano diversi fenomeni che si incontrano sul campo.
- Perché copiare 10.000 file piccoli è lento. Per ciascun file avvengono operazioni sui metadati: creazione del record MFT, registrazione del nome, impostazione della sicurezza. Più del trasferimento dei dati in sé, è il lavoro di registro a dominare (e ciascuno di quelli diventa anche bersaglio di ispezione dei filtri che si vedranno nella 6ª puntata).
- L’identità della frammentazione. I dati non residenti sono registrati come «colonna di intervalli consecutivi di cluster (run)». Se non si prende un’area consecutiva, il numero di run aumenta e aumentano i seek necessari alla lettura — questa è la frammentazione. La sequenza reale dei run si può spiare con
fsutil file layout. - Anche la «cartella» non è speciale. Una directory è «un file che ha un indice dai nomi file ai numeri di record MFT». Sul registro, tutto sta sullo stesso meccanismo.
3. I dati sono solo uno dei «flussi»
3.1. Un file, più sequenze di byte
In NTFS, un file può avere più flussi di dati. Quello che di solito si legge e scrive con ReadFile/WriteFile è il flusso predefinito senza nome, e con la sintassi nome file:nome flusso si può creare un flusso di dati alternativo (ADS).2
flowchart LR
subgraph F["Il file report.docx (un record MFT)"]
D0["Flusso predefinito (senza nome)<br/>= il contenuto che si vede di solito"]
D1[":Zone.Identifier<br/>informazioni di provenienza (Mark of the Web)"]
D2[":un nome qualsiasi<br/>informazioni aggiuntive proprie dell'app"]
end
Figura 4: Flussi di dati multipli. Nella visualizzazione della dimensione di Esplora risorse esce solo il flusso predefinito
L’ADS più familiare è Zone.Identifier. Ai file scaricati dal browser, in questo flusso viene registrata la provenienza (che viene da Internet ecc.), e diventa materiale di giudizio per «Windows ha protetto il PC» di SmartScreen e per la Visualizzazione protetta di Office. Il lato visibile di questo meccanismo è trattato in «Perché Windows mostra «Windows ha protetto il PC»» — l’identità dal lato di dietro era, semplicemente, un flusso NTFS.
3.2. Le trappole in cui casca lo sviluppatore
- Non si vede. Non esce né nella dimensione di Esplora risorse né nell’elenco di
dir. Si conferma condir /ro constreamsdi Sysinternals.11 - Non si porta. L’ADS è una funzione di NTFS, quindi in una copia via chiavetta USB FAT o storage cloud tende a perdersi. «L’avviso di download è sparito dopo la copia» è questo.
- Lo può aprire anche la propria app. Basta includere i due punti nel percorso, come
CreateFile("data.txt:meta", ...), e si legge e scrive.2 È comodo, ma ci si prende insieme la natura «non si porta» del punto precedente, quindi non è il posto in cui mettere il corpo dei dati aziendali.
4. Anche il nome è un attributo — Hard link e nomi 8.3
4.1. Hard link — Più nomi verso lo stesso record
Nella figura 2 si è scritto «l’attributo nome file se ne può avere più d’uno». Nello stesso volume, più percorsi fanno riferimento a un solo file — questo è l’hard link (CreateHardLink / mklink /H).3
flowchart TB
subgraph DIR1["Indice di C:\app\"]
E1["config.json → record #1234"]
end
subgraph DIR2["Indice di C:\backup\"]
E2["config-link.json → record #1234"]
end
REC["Record MFT #1234<br/>corpo dei dati (o riferimento ai run)<br/>numero di collegamenti: 2"]
E1 --> REC
E2 --> REC
Figura 5: Hard link. L’indice della directory punta allo stesso record MFT, e entrambi sono «il vero»
Qualsiasi nome si usi per modificare, è lo stesso file, quindi il contenuto coincide subito.3 E il significato di «eliminare» cambia — DeleteFile è «staccare un nome», e l’entità sparisce solo quando è staccato l’ultimo nome, gli handle aperti sono chiusi, e sono spariti anche tutti i riferimenti nel kernel come le sezioni di memory map. I due stadi visti nella 1ª puntata, cleanup (ultimo handle) e close (ultimo riferimento), agiscono così com’è anche sulla vita dell’eliminazione. C’è poi una stranezza nella visualizzazione degli attributi: anche se si cambiano gli attributi via un collegamento, la visualizzazione apparente degli altri collegamenti può restare vecchia, un comportamento annotato in modo ufficiale.3
4.2. Nomi 8.3 — Un altro nome nascosto
Per compatibilità storica, NTFS può generare in automatico un nome breve in formato 8.3 come REPORT~1.DOC per un nome file lungo. Anche questo coabita nel record come «un altro nome». In una cartella con tantissimi file, generazione e risoluzione delle collisioni dei nomi brevi diventano un costo, quindi con fsutil 8dot3name si può disattivare la generazione o rimuovere i nomi brevi esistenti (se c’è un’app vecchia che registra i percorsi di Registro in nome breve si rompe, quindi che ci sia una funzione di ispezione prima dello strip è un punto pratico).4
Qui va tenuto presente che se il nome breve c’è o no dipende dall’ambiente. Il comportamento predefinito è deciso dal valore di Registro NtfsDisable8dot3NameCreation, e ci sono 4 modi: 0 (genera su tutti i volumi), 1 (non genera su tutti i volumi), 2 (si imposta per volume), 3 (non genera fuori dal volume di sistema).4 Se si sceglie 2 si può commutare per volume, quindi non è detto che «su Windows esiste per forza un nome breve come PROGRA~1». Prima di scrivere codice o procedure che dipendono dal nome breve, si confermi lo stato attuale con fsutil 8dot3name query C: (omettendo il volume, l’impostazione predefinita comune a tutti i volumi).
Le trappole intorno a percorsi e nomi (MAX_PATH, nomi riservati, punto finale) sono trattate in dettaglio in «MAX_PATH e le trappole di percorsi e nomi file di Windows». Mettendo insieme la risoluzione dei nomi della 1ª puntata (Object Manager) e questo capitolo (i nomi dentro il file system), si ha il quadro d’insieme dei «nomi» di Windows.
5. Reparse point — Il meccanismo di «se si apre, un altro posto»
A file e directory si può attaccare un reparse point. L’entità è un attributo «tag + dati definiti dall’utente». Quando il file system apre un file con reparse point, il trattamento viene dirottato in base al tag — o un driver filtro che capisce il tag si prende il trattamento, o, se è un tag di rinomina, la risoluzione si rifà con il percorso di destinazione.5
sequenceDiagram
participant App as App
participant IOM as I/O Manager
participant FS as NTFS
App->>IOM: CreateFile("C:\data\link.txt")
IOM->>FS: IRP_MJ_CREATE (il mondo della 1ª puntata)
Note over FS: Trovato un reparse point sul bersaglio<br/>restituisce tag e dati
alt Collegamento simbolico / junction (rinomina)
FS-->>IOM: «il posto vero è questo»
IOM->>FS: Rifà la risoluzione col percorso di destinazione
else Tag gestito da un filtro (file cloud ecc.)
Note over FS: Il filtro che capisce il tag<br/>si prende il trattamento (6ª puntata)
end
Figura 6: Risoluzione di un reparse point. È diventato l’hook ufficiale che interrompe l’operazione «aprire»
Su questo unico meccanismo sono in fila funzioni familiari.
- Collegamento simbolico (
mklink) — un cartello che tiene il percorso di destinazione. Può puntare anche a un altro volume o a un percorso UNC.6 - Junction / punto di montaggio — un meccanismo anziano che collega una directory a una posizione di un altro volume locale.3
- File su richiesta di OneDrive — un file i cui dati veri non sono a portata di mano è rappresentato con un reparse point, e nell’istante in cui viene aperto il filtro scarica e porge il contenuto. È l’identità di «in Esplora risorse si vede, ma aprendo parte la comunicazione» (il meccanismo del filtro in sé è nella 6ª puntata).
L’attenzione pratica è una. «La destinazione del percorso non è detto che sia davvero quel posto locale». Uno strumento che percorre ricorsivamente un albero entra in un ciclo con una junction, il riepilogo delle dimensioni si duplica, un backup fa materializzare in massa il cloud — il codice che non sa dell’esistenza dei reparse point ci casca. Confermare l’attributo FILE_ATTRIBUTE_REPARSE_POINT della famiglia FindFirstFile è l’ingresso della contromisura.5
6. Due journal — $LogFile e USN
Si dice spesso «NTFS è un file system con journal», ma in NTFS ci sono due journal con ruoli diversi. Se si confondono, si legge male la garanzia.
flowchart TB
subgraph J1["$LogFile ── Log anticipato (per non rompersi)"]
A1["Le operazioni sui metadati (aggiornamento record, rinomina ecc.)<br/>si registrano nel log prima di eseguirle"]
A2["Al successivo avvio dopo un guasto di sistema<br/>si riproduce il log e si ripristina la coerenza della struttura"]
A1 --> A2
end
subgraph J2["Journal USN ── Cronologia delle modifiche (per sapere che cosa è cambiato)"]
B1["A ogni modifica a file/directory<br/>si registrano contenuto della modifica e nome"]
B2["Backup, indici di ricerca, strumenti di sincronizzazione<br/>colgono «che cosa è cambiato dall'ultima volta» senza una scansione intera"]
B1 --> B2
end
Figura 7: Due journal. $LogFile è per «non rompere», USN è per «sapere le modifiche»
La differenza, in tabella, è la seguente.
| Aspetto | $LogFile (log delle transazioni) |
Journal USN (journal delle modifiche) |
|---|---|---|
| Scopo | Dopo un guasto, riportare la struttura del file system in uno stato coerente7 | Sapere in seguito «che cosa è cambiato dall’ultima volta»8 |
| Che cosa registra | Log anticipato delle operazioni sui metadati (aggiornamento record, rinomina ecc.). Il contenuto dei file è fuori dal bersaglio | A ogni modifica, il contenuto della modifica e il nome del file/directory bersaglio8 |
| Chi lo usa | NTFS stesso. Lo usa per il ripristino automatico al successivo montaggio | App come backup, indici di ricerca, strumenti di sincronizzazione |
| Fino a dove si può risalire | Solo l’ambito necessario al ripristino. Riutilizza una dimensione fissa, quindi non si usa per seguire la cronologia passata | Se supera la dimensione obiettivo (MaximumSize), al checkpoint i record vecchi vengono tagliati. L’ambito a cui si può risalire dipende dall’impostazione della dimensione e dal volume di aggiornamenti del volume12 |
| Come consultarlo | Non c’è un mezzo ufficiale per leggere il contenuto (la dimensione si conferma con chkdsk /L) |
fsutil usn queryjournal per lo stato, fsutil usn readjournal per il contenuto. Da programma FSCTL_QUERY_USN_JOURNAL / FSCTL_READ_USN_JOURNAL12 |
| Si può fermare? | Non si può fermare (è parte di NTFS) | Un amministratore può eliminarlo o disattivarlo. Tuttavia costringe i servizi in uso a una scansione intera, quindi l’impatto è grande12 |
Tabella 2: Confronto dei due journal
$LogFile(log delle transazioni) è il log anticipato delle operazioni sui metadati. Anche se avviene un guasto di sistema, NTFS al successivo avvio ripristina in automatico la coerenza del file system da questo log e dalle informazioni di checkpoint.7 Ciò che qui è protetto è la struttura. Come si è visto nella 4ª puntata, il contenuto dei dati dirty in cache può perdersi in un’interruzione di corrente — «il volume non si rompe. Tuttavia l’ultima scrittura può sparire» è la lettura corretta.- Il journal USN (journal delle modifiche) è un registro che, a ogni modifica a file o directory nel volume, registra il contenuto della modifica e il nome del bersaglio.8 È il meccanismo perché backup o indicizzatore raccolgano «solo ciò che è cambiato dall’ultima volta» senza una scansione intera, e si usa anche per evitare la ricostruzione dell’indice dopo un guasto.8 In pratica, è utile ricordare che
fsutil usn readjournalsi può usare in indagine come registro di confronto che copre le perdite diFileSystemWatcher(«Guida pratica a FileSystemWatcher»).
7. Sparsi e compressione — Il discorso che la «dimensione» è due
In NTFS, la lunghezza logica del file e l’area effettivamente assegnata sono gestite a parte. Sono la «dimensione» e la «dimensione su disco» della schermata delle proprietà. I rappresentanti che generano lo scostamento sono due.
Un file sparso non assegna area reale agli intervalli di zeri consecutivi e li gestisce come «buchi».9 Che un file di disco virtuale di dimensione logica 42 GB usi su disco solo 500 MB — succede normalmente. Se si legge un buco, torna zero; se si scrive, viene assegnato solo per quella quantità.
flowchart LR
subgraph L["File logico (dimensione: 1 GB)"]
R1["Dati 10 MB"]
H1["Buco (zeri) 500 MB"]
R2["Dati 5 MB"]
H2["Buco (zeri) il resto"]
end
subgraph P["Assegnazione su disco (15 MB + informazioni di gestione)"]
A1["Run: entità di R1"]
A2["Run: entità di R2"]
end
R1 --> A1
R2 --> A2
Figura 8: File sparso. Ai «buchi» non c’è assegnazione, e dimensione logica e dimensione su disco si scostano
La compressione NTFS comprime e conserva i dati per unità di compressione.10 È trasparente e comoda, ma anche il costo non è trasparente — a ogni lettura e scrittura girano espansione e ricompressione, e anche la frammentazione avanza più facilmente. E, come si è visto nella sezione 5 della 2ª puntata, l’accesso a un file compresso non diventa asincrono (il file system lo converte in sincrono). È uno dei posti da sospettare quando «ho fatto I/O asincrono ma c’è un file che non accelera».
La dimensione reale su base di assegnazione si ottiene con GetCompressedFileSize. In un’indagine in cui «il totale delle dimensioni dei file» e «l’uso del disco» non coincidono, la pratica standard è sospettare in ordine i quattro: sparsi, compressione, ADS (capitolo 3), arrotondamento al cluster.
8. Verificare con i propri occhi
Anche questa volta, su un Windows a portata di mano si può osservare tutto (per alcune cose servono i privilegi di amministratore). Perché si possa giudicare da sé se il risultato dell’esecuzione è corretto, a ciascun comando si aggiunge dove guardare per capire che cosa.
:: Vedere i flussi di dati alternativi
dir /r C:\Users\%USERNAME%\Downloads
Qui si guarda: sotto la riga ordinaria del file, allineate con rientro, ci sono righe nella forma nome file:Zone.Identifier:$DATA con la lunghezza. Se c’è questa riga, a quel file è attaccato il Mark of the Web (capitolo 3). Ai file scaricati dal browser si attacca, ai file fatti da sé no. Eseguendo in entrambi i posti e confrontando, la presenza o assenza di ADS diventa chiara.
:: Vedere la disposizione (run) e gli attributi di un file sull'MFT
fsutil file layout C:\path\to\file.dat
:: Vedere solo gli extent (un sottocomando documentato ufficialmente)
fsutil file queryextents C:\path\to\file.dat
Qui si guarda: layout, per ciascun flusso, allinea dimensione, dimensione assegnata e, se non residente, l’elenco degli extent (terne VCN, LCN, numero di cluster). Un file piccolissimo in cui non esce una riga di extent è residente (sezione 2.2); se è spezzato in più righe, è frammentato. Eseguire e confrontare un file di testo di pochi byte e un file di alcune centinaia di MB è il modo più breve per sentire residente/non residente.
:: Impostazione della generazione dei nomi brevi 8.3, e i nomi brevi esistenti
fsutil 8dot3name query C:
dir /x
Qui si guarda: query restituisce se su quel volume la generazione dei nomi brevi è attiva o disattiva (omettendo il volume, l’impostazione predefinita comune a tutti i volumi).4 dir /x mostra la colonna del nome breve accanto al nome lungo, quindi se la colonna è vuota il nome breve non è stato creato. Si può confermare nel proprio ambiente il «non è detto che il nome breve ci sia» della sezione 4.2.
:: Stato del journal USN
fsutil usn queryjournal C:
Qui si guarda: vengono mostrati journal ID, ambito degli USN validi (First USN / Next USN), dimensione obiettivo (MaximumSize) e unità di assegnazione (AllocationDelta).12 Se si crea un file e si esegue di nuovo, Next USN dovrebbe essere avanzato, e questa è la conferma che «le modifiche vengono registrate». MaximumSize è l’indicazione di «fino a dove si può risalire» toccata nel capitolo 6. Su un volume in cui il journal è disattivo si ha un errore.
:: Confermare i reparse point (destinazione e tag)
dir /aL C:\Users\%USERNAME%
fsutil reparsepoint query "C:\Users\%USERNAME%\OneDrive"
Qui si guarda: ciò che esce in dir /aL è un reparse point (quelli con FILE_ATTRIBUTE_REPARSE_POINT alzato). Collegamenti simbolici e junction vengono mostrati con un tipo come <SYMLINKD> <JUNCTION>. fsutil reparsepoint query mostra il valore del tag di reparse e, se è di rinomina, il percorso di destinazione. Se si specifica un bersaglio che non è un reparse point si ha un errore, quindi che ci sia un errore è in sé la conferma «qui è una cartella ordinaria».
Se si insegue un’operazione sui file con Procmon, i personaggi di questa puntata scorrono con il loro nome ($LogFile in scrittura, percorsi con nome di flusso, trattamento di reparse). Per come usarlo, si veda «Guida pratica a Process Monitor (ProcMon)».
9. Conclusione
- Il centro di NTFS è l’MFT. Tutti i file sono record del registro, e le informazioni stanno «nel record» o «nell’area esterna che il record indica». I dati piccoli sono residenti, i dati grandi sono riferimento ai run, e la lentezza nel trattare tanti file piccoli e la frammentazione sono conseguenze di questa struttura.1
- I flussi di dati se ne possono avere più d’uno. Zone.Identifier (Mark of the Web) è solo un ADS, si vede con
dir /r, e fuori da NTFS non si porta.211 - Il nome è un attributo, e se ne possono avere più d’uno. L’hard link è un nome di pari rango verso lo stesso record, il nome 8.3 è un altro nome per compatibilità. «Eliminare = staccare un nome», e l’estinzione dell’entità è quando sono spariti tutti l’ultimo nome, gli handle e i riferimenti nel kernel (sezioni mappate ecc.).34
- Il reparse point è l’hook ufficiale su «aprire», e collegamenti simbolici, junction e file su richiesta sono tutti applicazioni di questo. Il codice che percorre un albero deve avere in mente
FILE_ATTRIBUTE_REPARSE_POINT.56 - I journal sono due.
$LogFileè il ripristino della coerenza della struttura (non rompersi), USN è la cronologia delle modifiche (che cosa è cambiato). Non è «c’è il journal quindi anche i dati sono al sicuro» — la durabilità dei dati si costruisce con gli strumenti della 4ª puntata.78 - Dimensione logica e assegnazione sono cose distinte. Sparsi, compressione, ADS, arrotondamento al cluster sono i quattro fattori di «le dimensioni non coincidono». Compreso il fatto che un file compresso non diventa I/O asincrono, è un cassetto per l’indagine delle prestazioni.910
Il seguito è la puntata finale, la 6ª, «Driver filtro e minifilter — Perché Procmon e la scansione antivirus possono interrompere l’I/O». Come interrompono l’I/O «quelli che si mettono in mezzo» comparsi di tanto in tanto dalla 1ª puntata — antivirus, Procmon, OneDrive, cifratura. Come chiusura della serie, si svela l’identità degli abitanti che stanno nello spazio dello stack di dispositivi.
Articoli correlati
- Le profondità dell’I/O di Windows (1ª puntata) — Ogni lettura e scrittura diventa un IRP: il quadro d’insieme del sistema I/O
- Le profondità dell’I/O di Windows (2ª puntata) — I/O sincrono e asincrono: il vero significato di OVERLAPPED
- Le profondità dell’I/O di Windows (4ª puntata) — Cache Manager: quando il vostro WriteFile arriva sul disco
- Perché Windows mostra «Windows ha protetto il PC»
- MAX_PATH e le trappole di percorsi e nomi file di Windows — Limite di 260 caratteri, nomi riservati, punto finale, maiuscole e minuscole
- Una guida pratica a FileSystemWatcher: gestire gli eventi persi e duplicati
- Le trappole dei drive di rete e dei percorsi UNC — La pratica di trattare un file server (cartella condivisa) in un’app aziendale
- Guida pratica a Process Monitor (ProcMon) — Individuare in 10 minuti «la configurazione non viene letta» e «ACCESS DENIED»
Aree di consulenza correlate
KomuraSoft LLC si occupa della progettazione e dell’indagine di app aziendali Windows radicate nel meccanismo di NTFS, come comportamenti inspiegabili di dimensione dei file o prestazioni di copia, e guasti legati a collegamenti e flussi.
- Sviluppo di applicazioni Windows
- Analisi dei bug e delle cause
- Riutilizzo di asset esistenti e supporto alla migrazione
- Contattaci
Riferimenti
-
Microsoft Learn, Master File Table. Sul fatto che per ogni file su un volume NTFS c’è almeno una voce nell’MFT, inclusa la voce dell’MFT stesso; sul fatto che tutte le informazioni, compresi dimensione, timestamp, permessi di accesso e contenuto dei dati del file, sono conservate nella voce MFT o in un’area fuori dall’MFT di cui la voce MFT descrive la posizione; sul fatto che all’eliminazione di un file la voce viene marcata come libera e riutilizzata ma la dimensione dell’MFT non si restringe; sul fatto che è riservata una zona MFT per tenere l’MFT continuo; sul fatto che, con il procedere dell’assegnazione, avviene la frammentazione dell’MFT. ↩ ↩2 ↩3 ↩4 ↩5 ↩6
-
Microsoft Learn, File Streams. Sul fatto che i dati di un file NTFS sono conservati come uno o più flussi; sul fatto che ci sono il flusso di dati predefinito (senza nome) e i flussi di dati alternativi con nome; sul fatto che si specifica un flusso nella forma «nome file:nome flusso» e lo si apre con CreateFile. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, Hard links and junctions. Sul fatto che un hard link è una rappresentazione sul file system in cui, nello stesso volume, più percorsi fanno riferimento a un solo file; sul fatto che si crea con CreateHardLink; sul fatto che una modifica via qualsiasi collegamento è subito visibile dagli altri collegamenti; sul fatto che la modifica degli attributi si propaga a tutti gli hard link, mentre la visualizzazione sulla voce di directory viene aggiornata solo sul collegamento da cui si è fatta la modifica, una stranezza di visualizzazione; e sulle junction (meccanismo che collega una directory a un altro volume locale). ↩ ↩2 ↩3 ↩4 ↩5 ↩6
-
Microsoft Learn, fsutil 8dot3name. Sul fatto che NTFS può generare un nome breve in formato 8.3 per un nome file lungo; sul fatto che con fsutil 8dot3name si possono consultare e impostare l’attivazione/disattivazione della generazione dei nomi brevi, rimuovere (strip) i nomi brevi esistenti, e scansionare i riferimenti di Registro che verrebbero interessati in caso di rimozione. ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn, Reparse points. Sul fatto che un reparse point è un insieme di dati definiti dall’utente e di un tag di reparse che identifica in modo univoco il formato di quei dati; sul fatto che all’apertura di un file con reparse point il file system tenta il trattamento corrispondente al tag (trattamento da parte di un filtro del file system che interpreta il tag); sul fatto che è usato nell’implementazione dei collegamenti del file system NTFS e dello storage remoto (memoria gerarchica); sul fatto che l’esistenza si conferma con l’attributo FILE_ATTRIBUTE_REPARSE_POINT. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, Symbolic links. Sul fatto che un collegamento simbolico è un oggetto del file system che punta a un altro file o directory e funziona come redirect trasparente verso la destinazione; sul fatto che ci sono collegamenti assoluti e relativi, e che sono possibili riferimenti che attraversano i volumi o verso percorsi remoti. ↩ ↩2 ↩3
-
Microsoft Learn, NTFS overview. Sul fatto che NTFS usa un file di log e informazioni di checkpoint e, in caso di guasto di sistema, al successivo avvio riproduce il log delle transazioni e ripristina in automatico la coerenza del file system; sul fatto che ha il remapping dinamico dei settori difettosi e self-healing NTFS che in background ripara i danneggiamenti lievi. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, Change Journals. Sul fatto che, a ogni modifica a file o directory in un volume, nel journal delle modifiche USN di quel volume vengono registrati il contenuto della modifica e il nome del file/directory bersaglio; sul fatto che il journal è mantenuto per volume; sul fatto che si può usare per il ripristino dell’indice del file system dopo un guasto e si può evitare di reindicizzare l’intero volume. ↩ ↩2 ↩3 ↩4 ↩5 ↩6
-
Microsoft Learn, Sparse Files. Sul fatto che in un file sparso, a un grande intervallo composto di zeri non si assegna area fisica su disco e si assegna area solo alle parti che contengono dati; sul fatto che leggere un intervallo senza assegnazione restituisce zero. ↩ ↩2 ↩3
-
Microsoft Learn, File Compression and Decompression. Sul fatto che la compressione dei file di NTFS avviene in modo trasparente e i dati vengono compressi e conservati per unità di compressione; sul fatto che con GetCompressedFileSize si ottiene la dimensione dopo la compressione (assegnazione reale); sul fatto che lettura e scrittura di un file compresso comportano il costo di espansione e ricompressione. ↩ ↩2 ↩3
-
Microsoft Learn, Streams - Sysinternals. Sul fatto che l’utilità streams di Sysinternals può enumerare ed eliminare i flussi di dati alternativi di un file NTFS. ↩ ↩2
-
Microsoft Learn, Creating, Modifying, and Deleting a Change Journal e fsutil usn. Sul fatto che MaximumSize del journal delle modifiche è un valore obiettivo, e che se la dimensione supera la somma di MaximumSize e AllocationDelta viene troncato al checkpoint di NTFS; sul fatto che AllocationDelta è l’unità di aggiunta in coda al journal e di eliminazione dalla testa; sul fatto che con fsutil usn queryjournal si consultano stato e capacità del journal, con readjournal il contenuto registrato; sul fatto che da programma si usano FSCTL_CREATE_USN_JOURNAL / FSCTL_QUERY_USN_JOURNAL / FSCTL_READ_USN_JOURNAL / FSCTL_DELETE_USN_JOURNAL; sul fatto che eliminazione o disattivazione di un journal attivo comporta una scansione dell’intero MFT e costringe i servizi che usano il journal a una nuova scansione del volume. ↩ ↩2 ↩3 ↩4
Articoli correlati
Articoli recenti con gli stessi tag per approfondire argomenti vicini.
Le profondità dell'I/O di Windows (4ª puntata) — Cache Manager: quando il vostro WriteFile arriva sul disco
Quarta puntata della serie che spiega con i diagrammi il Cache Manager di Windows. Si organizzano la cache implementata come file mapping...
Le profondità dell'I/O di Windows (6ª puntata · ultima) — Driver filtro e minifilter: perché Procmon e la scansione antivirus possono intercettare l'I/O
Puntata finale della serie che spiega con i diagrammi i driver filtro e i minifilter di Windows. Si organizzano Filter Manager e altitudi...
OneDrive «File su richiesta» e le applicazioni aziendali — le ipotesi che i segnaposto spezzano e come affrontarle
Un CSV sul desktop non si apre, o l'importazione fallisce con «file non trovato»: la causa può essere Known Folder Move e File su richies...
Proxy aziendale e app Windows — mettere in ordine la risoluzione del proxy in WinINET, WinHTTP e .NET
Il browser passa, ma solo l'app aziendale non attraversa il proxy aziendale. La causa è di solito un disallineamento su quali impostazion...
Best practice pratiche sul multithreading: edizione .NET — Cosa decidere prima di aggiungere altri thread
Le regole di progettazione per .NET/C# che impediscono che, dopo aver avviato un thread, l'app «crashi o si blocchi di tanto in tanto». L...
Argomenti correlati
Queste pagine collocano l’argomento in un contesto più ampio di servizi e decisioni.
Argomenti tecnici Windows
Portale su sviluppo Windows, analisi dei problemi e valorizzazione delle risorse esistenti.
Servizi collegati all’argomento
L’articolo è direttamente collegato ai servizi seguenti.
Sviluppo di applicazioni Windows
Applicazioni aziendali, integrazione di dispositivi e strumenti di comunicazione, dai requisiti allo sviluppo.
Domande frequenti
Domande che ricorrono nelle consulenze sull’argomento dell’articolo.
- Che cos'è l'MFT (Master File Table)?
- È la struttura dati che sta al cuore di un volume NTFS: un registro che, per ogni file sul volume, ha almeno una voce (un record di file). Include anche la voce dell'MFT stesso. Tutte le informazioni sul file — dimensione, timestamp, permessi di accesso, e fino al contenuto dei dati — sono conservate o dentro la voce MFT, o in un'area fuori dall'MFT che la voce MFT indica. Un file piccolo entra, dati compresi, nella voce MFT (residente); un file grande ha nella voce solo un riferimento al posto dei dati (la sequenza di cluster) (non residente). Eliminando un file la voce viene marcata come libera e riutilizzata, ma la dimensione dell'MFT in sé non si restringe.
- Che cosa sono i dati invisibili «Zone.Identifier» attaccati a un file?
- È uno dei flussi di dati multipli (flussi di dati alternativi) di NTFS. In NTFS un solo file può avere più sequenze di byte (flussi), e quello che di solito si legge e scrive è il flusso predefinito senza nome. In un flusso aggiuntivo specificato con i due punti, come «file.txt:Zone.Identifier», Windows registra la provenienza del file (scaricato da Internet ecc.). Questo è il cosiddetto «Mark of the Web», e diventa materiale di giudizio per l'avviso di SmartScreen e per la Visualizzazione protetta di Office. I flussi alternativi non compaiono nella visualizzazione della dimensione di Esplora risorse; si confermano con il comando dir /r o con lo strumento streams di Sysinternals. Va tenuto presente anche che, copiati su un file system diverso da NTFS (FAT ecc.), non si conservano.
- Che differenza c'è tra hard link e collegamento simbolico?
- L'hard link è «si aggiunge un altro nome di pari rango che punta alla stessa entità di file (lo stesso record MFT)». Si può creare solo nello stesso volume, da qualsiasi nome si accede allo stesso file, e eliminando un nome, se ne resta un altro, il file non sparisce. Il collegamento simbolico è «un cartello che indirizza a un altro percorso», implementato come reparse point. Poiché tiene solo la stringa del percorso di destinazione, può puntare anche a un altro volume o al remoto, ma se la destinazione sparisce diventa un vicolo cieco. In pratica la base è: l'hard link per condividere l'entità (cambia il significato dell'eliminazione), il collegamento simbolico per rindirizzare un percorso (spostamento o redirect).
- NTFS è un file system con journal, quindi i dati non spariscono nemmeno in un'interruzione di corrente?
- Occorre capire con precisione l'ambito di ciò che è protetto. Il log delle transazioni di NTFS ($LogFile) protegge la coerenza della struttura (i metadati) del file system. Anche se avviene un guasto di sistema, al successivo avvio usa il log per ripristinare in automatico la coerenza e previene la situazione «il volume è rotto e non si legge». Tuttavia non significa che venga ripristinato il contenuto dei dati in sé di un file che era a metà scrittura. Come si è visto nella 4ª puntata della serie, i dati dirty in cache si perdono in un'interruzione di corrente. Quindi la comprensione corretta è «il volume non si rompe, ma il contenuto dell'ultima scrittura può sparire»: se serve la durabilità dei dati in sé, va costruita con FlushFileBuffers, WRITE_THROUGH, o un progetto di scrittura dal lato app (file temporaneo + rinomina ecc.).
- Perché la «dimensione» del file e la «dimensione su disco» sono diverse?
- Perché in NTFS la lunghezza logica del file e lo spazio su disco effettivamente assegnato sono gestiti a parte. Anche in un file ordinario c'è una differenza perché si assegna arrotondando all'unità cluster (per default 4 KB), ma lo scostamento grande avviene con i file sparsi e i file compressi. In un file sparso, agli intervalli di zeri consecutivi non si assegna area reale e si gestiscono come «buchi», quindi può succedere che la dimensione logica sia di alcuni GB e su disco siano alcuni MB. In un file compresso viene assegnata solo la dimensione dopo la compressione. Al contrario, se la «dimensione su disco» appare più grande, possono essere la causa l'arrotondamento al cluster o un flusso di dati alternativo.
Profilo dell’autore
Pagina di presentazione dell’autore dell’articolo.
Go Komura
Rappresentante di KomuraSoft LLC
Specializzato nello sviluppo di software Windows, nella consulenza tecnica e nell’analisi dei malfunzionamenti, soprattutto nei progetti con sistemi esistenti e guasti difficili da riprodurre.