Gestire files e directory

I file presenti sul PC vengono normalmente salvati su un hard disk; questo può memorizzare una sequenza di byte, raggruppati in blocchi, e nessuna struttura aggiuntiva. Il sistema operativo mostra una rappresentazione strutturata di questi dati, che viene chiamata file system.

Grafi ed alberi

La struttura dei file viene memorizzata come un albero (che è un particolare tipo di grafo); un grafo è in generale un insieme di nodi (o vertici) e di archi che li connettono. Si può definire matematicamente come una coppia ordinata $(V, E)$ dove $V$ è un insieme di nodi, e $E \subseteq V \times V$ sono gli archi. Un grafo viene detto albero quando non presenta cicli.

Nella terminologia degli alberi solitamente si riconosce un nodo principale, detto radice; i nodi a lui connessi tramite un arco sono detti figli; analogamente, questi altri nodi avranno degli altri figli, corrispondenti ai nodi raggiungibili in due passi dalla radice, e così via. I nodi che non hanno figli vengono detti foglie.

Si noti che la distanza dalla radice è una distanza ben definita su $V$, perché se esistesse più di un cammino che collega la radice e qualsiasi altro nodo dovremmo necessariamente avere un ciclo.

File system

Nei file system su Linux il nodo radice viene denotato da /; i suoi figli hanno un nome del tipo

/figlio1
/figlio2
/figlio3
...
Analogamente, queste possono avere ulteriori figli come /figlio1/sottofiglio1. Ogni foglia nell'albero può corrispondere ad un file, oppure ad una directory vuota.

In questa nuova ottica, possiamo pensare al comando ls come ad un comando che elenca i figli di un dato nodo. Similmente, il comando tree mostra graficamente tutto il sottoalbero ottenuto a partire da un determinato nodo.

Un altro comando utile per rappresentare la struttura di una directory è il comando tree. Si provi ad utilizzarlo nella propria home directory.

Per interrompere un comando che si è bloccato, o richiede troppo tempo per essere eseguito, si può usare la combinazione di tasti CTRL+C. Provare ad esempio a digitare tree /. Questo comando lista tutto l'albero dei files presenti nel sistema.

Le directory home, dove gli utenti memorizzano i dati, vengono create come "figli" della directory /home, e prendono come nome /home/mario, /home/pippo, ecc., a seconda del nome dell'utente. Dato che questa directory è di uso molto comune, può essere sempre rimpiazzata dal simbolo ~, come si è visto negli esercizi precedenti.

Per spostarsi da una directory all'altra, è possibile utilizzare il comando cd; provare ad esempio ad entrare nella cartella ~/.ssh dando il comando
$ cd .ssh
Si noti che non è necessario inserire la tilde, perché il percorso in cui spostarsi viene specificato in modo relativo (ovvero, entra nella cartella .ssh a partire da dove sono ora).

Files e inode

Ogni file corrisponde ad una determinata sequenza di byte, che deve essere salvata sul supporto di archiviazione (SSD, Hard disk, DVD, ecc.) Per sapere in quale punto del disco il file viene memorizzato, ad ogni filename viene associato un numero intero detto inode.

Si utilizzi il comando ls -i ~/.ssh per visualizzare gli inode relativi ai file contenuti nella cartella ~/.ssh. Si provi a visualizzare anche gli inode legati ad altri file, più vicini alla radice.

Possiamo definire il file come l'insieme di dati memorizzati, l'inode come l'identificatore dell'area dove questi sono memorizzati, ed il filename come un'etichetta per questo inode.

La corrispondenza fra filename e inode non è biunivoca: ad un inode possono corrispondere più filename; chiaramente, cambiare il contenuto di un file altera anche il contenuto di quello disponibile sotto un'etichetta (filename) diverso, ma che corrisponde allo stesso inode. Ad entrambi corrispondono gli stessi dati fisici sul disco. Normalmente, si dice che i due filename sono collegati; il termine utilizzato in Linux per questo collegamento è hard link.

Si utilizzi il comando echo combinato con la redirezione dell'output per creare un file con del testo nella cartella corrente, ad esempio:
$ echo "testo di prova" > miofile.txt
Si controlli l'esistenza del nuovo file con ls, e si stampi il contenuto con cat; si crei poi un hard link a quel file con il comando
$ ln miofile.txt altrofile.txt
Si controlli il contenuto di altrofile.txt, che dovrà essere lo stesso di file.txt; si provi ad aggiornare il contenuto del file con il comando echo. Si controlli il numero di inode dei due filename utilizzando ls -i.

Per eliminare un file, si può utilizzare il comando rm. Quest'operazione rimuove l'etichetta di un determinato inode. Se quell'etichetta era l'unica che identificava quei file, allora i dati non saranno più disponibili. Ad esempio, rm miofile.txt rimuove il filename che è stato appena creato. Normalmente, questo rende inaccessibili i dati precedentemente salvati, perché la maggior parte dei file è disponibile attraverso un unico filename.

Tuttavia, nell'esempio in considerazione gli stessi dati sono identificati anche dal file altrofile.txt che quindi rimarrà disponibile. Tramite il comando ls è sempre possibile vedere quanti file puntano un determinato inode (è il numero nella seconda della colonna dell'output di ls -l).

Sperimentare con il comando rm sui file creati tramite hard-link. Si può osservare che il comando rm si limita a scollegare un hard-link. Verificare utilizzando ls -l.

Ci sono altre due operazioni basilari che si possono effettuare sui file: la copia (tramite il comando cp) e lo spostamento (tramite il comando mv). La sintassi per cp è la seguente:

$ cp sorgente destinazione
Questi comandi sembrano simili, ma sono fondamentalmente differenti:

Esiste un'opzione del comando cp che permette di copiare i file effettuando degli hard-link, invece che delle vere copie. In questo senso, il comando diventa sostanzialmente equivalente a ln. Utilizzare man per determinare questa opzione, e provare a fare una copia di un file di testo.

Directories

Per creare directories, è possibile utilizzare il comando mkdir.

Creare una cartella di nome test, e al suo interno generare almeno tre file che contengano del testo a propria scelta. È possibile avere dettagli sull'utilizzo di mkdir con il comando man mkdir. Utilizzare il comando cd per spostarsi fra le cartella. Si ricordi che .. indica la cartella superiore, e dunque per "uscire" da una cartella si può usare il comando cd ..

I comandi mv e cp permettono di spostare e copiare cartelle, oltre che file. Ad esempio, per spostare una cartella si può usare la sintassi

$ mv nomevecchio nomenuovo
Si sperimentino i comandi mv e cp sui file creati in precedenza dentro la cartella test; nel caso fossero stati eliminati, ricrearli.

Il comando cp non permette di spostare cartelle, almeno senza parametri aggiuntivi; questo perché lo spostamento richiede solo di rinominare un nodo del grafo (un'operazione relativamente semplice), mentre una copia di una directory richiede di copiare ricorsivamente anche tutto il sottoalbero.

Utilizzando il manuale di cp, scoprire l'opzione necessaria per attivare la modalità di copia ricorsiva, ed utilizzarla per copiare la cartella test in una di nome test2. Controllare che tutti i file siano stati copiati correttamente.

Come per cp, anche il comando di rimozione rm deve agire ricorsivamente per eliminare delle cartelle.

Leggere il manuale di rm ed utilizzare la modalità ricoriva per eliminare la cartella test2, ed anche la cartella test. Attenzione! Un uso improprio di rm potrebbe rimuovere tutti i vostri file.

Metadati

Nel filesystem, oltre ai dati contenuto nel file stesso, vengono memorizzati anche dei metadati riguardanti alcuni attributi del file. Un esempio che è già stato incontrato è quello del nome del file (l'etichetta); altri dati che possono venire memorizzati sono ad esempio i permessi, o le date di accesso/modifica/creazione. Il tipo di dati che viene memorizzati dipende dal file-system utilizzato. Ad esempio, i primi file-system utilizzati su DOS verso la fine degli anni'80 permettevano di usare per il nome del file solo 8 caratteri, più 3 per l'estensione. Sebbene molti di voi non abbiano vissuto quel periodo, può ancora capitare di trovare del vecchio codice (magari scritto in C o in FORTRAN) in cui i file utilizzano nomi molto brevi.