From: Simone Piccardi Date: Sun, 8 Jul 2001 21:30:27 +0000 (+0000) Subject: Continua la risistemazione. Aggiunta roba su ext2 ed iniziato la parte X-Git-Url: https://gapil.gnulinux.it/gitweb/?a=commitdiff_plain;h=a88d4dd8fdd85cdfe8fd04684d4afb4c24174995;p=gapil.git Continua la risistemazione. Aggiunta roba su ext2 ed iniziato la parte attinente stat & compny. --- diff --git a/filedir.tex b/filedir.tex index d811bfc..361e05a 100644 --- a/filedir.tex +++ b/filedir.tex @@ -5,8 +5,444 @@ In questo capitolo tratteremo in dettaglio le modalit files e directories, ed in particolare esamineremo come è strutturato il sistema base di protezioni e controllo di accesso ai files, e tutta l'interfaccia che permette la manipolazione dei vari attributi di files e -directories. Tutto quello che riguarda invece la manipolazione dei contenuti è -lasciato ai capitoli successivi. +directories. Tutto quello che riguarda invece la manipolazione del contenuto +dei file è lasciato ai capitoli successivi. + + +\section{La gestione di file e directory} + +Le prime funzioni che considereremo sono quelle relative alla gestione di file +e directory, secondo le caratteristiche standard che essi presentano in un +filesystem unix, già esaminate in precedenza (vedi +\secref{sec:fileintr_filesystem}). + +\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. + +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} + +\section{La manipolazione delle directories} +\label{sec:filedir_dir_handling} + +\subsection{Le funzioni \texttt{mkdir} e \texttt{rmdir}} +\label{sec:filedir_dir_creat_rem} + +Per creare una nuova directory si può usare la seguente funzione, omonima +dell'analogo comando di shell \texttt{mkdir}; per accedere ai tipi usati +programma deve includere il file \texttt{sys/types.h}. + +\begin{prototype}{sys/stat.h} +{int mkdir (const char * dirname, mode\_t mode)} + Questa funzione crea una nuova directory vuota con il nome indicato da + \texttt{dirname}, assegnandole i permessi indicati da \texttt{mode}. Il nome + può essere indicato con il pathname assoluto o relativo. + + La funzione restituisce zero in caso di successo e -1 per un errore, in caso + di errore \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{EACCESS} + Non c'è il permesso di scrittura per la directory in cui si vuole inserire + la nuova directory. + \item \texttt{EEXIST} Un file (o una directory) con quel nome esiste di già. + \item \texttt{EMLINK} La directory in cui si vuole creare la nuova directory + contiene troppi file. Sotto Linux questo normalmente non avviene perché il + filesystem standard consente la creazione di un numero di file maggiore di + quelli che possono essere contenuti nell'hard-disk, ma potendo avere a che + fare anche con filesystem di altri sistemi questo errore può presentarsi. + \item \texttt{ENOSPC} Non c'è abbastanza spazio sul file system per creare + la nuova directory. + \item \texttt{EROFS} La directory su cui si vuole inserire la nuova + directory è su un filesystem montato readonly. + \end{errlist} +\end{prototype} + + +\subsection{Accesso alle directory} +\label{sec:filedir_dir_read} + +Benché le directory siano oggetti del filesystem come tutti gli altri non ha +ovviamente senso aprirle come fossero dei file di dati. Può però essere utile +poterne leggere il contenuto ad esempio per fare la lista dei file che esse +contengono o ricerche sui medesimi. + +Per accedere al contenuto delle directory si usano i cosiddetti +\textit{directory streams} (chiamati così per l'analogia con i file stream); +la funzione \texttt{opendir} apre uno di questi stream e la funzione +\texttt{readdir} legge il contenuto della directory, i cui elementi sono le +\textit{directory entries} (da distinguersi da quelle della cache di cui +parlavamo in \secref{sec:fileintr_vfs}) in una opportuna struttura +\texttt{struct dirent}. + + +\subsection{La directory di lavoro} +\label{sec:filedir_work_dir} + +A ciascun processo è associato ad una directory nel filesystem che è chiamata +directory corrente o directory di lavoro (\textit{current working directory}) +che è quella a cui si fa riferimento quando un filename è espresso in forma +relativa (relativa appunto a questa directory). + +Quando un utente effettua il login questa directory viene settata alla +cosiddetta \textit{home directory} del suo account, il comando \texttt{cd} +della shell consente di cambiarla a piacere, spostandosi da una directory ad +un'altra. Siccome la directory corrente resta la stessa quando viene creato +un processo figlio, la directory corrente della shell diventa anche la +directory corrente di qualunque comando da essa lanciato. + +Le funzioni qui descritte servono esaminare e cambiare la directory di lavoro +corrente. + +\begin{prototype}{unistd.h}{char * getcwd (char * buffer, size\_t size)} + Restituisce il filename completo della directory di lavoro corrente nella + stringa puntata da \texttt{buffer}, che deve essere precedentemente + allocata, per una dimensione massima di \texttt{size}. Si può anche + specificare un puntatore nullo come \textit{buffer}, nel qual caso la + stringa sarà allocata automaticamente per una dimensione pari a + \texttt{size} qualora questa sia diversa da zero, o della lunghezza esatta + del pathname altrimenti. In questo caso si deve ricordare di disallocare la + stringa una volta cessato il suo utilizzo. + + La funzione restituisce il puntatore \texttt{buffer} se riesce, + \texttt{NULL} se fallisce, in quest'ultimo caso la variabile + \texttt{errno} è settata con i seguenti codici di errore: + \begin{errlist} + \item \texttt{EINVAL} L'argomento \texttt{size} è zero e \texttt{buffer} non + è nullo. + \item \texttt{ERANGE} L'argomento \texttt{size} è più piccolo della + lunghezza del pathname. + \item \texttt{EACCESS} Manca il permesso di lettura o di ricerca su uno dei + componenti del pathname (cioè su una delle directory superiori alla + corrente). + \end{errlist} +\end{prototype} + +Di questa funzione esiste una versione \texttt{char * getwd(char * buffer)} +fatta per compatibilità all'indietro con BSD, che non consente di specificare +la dimensione del buffer; esso deve essere allocato in precedenza ed avere una +dimensione superiore a \texttt{PATH\_MAX} (di solito 256 bytes, vedi +\secref{sec:xxx_limits}; il problema è che in Linux non esiste una dimensione +superiore per un pathname, per cui non è detto che il buffer sia sufficiente a +contenere il nome del file, e questa è la ragione principale per cui questa +funzione è deprecata. + +Una seconda funzione simile è \texttt{char * get\_current\_dir\_name(void)} +che è sostanzialmente equivalente ad una \texttt{getcwd(NULL, 0)}, con la sola +differenza che essa ritorna il valore della variabile di ambiente +\texttt{PWD}, che essendo costruita dalla shell può contenere anche dei +riferimenti simbolici. + +Come già detto in unix anche le directory sono file, è possibile pertanto +riferirsi ad esse tramite il file descriptor dell'interfaccia a basso livello, +e non solo tramite il filename; per questo motivo ci sono due diverse funzioni +per cambiare directory di lavoro. + +\begin{prototype}{unistd.h}{int chdir (const char * pathname)} + Come dice il nome (che significa \textit{change directory}) questa funzione + serve a cambiare la directory di lavoro a quella specificata dal pathname + contenuto nella stringa \texttt{pathname}. +\end{prototype} + +\begin{prototype}{unistd.h}{int fchdir (int filedes)} + Analoga alla precedente, ma usa un file descriptor invece del pathname. + + Entrambe le funzioni restituiscono zero in caso di successo e -1 per un + errore, in caso di errore \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 aggiunge il codice + \texttt{ENOTDIR} nel caso il \texttt{filename} indichi un file che non sia + una directory. +\end{prototype} \section{La manipolazione delle caratteristiche dei files} @@ -25,14 +461,28 @@ manipolazione sar \label{sec:filedir_stat} La lettura delle informazioni relative ai file è fatta attraverso la famiglia -delle funzioni \texttt{stat}, questa è la funzione che il comando \texttt{ls} -usa per poter stampare tutti i dati dei files; il prototipo della funzione è -il seguente; -\begin{prototype}{unistd.h} -{int stat(const char *file\_name, struct stat *buf)} +delle funzioni \texttt{stat}, che è la funzione che il comando \texttt{ls} usa +per poter stampare tutti i dati dei files. I prototipi di queste funzioni sono +i seguenti: +\begin{functions} + \headdecl{sys/types.h} + \headdecl{sys/stat.h} + \headdecl{unistd.h} + + \funcdecl{int stat(const char *file\_name, struct stat *buf)} Legge le + informazione del file specificato da \var{file\_name} e le inserisce in + \var{buf}. - La funzione restituisce zero in caso di successo e -1 per un errore, in caso - di errore \texttt{errno} viene settato ai valori: + \funcdecl{int lstat(const char *file\_name, struct stat *buf)} Identica a + \func{stat} eccetto che se il \var{file\_name} è un link simbolico vengono + lette le informazioni relativa ad esso e non al file a cui punta. + + \funcdecl{int fstat(int filedes, struct stat *buf)} Identica a \func{stat} + eccetto che funziona con un file aperto, specificato tramite il suo file + descriptor \var{filedes}. + + Le funzioni restituiscono zero in caso di successo e -1 per un errore, in + caso di errore \texttt{errno} viene settato ai valori: \begin{errlist} \item \texttt{EACCESS} Non c'è il permesso di accedere al file. \item \texttt{ENOTDIR} Una componente del pathname non è una directory. @@ -43,7 +493,7 @@ il seguente; completare l'operazione. \item \texttt{ENAMETOOLONG} Il filename è troppo lungo. \end{errlist} -\end{prototype} +\end{functions} La struttura \texttt{stat} è definita nell'header \texttt{sys/stat.h} e in generale dipende dall'implementazione, la versione usata da Linux è mostrata @@ -81,23 +531,88 @@ struct stat { Si noti come i vari membri della struttura siano specificati come tipi nativi del sistema (di quelli definiti in \tabref{tab:xxx_sys_types}, e dichiarati in -\texttt{sys/types.h}) - - +\texttt{sys/types.h}). \subsection{I tipi di file} \label{sec:filedir_file_types} -Come riportato in \tabref{tab:fileintr_file_types} in linux oltre ai file e +Come riportato in \tabref{tab:fileintr_file_types} in Linux oltre ai file e alle directory esistono vari altri oggetti che possono stare su un filesystem; -il tipo di file è ritornato dalla \texttt{stat} nel campo \texttt{st\_mode}, -dato che il valore numerico può variare a seconda delle implementazioni +il tipo di file è ritornato dalla \texttt{stat} nel campo \texttt{st\_mode}. +Dato che il valore numerico può variare a seconda delle implementazioni lo +standard POSIX definisce un insieme di macro per verificare il tipo di files, +queste venfono usate anche da Linux che supporta pure le estensioni per link +simbolici e socket definite da BDS, l'elenco è riportato in \ntab: +\begin{table}[htb] + \centering + \footnotesize + \begin{tabular}[c]{|l|l|} + \hline + Macro & Tipo del file \\ + \hline + \hline + \macro{S\_ISREG(m)} & file normale \\ + \macro{S\_ISDIR(m)} & directory \\ + \macro{S\_ISCHR(m)} & device a caraetteri \\ + \macro{S\_ISBLK(m)} & device a blocchi\\ + \macro{S\_ISFIFO(m)} & fifo \\ + \macro{S\_ISLNK(m)} & link simbolico \\ + \macro{S\_ISSOCK(m)} & socket \\ + \hline + \end{tabular} + \caption{Macro per i tipi di file (definite in \texttt{sys/stat.h})} + \label{tab:filedir_file_type_macro} +\end{table} + +Oltre a queste macro è possibile usare direttamente il valore di +\var{st\_mode} per ricavare il significato dei vari bit del campo attraverso +l'uso dei flag riportati in \ntab: +\begin{table}[htb] + \centering + \footnotesize + \begin{tabular}[c]{|l|c|l|} + \hline + Flag & Valore & Significato \\ + \hline + \hline + \macro{S\_IFMT} & 0170000 & bitmask for the file type bitfields \\ + \macro{S\_IFSOCK} & 0140000 & socket \\ + \macro{S\_IFLNK} & 0120000 & symbolic link \\ + \macro{S\_IFREG} & 0100000 & regular file \\ + \macro{S\_IFBLK} & 0060000 & block device \\ + \macro{S\_IFDIR} & 0040000 & directory \\ + \macro{S\_IFCHR} & 0020000 & character device \\ + \macro{S\_IFIFO} & 0010000 & fifo \\ + \macro{S\_ISUID} & 0004000 & set UID bit \\ + \macro{S\_ISGID} & 0002000 & set GID bit (see below) \\ + \macro{S\_ISVTX} & 0001000 & sticky bit (see below) \\ + \macro{S\_IRWXU} & 00700 & mask for file owner permissions \\ + \macro{S\_IRUSR} & 00400 & owner has read permission \\ + \macro{S\_IWUSR} & 00200 & owner has write permission \\ + \macro{S\_IXUSR} & 00100 & owner has execute permission \\ + \macro{S\_IRWXG} & 00070 & mask for group permissions \\ + \macro{S\_IRGRP} & 00040 & group has read permission \\ + \macro{S\_IWGRP} & 00020 & group has write permission \\ + \macro{S\_IXGRP} & 00010 & group has execute permission \\ + \macro{S\_IRWXO} & 00007 & mask for permissions for others (not in + group) \\ + \macro{S\_IROTH} & 00004 & others have read permission \\ + \macro{S\_IWOTH} & 00002 & others have write permisson \\ + \macro{S\_IXOTH} & 00001 & others have execute permission \\ + \hline + \end{tabular} + \caption{Flag per il campo \var{st\_mode} (definite in + \texttt{sys/stat.h})} + \label{tab:filedir_file_mode_flags} +\end{table} \subsection{La dimensione dei file} \label{sec:filedir_file_size} +Il membro \var{st\_size} contiene la dimensione del + \subsection{I tempi dei file} \label{sec:filedir_file_times} @@ -176,141 +691,6 @@ pertanto accesso senza restrizione a qualunque file del sistema. \label{sec:filedir_chown} -\section{La manipolazione delle directories} -\label{sec:filedir_dir_handling} - -\subsection{Le funzioni \texttt{mkdir} e \texttt{rmdir}} -\label{sec:filedir_dir_creat_rem} - -Per creare una nuova directory si può usare la seguente funzione, omonima -dell'analogo comando di shell \texttt{mkdir}; per accedere ai tipi usati -programma deve includere il file \texttt{sys/types.h}. - -\begin{prototype}{sys/stat.h} -{int mkdir (const char * dirname, mode\_t mode)} - Questa funzione crea una nuova directory vuota con il nome indicato da - \texttt{dirname}, assegnandole i permessi indicati da \texttt{mode}. Il nome - può essere indicato con il pathname assoluto o relativo. - - La funzione restituisce zero in caso di successo e -1 per un errore, in caso - di errore \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{EACCESS} - Non c'è il permesso di scrittura per la directory in cui si vuole inserire - la nuova directory. - \item \texttt{EEXIST} Un file (o una directory) con quel nome esiste di già. - \item \texttt{EMLINK} La directory in cui si vuole creare la nuova directory - contiene troppi file. Sotto Linux questo normalmente non avviene perché il - filesystem standard consente la creazione di un numero di file maggiore di - quelli che possono essere contenuti nell'hard-disk, ma potendo avere a che - fare anche con filesystem di altri sistemi questo errore può presentarsi. - \item \texttt{ENOSPC} Non c'è abbastanza spazio sul file system per creare - la nuova directory. - \item \texttt{EROFS} La directory su cui si vuole inserire la nuova - directory è su un filesystem montato readonly. - \end{errlist} -\end{prototype} - - -\subsection{Accesso alle directory} -\label{sec:filedir_dir_read} - -Benché le directory siano oggetti del filesystem come tutti gli altri non ha -ovviamente senso aprirle come fossero dei file di dati. Può però essere utile -poterne leggere il contenuto ad esempio per fare la lista dei file che esse -contengono o ricerche sui medesimi. - -Per accedere al contenuto delle directory si usano i cosiddetti -\textit{directory streams} (chiamati così per l'analogia con i file stream); -la funzione \texttt{opendir} apre uno di questi stream e la funzione -\texttt{readdir} legge il contenuto della directory, i cui elementi sono le -\textit{directory entries} (da distinguersi da quelle della cache di cui -parlavamo in \secref{sec:fileintr_vfs}) in una opportuna struttura -\texttt{struct dirent}. - - -\subsection{La directory di lavoro} -\label{sec:filedir_work_dir} - -A ciascun processo è associato ad una directory nel filesystem che è chiamata -directory corrente o directory di lavoro (\textit{current working directory}) -che è quella a cui si fa riferimento quando un filename è espresso in forma -relativa (relativa appunto a questa directory). - -Quando un utente effettua il login questa directory viene settata alla -cosiddetta \textit{home directory} del suo account, il comando \texttt{cd} -della shell consente di cambiarla a piacere, spostandosi da una directory ad -un'altra. Siccome la directory corrente resta la stessa quando viene creato -un processo figlio, la directory corrente della shell diventa anche la -directory corrente di qualunque comando da essa lanciato. - -Le funzioni qui descritte servono esaminare e cambiare la directory di lavoro -corrente. - -\begin{prototype}{unistd.h}{char * getcwd (char * buffer, size\_t size)} - Restituisce il filename completo della directory di lavoro corrente nella - stringa puntata da \texttt{buffer}, che deve essere precedentemente - allocata, per una dimensione massima di \texttt{size}. Si può anche - specificare un puntatore nullo come \textit{buffer}, nel qual caso la - stringa sarà allocata automaticamente per una dimensione pari a - \texttt{size} qualora questa sia diversa da zero, o della lunghezza esatta - del pathname altrimenti. In questo caso si deve ricordare di disallocare la - stringa una volta cessato il suo utilizzo. - - La funzione restituisce il puntatore \texttt{buffer} se riesce, - \texttt{NULL} se fallisce, in quest'ultimo caso la variabile - \texttt{errno} è settata con i seguenti codici di errore: - \begin{errlist} - \item \texttt{EINVAL} L'argomento \texttt{size} è zero e \texttt{buffer} non - è nullo. - \item \texttt{ERANGE} L'argomento \texttt{size} è più piccolo della - lunghezza del pathname. - \item \texttt{EACCESS} Manca il permesso di lettura o di ricerca su uno dei - componenti del pathname (cioè su una delle directory superiori alla - corrente). - \end{errlist} -\end{prototype} - -Di questa funzione esiste una versione \texttt{char * getwd(char * buffer)} -fatta per compatibilità all'indietro con BSD, che non consente di specificare -la dimensione del buffer; esso deve essere allocato in precedenza ed avere una -dimensione superiore a \texttt{PATH\_MAX} (di solito 256 bytes, vedi -\secref{sec:xxx_limits}; il problema è che in Linux non esiste una dimensione -superiore per un pathname, per cui non è detto che il buffer sia sufficiente a -contenere il nome del file, e questa è la ragione principale per cui questa -funzione è deprecata. - -Una seconda funzione simile è \texttt{char * get\_current\_dir\_name(void)} -che è sostanzialmente equivalente ad una \texttt{getcwd(NULL, 0)}, con la sola -differenza che essa ritorna il valore della variabile di ambiente -\texttt{PWD}, che essendo costruita dalla shell può contenere anche dei -riferimenti simbolici. - -Come già detto in unix anche le directory sono file, è possibile pertanto -riferirsi ad esse tramite il file descriptor dell'interfaccia a basso livello, -e non solo tramite il filename; per questo motivo ci sono due diverse funzioni -per cambiare directory di lavoro. - -\begin{prototype}{unistd.h}{int chdir (const char * pathname)} - Come dice il nome (che significa \textit{change directory}) questa funzione - serve a cambiare la directory di lavoro a quella specificata dal pathname - contenuto nella stringa \texttt{pathname}. -\end{prototype} - -\begin{prototype}{unistd.h}{int fchdir (int filedes)} - Analoga alla precedente, ma usa un file descriptor invece del pathname. - - Entrambe le funzioni restituiscono zero in caso di successo e -1 per un - errore, in caso di errore \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 aggiunge il codice - \texttt{ENOTDIR} nel caso il \texttt{filename} indichi un file che non sia - una directory. -\end{prototype} - - %La struttura fondamentale che contiene i dati essenziali relativi ai file è il diff --git a/fileintro.tex b/fileintro.tex index 85098c8..d1c8e13 100644 --- a/fileintro.tex +++ b/fileintro.tex @@ -1,6 +1,7 @@ + \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 +72,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 +93,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,10 +120,6 @@ 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} @@ -162,15 +161,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 +187,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 +201,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 +236,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} @@ -332,7 +332,7 @@ 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 +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. @@ -345,19 +345,53 @@ di I/O sul dispositivo fisico, secondo lo schema riportato in \nfig. \end{figure} Il VFS definisce un insieme di funzioni che tutti i filesystem devono -implementare, queste funzioni - +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:fileintro_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ù 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. +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 @@ -527,298 +561,70 @@ cui si era partiti avr 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. +\subsection{Il filesystem \texttt{ext2}} +\label{sec:fileintro_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 + peremttono 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 è +riportata in \nfig; su ciascun gruppo di blocchi contiene una copia delle +informazioni essenziali del filesystem (superblock e descrittore del +filesystem) per una maggiore affidabilità e possibilità di recupero in caso di +corruzione del superblock principale. -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. +\begin{figure}[htb] + \centering - 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} + \caption{Organizzazione logica del \textit{second extented filesystem}.} + \label{fig:fileintr_ext2_struct} +\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 di entrate di dimensione +variabile. Ciascuna entry contiene il numero di inode, la sua lunghezza, il +nome del file e la sua lunghezza. + + + + diff --git a/gapil.tex b/gapil.tex index a8b017b..2564ee7 100644 --- a/gapil.tex +++ b/gapil.tex @@ -1,4 +1,4 @@ -%% +%% %% GaPiL : Guida alla Programmazione in Linux %% %% S. Piccardi Feb. 2001