Aggiunte readdir_r, telldir, seekdir e varie spiegazioni e macro relative la
[gapil.git] / filedir.tex
index 84b01947ef95859750c150fc36d8508a4f81c523..61e39aa08bc0961da309d618c5f3d8cc5d4f709c 100644 (file)
@@ -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