X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=filedir.tex;h=361e05a5afbcf9fffca3288cefe625b79ed41e48;hp=d811bfccee48f6f716d831bd1cb07487bb5be0b9;hb=a88d4dd8fdd85cdfe8fd04684d4afb4c24174995;hpb=056bbc90c8a0710b57fa7b13f5f0dfdad1b3ff3f 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