Questo file forma parte di PFS3 (File-System Professionale 3) Scritto da Michiel Pelt Copyright 1998 da GREat Effects Development $Id: pfsls.guide 1.1 1999/04/23 06:32:36 Michiel Exp Michiel $ 1 7 1999 PFS3 struttura disco ------------------- Questo documento descrive i blocchi e le strutture usate da PFS. Solo la nuova versione per harddisk verrà descritta in questa sede. Per la versione floppy si faccia riferimento alle versioni precedenti. ********************* * i bootblock ********************* I primi due blocchi costituiscono il bootblock, come richiesto da AmigaDOS. La prima longword del primo bootblock contiene il dostype: PFS\1. La restante parte è vuota. Infatti il primo bootblock è simile a questo mostrato qui sotto: ___________________ | | 000 | disktype | |___________________| 004 | | | | | . | | . | 200 |___________________| ******************** * il rootblock ******************** Subito dopo il bootblock è presente il rootblock, per l'esattezza nel blocco 2. Questo è il blocco più importante di un disco PFS. PFS tiene questo blocco sempre in cache. Esso assomiglia a questo: ___________________ | | 000 | disktype | 'PFS\1' 004 | opzioni | vedi sotto 008 | datestamp | |___________________| | | | 00c | cday | cminute | data di creazione (formato DOS) 010 | ctick | prot | protezione |_________|_________| | | i 32 car. del nome del disco. Dimensione di stringa seguita 014 | diskname | con quel numero di caratteri | | |___________________| | | 034 | ultimo riservato | primo e ultimo blocco riservato (blocknumbers) 038 | prima riservato | 03c | riservato libero | numero di blocchi riservati liberi |___________________| | | | 040 | blksize | rblkclt | blocksize riservato; raggruppamento rootblock |_________|_________| | | 044 | blocchi libero | numero di blocchi liberi 048 | sempre libero | numero di blocchi tenuti sempre liberi 04c | roving puntatore | usato per allocazione 050 | deldir | la posizione della directory delete 054 | disksize | la dimensione del disco in blocchi 058 | rblk estensione | riferimento all'estensione rootblock 05c | riservato_2 | |___________________| 060 | | | indice di bitmap | riferimento ai blocchi di indice della bitmap | | |___________________| 074 | | | anode indice | riferimento ad indice degli anode block | | (non valido se il Modo_SUPERINDEX è abilitato) 200 |___________________| Tramite il campo disktype PFS riconosce che il disco è di tipo PFS. Il valore ivi contenuto è lo stesso come che si può trovare nel bootblock. Il campo opzioni 32 indica che le estensioni di PFS sono abilitate. La tavola sotto stabilisce il numero di bit, il nome simbolico, la versione con cui l'opzione fu introdotta ed il suo significato. bit | nome | rel | funzione ----|----------------------|-----|------------------------------------------------ 0 | Mode_HARDDISK | 4.1 | modo harddisk se a 1; attualmente sempre a 1 1 | Mode_SPLITTED_ANODES | 4.1 | se a 1 anodes diviso in blocco/offset 2 | Modo_DIR_Estensione | 4.1 | abilita le estensioni delle directory-entry 3 | Modo_DELDIR | 4.1 | deldir abilitato se a 1 4 | Modo_SIZEFIELD | 4.1 | il campo disksize (offset 0x54) è valido 5 | Modo_Estensione | 4.1 | l'estensione rootblock è abilitata 6 | Modo_DATESTAMP | 4.1 | blocco datestamps abilitato se 1 7 | Modo_SUPERINDEX | 4.2 | estensione che rende possibile uso di dischi >5G PFS ha, di default, tutte le opzioni abilitate. Fanno eccezione Mode_SUPERINDEX, che è abilitato solo per dischi più grandi di 5G. Se il Modo_SUPERINDEX è abilitato, la lista dei blocchi di indice della bitmap è più grande e copre offset del rootblock che vanno da 060 a 200. I blocchi anodeindex sono riferiti ad un nuovo blocktype: il superblock che può essere letto nell'estensione rootblock. PFS controlla le opzioni quando il volume viene montato. Se Mode_DELDIR è corretto, PFS automaticamente creerà una directory delete assegnandogli il Mode_DELDIR. Anche l'estensione rootblock automaticamente viene creata se non esiste. Se eventuali versioni future di PFS estenderanno la diskstructure questo sarà evidenziato da un nuovo bit opzionale. Tutti i campi 'not used' sono riservati per un uso futuro e devono essere settati a 0. Il Primo e l'ultimo bit riservato indicano la 'reserved area'. Tutta le informazione del disco, come directory, dati di allocazione etc sono conservati in questa area riservata. Il resto del disco è disponibile per i dati. Attualmente 'first reserved' è sempre a 2, così l'area riservata inizia con il rootblock. 'Reserved free' indica il numero di blocchi riservati che sono liberi. Il 'datestamp' è un contatore di aggiornamento. Quando il disco è formattato, tutti i blocchi avranno un datestamp a 0. Ogni volta che il disco è aggiornato (va da uno stato al succesivo uso di atomico commit), il datestamp viene incrementato di un punto. Usando il datestamp tutti i blocchi nell'area riservata possono essere ordinati in base all'ora. Questo risulterà conveniente per gli strumenti di riparazione permettemdogli un recupero più facile ed affidabile di un volume danneggiato. 'Blksize' indica la dimensione di blocchi riservati in byte. Attualmente questo è sempre di 1024 (1K), indipendente del vero blocksize. Il vero blocksize (come specificato nella mountlist) può essere o 512 o 1024 byte. Così se i blocchi sono di 512 byte, caso normale, ogni blocco riservato alloca due blocchi sul disco. BTW: il precendentemente primo e l'ultimo riservato indicano i veri blocknumbers, non i numeri di blocco riservati. Tuttavia, 'reserved free' fà riferimento ai blocchi riservati. Esso indica il numero di blocchi riservati che possono essere allocati prima che l'area riservata sia piena. Blocchi libero indica il numero di blocchi liberi. Esso è uguale al numero totale di blocchi sul disco - il numero di blocchi riservati - 2 - il numero di blocchi occupati dai dati. PFS tiene sempre una piccola parte dell'area dati libera. Ciò viene indicato da 'always free'. Il puntatore roving viene usato per allocare. Se tu modifichi qualsiasi blocco di bitmap sarebbe preferibile settare questo puntatore a zero. Questo non provocherà mai danni. ******************** * Blocco ID ******************** I seguenti blocchi hanno sempre 2 blocchi di byte id per campo. Questo indica il blocktype. Gli IDs usati correntemente sono: DB -- dirblock AB -- anodeblock IB -- indice anode block BM -- blocco di bitmap MI -- blocco indice bitmap DD -- blocco deldir Ex -- estensione rootblock SB -- super block ******************** * blocchi di Bitmap ******************** Per tenere traccia di quali blocchi sono occupati e di quelli che non lo sono, PFS usa blocchi di bitmap. Un tale blocco assomiglia a questo: ___________________ | | | 000 | id | x | |________|__________| | | 004 | datestamp | 008 | numero di sequenza| |___________________| 00c | | | la bitmap | | | 400 |___________________| Ogni blocco ha spazio per 253 longword allocandosi quindi 8096 blocchi. Ogni bit rappresenta un blocco e un bit viene alzato se è disponibile, mentre di contro un bit viene abbassato quando viene riempito. Ci sono due bitmap, una per l'area riservata e una per l'area dati. Per l'area dati sono necessari molti blocchi bitmap. Essi sono numerati nel campo di numero di sequenza, a partire da 0. Il primo pezzo del primo blocco bitmap rappresenta il primo blocco dati (il blocco direttamente dietro l'ultimo blocco riservato) La bitmap per l'area riservata è direttamente dietro il rootblock. Il rootblock raggruppato nel campo rootblock (rblkclt) indica il numero di blocchi occupati dal rootblock insieme con la bitmap riservata. La bitmap riservata ha lo stesso header della bitmap dati, ma ha una dimensione differente. Il cluster del rootblock è scelto in base, al fatto che può contenerlo insieme all'intera bitmap riservata, ed esso viene arrotondato ad un multiplo di 1024 blocchi di byte. Il primo pezzo della bitmap riservata rappresenta il primo blocco riservato (normalmente 2). Ogni bit rappresenta 1024 byte di blocco riservato. ******************** * blocchi indice ******************** PFS fà riferimento alla bitmap e ai blocchi anode usando blocchi indice. Questi blocchi assomigliano a questo: ___________________ | | | 000 | id | x | |_________|_________| | | 004 | datestamp | 008 | numero di sequenza| |___________________| 00c | | | 253 indicatori | | | 400 |___________________| Ogni blocco contiene riferimenti a 253 blocchi anode o a blocchi di bitmap. Per i dischi grandi saranno necessari molti blocchi indice. Essi sono numerati con il numero di sequenza, a partire da 0. C'è un massimo di 5 blocchi indice bitmap e di 99 anode nei blocchi indice. Il rootblock contiene i puntatori a questi blocchi. Un anode o un blocco di bitmap di un certo numero di sequenza non esiste se il campo corrispondente nell'indice è zero. Buchi nell'indice sono permessi (per esempio è possibile per il blocco anode il numero 5 per esistere, mentre 4 non sarà possibile). ******************** * Blocchi Anode ******************** File e directory occupano spazio su disco. PFS tiene traccia di quali oggetti occupa e quali blocchi per mezzo dei cosiddetti anodes. Gli Anodes sono conservati nei blocchi anode, che assomigliano a questo: ___________________ | | | 000 | id | x | |_________|_________| | | 004 | datestamp | |___________________| | | 008 |numero di sequenza | |___________________| | | 00c | riservato | |___________________| 010 | | | 84 anodes | | | 400 |___________________| Il modo con cui gli anode sono numerati dipende dal Mode_Splitted_ANODES: Modo_Splitted_ANODES disabilitato: Gli anodes sono numerati a partire da 0. Il primi 84 sono nell'anodeblock 0, i successivi 84 nell'anodeblock 1 etc. Ogni oggetto (file o directory) è identificata da un tale numero anode. Modo_Splitted_ANODES abilitato: Le prime 16 parti di anode indicano per anodeblock il numero di sequenza. Il successivi 16 bit indicano l'offset all'interno del anodeblock. Infatti 0x00010004 è il quinto anode nel secondo anodeblock. Un anode assomiglia a questo: ___________________ | | 000 | clustersize | 004 | blocknr | 008 | prossimo | |___________________| Il clustersize indica quanti blocchi sono allocati da questo anode. Il blocknr è il primo blocco allocato. Così un file deframmentato può sempre essere allocato in un singolo anode. Un file frammentato, tuttavia, ha bisogno di un anode per ogni frammento. Per questo motivo è il campo successivo. Esso indica il numero anode del successivo frammento. Se questo è l'ultimo frammento, il campo successivo avrà valore zero. Il clustersize ed il blocknr in un anode fanno sempre riferimento ai numeri reali di blocco, anche se i blocchi sono locati nell'area riservata. Se tutti i campi di anode sono a zero, esso viene considerato libero e può quindi essere riusato. È possibile associare un anode ad un file senza allocare nessun blocco. Questo può essere fatto settando il clustersize ed i campi successivi a 0, oltre al campo blocknr a -1. Il primi sei anodes hanno un significato speciale: anode nome uso ---------------------------------------------- 0 ANODE_EOF dovrebbe sempre essere 0 1 non usato, settare a 0 2 non usato, settare a 0 3 non usato, settare a 0 4 ANODE_BADBLOCKS Elenco blocchi bad. Non usato da PFS. strumenti di Riparazione possono incatenare i blocchi a questo anode 5 ANODE_ROOTDIR L'anode della directory di radice. Tu puoi trovare la directory di radice guardando questo anode Tutto gli anodes da 6 in su sono usati per le directory e l'allocazione dei file. ******************** * dirblocks ******************** Le Directory hanno un numero anode, proprio come i file. Ogni anode punta a un blocco di directory di 1024 byte (per questo motivo, con 512 blocchi di byte, il campo clustersize di un anode appartenente ad una directory è sempre 2). Se 1024 byte non sono abbastanza per la directory, un nuovo blocco con un nuovo anode viene allocato e incatenato prima di tutto. Due anodes appartenente alla stessa directory non sono mai uniti per formarne uno (incrementando il clustersize). Un dirblock assomiglia a questo. ___________________ | | | 000 | id | x | |_________|_________| 004 | | | datestamp | |___________________| | | 008 | riservato | |___________________| | | 00c | anodenr | 010 | genitore | |___________________| 014 | | |entrate directory | 400 |___________________| Il anodenr (anode numero) fà riferimento all'anode appartenente alla directory, non all'anode appartenente al blocco. Infatti punterà sempre punta all'inizio dell'incatenamento dell'anode, ed esso è lo stesso per tutti i blocchi della stessa directory. Il genitore è il numero anode del genitore di questa directory, o 0 se questo è il rootdirectory (che non ha un genitore). Un'entrata di directory assomiglia a questo: _____________________ | | | 000 |prossimo | tipo | |_________|___________|_________________ | | 002 | anode numero | 006 | dimensione | |_______________________________________| | | 00a | giorno di creazione | 00c | minuto di creazione | 00e | creazione tick | |_____________________| | | | 010 | prot | nlength | |_________|___________| | | 012 | nome | | | |_____________________| 012 + | | nlength | flength | |_________|___________ 013 + | | nlength | filenote | | | |_____________________| | | solo Modo_DIREXTENSION | estensione | | | |_____________________| Il campo successivo indica la lunghezza di questa entrata della directory in byte. Questo deve avvenire sempre. Il tipo è il tipo di direntry, proprio come in FFS: ST_File, ST_USERDIR etc. Vedere gli include file per ulteriori dettagli. Il numero anode è alla testa dell'incatenamento anode per questo oggetto. La dimensione è la dimensione_del file in byte. Il numero di blocchi nella catena anode devono corrispondere al numero di blocchi necessari per conservare la 'dimensione' dei byte. Il giorno di creazione, minuto e tick è il timestamp DOS dell'oggetto. La protezione consiste negli 8 bit inferiori di protezione di file, come per FFS. Il nome e il filenote sono stringhe pascal (la lunghezza è eseguita con quel numero di caratteri). Essi sono messi direttamente dietro l'un all'altro e sono byte allineato. Se il file non ha nessun filenote, flength sarà a zero. Ogni entrata di directory è riempita se necessario con la word allineata alla successiva entrata di directory. Il blocco finale della directory viene indicato aggiungendo un zero alla fine dell'ultima entrata. La directory finisce con l'ultima entrata nell'ultimo blocco, dove i blocchi sono incatenati con gli anodes. ******************** * dirextension ******************** Se Mode_DIREXTENSION è abilitato alcuni facoltativi campi extra di dimensione word sono aggiunti dopo l'aggiunta della word allineata. L'ultimo campo estensione è una word size bitfield che indica quali campi sono presenti. Attualmente i campi extra includono: ______________________ | | | link (alto) | Anodenr collegamento |______________________| | | | link (basso) | |______________________| | | | uid | ID Utente |______________________| | | | gid | ID Gruppo |______________________| | | | prot (alto) | campo protezione da 32 bit |______________________| | | | prot (basso) | |______________________| | | | virtualsize (alto) | dimensione virtuale 32 bit (per rollover file) |______________________| | | | virtualsize (basso) | |______________________| | | | rollpointer (alto) | rollpointer 32 bit (per rollover file) |______________________| | | | rollpointer (basso) | |______________________| | | | flagfield | Unico campo sempre presente |______________________| 'Link' è per i link, descritto in seguito. Il campo prot è collegato con il campo 8 di protezione bit direntry->protection (O operazione) per formare un valore di protezione di 32 bit. Se i 24 bit superiori sono a zero, questo campo prot non verrà usato. Il filesystem controlla solo direntry->protection nel momento in cui sta accedendo al file. I seguenti frammenti di codice mostrano come estrarre e come fare extrafields. Le Macro da usare nonché i tipi possono essere trovati in 'pfs.h'. void GetExtraFields (struct direntry *direntry, struct extrafields *extrafields) { UWORD *extra = (UWORD *)extrafields; UWORD *fields = (UWORD *)(((UBYTE *)direntry)+direntry->next); UWORD flags, i; flags = *(--fields); for (i=0; i < sizeof(struct extrafields)/2; i++, flags>>=1) *(extra++) = (flags&1) ? *(--fields) : NULL; } static void AddExtraFields (struct direntry *direntry, struct extrafields *extra) { UWORD offset, *dirext; UWORD array[16], i=0, j=0; UWORD flags = 0, orvalue; UWORD *fields = (UWORD *)extra; offset = (sizeof(struct direntry) + (direntry->nlength) + *FILENOTE(direntry))&0xfffe; dirext = (UWORD *)((UBYTE *)(direntry) + (UBYTE)offset); orvalue = 1; /* fill packed field array */ for (i=0; i < sizeof(struct extrafields)/2; i++) { if (*fields) { array[j++] = *fields++; flags |= orvalue; } else { fields++; } orvalue <<= 1; } /* add fields to direntry */ i=j; while (i) *dirext++ = array[--i]; *dirext++ = flags; direntry->next = offset + 2*j + 2; } BTW: se Mode_DIREXTENSION è abilitato, il campo flag deve essere sempre presente, anche se nessuno degli altri campi viene usato. Un campo non usato assume il valore zero. ******************** * hard links ******************** L'oggetto principale (l'oggetto che è linkato a) è di tipo ST_File (ST_DIR) come un file ordinario (dir). Il suo anodenr punta ai oggetto dati, come avviene di solito. Il campo di collegamento nell'estensione directory punta alla testa della LINK LIST. La LINK LIST è mappata su un anode list. Il 'collegamento' è nient'altro che un numero anode. I campi sono stati ridefiniti, tuttavia: ___________________ | | 000 | oggetto dir | 004 | link dir | 008 | successivo | |___________________| Ogni entrata nella LINK LIST rappresenta un collegamento (l'oggetto non ha un nodo con LINK LIST). L''oggetto dir' è il numero anode della directory dove l'oggetto può essere trovato. Il 'link dir' è l'anodenr della directory dove il collegamento può essere trovato. 'successivo' è il anodenr del successivo LIST NODE o 0 se si è alla fine della lista. In un collegamento di tipo ST_LINKFILE (ST_LINKDIR). Il suo numero anode punta al suo elemento di LINK LIST. La LINK ENTRY nell'estensione directory è il numero anode dell'oggetto. Un collegamento può essere analizzato come segue: · Get LINK LIST element (anodenr in directory) · Get object dir (campo oggetto dir) · Localizzare l'oggetto cercando l'anodenr come stabilito nell'estensione di directory link field. BTW: il numero anode come stabilito nella directory è un identificatore di entrata unico della directory, anche per quanto concerne i collegamenti. ******************** * soft links ******************** Un softlink è un file di lunghezza strlen(target) e di tipo ST_SOFTLINK. Il blocco che contiene il nome del target può essere localizzato leggendo il collegamento come un file (anode.blocknr). ******************** * deldir ******************** La deldir è una directory nascosta che contiene gli ultimi 31 file recentemente cancellati e/o sovrascritti. Essa è accessibile usando la radice dal suo nome '.deldir'. La directory delete assomiglia a questo: ___________________ | | | 000 | id | x | |_________|_________| | | 004 | datestamp | |___________________| | | 010 | roving | corrente delete posizione 012 | uid | deldir utente id 014 | gid | deldir gruppo id 016 | protezione | deldir protezione (LW) 01a | creationday | 01c | creationminute | 01e | creationtick | |___________________| 020 | | | | | 31 deldirentries | | | 400 |___________________| Il deldir contiene 31 slot che contengono deldirentries. Questi slot sono riempiti in modo round-robin, ed usa il 'roving' come puntatore di posizione. Un deldirentry assomiglia a questo: ___________________ | | 000 | anodenr | 004 | dimensione | dimensione in byte 008 | creationday | datestamp (copiato da file originale) 00a | creationminute | 00c | creationtick | |___________________| 00e | | | nome file | nome del file, troncato a 17 caratteri 020 |___________________| 'nome file' è una stringa pascal; lunga 17 caratteri. Quando un file è cancellato o sovrascritto esso viene aggiunto alla deldir nello slot indicato da 'roving'. Solo i file sono messi nella deldir, nessuna directory o link. Lo spazio su disco occupato da questi file viene liberato nel momento in cui il file originale viene cancellato, perciò un'entrata della deldir può divenire non valida se in un qualsiasi momento dei dati sono scritti nel disco. Quando la deldir viene esaminata (per esempio scrivendo "dir pfs:.deldir") PFS controllerà la validità di ogni entrata e visualizzerà solo le entrate valide. La routine di esame aggiunge il numero di slot di deldir per ogni entrata (per esempio foo@003) per accertarsi che ogni entrata ha un nome unico. I File nel deldir dovrebbe essere visualizzati con lo stesso nome. L'anodechain preso da un deldirentry non viene liberato finchè il deldirentry viene riusato. ********************** * estensione rootblock ********************** Con la versione 16.4 di AFS è stata introdotta l'estensione rootblock. Essa è un blocco di area riservato che contiene informazione generali sul disco che non sono riportate nel rootblock. Il blocco è descritto nella 'estensione' campo nel rootblock. La sua presenza viene indicata dal bit Mode_Extension bit nel campo opzioni rootblock. PFS creerà automaticamente l'estensione rootblock sui dischi più vecchi, così da avere un blocco di estesione su ogni disco impiegato con PFS. L'estensione rootblock assomiglia a questo: ______________________ | | | 000 | id | x | |___________|__________| | | 004 | ext. opzioni | flag per opzioni (future). Attualmente 0. 008 | datestamp | 00c | pfsversion | PFS revisione id. |______________________| | | 010 | rootdate giorno, min | la directory di radice datestamp |______________________| | | 014 | tick | |__________|___________ | | 016 | voldate giorno, min | il volume datestamp |______________________| | | 01a | tick | |__________|___________ | | 01c | postecipato - | | operazione | |______________________| | | 02c | riservato roving | area riservata al puntatore roving |______________________| | | 030 | roving bit | bitnumber del puntatore roving (area normale) |______________________| | | 032 | corrente anode seq | puntatore roving per allocazione anode |______________________| | | 034 | riservata | |______________________| | | 040 | superindex | solo Modo_SUPERINDEX : sino a superblock 64 | | | | | | |______________________| 100 | . | | . | | . | 400 |______________________| PFS deposita l'id della revisione corrente (numero versione nella high word, numero di revisione in low word, per esempio $00100004 per la versione 16.4) nel campo 'pfsversion' nel momento in cui si sta formattando un disco. In questo modo si può identificare qual'é la più vecchia versione di PFS che e' stata usate sul volume. I nuovi dati, rootdate e volumedate, sono un complemento del creationdate nel rootblock. Il tre datestamps sono usati come segue: Data di Creazione Volume (rootblock): Influenzato solo dal formato e dall' ACTION_SERIALIZE_DISK. Data Volume (estensione): Zerod da formato. Corretto ad ogni aggiornamento. Data Radice (estensione): datestamp della directory Radice. L'operazione postecipata è un campo di 4 longword usato internamente da PFS. Deve essere considerato come errore se questi campi non contengano zero su un volume PFS inibito. Il superindex usato solo in Modo_SUPERINDEX. Le longword nel superindex sono riferimenti a superblocks. Un superblock è un indexblock che indicizza i blocchi anodeindex. ************************* * contatore file rollover ************************* I file Rollover sono file con un filesystem con un controllo sulla dimensione massima. Quando il file vieve aggiunto ad esso sarà occupato a tenere la dimensione sotto il massimo. I file Rollover file sono identificati dal filetype ST_ROLLOVERFILE (== -16). Il campo dimensione nella directory specifica quanto spazio su disco è allocato per il file rollover. Il campo virtualsize nell'extrafields indica quanto dello spazio allocato è attualmente in uso. Questo inizialmente sarà 0 e crescerà finchè non sarà uguale allo spazio allocato su disco (extrafields->vitualsize == direntry->dimensione). La dimensione virtuale non può mai essere più grande della dimensione allocata. Il campo rollpointer nel campo extrafields specifica la posizione nell'area allocata dove il file rollover inizia. I file Rollover sono letti in modo circolare, iniziando e finendo al puntatore rollover. Esempio rollover file con 2048 byte allocati: 0 offsets reali 2047 ______________________________________________________________ | | | | | L|N|F | |____________________________|_|_______________________________| offsets virtuali 2046 0 <--------------------------------------------------------------> area allocata 2048 bytes L = ultimo byte di file N = fine di file F = primo byte di file La dimensione usabile di file rollover sempre un multiplo del blocksize meno uno.