Lezione 20 File system Linux - WEB Lab

Pagina creata da Marika Spada
 
CONTINUA A LEGGERE
Lezione 20 File system Linux - WEB Lab
Lezione 20
File system Linux
Sistemi Operativi (9 CFU), CdL Informatica, A. A. 2020/2021
Dipartimento di Scienze Fisiche, Informatiche e Matematiche
Università di Modena e Reggio Emilia
http://weblab.ing.unimo.it/people/andreolini/didattica/sistemi-operativi
                                                                           1
Quote of the day
                  (Meditate, gente, meditate...)

“I think the major good idea
in Unix was its clean and
simple interface: open, close,
read, and write.
Ken Thompson (1943-)
Programmatore
Il padre dei SO UNIX e Plan 9
Ideatore dei linguaggi B e Go
                                                   2
FILE: RAPPRESENTAZIONE E ACCESSO

                                   3
Definizioni preliminari
                 (File, directory, file system)

Nei SO moderni (non solo UNIX), le informazioni
possono essere memorizzate in maniera
strutturata e permanente su supporto
secondario.
Paradigma d'uso: memorizzazione gerarchica
tramite cartelle (directory) e fascicoli (file).
Un file system è una gerarchia di directory e file,
ospitata su un dispositivo di memorizzazione
secondaria.
                                                  4
Il file
               (Not so easy as you might think)

Un file è una sequenza di byte memorizzata su
supporto secondario.
  È identificabile univocamente tramite un nome.
  È un contenitore di dati arbitrari.
Un file è composto da due parti.
  Una struttura di controllo che memorizza le proprietà
  durevoli (meritevoli di sopravvivere al riavvio).
  Un insieme di blocchi di dati.
                                                      5
File Control Block
                   (La struttura di controllo)
                                                        FCB

Il File Control Block è la
struttura che memorizza le
proprietà durevoli di un file.
   Proprietario.
   Date notevoli (creazione,
   ultimo accesso, modifica).
   Dimensione.
   Permessi di accesso.
   Puntatori a blocchi di dati
   (il primo o tutti).
Il FCB è memorizzato su disco.                   Hard         6
                                                 disk
Recupero dei metadati
                      (API GNU/Linux)

int stat(const char *path, Riempie la struttura dati buf
struct stat &buf);         con i metadati del file puntato
                           da path.

                                                         7
Recupero dei metadati
                        (API)

In GNU/Linux, la chiamata di sistema stat()
ritorna una struttura dati contenente i metadati
di un file.
I parametri passati in ingresso sono due:
  il nome del file.
  il puntatore ad una struttura dati che sarà riempito
  con i metadati.
                                                     8
Tipi di file
          (File di testo, documenti, eseguibili, script di shell)

I file possono essere classificati in tipi, in modo
tale da assegnare ad essi una applicazione di
default che li possa gestire.
Esempi:
  Codice sorgente → editor del programmatore.
  File multimediale → riproduttore audio/video.
Come fa il SO a riconoscere il tipo di file?
  Associazione di una estensione.
  Analisi del contenuto del file.                                   9
Estensione
                    (.txt, .doc, .exe, .sh)

Si aggiunge al nome del file una estensione
secondo lo schema:
  
Esempi:
  command.com, autoexec.bat, report.doc
In tale schema:
  nome_file è un nome assegnato dall'utente.
  estensione      è     una   stringa    rappresentante
  univocamente il tipo di dato in questione.
  separatore è un carattere che delinea il nome       10
  dall'estensione (solitamente, un punto).
Supporto per le estensioni:
           associazione diretta
              (Il SO decide l'applicazione di default)

Il meccanismo più semplice di riconoscimento
del tipo del file è la associazione diretta.
Il SO legge l'estensione del file e gli associa
automaticamente una applicazione tipo.
Il nome dell'applicazione tipo:
  è cablato nel SO (MS-DOS, UNIX                         linea   di
  comando con filtro lesspipe).
  è scritto come metadato del file (Mac OS).
                                                                 11
Supporto per le estensioni:
          lista di estensioni 1/2
          (L'applicazione dichiara la sua lista di estensioni)

Ciascuna applicazione gestisce una lista di
estensioni gradite.
  Ad esempio, Libreoffice → .doc, .odt, .docx
Diverse applicazioni possono leggere lo stesso
tipo di file.
  Abiword, Openoffice, Libreoffice → .doc
Una sola applicazione può essere impostata
come il default per un dato tipo di file. 12
Supporto per le estensioni:
          lista di estensioni 2/2
          (L'applicazione dichiara la sua lista di estensioni)
Quando un utente clicca due volte sull'icona di
un file in un ambiente desktop, il SO carica
l'applicazione di default.
Quando un utente clicca col tasto destro
sull'icona del file e seleziona “Apri con...”, viene
mostrata la lista delle applicazioni in grado di
gestire il tipo di file.
Approccio usato nei SO:
  Windows                                                        13
  UNIX (desktop grafico)
Analisi del contenuto
  (Approccio “signature-based”, simile al modus operandi di un antivirus)

Ciascun file è riconoscibile da una o più sequenze
di byte (dette magic number) in offset strategici.
  Ad esempio, un eseguibile in formato ELF contiene i
  caratteri 'E', 'L', 'F' nel secondo, terzo e quarto byte.
  Si digiti less /bin/ls per verificare.
Il sistema operativo contiene tutti i magic
number in un database locale su file, detto magic
file.
  /usr/share/file/misc/magic
                                                                            14
L'interfaccia ai magic file
    (Approccio “signature-based”; molto più potente delle estensioni)

Il comando file (UNIX, linea di comando)
scandisce un file alla ricerca dei magic number,
fino a quando non ne trova uno corretto.
  file file.txt
  file.txt: ASCII text, with very long lines.

                                                                        15
Il tipo di dato “file eseguibile”
    (AKA Come far partire i programmi eseguibili digitando il loro nome)

In GNU/Linux, un file eseguibile (riconosciuto
dalla signature del formato ELF) è associato ad un
programma detto caricatore (loader).
   /lib/ld-linux.so.2
Il caricatore:
   carica in memoria le librerie necessarie all'esecuzione.
   carica il programma.
                                                                           16
Il tipo di dato “file eseguibile”
        (AKA Come far partire gli script digitando il loro nome)

Il caricatore controlla se il file inizia con una riga
simile (detta she-bang):
  #!/bin/bash
Tale linea specifica l'interprete dello script.
In tal caso, il caricatore:
  carica l'interprete (con relative librerie)
  esegue l'interprete con argomento pari al nome dello
  script.
                                                                   17
FILE: ORGANIZZAZIONE INTERNA

                               18
Organizzazione logica e fisica
           (Come viene visto il file dall'utente e dal SO)

L'organizzazione           del                               Struttura logica
contenuto di un file è                                       (una riga del file,
                                                             una informazione)
suddivisa in due aspetti.
                                                         Struttura          fisica
Logica: il file è acceduto per                           (le righe del file sono
                                                         impacchettate in 4
unità logiche (singoli byte,                             blocchi del disco)
righe o record, indici).
Fisica: impacchettamento
delle unità logiche nei
blocchi fisici del disco.                                                     19
Impacchettamento del file su disco
               (Unità logiche → blocchi su disco)

L'unità logica del file è mappata sulla
rappresentazione fisica del disco (settore). Nel
caso degli hard disk, un settore è spesso lungo
512 byte.
In un file, l'unità logica è quasi sempre di
dimensione diversa rispetto al settore.
  Tipicamente, il record logico è più piccolo
  →Il gestore del file system cerca di impacchettare più
  record logici nei settori.                           20
Organizzazione logica
                  (Byte, linea, indice)

Un file può essere organizzato logicamente in tre
modi distinti.
  Organizzazione “per flusso di byte”.
  Organizzazione “per record logici”.
  Organizzazione “per indice”.
                                                21
Organizzazione per flussi di byte
            (The true UNIX way; keep it simple and stupid)

                                             1 record
                                             logico
Un file è visto come una sequenza
di record logici di lunghezza pari
ad 1 (sequenza di byte).
Non esiste una strutturazione;
l'applicazione legge flussi di byte.
È compito della applicazione dare
un significato al flusso di byte.
                                                             22
Organizzazione per record logici
          (L'unità è la riga di testo o la struttura dati binaria)

                                                  1 record
                                                  logico
Un file è visto come una sequenza
di record logici di lunghezza
maggiore di 1.
L'applicazione legge e scrive un
certo numero di record logici.
   Linee (I/O formattato).
   Strutture dati.
                                                                     23
Organizzazione per indice
                    (Usata nelle basi di dati)

                                            1 record   Indice: 1
Un file contiene una sequenza di            logico     Dati
record logici di lunghezza fissa.                      Indice: 2
Ciascun record contiene un campo                       Dati
indice in una posizione fissa.                         Indice: 3
L'albero è ordinato in base                            Dati
all'indice.                                            Indice: 4
Con una ricerca binaria sull'indice,                   Dati
si trova l'elemento i-mo in O(log n)
passi (n=numero di record logici).                                 24
L'indice doppio
        (Fondamentale in caso di accesso frequente alla base di dati)
In caso di cancellazioni ed
inserimenti frequenti dei record               File indice              File dati
logici, diventa molto costoso                                    Mario Rossi 30
mantenere ordinato il file.
Si usano due file:
  Un file indice contenente
  coppie .              Rossi
  Un file dati contenente i record
  logici.
Cancellazioni e inserimenti non
comportano il riordino fisico del                                               25
file dati.
L'indice gerarchico
          (Fondamentale in caso di basi di dati di grandi dimensioni)

                                                 File indice              File indice
                                                  primario              secondario
Se il file indice cresce a dismisura,                                   i
si adotta un indice multilivello.
   → Schema gerarchico.                                                     ...
   Un file indice primario punta ad
   un file indice secondario.
   Il file indice secondario punta al           Rossi    i
   record.
Tecnica utilizzata nei DBMS (IBM                                 Mario Rossi 30
ISAM).
                                                                File dati         26
Metodi di accesso ai file
               (Sequenziale, diretto, con indice)

Un file può essere acceduto in tre modi distinti.
  Accesso sequenziale.
  Accesso diretto.
  Accesso per indice.

                                                    27
Accesso sequenziale
    (Le unità logiche sono accessibili soltanto dalla prima all'ultima)

L'informazione contenuta nel file viene acceduta
sequenzialmente, ossia un record dopo l'altro.
Il modello considerato è quello di un nastro.
Applicazioni: copie di file, caricamento di un
programma.

                                                                          28
Accesso diretto
       (Le unità logiche sono accessibili anche direttamente)

L'informazione contenuta nel file viene acceduta
per    singoli blocchi fisici, direttamente
(casualmente).
Modello di un disco.
Applicazioni: deframmentazione di un disco.

                                                                29
Accesso per indice
     (Le unità logiche sono accessibili velocemente tramite indice)

L'informazione contenuta nel file viene acceduta
per indice, casualmente.
Modello di una base di dati.
Applicazioni: Database Management System
(DBMS).

                                                                      30
Relazione struttura interna ↔ accesso
                         (La norma)

Solitamente:
Accesso sequenziale → organizzazione per flussi di byte.
Accesso diretto → organizzazione per record logici.
Accesso tramite indice → organizzazione per indice.
Tuttavia, ciò non è sempre vero.
   La copia efficiente di un file contenente un DBMS
   (rappresentazione ad indice) avviene tramite letture e
   scritture a blocchi.
   → In realtà, è il tipo di applicazione che determina il
   tipo di accesso!                                     31
Fine del file
       (Il kernel deve comunicarlo all'utente in qualche modo)

Nei metodi di accesso sequenziale e diretto, può
capitare di leggere oltre la fine del file (End Of
File, EOF). Il SO deve rilevare questa condizione e
segnalarla all'utente.
Due strategie:
  Si fa ritornare un valore opportuno alla operazione di
  lettura.
  Si usa una operazione apposita per il controllo sul
  raggiungimento della fine del file.                  32
La tabella dei file aperti
        (Il kernel deve sapere quali file ha aperto un processo)

Ciascun PCB di processo contiene un puntatore
ad una tabella dei file aperti. Tale tabella
contiene strutture dati descriventi, all'intenro del
kernel, i file attualmente aperti dal processo.
In Linux, la task_struct ha un campo
struct files_struct *files.
                                                                   33
I/O low-level e bufferizzato
 (Si interagisce direttamente col kernel oppure si usa un buffer della GLIBC)

I/O diretto (basso livello, low-level): le
operazioni sono inviate direttamente al kernel,
una per una.
I/O bufferizzato: le operazioni di I/O sono gestite
da un buffer intermedio. Letture e scritture sono
“ritardate” fino al riempirsi del buffer.
                                                                                34
Buffering in GNU/Linux
            (Due buffer; uno applicativo, uno del kernel)

Buffer applicativo.
  Usato dalle funzioni di libreria del C.
  Le operazioni di I/O lavorano con un buffer più
  grande di un carattere.
  Una chiamata di sistema → Un minimo di lavoro per il
  kernel.
Buffer del kernel.
  Usato per “ricordarsi” delle letture fatte (le richieste
  successive sono servite da RAM).
  Usato per “raggruppare” le scritture (essendo più lente
  delle letture, sono fatte tutte insieme).              35
Buffering in GNU/Linux
                        (Un'immagine vale 1000 parole)
         Applicazione        Libreria del C
                                        Funzioni di I/O       Buffer
                                      (Bufferizzato o no)   applicativo

User                                          Chiamate
                                              di sistema
Kernel

                    Esecutore                  Buffer
                       I/O                     kernel
Hardware
                                                                          36
Esempio: read bufferizzata
                        (Un'immagine vale 1000 parole)
         Applicazione        Libreria del C
                         9              Funzioni di I/O          Buffer
                                      (Bufferizzato o no)      applicativo
                                 1
                                                           8
                                              2                 7
User                                          Chiamate
                                              di sistema
Kernel
                             3                             6

                    Esecutore                     Buffer
                       I/O                        kernel
Hardware                     4                5
                                                                             37
Impostazione del buffer applicativo
                 (Tre modalità distinte)

Nessun buffer: il buffer ha dimensione nulla (non
viene utilizzato).
Singola riga: il buffer è considerato riempito
quando raggiunge la sua massima dimensione o
quando si incontra un carattere newline.
Buffering completo: il buffer è considerato
riempito quando raggiunge la sua massima
dimensione.
                                               38
Flushing dei buffer
                   (Applicativi e kernel)

È possibile forzare in ogni istante il contenuto dei
buffer applicativo e/o kernel sul disco.
Un concetto, due nomi distinti.
Flush: svuotamento del buffer applicativo.
Sync: svuotamento del buffer del kernel.
                                                  39
I/O diretto e file descriptor
        (Il legame tra descrittore di file e tabella dei file aperti)

In caso di I/O diretto, un file aperto è identificato
da un intero detto descrittore di file (file
descriptor). Il descrittore di file è un indice
all'elemento relativo della tabella dei file aperti.
Il descrittore di file è ottenuto come valore di
ritorno della chiamata di sistema open().
                                                                        40
I/O bufferizzato e FILE *
            (Il legame tra FILE * e tabella dei file aperti)
In caso di I/O bufferizzato, un file aperto è
chiamato stream ed è identificato da un
puntatore ad una struct _IO_FILE (FILE *
nella libreria del C). Tale struttura contiene:
  il descrittore del file con cui identificare l'elemento
  della tabella dei file aperti.
  un puntatore al buffer applicativo di default.
  informazioni di controllo dello stream (posizione
  della testina, lunghezza del buffer, ...).
Il FILE * è ottenuto come valore di ritorno della
                                                41
funzione di libreria fopen().
Descrittore di file e FILE *
                               (Un'immagine vale 1000 parole)
                      FILE *                            I/O
     Applicazione
                                                    bufferizzato
Descrittore
    del file                I/O non           Descrittore
                          bufferizzato            del file
                    Descrittore
      User              del file

      Kernel                        Tabella dei
                                    file aperti

      Hardware
                                                                   42
Accesso non bufferizzato 1/2
                       (API GNU/Linux)
int open(const char    Apre un file di nome pathname nella
*pathname, int         modalità indicata da flags e con i
flags, mode_t mode); permessi indicati da mode. Si ottiene
                       un descrittore al file.
ssize_t read(int fd, Legge count byte dal file identificato
void   *buf,    size_t da fd nel buffer puntato da buf.
count);                Ritorna il numero di byte letti, 0 se
                       fine file,
Accesso non bufferizzato 2/2
                   (API GNU/Linux)

off_t lseek(int   fd, Sposta la testina di lettura del file
off_t   offset,   int indicato da fd alla posizione offset,
whence);              partendo da whence.
int close(fd);         Chiude il file indicato da fd.

                                                         44
Accesso bufferizzato 1/3
                     (API GNU/Linux)
FILE *fopen(const        Apre uno stream di nome pathname
char *pathname,          nella modalità e con i permessi indicati
const char *mode);       da mode. Si ottiene un puntatore al file
                         (descrittore e puntatori agli stream).
ssize_t   fread(void     Legge nmemb strutture dati di
*ptr, size_t size,       dimensione size dallo stream
size_t nmemb, FILE *     indicato da stream e le memorizza
stream);                 nel buffer puntato da ptr. Ritorna il
                         numero di strutture lette, 0 se fine
                         file o errore.
ssize_t  fwrite(void     Scrive nmemb strutture dati di
*ptr, size_t size,       dimensione size (contenute nel
size_t nmemb, FILE *     buffer puntato da ptr) nello stream
                                                                45
stream);                 indicato da stream. Ritorna il numero
Accesso bufferizzato 2/3
                       (API GNU/Linux)
int feof(FILE              Ritorna 1 se è stata raggiunta la fine
*stream);                  dello stream puntato da stream.
int ferror(FILE       Ritorna 1 se è stato rilevato un errore
*stream);             nelle operazioni sullo stream puntato
                      da stream.
int     clearerr(FILE Pulisce gli indicatori di errore e di
*stream);             EOF per lo stream puntato da stream.
int        fseek(FILE Sposta la testina di lettura dello
*stream,         long stream indicato da stream alla
offset, int whence)   posizione offset, partendo da
                      whence.
int fclose(FILE       Chiude lo stream indicato da         46
*fp);                 stream.
Accesso bufferizzato 3/3
                      (API GNU/Linux)
int fileno(FILE          Ritorna il descrittore di file associato
*stream);                allo stream puntato da stream.
void setvbuf(FILE        Imposta il tipo di buffering dello stream
*stream, char *buf,      puntato da stream nella modalità
int mode, size_t         specificata da mode. Il buffer puntato
size);                   da buf può essere nullo o di
                         dimensione massima pari a size.
int   fflush(FILE        Svuota il buffer applicativo associato
*stream);                allo stream puntato da stream.
int fsync(int fd);       Svuota il contenuto del buffer del
                         kernel relativo allo stream associato
                         al descrittore di file fd.
                                                             47
void sync(void);         Svuota l'intero buffer del kernel.
DIRECTORY: RAPPRESENTAZIONE

                              48
La directory
                  (Easier than I thought)

Una directory è un file
                                            nome   FCB
contenente coppie del tipo                  nome   FCB
(nome, puntatore).                          nome   FCB
                                            nome   FCB
Nome: Nome ad alto livello di
un contenitore di informazioni
(file, directory).
Puntatore: punta ad una
struttura dati contenente i
metadati di un file o di un'altra
                                                         49
directory.
Strutture di directory
               (Oggi si usa il modello a grafo)

                                      1.          2.
Una directory può essere
rappresentata mediante
diversi modelli (e relative
strutture dati).                      3.          4.
1.A singolo livello.
2.A due livelli.
3.Ad albero.
4.A grafo.                                             50
I difetti dei primi schemi
            (AKA “Perché oggi si usa lo schema a grafo”)

Schema a singolo livello (console anni '80):
estremamente scomodo nei sistemi multiutente
(che succede se due utenti nominano allo stesso
modo un file?).
Schema a doppio livello (VMS): esiste un
completo isolamento fra utenti.
Schema ad albero (MSDOS): è scomodo condi-
videre file fra utenti senza copiarli; è impossibile
creare “collegamenti a file”.                      51
Directory a grafo aciclico
            (Aciclico → niente cicli infiniti di directory)

Il file system è modellato con un grafo aciclico.
  Vertici: directory o file.
  Archi: relazioni fra directory e file contenuti.
  Vertice radice: rappresenta la directory radice del file
  system (UNIX: /, Windows: C:\).
In tale modello, il contenuto di un file può essere
referenziato da due elementi di directory (hard
link) distinti.
Usato da: SO UNIX.                                52
Directory a grafo aciclico
                (Aciclico → niente cicli infiniti di directory)

        /

                             I due elementi di directory
home          bin            puntano allo stesso FCB
                             (dunque, allo stesso contenuto).
                            Hard link

       amap         amap6

                            Hard link

                                                                  53
Un esempio di hard link
                       (Debian)
Nel SO Debian GNU/Linux, i due comandi
eseguibili sudo e sudoedit (in /usr/bin)
sono due hard link allo stesso contenuto.
  ls -l /usr/bin/sudo*
  Si osserva il contatore di hard link (secondo campo).
  Il contatore è posto a 2 (due elementi di directory
  puntano allo stesso contenuto).
Rationale: il programma si comporta in maniera
diversa a seconda del suo nome (ARGV[0]).
  Non c'è bisogno di installare due programmi quasi54
  identici; se ne usa uno solo → risparmio di spazio.
Limitazioni del modello a grafo aciclico
                      (Diverse, purtroppo)

Non è possibile introdurre un ciclo nel grafo.
  → Niente link a directory superiori (si creerebbe un
  ciclo infinito).
  cd directory in una directory con ciclo → stallo.
Non è possibile creare un hard link ad un file in un
altro file system.
  File system diversi → implementazioni diverse delle
  directory.
  Ogni file system dovrebbe conoscere l'implementazione
  delle directory di ogni altro file system → impraticabile. 55
Directory a grafo ciclico
            (Ciclico → possibili cicli infiniti di directory)

Il file system è modellato con un grafo ciclico.
  Vertici: directory o file.
  Archi: relazioni fra directory e file contenuti.
  Vertice radice: rappresenta la directory radice del file
  system (UNIX: /, Windows: C:\).
In tale modello, è possibile creare link in grado di
chiudere cicli (noti con il nome di soft link).
Il contenuto è unico! I metadati del file sono unici!
Usato da: SO UNIX (soft link), Windows
                                                   56
(collegamenti simbolici).
Directory a grafo ciclico
                (Ciclico → possibili cicli infiniti di directory)

        /                      I due elementi di directory
                               puntano ad FCB diversi.
                          Il contenuto puntato Il contenuto puntato
                          da questo FCB è il da questo FCB è
home          bin         percorso del file quello del file originale.
                          collegato.
                            Hard link

       gawk         awk

                            Hard link

                                                                    57
                                     Soft link awk → gawk
Un esempio di soft link
                          (Debian)

Nel SO Debian GNU/Linux, il comando eseguibile
xzcat (in /usr/bin) è un link simbolico al file
xz.
  ls -l /usr/bin/xz{cat,}
  Il tipo di file è il link simbolico (lettera 'l' iniziale).
  La dimensione del link simbolico è 2 (“xz”).
  Gli hard link sono posti ad 1 (due istanze uniche di
  contenuti; il contenuto originale ed il percorso ad
  esso).
Rationale: gli stessi degli hard link.                     58
Soft link vs. hard link
                         (2:0)

I soft link possono essere creati fra molteplici file
system.
  Se il file destinazione non è presente (ad es. è su un
  CDROM non inserito), il link è colorato di rosso.
I soft link possono essere creati verso directory
superiori.
                                                      59
Gestione dei cicli infiniti
                         (2:0)
                                                /
Scenario:      il comando
find       scandisce      un
sottoalbero di directory               home         bin
con un soft link alla
directory di partenza.
→ Ciclo infinito.                studente     andreoli
La gestione dei cicli infiniti
è delegata alle applicazioni.
find /home/andreoli -name
                                              andreoli
  andreoli -follow                                        60
Cancellazione di file
            (“Si tagliano gli hard link con le forbici”)

L'hard link di un file è un conteggio di
riferimento. Il conteggio serve ad impedire la
distruzione del contenuto di un file in presenza di
utenti che ne usufruiscono.
Quando si cancella un file, si decrementa di uno il
conteggio degli hard link.
Se il conteggio è zero, si stacca il contenuto del
file dal suo FCB.
                                                           61
Alcune doverose osservazioni
                     (Da ricordare)

Il contenuto del file non è fisicamente cancellato,
bensì staccato dal file system. È possibile
recuperarlo con strumenti appositi.
Un file aperto da una applicazione rimane ancora
accessibile fino alla chiusura del descrittore.

                                                 62
Gestione dei link
                   (API GNU/Linux)

int link(const char    Crea un nuovo link hard di nome
*oldpath, const char   newpath al file identificato dal nome
*newpath);             oldpath.
int symlink(const      Crea un nuovo link soft di nome
char *oldpath, const   newpath al file identificato dal nome
char *newpath);        oldpath.

int unlink(const       Decrementa di uno il contatore degli
char *pathname);       hard link. Se il contatore diventa
                       zero, il file non è più accessibile con
                       mezzi standard.
                                                               63
Implementazione delle directory
                    (Una semplice lista?)

L'implementazione più semplice di una directory
è attraverso una lista semplice di strutture dati
contenenti, ciascuna:
  un nome di file/directory.
  un puntatore al FCB.
L'implementazione è semplice, l'efficienza può
essere molto bassa (scansione lineare della lista
→ O(n) con il numero di file nella directory).
Implementato in Linux (EXT2, EXT3).             64
Implementazione delle directory
                   (Una tabella hash?)

Un'altra implementazione della tabella delle
directory fa uso di una tabella hash e di una lista
semplice (Linux, EXT3, EXT4 prime versioni).
Lista semplice:
Contiene le coppie .
Tabella hash:
  Chiave: un hash del nome del file.
  Valore: Un puntatore all'elemento      della   lista
  corrispondente.
                                                    65
Implementazione delle directory
                       (Binary tree?)

Un'altra implementazione della tabella delle
directory fa uso di un albero binario (Linux, EXT4
versione attuale).
  L'albero binario contiene hash dei nomi di file ordinati
  alfanumericamente.
  I nodi foglia dell'albero contengono puntatori ai FCB.

                                                        66
Accesso alle directory
           (Molto simile all'accesso bufferizzato ai file)
L'accesso alle directory avviene mediante un
descrittore di directory simile al puntatore allo
stream usato nell'I/O bufferizzato.
Tale descrittore è rappresentato dalla struttura
struct __dirstream rinominata in DIR
nella libreria del C).
Si ottiene un puntatore a tale descrittore
mediante la funzione di libreria opendir() che,
analogamente a fopen(), apre una directory.
                                                             67
Elementi di directory
                (Un elemento ↔ una struct dirent)

Nei sistemi GNU/Linux, ogni elemento di
directory è identificato da una struct dirent,
definita nel file seguente:
$LINUX/include/dirent.h.
  Nome dell'elemento.
  Tipo di file (regolare, directory, speciale, link, …).
  Puntatore al FCB associato al file.

                                                           68
Operazioni su una directory
                 (Directory ↔ Stream)

La directory viene gestita come uno stream di
record logici di tipo struct dentry.
  Riposizionamento dello stream.
  Recupero posizione dello stream.
  Lettura della prossima struct dentry.

                                            69
Gestione delle directory
                      (API GNU/Linux)
DIR *opendir(const       Apre la directory di percorso name e
char *name);             ritorna un descrittore di directory.
struct dirent *          Ritorna il prossimo elemento della
readdir(DIR *dirp);      directory identificata da dirp. Ritorna
                         NULL se la directory è stata scandita
                         tutta.
void rewinddir(DIR       Reimposta il prossimo elemento da
*dirp);                  scandire al primo file della directory.
long telldir(DIR         Ritorna la posizione dell'ultimo
*dirp);                  elemento scandito nella directory.
int closedir(DIR         Chiude la directory identificata da dirp.
*dirp);                                                              70
Creazione e cancellazione di directory
                   (API GNU/Linux)

int mkdir(const char   Crea la directory di nome pathname
*pathname, mode_t      con i permessi specificati da mode.
mode);
int rmdir(const char   Rimuove la directory di nome
*pathname);            pathname. La directory deve essere
                       vuota.

                                                             71
MONTAGGIO E SMONTAGGIO

                         72
Aggancio di un nuovo file system
                   (File system mount)

Un file system, prima di essere utilizzato
  deve essere associato ad un dispositivo di
  memorizzazione secondaria.
  deve essere agganciato ad un file system esistente,
  usando una directory come punto di attacco.
Tali due operazioni prendono il nome di file
system mount o, più brevemente, mount.
La directory di aggancio prende il nome di
mount point (punto di attacco).
                                                   73
La tabella di mount
            (Analogia con la tabella dei file aperti)

Il kernel mantiene una tabella di mount. In tale
tabella sono mantenute tutte le associazioni
dispositivo ↔ mount point.
In Linux, la tabella di mount è implementata
tramite la struttura dati struct vfsmount.
  File $LINUX/include/mount.h

                                                        74
Sgancio del file system
                  (File system umount)
Il file system può essere staccato dal suo mount
point tramite l'operazione di unmount (umount
nel gergo UNIX), sostanzialmente l'inversa di
mount. L'unmount è preceduto da un flush dei
buffer del kernel.
NOTA BENE: per motivi di efficienza, le scritture
su di un file system sono eseguite in blocco, al
momento più favorevole.
→ Estrarre fisicamente un dispositivo senza aver
smontato il suo file system equivale a75
corromperne i dati!
Root file system
                  (La radice di tutti i mali)

Almeno un file system deve essere presente
all'avvio del SO, affinché il mount degli altri file
system sia sempre possibile.
Tale file system prende il nome di
root file system e contiene almeno il comando
init (directory /sbin o /usr/bin) per
avviare i servizi della macchina.
Tipicamente, il root file system è associato ad un
disco rigido installato permanentemente.           76
Aggancio file system: prima
                          (Due alberi staccati)
Tabella di mount                                  Root file system
                                                   su disco rigido
       /           Disco rigido
                                                                Root directory
                                                                      /
File system
su CD-ROM
                                          Mount point
                                         /media/cdrom

                                                                           77
Aggancio file system: dopo
                            (Due alberi uniti)
Tabella di mount                                 Root file system
                                                  su disco rigido
       /           Disco rigido
                                                               Root directory
/media/cdrom         CDROM                                           /
File system
su CD-ROM
                                           Mount point
                                          /media/cdrom

                                                                          78
Opzioni di mount
         (Lettura e scrittura, esecuzione, sincrona, asincrona)

read-only: il file system è montato in sola lettura.
sync: le scritture sono sincrone (eseguite una
dietro l'altra, in maniera bloccante).
async: le scritture sono asincrone (eseguite in
blocco, più avanti, nel momento più favorevole).
exec: si permette l'esecuzione dei programmi.
                                                                  79
Montaggio e smontaggio
                    (API GNU/Linux)
int mount(const char   Monta il file system identificato dal
*source, const char    percorso source nel mountpoint
*target, const char*   identificato dal percorso target. È
filesystemtype,        possibile specificare direttamente il
                       tipo di filesystem nella stringa di nome
unsigned long          filesystemtype.     Le      opzioni    di
mountflags, const      montaggio        sono      impacchettate
void *data);           nell'intero lungo mountflags. Il
                       puntatore data permette di passare
                       informazioni      specifiche     di   un
                       filesystem.
int umount (const      Rimuove l'associazione fra dispositivo e
char *target);         mountpoint.
                                                               80
Puoi anche leggere