X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=fileintro.tex;h=966625f1c12f88f0cc64ec2ae74bb8eecb16af4e;hp=a7df9939b1089dcc33a5f2889978a390bfd5252f;hb=d99b4995b23505a9afde30adf3a716aa7a55f0e9;hpb=056bbc90c8a0710b57fa7b13f5f0dfdad1b3ff3f diff --git a/fileintro.tex b/fileintro.tex index a7df993..966625f 100644 --- a/fileintro.tex +++ b/fileintro.tex @@ -1,6 +1,6 @@ \chapter{I files: l'architettura} \label{cha:files_intro} - + Uno dei concetti fondamentali della architettura di unix è il cosiddetto \textit{everything is a file}, cioè il fatto che l'accesso ai vari dispositivi di input/output del computer viene effettuato attraverso un'interfaccia @@ -71,9 +71,11 @@ convenzione, sono inseriti nella directory \texttt{/dev}). L'organizzazione dei nomi dei file deriva direttamente dall'organizzazione dei medesimi nell'albero descritto in precedenza; una directory comunque, come già specificato in \secref{sec:fileintr_vfs}, è solo un particolare tipo di file -che contiene le informazioni che associano un nome al contenuto. Per questo, -anche se è usuale parlare di ``file in una directory'' in realtà una directory -contiene solo delle etichette per fare riferimento ai file stessi. +che contiene le informazioni che associano un nome al contenuto. + +% Per questo, anche se è usuale parlare di ``file in una directory'' in realtà +% una directory contiene solo delle etichette per fare riferimento ai file +% stessi. I manuale delle glibc chiama i nomi contenuti nelle directory \textsl{componenti} (in inglese \textit{file name components}), noi li @@ -90,7 +92,7 @@ consecutive sono considerate equivalenti ad una sola). Il nome completo di un file viene usualmente chiamato \textit{pathname}, e anche se il manuale della glibc depreca questo nome (poiché genererebbe confusione, dato che con \textit{path} si indica anche un insieme di directory su cui effettuare una -ricerca, come quello in cui si cercano i comandi) l'uso è ormai così comune +ricerca, come quello in cui si cercano i comandi); l'uso è ormai così comune che è senz'altro più chiaro dell'alternativa proposta. Il processo con cui si associa ad un pathname uno specifico file è chiamato @@ -117,23 +119,19 @@ la directory che contiene il riferimento alla directory corrente; nel caso questa sia la directory radice allora il riferimento è a se stessa. -% \subsection{Il controllo di accesso} -% \label{sec:fileintr_access_ctrl} - - \subsection{I tipi di files} \label{sec:fileintr_file_types} Come detto in precedenza in unix esistono vari tipi di file, in Linux questi -sono implementati come oggetti del \textit{Virtual File System} e sono -presenti in tutti i filesystem unix-like utilizzabili con Linux. L'elenco dei -vari tipi di file definiti dal Virtual File System è riportato in \ntab. +sono implementati come oggetti del \textit{Virtual File System} (vedi +\secref{sec:fileintr_vfs}) e sono presenti in tutti i filesystem unix-like +utilizzabili con Linux. L'elenco dei vari tipi di file definiti dal Virtual +File System è riportato in \ntab. Si tenga ben presente che questa classificazione non ha nulla a che fare con la classificazione sui tipi di file (che in questo caso sono sempre file di dati) in base al loro contenuto, o tipo di accesso. - \begin{table}[htb] \begin{center} \begin{tabular}[c]{l l p{7cm}} @@ -162,15 +160,15 @@ dati) in base al loro contenuto, o tipo di accesso. \end{center} \end{table} -Una delle differenze principali con altri sistemi operativi (come il VMS o -Windows) è che per Unix tutti i file di dati sono identici e contengono un -flusso continuo di bytes; non esiste cioè differenza per come vengono visti +Infatti una delle differenze principali con altri sistemi operativi (come il +VMS o Windows) è che per Unix tutti i file di dati sono identici e contengono +un flusso continuo di bytes. Non esiste cioè differenza per come vengono visti dal sistema file di diverso contenuto o formato (come nel caso di quella fra file di testo e binari che c'è in Windows) né c'è una strutturazione a record -per il cosiddetto ``accesso diretto'' come nel caso del VMS. -% (con i kernel -% della serie 2.4 è disponibile una forma di accesso diretto ai dischi il -% \textit{raw access} che però non ha nulla a che fare con questo). +per il cosiddetto ``accesso diretto'' come nel caso del VMS\footnote{con i + kernel della serie 2.4 è disponibile una forma di accesso diretto ai dischi + (il \textit{raw access}) attraverso dei device file appositi, che però non + ha nulla a che fare con questo}. Una seconda differenza è nel formato dei file ASCII; in Unix la fine riga è codificata in maniera diversa da Windows o MacIntosh, in particolare il fine @@ -188,7 +186,7 @@ programmazione sono due, basate su due diversi meccanismi con cui accedere al loro contenuto. La prima è l'interfaccia standard di unix, quella che il manuale delle glibc -chiama interfaccia dei descrittore di file (o \textit{file descriptor}). È +chiama interfaccia dei descrittori di file (o \textit{file descriptor}). È un'interfaccia specifica di unix e provvede un accesso non bufferizzato. L'interfaccia è primitiva ed essenziale, l'accesso viene detto non @@ -202,11 +200,11 @@ nell'header \texttt{unistd.h}. La seconda interfaccia è quella che il manuale della glibc chiama degli \textit{stream}, essa provvede funzioni più evolute e un accesso bufferizzato (controllato dalla implementazione fatta dalle librerie del C). Questa è -l'interfaccia standard usata dal linguaggio C e perciò si trova anche su tutti -i sistemi non Unix. Gli stream sono oggetti complessi e sono rappresentati da -puntatori ad un opportuna struttura definita dalle librerie del C, si accede -ad essi sempre in maniera indiretta utilizzando il tipo \texttt{FILE *}. -L'interfaccia è definita nell'header \texttt{stdio.h}. +l'interfaccia standard specificata dall'ANSI C e perciò si trova anche su +tutti i sistemi non Unix. Gli stream sono oggetti complessi e sono +rappresentati da puntatori ad un opportuna struttura definita dalle librerie +del C, si accede ad essi sempre in maniera indiretta utilizzando il tipo +\texttt{FILE *}. L'interfaccia è definita nell'header \texttt{stdio.h}. Entrambe le interfacce possono essere usate per l'accesso ai file come agli altri oggetti del VFS (pipes, socket, device), ma per poter accedere alle @@ -237,6 +235,7 @@ essendo questi ultimi definiti nello standard ANSI C; l'interfaccia con i file descriptor invece segue solo lo standard POSIX.1 dei sistemi unix ed è pertanto di portabilità più limitata. + \subsection{Caratteristiche specifiche dei file in unix} \label{sec:fileint_unix_spec} @@ -292,7 +291,7 @@ una convenzione. \section{L'architettura della gestione dei file} -\label{sec:fileintro_architecture} +\label{sec:fileintr_architecture} Per capire fino in fondo le proprietà di files e directories in un sistema unix ed il funzionamento delle relative funzioni di manipolazione occorre una @@ -301,9 +300,9 @@ un filesystem unix. In particolare occorre tenere presente dov' la divisione fondamentale fra kernel space e user space che tracciavamo al \capref{cha:intro_unix}. -In questa sezione esamineremo allora come viene implementato l'accesso ai -files in Linux, come il kernel gestisce i vari filesystem, descrivendo poi in -maniera un po' più dettagliata il filesystem standard di Linux, +In questa sezione esamineremo come viene implementato l'accesso ai files in +Linux, come il kernel può gestire diversi tipi di filesystem, descrivendo +poi in maniera un po' più dettagliata il filesystem standard di Linux, l'\texttt{ext2}, come esempio di un filesystem unix-like. @@ -322,7 +321,7 @@ l'\texttt{ext2}, come esempio di un filesystem unix-like. % \textit{inode}, \textit{dentry}, \textit{dcache}. In Linux il concetto di \textit{everything is a file} è stato implementato -attraverso il \textit{virtual filesystem} (da qui in avanti VFS) che è +attraverso il \textit{Virtual File System} (da qui in avanti VFS) che è l'interfaccia che il kernel rende disponibile ai programmi in user space attraverso la quale vengono manipolati i files; esso provvede un livello di indirezione che permette di collegare le operazioni di manipolazione sui files @@ -332,24 +331,66 @@ di filesystem differenti all'interno dello stesso albero delle directory Quando un processo esegue una system call che opera su un file il kernel chiama sempre una funzione implementata nel VFS; la funzione eseguirà le -manipolazioni sulle strutture generiche e ridirigendo la chiamata alla -opportune routine del filesystem specifico a cui si fa riferimento, saranno -queste a chiamare le funzioni di piu basso livello che eseguono le operazioni +manipolazioni sulle strutture generiche e utilizzaerà poi la chiamata alla +opportune routine del filesystem specifico a cui si fa riferimento. Saranno +queste a chiamare le funzioni di più basso livello che eseguono le operazioni di I/O sul dispositivo fisico, secondo lo schema riportato in \nfig. \begin{figure}[htb] \centering - + \includegraphics[width=7cm]{img/vfs.eps} \caption{Schema delle operazioni del VFS} - \label{fig:fileintro_VFS_scheme} + \label{fig:fileintr_VFS_scheme} \end{figure} -La funzione più importante implementata dal VFS è la system call \texttt{open} -che permette di aprire un file. Dato un pathname viene eseguita una ricerca -dentro la \textit{directory entry cache} (in breve \textit{dcache}), -una tabella di hash che contiene tutte le \textit{directory entry} (in breve -\textit{dentry}) che permette di associare in maniera rapida ed efficiente il -pathname a una specifica dentry. +Il VFS definisce un insieme di funzioni che tutti i filesystem devono +implementare. L'interfaccia comprende tutte le funzioni che riguardano i +files; le operazioni sono suddivise su tre tipi di oggetti: filesystem, inode +e file, corrispondenti a tre apposite strutture definite nel kernel. + +Il VFS usa una tabella mantenuta dal kernel che contiene il nome di ciascun +filesystem supportato, quando si vuole inserire il supporto di un nuovo +filesystem tutto quello che occorre è una chiamata alla funzione +\func{register\_filesystem} passando un'apposita struttura che +(\var{file\_system\_type}) contiene l'implementazione edl medesimo, che sarà +aggiunta alla citata tabella. + + +In questo modo quando viene effettuata la richiesta di montare un nuovo disco +(o qualunque altro \textit{block device} che può contenere un filesystem), il +VFS può ricavare dalla citata tabella il puntatore alle funzioni da chiamare +nelle operazioni di montaggio. Quest'ultima è responsabile di leggere da disco +il superblock (vedi \ref{sec:fileintr_ext2}), inizializzare tutte le +variabili interne e restituire uno speciale descrittore dei filesystem montati +al VFS; attraverso quest'ultimo diventa possible accedere alle routine +specifiche per l'uso di quel filesystem. + +Il primo oggetto usato dal VFS è il descrittore di filesystem, un puntatore ad +una apposita struttura che contiene vari dati come le informazioni comuni ad +ogni filesystem, i dati privati relativi a quel filesystem specifico, e i +puntatori alle funzioni del kernel relative al filesystem. Il VFS può così +usare le funzioni contenute nel filesystem decriptor per accedere alle routine +specifiche di quel filesystem. + +Gli altri due descrittori usati dal VFS sono relativi agli altri due oggetti +su cui è strutturata l'interfaccia. Ciascuno di essi contiene le informazioni +relative al file in uso, insieme ai puntatori alle funzioni dello specifico +filesystem usate per l'accesso dal VFS; in particolare il descrittore +dell'inode contiene i puntatori alle funzioni che possono essere usate su +qualunque file (come \func{link}, \func{stat} e \func{open}), mentre il +descrittore di file contiene i puntatori alle funzioni che vengono usate sui +file già aperti. + + +\subsection{Il funzionamento del VFS} +\label{sec:fileintr_vfs_work} + +La funzione più fondamentale implementata dal VFS è la system call +\texttt{open} che permette di aprire un file. Dato un pathname viene eseguita +una ricerca dentro la \textit{directory entry cache} (in breve +\textit{dcache}), una tabella di hash che contiene tutte le \textit{directory + entry} (in breve \textit{dentry}) che permette di associare in maniera +rapida ed efficiente il pathname a una specifica dentry. Una singola dentry contiene in genere il puntatore ad un \textit{inode}; quest'ultimo è la struttura base che sta sul disco e che identifica un singolo @@ -393,9 +434,11 @@ previste dal kernel \begin{table}[htb] \centering - \begin{tabular}[c]{c p{7cm}} + \begin{tabular}[c]{|c|p{7cm}|} + \hline \textbf{funzione} & \textbf{operazione} \\ \hline + \hline \textit{open} & apre il file \\ \textit{read} & legge dal file \\ \textit{write} & scrive sul file \\ @@ -443,31 +486,39 @@ daremo una descrizione a grandi linee che si adatta alle caratteristiche comuni di un qualunque filesystem standard unix. Dato un disco lo spazio fisico viene usualmente diviso in partizioni; ogni -partizione può contenere un filesystem; quest'ultimo è in genere strutturato -secondo \nfig, con una lista di inodes all'inizio e il resto dello spazio a -disposizione per i dati e le directory. +partizione può contenere un filesystem; la strutturazione tipica +dell'informazione su un disco è riportata in \nfig; in essa si fa riferimento +alla struttura del filesystem ext2, che prevede una separazione dei dati in +\textit{blocks group} che replicano il superblock (ma sulle caratteristiche di +ext2 torneremo in \secref{sec:fileintr_ext2}). È comunque caratteristica +comune di tutti i filesystem unix, indipendentemente da come poi viene +strutturata nei dettagli questa informazione, prevedere una divisione fra la +lista degli inodes e lo spazio a disposizione per i dati e le directory. \begin{figure}[htb] \centering - + \includegraphics[width=9cm]{img/disk_struct.eps} \caption{Organizzazione dello spazio su un disco in partizioni e filesystem} \label{fig:fileintr_disk_filesys} \end{figure} -Se si va ad esaminare come è strutturata l'informazione all'interno di un -singolo filesystem (tralasciando le parti connesse alla strutturazione e al -funzionamento del filesystem stesso come il super-block) avremo una situazione -del tipo di quella esposta in \nfig. +Se si va ad esaminare con maggiore dettaglio la strutturazione +dell'informazione all'interno del singolo filesystem (tralasciando i dettagli +relativi al funzionamento del filesystem stesso come la strutturazione in +gruppi dei blocchi, il superblock e tutti i dati di gestione) possiamo +esemplificare la situazione con uno schema come quello esposto in \nfig. + \begin{figure}[htb] \centering - - \caption{Organizzazione di un filesystem} + \includegraphics[width=11cm]{img/filesys_struct.eps} + \caption{Strutturazionne dei dati all'interno di un filesystem} \label{fig:fileintr_filesys_detail} \end{figure} -da questa figura si evidenziano alcune caratteristiche su cui è bene porre -attenzione in quanto sono fondamentali per capire il funzionamento delle -funzioni che manipolano i file e le directory su cui torneremo fra poco; in -particolare è opportuno ricordare sempre che: + +Da \curfig\ si evidenziano alcune caratteristiche base di ogni filesystem su +cui è bene porre attenzione in quanto sono fondamentali per capire il +funzionamento delle funzioni che manipolano i file e le directory su cui +torneremo in seguitp; in particolare è opportuno ricordare sempre che: \begin{enumerate} @@ -486,331 +537,114 @@ particolare numero di riferimenti (\textit{link count}) che sono stati fatti ad esso; solo quando questo contatore si annulla i dati del file vengono effettivamente rimossi dal disco. Per questo la funzione per cancellare un - file si chiama \texttt{unlink}, ed in realtà non cancella affatto i dati del + file si chiama \func{unlink}, ed in realtà non cancella affatto i dati del file, ma si limita a eliminare la relativa voce da una directory e decrementare il numero di riferimenti nell'\textit{inode}. \item Il numero di \textit{inode} nella voce si riferisce ad un \textit{inode} nello stesso filesystem e non ci può essere una directory che contiene riferimenti ad \textit{inodes} relativi ad altri filesystem. Questo limita - l'uso del comando \texttt{ln} (che crea una nuova voce per un file - esistente, con la funzione \texttt{link}) al filesystem corrente. + l'uso del comando \cmd{ln} (che crea una nuova voce per un file + esistente, con la funzione \func{link}) al filesystem corrente. \item Quando si cambia nome ad un file senza cambiare filesystem il contenuto del file non deve essere spostato, viene semplicemente creata una nuova voce per l'\textit{inode} in questione e rimossa la vecchia (questa è la modalità - in cui opera normalmente il comando \texttt{mv} attraverso la funzione - \texttt{rename}). + in cui opera normalmente il comando \cmd{mv} attraverso la funzione + \func{rename}). \end{enumerate} Infine è bene avere presente che essendo file pure loro, esiste un numero di riferimenti anche per le directories; per cui se ad esempio a partire dalla -situazione mostrata in \curfig\ creiamo una nuova directory \texttt{textdir} -nella directory corrente avremo una situazione come quella in \nfig, dove per +situazione mostrata in \curfig\ creiamo una nuova directory \texttt{img} nella +directory \file{gapil}: avremo una situazione come quella in \nfig, dove per chiarezza abbiamo aggiunto dei numeri di inode. +\begin{figure}[htb] + \centering + \includegraphics[width=11cm]{img/dir_links.eps} + \caption{Organizzazione dei link per le directory} + \label{fig:fileintr_dirs_link} +\end{figure} + La nuova directory avrà allora un numero di riferimenti pari a due, in quanto è referenziata dalla directory da cui si era partiti (in cui è inserita la -nuova voce che fa riferimento a \texttt{textdir}) e dalla voce \texttt{.} +nuova voce che fa riferimento a \file{img}) e dalla voce \file{.} che è sempre inserita in ogni directory; questo vale sempre per ogni directory che non contenga a sua volta altre directories. Al contempo la directory da cui si era partiti avrà un numero di riferiementi di almeno tre, in quanto -adesso sarà referenziata anche dalla voce \texttt{..} di \texttt{textdir}. - - -\subsection{Le funzioni \texttt{link} e \texttt{unlink}} -\label{sec:fileintr_link} - -Una delle caratteristiche usate quando si opera con i file è quella di poter -creare dei nomi fittizi (alias o collegamenti) per potersi riferire allo -stesso file accedendovi da directory diverse. Questo è possibile anche in -ambiente unix, dove tali collegamenti sono usualmente chiamati \textit{link}, -ma data la struttura del sistema ci sono due metodi sostanzialmente diversi -per fare questa operazione. - -Come si è appena detto l'accesso al contenuto di un file su disco avviene -attraverso il suo inode, e il nome che si trova in una directory è solo una -etichetta associata ad un puntatore a detto inode. Questo significa che la -realizzazione di un link è immediata in quanto uno stesso file può avere tanti -nomi diversi allo stesso tempo, dati da altrettante diverse associazioni allo -stesso inode; si noti poi che nessuno di questi nomi viene ad assumere una -particolare preferenza rispetto agli altri. - -Per aggiungere un nome ad un inode si utilizza la funzione \texttt{link}; si -suole chiamare questo tipo di associazione un collegamento diretto (o -\textit{hard link}). Il prototipo della funzione e le sue caratteristiche -principali, come risultano dalla man page, sono le seguenti: -\begin{prototype}{unistd.h} -{int link(const char * oldpath, const char * newpath)} - Crea un nuovo collegamento diretto al file indicato da \texttt{oldpath} - dandogli nome \texttt{newpath}. - - La funzione restituisce zero in caso di successo e -1 per un errore, in caso - di errore. La variabile \texttt{errno} viene settata secondo i seguenti - codici di errore: - \begin{errlist} - \item \texttt{EXDEV} \texttt{oldpath} e \texttt{newpath} non sono sullo - stesso filesystem. - \item \texttt{EPERM} il filesystem che contiene \texttt{oldpath} e - \texttt{newpath} non supporta i link diretti o è una directory. - \item \texttt{EFAULT} una delle stringhe passate come parametri è fuori - dello spazio di indirizzi del processo. - \item \texttt{EACCESS} errore di accesso (mancano i permessi per scrivere o - per attraversare le directories), vedi \secref{sec:filedir_access_control} - per i dettagli. - \item \texttt{ENAMETOOLONG} una dei due pathname è troppo lungo. - \item \texttt{ENOENT} un componente di \texttt{oldpath} o \texttt{newpath} - non esiste o è un link simbolico spezzato. - \item \texttt{ENOTDIR} un componente di \texttt{oldpath} o \texttt{newpath} - non è una directory. - \item \texttt{ENOMEM} il kernel non ha a disposizione memoria sufficiente a - completare l'operazione. - \item \texttt{EROFS} la directory su cui si vuole inserire il nuovo link è - su un filesystem montato readonly. - \item \texttt{EEXIST} un file (o una directory) con quel nome esiste di - già. - \item \texttt{EMLINK} ci sono troppi link al file \texttt{oldpath} (il - numero massimo è specificato dalla variabile \texttt{LINK\_MAX}, vedi - \secref{sec:xxx_limits}). - \item \texttt{ELOOP} si incontrati troppi link simbolici nella risoluzione - di \texttt{oldpath} o \texttt{newpath}. - \item \texttt{ENOSPC} la directory in cui si vuole creare il link non ha - spazio per ulteriori voci. - \item \texttt{EIO} c'è stato un errore di input/output. - \end{errlist} -\end{prototype} - -La creazione di un nuovo collegamento diretto non copia il contenuto del file, -ma si limita ad aumentare di uno il numero di referenze al file aggiungendo il -nuovo nome ai precedenti. Si noti che uno stesso file può essere così -richiamato in diverse directory. - -Per quanto dicevamo in \secref{sec:fileintr_filesystem} la creazione del -collegamento diretto è possibile solo se entrambi i pathname sono nello stesso -filesystem; inoltre il filesystem deve supportare i collegamenti diretti (non è -il caso ad esempio del filesystem \texttt{vfat} di windows). - -La funzione opera sui file ordinari, come sugli altri oggetti del filesystem, -ma solo l'amministratore è in grado di creare un collegamento diretto ad -un'altra directory, questo lo si fa perché in questo caso è possibile creare -dei circoli nel filesystem (vedi \secref{sec:fileintr_symlink}) che molti -programmi non sono in grado di gestire e la cui rimozione diventa estremamente -complicata (in genere occorre far girare il programma \texttt{fsck} per -riparare il filesystem); data la sua pericolosità in Linux questa -caratteristica è stata disabilitata, e la funzione restituisce l'errore -\texttt{EPERM}. - -La rimozione di un file (o più precisamente della voce che lo referenzia) si -effettua con la funzione \texttt{unlink}; il suo prototipo è il seguente: - -\begin{prototype}{unistd.h}{int unlink(const char * pathname)} - Cancella il nome specificato dal pathname nella relativa directory e - decrementa il numero di riferimenti nel relativo inode. Nel caso di link - simbolico cancella il link simbolico; nel caso di socket, fifo o file di - dispositivo rimuove il nome, ma come per i file i processi che hanno aperto - uno di questi oggetti possono continuare ad utilizzarlo. - - La funzione restituisce zero in caso di successo e -1 per un errore, nel - qual caso il file non viene toccato. La variabile \texttt{errno} viene - settata secondo i seguenti codici di errore: - \begin{errlist} - \item \texttt{EACCESS} errore di accesso (mancano i permessi per scrivere o - per attraversare le directories), vedi \secref{sec:filedir_access_control} - per i dettagli. - \item \texttt{EISDIR} \texttt{pathname} si riferisce ad una directory - (valore specifico ritornato da linux che non consente l'uso di - \texttt{unlink} con le directory, e non conforme allo standard POSIX, che - prescrive invece l'uso di \texttt{EPERM} in caso l'operazione non sia - consnetita o il processo non abbia privilegi sufficienti). - \item \texttt{EFAULT} la stringa - passata come parametro è fuori dello spazio di indirizzi del processo. - \item \texttt{ENAMETOOLONG} il pathname troppo lungo. - \item \texttt{ENOENT} uno dei componenti del pathname non esiste o è un link - simbolico spezzato. - \item \texttt{ENOTDIR} uno dei componenti del pathname non è una directory. - \item \texttt{EISDIR} \texttt{pathname} fa riferimento a una directory. - \item \texttt{ENOMEM} il kernel non ha a disposizione memoria sufficiente a - completare l'operazione. - \item \texttt{EROFS} \texttt{pathname} è su un filesystem montato in sola - lettura. - \item \texttt{ELOOP} ci sono troppi link simbolici nella risoluzione del - pathname. - \item \texttt{EIO} errore di input/output. - \end{errlist} -\end{prototype} - -Per cancellare una voce in una directory è necessario avere il permesso di -scrittura su di essa (dato che si va a rimuovere una voce dal suo contenuto) e -il diritto di esecuzione sulla directory che la contiene (torneremo in -dettaglio sui permessi e gli attributi fra poco), se inoltre lo -\textit{sticky} bit è settato occorrerà anche essere proprietari del file o -proprietari della directory (o root, per cui nessuna delle restrizioni è -applicata). - -Una delle caratteristiche di queste funzioni è che la creazione/rimozione -della nome dalla directory e l'incremento/decremento del numero di riferimenti -nell'inode deve essere una operazione atomica (cioè non interrompibile da -altri) processi, per questo entrambe queste funzioni sono realizzate tramite -una singola system call. - -Si ricordi infine che il file non viene eliminato dal disco fintanto che tutti -i riferimenti ad esso sono stati cancellati, solo quando il \textit{link - count} mantenuto nell'inode diventa zero lo spazio occupato viene rimosso. A -questo però si aggiunge una altra condizione, e cioè che non ci siano processi -che abbiano detto file aperto. Come accennato questa proprietà viene spesso -usata per essere sicuri di non lasciare file temporanei su disco in caso di -crash dei programmi; la tecnica è quella di aprire il file e chiamare -\texttt{unlink} subito dopo. - -\subsection{Le funzioni \texttt{remove} e \texttt{rename}} -\label{sec:fileintr_remove} - -Al contrario di quanto avviene con altri unix in Linux non è possibile usare -\texttt{unlink} sulle directory, per cancellare una directory si può usare la -funzione \texttt{rmdir} (vedi \secref{sec:filedir_dir_creat_rem}), oppure la -funzione \texttt{remove}. Questa è la funzione prevista dallo standard ANSI C -per cancellare un file o una directory (e funziona anche per i sistemi che non -supportano i link diretti), che per i file è identica alla \texttt{unlink} e -per le directory è identica alla \texttt{rmdir}: - -\begin{prototype}{stdio.h}{int remove(const char *pathname)} - Cancella un nome dal filesystem. Usa \texttt{unlink} per i file e - \texttt{rmdir} per le directory. - - La funzione restituisce zero in caso di successo e -1 per un errore, nel - qual caso il file non viene toccato. Per i codici di errori vedi quanto - riportato nella descrizione di \texttt{unlink} e \texttt{rmdir}. -\end{prototype} - -Per cambiare nome ad un file si usa invece la funzione \texttt{rename}, il -vantaggio nell'uso di questa funzione al posto della chiamata successiva di -\texttt{unlink} e \texttt{link} è che l'operazione è eseguita atomicamente, in -questo modo non c'è la possibilità che un processo che cerchi di accedere al -nuovo nome dopo che il vecchio è stato cambiato lo trovi mancante. - -\begin{prototype}{stdio.h} -{int rename(const char *oldpath, const char *newpath)} - Rinomina un file, spostandolo fra directory diverse quando richiesto. - - La funzione restituisce zero in caso di successo e -1 per un errore, nel - qual caso il file non viene toccato. La variabile \texttt{errno} viene - settata secondo i seguenti codici di errore: - \begin{errlist} - \item \texttt{EISDIR} \texttt{newpath} è una directory già esistente mentre - \texttt{oldpath} non è una directory. - \item \texttt{EXDEV} \texttt{oldpath} e \texttt{newpath} non sono sullo - stesso filesystem. - \item \texttt{ENOTEMPTY} \texttt{newpath} è una directory già esistente e - non vuota. - \item \texttt{EBUSY} o \texttt{oldpath} o \texttt{newpath} sono in uso da - parte di qualche processo (come directory di lavoro o come root) o del - sistema (come mount point). - \item \texttt{EINVAL} \texttt{newpath} contiene un prefisso di - \texttt{oldpath} o più in generale si è cercato di creare una directory - come sottodirectory di se stessa. - \item \texttt{EMLINK} \texttt{oldpath} ha già il massimo numero di link - consentiti o è una directory e la directory che contiene \texttt{newpath} - ha già il massimo numero di link. - \item \texttt{ENOTDIR} Uno dei componenti dei pathname non è una directory - o\texttt{oldpath} è una directory e \texttt{newpath} esiste e non è una - directory. - \item \texttt{EFAULT} o \texttt{oldpath} o \texttt{newpath} è fuori dello - spazio di indirizzi del processo. - \item \texttt{EACCESS} Non c'è il permesso di scrittura per la directory in - cui si vuole creare il nuovo link o una delle directory del pathname non - consente la ricerca (permesso di esecuzione). - \item \texttt{EPERM} le directory contenenti \texttt{oldpath} o - \texttt{newpath} hanno lo sticky bit attivo e i permessi del processo non - consentono rispettivamente la cancellazione e la creazione del file, o il - filesystem non supporta i link. - \item \texttt{ENAMETOOLONG} uno dei pathname è troppo lungo. - \item \texttt{ENOENT} Uno dei componenti del pathname non esiste o è un link - simbolico spezzato. - \item \texttt{ENOMEM} il kernel non ha a disposizione memoria sufficiente a - completare l'operazione. - \item \texttt{EROFS} I file sono su un filesystem montato in sola lettura. - \item \texttt{ELOOP} Ci sono troppi link simbolici nella risoluzione del - pathname. - \item \texttt{ENOSPC} Il device di destinazione non ha più spazio per la - nuova voce. - \end{errlist} -\end{prototype} - -\subsection{I link simbolici} -\label{sec:fileintr_symlink} - -Siccome la funzione \texttt{link} crea riferimenti agli inodes, essa può -funzionare soltanto per file che risiedono sullo stesso filesystem, dato che -in questo caso è garantita l'unicità dell'inode, e solo per un filesystem di -tipo unix. Inoltre in Linux non è consentito eseguire un link diretto ad una -directory. +adesso sarà referenziata anche dalla voce \file{..} di \file{img}. + +\subsection{Il filesystem \texttt{ext2}} +\label{sec:fileintr_ext2} + +Il filesystem standard usato da Linux è il cosidetto \textit{second extended + filesystem}, identificato dalla sigla \texttt{ext2}. Esso supporta tutte le +caratteristiche di un filesystem standard unix, è in grado di gestire +filenames lunghi (256 caratteri, estendibili a 1012), una dimensione fino a +4~Tb. + +Oltre alle caratteristiche standard ext2 fornisce alcune estensioni che non +sono presenti sugli altri filesystem unix. Caratteristiche particolari di ext2 +sono le seguenti'' + +\begin{itemize} +\item i \textit{file attributes} consentono di modificare il comportamento del + kernel quando agisce su gruppi di file. Possono essere settati su file e + directory e in quest'ultimo caso i nuovi file creati nella directory + ereditano i suoi attributi. +\item sono supportate entrambe le semantiche di BSD e SysV come opzioni di + montaggio. La semantica BSD comporta che i file in una directory sono creati + con lo stesso identificatore di gruppo della directory che li contiene. La + semantica SysV comporta che i file vengono creati con l'identificatore del + gruppo primario del processo, eccetto il caso in cui la directory ha il bit + di setgid settata (per una descrizione dettagliata del sigificato di questi + termini si veda \secref{sec:filedir_access_control}), nel qual caso file e + sottodirectory ereditano sia il group id che il setgid. +\item l'amministratore può scegliere la dimensione dei blocchi del filesystem + in fase di creazione, a seconda delle sue esigenze (blocchi più grandi + permettono un accesso più veloce, ma sprecano più spazio disco). +\item il filesystem implementa link simbolici veloci, in cui il nome del file + non è salvato su un blocco, ma tenuto all'interno dell'inode (evitando + letture multiple e spreco di spazio), non tutti i nomi però possono essere + gestiti così per limiti di spazio (il limite è 60 caratteri). +\item vengono supportati i file immutabili (che possono solo essere letti) per + la protezione di file di configurazione sensibili, o file + \textit{append-only} che possono essere aperti in scrittura solo per + aggiungere dati (caratteristica utilizzabile per la protezione dei file di + log). +\end{itemize} + +La struttura di ext2 è stata ispirata a quella del filesystem di BSD, un +filesystem è composto da un insieme di blocchi, la struttura generale è quella +riportata in \figref{fig:fileintr_filesys_detail}, in cui la partizione è +divisa in gruppi di blocchi. + +Ciascun gruppo di blocchi contiene una copia delle informazioni essenziali del +filesystem (superblock e descrittore del filesystem sono quindi ridondati) per +una maggiore affidabilità e possibilità di recupero in caso di corruzione del +superblock principale. + + +\begin{figure}[htb] + \centering + \includegraphics[width=9cm]{img/dir_struct.eps} + \caption{Struttura delle directory nel \textit{second extented filesystem}.} + \label{fig:fileintr_ext2_dirs} +\end{figure} + +L'utilizzo di raggrupamenti di blocchi ha inoltre degli effetti positivi nelle +performance dato che viene ridotta la distanza fra i dati e la tabella degli +inodes. + +Le directory sono implementate come una linked list con voci di dimensione +variabile. Ciascuna voce della lista contiene il numero di inode, la sua +lunghezza, il nome del file e la sua lunghezza, secondo lo schema in \curfig; +in questo modo è possibile implementare nomi per i file anche molto lunghi +(fino a 1024 caratteri) senza sprecare spazio disco. + + -Per ovviare a queste limitazioni i sistemi unix supportano un'altra forma di -link (i cosiddetti \textit{soft link} o \textit{symbolic link}), che sono, -come avviene in altri sistemi operativi, dei file che contengono il -semplicemente il riferimento ad un altro file (o directory). In questo modo è -possibile effettuare link anche attraverso filesystem diversi e a directory, e -pure a file che non esistono ancora. - -Il sistema funziona in quanto i link simbolici sono contrassegnati come tali -al kernel (analogamente a quanto avviene per le directory) per cui la chiamata -ad una \texttt{open} o una \texttt{stat} su un link simbolico comporta la -lettura del contenuto del medesimo e l'applicazione della funzione al file -specificato da quest'ultimo. Invece altre funzioni come quelle per cancellare -o rinominare i file operano direttamente sul link simbolico. Inoltre esistono -funzioni apposite, come la \texttt{readlink} e la \texttt{lstat} per accedere -alle informazioni del link invece che a quelle del file a cui esso fa -riferimento. - -Le funzioni per operare sui link simbolici sono le seguenti, esse sono tutte -dichiarate nell'header file \texttt{unistd.h}. - -\begin{prototype}{unistd.h} -{int symlink(const char * oldname, const char * newname)} - Crea un nuovo link simbolico al file indicato da \texttt{oldname} dandogli - nome \texttt{newname}. - - La funzione restituisce zero in caso di successo e -1 per un errore, in caso - di errore. La variabile \texttt{errno} viene settata secondo i codici di - errore standard di accesso ai files (trattati in dettaglio in - \secref{sec:filedir_access_control}) ai quali si aggiungono i seguenti: - \begin{errlist} - \item \texttt{EEXIST} Un file (o una directory) con quel nome esiste di - già. - \item \texttt{EROFS} La directory su cui si vuole inserire il nuovo link è - su un filesystem montato readonly. - \item \texttt{ENOSPC} La directory o il filesystem in cui si vuole creare il - link è piena e non c'è ulteriore spazio disponibile. - \item \texttt{ELOOP} Ci sono troppi link simbolici nella risoluzione di - \texttt{oldname} o di \texttt{newname}. - \end{errlist} -\end{prototype} - -Dato che la funzione \texttt{open} segue i link simbolici, è necessaria usare -un'altra funzione quando si vuole leggere il contenuto di un link simbolico, -questa funzione è la: - -\begin{prototype}{unistd.h} -{int readlink(const char * path, char * buff, size\_t size)} - Legge il contenuto del link simbolico indicato da \texttt{path} nel buffer - \texttt{buff} di dimensione \texttt{size}. Non chiude la stringa con un - carattere nullo e la tronca a \texttt{size} nel caso il buffer sia troppo - piccolo per contenerla. - - La funzione restituisce il numero di caratteri letti dentro \texttt{buff} o - -1 per un errore, in caso di errore. La variabile \texttt{errno} viene - settata secondo i codici di errore: - \begin{errlist} - \item \texttt{EEXIST} Un file (o una directory) con quel nome esiste di - già. - \item \texttt{EROFS} La directory su cui si vuole inserire il nuovo link è - su un filesystem montato readonly. - \item \texttt{ENOSPC} La directory o il filesystem in cui si vuole creare il - link è piena e non c'è ulteriore spazio disponibile. - \item \texttt{ELOOP} Ci sono troppi link simbolici nella risoluzione di - \texttt{oldname} o di \texttt{newname}. - \end{errlist} -\end{prototype}