X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=filedir.tex;h=8b522d6f78b927da1beed793b24bdb1f00df8541;hp=0264b90e5709d9fd5ec2ffe9806ce9d277072366;hb=96256b851638bcd0bae29eafa53a22b01815490d;hpb=da0899b61653d07d75c8df134906261f1afd2485 diff --git a/filedir.tex b/filedir.tex index 0264b90..8b522d6 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,32 +643,43 @@ 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. Inoltre si - - Può però essere utile poterne -leggere il contenuto ad esempio per fare la lista dei file che esse contengono -o ricerche sui medesimi. Solo il kernel può scrivere direttamente il contenuto -di una directory (onde evitare inconsistenze all'interno del filesystem), i -processi devono creare i file usando le apposite funzioni. - -Per accedere al contenuto delle directory si usano i cosiddetti -\textit{directory streams} (chiamati così per l'analogia con i file stream di -\capref{cha:files_std_interface}); la funzione \funcd{opendir} 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} - \funcdecl{DIR * opendir(const char *name)} + \funcdecl{DIR * opendir(const char *dirname)} Apre un \textit{directory stream}. @@ -677,16 +689,17 @@ questi stream, il suo prototipo \errval{ENOENT}, \errval{ENOMEM} e \errval{ENOTDIR}.} \end{functions} -La funzione apre un \textit{directory stream} per la directory indicata da -\param{name}, ritornando il puntatore allo stesso, e posizionandosi sulla -prima voce della directory. +La funzione apre un \textit{directory stream} per la directory +\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ò 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 è: +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} @@ -698,30 +711,86 @@ il cui prototipo caso di successo e -1 in caso di errore.} \end{functions} -La funzione\footnote{questa funzione è una estensione di BSD 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}. - - +La funzione\footnote{questa funzione è una estensione di BSD non presente in + 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}. 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 della directory viene effettuata attraverso la funzione +\funcd{readdir}; il suo prototipo è: +\begin{functions} + \headdecl{sys/types.h} \headdecl{dirent.h} + + \funcdecl{struct dirent *readdir(DIR *dir)} + + 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, 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 \func{readdir} legge il contenuto della directory, i cui elementi -sono le \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}. +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 la +lettura di una voce 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 della struttura precedentemente allocata e specificata +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; sia BSD che SVr4\footnote{POSIX prevede invece solo + la presenza del campo \var{d\_fileno}, identico \var{d\_ino}, che in Linux è + definito come alias di quest'ultimo. Il campo \var{d\_name} è considerato + dipendente dall'implementazione.} prevedono che siano sempre presenti il +campo \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}; in SVr4 la lunghezza del campo è + definta come \code{NAME\_MAX+1} che di norma porta al valore di 256 byte + usato anche in Linux.} ed il campo \var{d\_ino}, che contiene il numero di +inode cui il file è associato (di solito corriponde al campo \var{st\_ino} di +\struct{stat}). \begin{figure}[!htb] - \footnotesize - \centering + \footnotesize \centering \begin{minipage}[c]{15cm} \begin{lstlisting}[labelstep=0]{}%,frame=,indent=1cm]{} struct dirent { - ino_t d_ino; - unsigned short int d_reclen; - unsigned char d_type; - char d_name[256]; /* We must not include limits.h! */ + 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! */ }; \end{lstlisting} \end{minipage} @@ -731,6 +800,158 @@ 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} + +Per quanto riguarda il significato dei campi opzionali, 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 invece la posizione della voce successiva della +directory, mentre il campo \var{d\_reclen} la lunghezza totale della voce +letta. Con questi due campi diventa possibile, determinando la posizione delle +varie voci, 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} + +La sola funzione di posizionamento nello stream prevista dallo standard POSIX +è \funcd{rewinddir}, che riporta la posizione a quella iniziale; il suo +prototipo è: +\begin{functions} + \headdecl{sys/types.h} \headdecl{dirent.h} + + \funcdecl{void rewinddir(DIR *dir)} + + Si posiziona all'inzio di un \textit{directory stream}. +\end{functions} + + +Una volta completate le operazioni si può chiudere il \textit{directory + stream} con la funzione \funcd{closedir}, il cui prototipo è: +\begin{functions} + \headdecl{sys/types.h} \headdecl{dirent.h} + + \funcdecl{int closedir(DIR * dir)} + + Chiude un \textit{directory stream}. + + \bodydesc{La funzione restituisce 0 in caso di successo e -1 altrimenti, nel + qual caso \var{errno} assume il valore \errval{EBADF}.} +\end{functions} + +A parte queste funzioni di base in BSD 4.3 è stata introdotta un'altra +funzione che permette di eseguire una scansione completa (con tanto di ricerca +ed ordinamento) del contenuto di una directory; la funzione è +\funcd{scandir}\footnote{in Linux questa funzione è stata introdotta fin dalle + libc4.} ed il suo prototipo è: +\begin{prototype}{dirent.h}{int scandir(const char *dir, + struct dirent ***namelist, int(*select)(const struct dirent *), + int(*compar)(const struct dirent **, const struct dirent **))} + + Esegue una scansione di un \textit{directory stream}. + + \bodydesc{La funzione restituisce in caso di successo il numero di voci + trovate, e -1 altrimenti.} +\end{prototype} + +Al solito, per la presenza fra gli argomenti di due puntatori a funzione, il +prototipo non è molto comprensibile; queste funzioni però sono quelle che +controllano rispettivamente la selezione di una voce (\param{select}) e +l'ordinamento di tutte le voci selezionate (\param{compar}). + +La funzione legge tutte le voci della directory indicata dall'argomento +\param{dir}, passando ciascuna di esse come argomento alla funzione di +\param{select}; se questa ritorna un valore diverso da zero la voce viene +inserita in una struttura allocata dinamicamante con \func{malloc}, qualora si +specifichi un valore \val{NULL} per \func{select} vengono selezionate tutte le +voci. Tutte le voci selezionate vengono poi inserite un una lista (anch'essa +allocata con \func{malloc}, che viene riordinata tramite \func{qsort} usando +la funzione \param{compar} come criterio di ordinamento; alla fine l'indirizzo +della lista ordinata è restituito nell'argomento \param{namelist}. + +Per l'ordinamento sono disponibili anche due funzioni predefinite, +\funcd{alphasort} e \funcd{versionsort}, i cui prototipi sono: +\begin{functions} + \headdecl{dirent.h} + + \funcdecl{int alphasort(const void *a, const void *b)} + + \funcdecl{int versionsort(const void *a, const void *b)} + + Funzioni per l'ordinamento delle voci di \textit{directory stream}. + + \bodydesc{Le funzioni restituiscono un valore minore, uguale o maggiore di + zero qualora il primo argomento sia rispettivamente minore, uguale o + maggiore del secondo.} +\end{functions} + + +La funzione \func{alphasort} deriva da BSD ed è presente in Linux fin dalle +libc4\footnote{la versione delle libc4 e libc5 usa però come argomenti dei + puntatori a delle strutture \struct{dirent}; le glibc usano il prototipo + originario di BSD, mostrato anche nella definizione, che prevede puntatori a + \ctyp{void}.} e deve essere specificata come argomento \param{compare} per +ottenere un ordinamento alfabetico (secondo il valore del campo \var{d\_name} +delle varie voci). Le \acr{glibc} prevedono come estensione\footnote{le glibc, + a partire dalla versione 2.1, effettuano anche l'ordinamento alfabetico + tenendo conto delle varie localizzazioni, usando \func{strcoll} al posto di + \func{strcmp}.} anche \func{versionsort}, che ordina i nomi tenendo conto +del numero di versione (cioè qualcosa per cui \file{file10} viene comunque +dopo \func{file4}.) + @@ -1500,21 +1721,21 @@ Esistono varie estensioni a questo modello,\footnote{come le \textit{Access come il \textit{mandatory access control} di SE-Linux.} ma nella maggior parte dei casi il meccanismo standard è più che sufficiente a soddisfare tutte le necessità più comuni. I tre permessi di base associati ad ogni file sono: -\begin{itemize} +\begin{itemize*} \item il permesso di lettura (indicato con la lettera \texttt{r}, dall'inglese \textit{read}). \item il permesso di scrittura (indicato con la lettera \texttt{w}, dall'inglese \textit{write}). \item il permesso di esecuzione (indicato con la lettera \texttt{x}, dall'inglese \textit{execute}). -\end{itemize} +\end{itemize*} mentre i tre livelli su cui sono divisi i privilegi sono: -\begin{itemize} +\begin{itemize*} \item i privilegi per l'utente proprietario del file. \item i privilegi per un qualunque utente faccia parte del gruppo cui appartiene il file. \item i privilegi per tutti gli altri utenti. -\end{itemize} +\end{itemize*} L'insieme dei permessi viene espresso con un numero a 12 bit; di questi i nove meno significativi sono usati a gruppi di tre per indicare i permessi base di @@ -1769,11 +1990,11 @@ invece assunto un uso importante per le directory;\footnote{lo \textsl{sticky impostato un file potrà essere rimosso dalla directory soltanto se l'utente ha il permesso di scrittura su di essa ed inoltre è vera una delle seguenti condizioni: -\begin{itemize} +\begin{itemize*} \item l'utente è proprietario del file \item l'utente è proprietario della directory \item l'utente è l'amministratore -\end{itemize} +\end{itemize*} un classico esempio di directory che ha questo bit impostato è \file{/tmp}, i permessi infatti di solito sono i seguenti: \begin{verbatim} @@ -1801,11 +2022,11 @@ per la creazione di nuove directory (procedimento descritto in Lo standard POSIX prescrive che l'\acr{uid} del nuovo file corrisponda all'userid effettivo del processo che lo crea; per il \acr{gid} invece prevede due diverse possibilità: -\begin{itemize} +\begin{itemize*} \item il \acr{gid} del file corrisponde al groupid effettivo del processo. \item il \acr{gid} del file corrisponde al \acr{gid} della directory in cui esso è creato. -\end{itemize} +\end{itemize*} in genere BSD usa sempre la seconda possibilità, che viene per questo chiamata semantica BSD. Linux invece segue quella che viene chiamata semantica SVr4; di norma cioè il nuovo file viene creato, seguendo la prima opzione, con il