X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=filedir.tex;h=61e39aa08bc0961da309d618c5f3d8cc5d4f709c;hp=84b01947ef95859750c150fc36d8508a4f81c523;hb=1a416451168660c50fefa8802e5d531e331c8063;hpb=d6de060b2497ec17ae8a21ea458f8c2581b5d431 diff --git a/filedir.tex b/filedir.tex index 84b0194..61e39aa 100644 --- a/filedir.tex +++ b/filedir.tex @@ -396,8 +396,8 @@ direttamente sul suo contenuto. Si noti che non si è specificato il comportamento delle funzioni che operano con i file descriptor, in quanto la risoluzione del link simbolico viene in genere effettuata dalla funzione che restituisce il file descriptor -(normalmente la \func{open}) e tutte le operazioni seguenti fanno riferimento -solo a quest'ultimo. +(normalmente la \func{open}, vedi \secref{sec:file_open}) e tutte le +operazioni seguenti fanno riferimento solo a quest'ultimo. Dato che, come indicato in \tabref{tab:file_symb_effect}, funzioni come la \func{open} seguono i link simbolici, occorrono funzioni apposite per accedere @@ -438,12 +438,13 @@ Un caso comune che si pu cosiddetti \textit{loop}. La situazione è illustrata in \figref{fig:file_link_loop}, che riporta la struttura della directory \file{/boot}. Come si vede si è creato al suo interno un link simbolico che -punta di nuovo a \file{/boot}.\footnote{Questo tipo di loop è stato effettuato - per poter permettere a \cmd{grub} (un bootloader in grado di leggere - direttamente da vari filesystem il file da lanciare come sistema operativo) - di vedere i file in questa directory con lo stesso path con cui verrebbero - visti dal sistema operativo, anche se essi si trovano, come è solito, su una - partizione separata (e che \cmd{grub} vedrebbe come radice).} +punta di nuovo a \file{/boot}.\footnote{il loop mostrato in + \figref{fig:file_link_loop} è un usato per poter permettere a \cmd{grub} (un + bootloader in grado di leggere direttamente da vari filesystem il file da + lanciare come sistema operativo) di vedere i file contenuti nella directory + \file{/boot} con lo stesso pathname con cui verrebbero visti dal sistema + operativo, anche se essi si trovano, come accade spesso, su una partizione + separata (che \cmd{grub}, all'avvio, vede come radice).} Questo può causare problemi per tutti quei programmi che effettuano la scansione di una directory senza tener conto dei link simbolici, ad esempio se @@ -642,28 +643,39 @@ Per creare una fifo (un file speciale, su cui torneremo in dettaglio in \errval{EEXIST}, \errval{ENAMETOOLONG}, \errval{ENOENT}, \errval{ENOSPC}, \errval{ENOTDIR} e \errval{EROFS}.} \end{functions} -\noindent come per \func{mknod} il file \param{pathname} non deve esistere -(neanche come link simbolico); al solito i permessi specificati da -\param{mode} vengono modificati dal valore di \var{umask}. + +La funzione crea la fifo \param{pathname} con i permessi \param{mode}. Come +per \func{mknod} il file \param{pathname} non deve esistere (neanche come link +simbolico); al solito i permessi specificati da \param{mode} vengono +modificati dal valore di \var{umask}. \subsection{Accesso alle directory} \label{sec:file_dir_read} -Benché le directory siano oggetti del filesystem come tutti gli altri non ha -senso aprirle come fossero dei file di dati; per questo solo il kernel può -scrivere direttamente il contenuto di una directory (onde evitare -inconsistenze all'interno del filesystem), mentre i processi devono creare i -file usando le apposite funzioni. Può però essere utile potere leggere il -contenuto di una directory, ad esempio per fare la lista dei file che contiene -o per delle ricerche. - -Per far questo nello standard POSIX\footnote{le funzioni sono previste pure in - BSD e SVID.} ha introdotto i cosiddetti \textit{directory streams} (chiamati -così per l'analogia con i file stream di \capref{cha:files_std_interface}) ed -alcune di funzioni per la loro gestione. La prima di queste è \funcd{opendir}, -che apre uno di questi stream, il suo prototipo è: +Benché le directory alla fine non siano altro che dei file che contengono +delle liste di nomi ed inode, per il ruolo che rivestono nella struttura del +sistema, non possono essere trattate come dei normali file di dati. Ad +esempio, onde evitare inconsistenze all'interno del filesystem, solo il kernel +può scrivere il contenuto di una directory, e non può essere un processo a +inserirvi direttamente delle voci con le usuali funzioni di scrittura. + +Ma se la scrittura e l'aggiornamento dei dati delle directory è compito del +kernel, sono molte le situazioni in cui i processi necessitano di poterne +leggere il contenuto. Benché questo possa essere fatto direttamente (vedremo +in \secref{sec:file_open} che è possibile aprire una directory come se fosse +un file, anche se solo in sola lettura) in generale il formato con cui esse +sono scritte può dipendere dal tipo di filesystem, tanto che, come riportato +in \tabref{tab:file_file_operations}, il VFS del kernel prevede una apposita +funzione per la lettura delle directory. + +Tutto questo si riflette nello standard POSIX\footnote{le funzioni sono + previste pure in BSD e SVID.} che ha introdotto una apposita interfaccia per +la lettura delle directory, basata sui cosiddetti \textit{directory streams} +(chiamati così per l'analogia con i file stream dell'interfaccia standard di +\capref{cha:files_std_interface}). La prima funzione di questa interfaccia è +\funcd{opendir}, il cui prototipo è: \begin{functions} \headdecl{sys/types.h} \headdecl{dirent.h} @@ -678,16 +690,16 @@ che apre uno di questi stream, il suo prototipo \end{functions} La funzione apre un \textit{directory stream} per la directory -\param{dirname}, ritornando il puntatore alla relativa struttura \ctyp{DIR} da -usare per le successive operazioni, si posiziona inoltre sulla prima voce -della directory. - -Dato che le directory sono comunque dei file, in alcuni casi può essere utile -conoscere il file descriptor sottostante un \textit{directory stream}, ad -esempio per utilizzarlo con la funzione \func{fchdir} per cambiare la -directory di lavoro (vedi \secref{sec:file_work_dir}) a quella relativa allo -stream che si è aperto. A questo scopo si può usare la funzione \funcd{dirfd}, -il cui prototipo è: +\param{dirname}, ritornando il puntatore ad un oggetto di tipo \type{DIR} (che +è il tipo opaco\index{tipo!opaco} usato dalle librerie per gestire i +\textit{directory stream}) da usare per tutte le operazioni successive, la +funzione inoltre posiziona lo stream sulla prima voce contenuta nella +directory. + +Dato che le directory sono comunque dei file, in alcuni casi può servire +conoscere il \textit{file descriptor} associato ad un \textit{directory + stream}, a questo scopo si può usare la funzione \funcd{dirfd}, il cui +prototipo è: \begin{functions} \headdecl{sys/types.h} \headdecl{dirent.h} @@ -703,9 +715,12 @@ La funzione\footnote{questa funzione POSIX, introdotta con BSD 4.3-Reno; è presente in Linux con le libc5 (a partire dalla versione 5.1.2) e con le \acr{glibc}.} restituisce il file descriptor associato al \textit{directory stream} \param{dir}, essa è -disponibile solo definendo \macro{\_BSD\_SOURCE} o \macro{\_SVID\_SOURCE}. +disponibile solo definendo \macro{\_BSD\_SOURCE} o \macro{\_SVID\_SOURCE}. Di +solito si utilizza questa funzione in abbinamento alla funzione \func{fchdir} +per cambiare la directory di lavoro (vedi \secref{sec:file_work_dir}) a quella +relativa allo stream che si sta esaminando. -La lettura di una voce nella directory viene effettuata attraverso la funzione +La lettura di una voce della directory viene effettuata attraverso la funzione \funcd{readdir}; il suo prototipo è: \begin{functions} \headdecl{sys/types.h} \headdecl{dirent.h} @@ -715,26 +730,63 @@ La lettura di una voce nella directory viene effettuata attraverso la funzione Legge una voce dal \textit{directory stream}. \bodydesc{La funzione restituisce il puntatore alla struttura contentente i - dati in caso di successo e \val{NULL} altrimenti, nel qual caso - \var{errno} assumerà il valore \errval{EBADF}.} + dati in caso di successo e \val{NULL} altrimenti, in caso di descrittore + non valido \var{errno} assumerà il valore \errval{EBADF}, il valore + \val{NULL} viene restituito anche quando si raggiunge la fine dello + stream.} \end{functions} -La funzione legge una voce dalla directory (una \textit{directory entry}, da -distinguersi da quelle della cache di cui parlavamo in \secref{sec:file_vfs}) -in un'opportuna struttura \struct{dirent} definita in -\figref{fig:file_dirent_struct}, il suo pro +La funzione legge la voce corrente nella directory, posizionandosi sulla voce +successiva. I dati vengono memorizzati in una struttura \struct{dirent} (la +cui definizione\footnote{la definizione è quella usata a Linux, che si trova + nel file \file{/usr/include/bits/dirent.h}, essa non contempla la presenza + del campo \var{d\_namlen} che indica la lunghezza del nome del file (ed + infatti la macro \macro{\_DIRENT\_HAVE\_D\_NAMLEN} non è definita.} è +riportata in \figref{fig:file_dirent_struct}). La funzione restituisce il +puntatore alla struttura; si tenga presente però che quest'ultima è allocata +staticamente, per cui viene sovrascritta tutte le volte che si ripete una +lettura sullo stesso stream. + +Di questa funzione esiste anche una versione rientrante, \func{readdir\_r} che +non usa una struttura allocata staticamente, e può essere utilizzata anche con +i thread; il suo prototipo è: +\begin{functions} + \headdecl{sys/types.h} \headdecl{dirent.h} + + \funcdecl{int readdir\_r(DIR *dir, struct dirent *entry, + struct dirent **result)} + + Legge una voce dal \textit{directory stream}. + + \bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di + errore, gli errori sono gli stessi di \func{readdir}.} +\end{functions} + +La funzione restituisce in \param{result} (come \textit{value result + argument}) l'indirizzo dove sono stati salvati i dati, che di norma +corriponde a quallo specificato dall'argomento \param{entry} (anche se non è +assicurato che la funzione usi lo spazio fornito dall'utente). + +I vari campi di \struct{dirent} contengono le informazioni relative alle voci +presenti nella directory; i soli campi sempre presenti secondo lo standard +POSIX sono \var{d\_name}, che contiene il nome del file nella forma di una +stringa terminata da uno zero,\footnote{lo standard POSIX non specifica una + lunghezza, ma solo un limite \const{NAME\_MAX}, anche se di norma il valore + massimo per un nome è di 256 byte.} e \var{d\_fileno} che contiene il numero +di inode cui il file è associato (di solito corriponde al campo \var{st\_ino} +di \struct{stat}); questo campo viene anche chiamato \var{d\_ino}, per +compatibilità con la definizione usata da BSD. \begin{figure}[!htb] - \footnotesize - \centering + \footnotesize \centering \begin{minipage}[c]{15cm} \begin{lstlisting}[labelstep=0]{}%,frame=,indent=1cm]{} struct dirent { - ino_t d_ino; /* inode number */ - off_t d_off; /* offset to the next dirent */ - unsigned short int d_reclen; /* length of this record */ - unsigned char d_type; /* type of file */ - char d_name[256]; /* We must not include limits.h! */ + ino_t d_fileno; /* inode number */ + off_t d_off; /* offset to the next dirent */ + unsigned short int d_reclen; /* length of this record */ + unsigned char d_type; /* type of file */ + char d_name[256]; /* We must not include limits.h! */ }; \end{lstlisting} \end{minipage} @@ -744,6 +796,73 @@ struct dirent { \label{fig:file_dirent_struct} \end{figure} +La presenza di ulteriori campi opzionali è segnalata dalla definizione di +altrettante macro nella forma \code{\_DIRENT\_HAVE\_D\_XXX} dove \code{XXX} è +il nome del relativo campo; nel nostro caso sono definite le macro +\macro{\_DIRENT\_HAVE\_D\_TYPE}, \macro{\_DIRENT\_HAVE\_D\_OFF} e +\macro{\_DIRENT\_HAVE\_D\_RECLEN}. + +\begin{table}[htb] + \centering + \footnotesize + \begin{tabular}[c]{|l|l|} + \hline + \textbf{Valore} & \textbf{Significato} \\ + \hline + \hline + \const{DT\_UNKNOWN} & tipo sconosciuto. \\ + \const{DT\_REG} & file normale. \\ + \const{DT\_DIR} & directory. \\ + \const{DT\_FIFO} & fifo. \\ + \const{DT\_SOCK} & socket. \\ + \const{DT\_CHR} & dispositivo a caratteri. \\ + \const{DT\_BLK} & dispositivo a blocchi. \\ + \hline + \end{tabular} + \caption{Costanti che indicano i vari tipi di file nel campo \var{d\_type} + della struttura \struct{dirent}.} + \label{tab:file_dtype_macro} +\end{table} + +Il campo \var{d\_type} indica il tipo di file (fifo, directory, link +simbolico, ecc.); i suoi possibili valori sono riportati in +\tabref{tab:file_dtype_macro}; per la conversione da e verso l'analogo valore +mantenuto dentro il campo \var{st\_mode} di \struct{stat} sono definite anche +due macro di conversione \macro{IFTODT} e \macro{DTTOIF}: +\begin{functions} + \funcdecl{int IFTODT(mode\_t MODE)} Converte il tipo di file dal formato di + \var{st\_mode} a quello di \var{d\_type}. + + \funcdecl{mode\_t DTTOIF(int DTYPE)} Converte il tipo di file dal formato di + \var{d\_type} a quello di \var{st\_mode}. +\end{functions} + +Il campo \var{d\_off} contiene la posizione della successiva voce nella +directory, mentre il campo \var{d\_reclen} la lunghezza totale della voce. Con +questi campi diventa possibile spostarsi all'interno dello stream usando la +funzione \func{seekdir},\footnote{sia questa funzione, che la corrispondente + \func{telldir}, sono estensioni prese da BSD, non previste dallo standard + POSIX.} il cui prototipo è: +\begin{prototype}{dirent.h}{void seekdir(DIR *dir, off\_t offset)} + Cambia la posizione all'interno di un \textit{directory stream}. +\end{prototype} + +La funzione non ritorna nulla e non segnala errori, è però necessario che il +valore dell'argomento \param{offset} sia valido per lo stream \param{dir}; +esso pertanto deve essere stato ottenuto o dal valore di \var{d\_off} di +\struct{dirent} o dal valore restituito dalla funzione \func{telldir}, che +legge la posizione corrente; il prototipo di quest'ultima è: +\begin{prototype}{dirent.h}{off\_t telldir(DIR *dir)} + Ritorna la posizione corrente in un \textit{directory stream}. + + \bodydesc{La funzione restituisce la posizione corrente nello stream (un + numero positivo) in caso di successo, e -1 altrimenti, nel qual caso + \var{errno} assume solo il valore di \errval{EBADF}, corrispondente ad un + valore errrato per \param{dir}.} +\end{prototype} + + + Una volta completate le operazioni si può chiudere il \textit{directory