file su disco avviene passando attraverso il suo inode\index{inode}, che è la
struttura usata dal kernel che lo identifica univocamente all'interno di un
singolo filesystem. Il nome del file che si trova nella voce di una directory
-è solo un'etichetta che viene associata ad un puntatore che fa riferimento al
-suddetto inode.
+è solo un'etichetta, mantenuta all'interno della directory, che viene
+associata ad un puntatore che fa riferimento al suddetto inode.
Questo significa che, fintanto che si resta sullo stesso filesystem, la
realizzazione di un link è immediata, ed uno stesso file può avere tanti nomi
-diversi allo stesso tempo, dati da altrettante diverse associazioni allo
-stesso inode\index{inode}. Si noti anche che nessuno di questi nomi viene ad
-assumere una particolare preferenza o originalità rispetto agli altri.
+diversi, dati da altrettante diverse associazioni allo stesso
+inode\index{inode} di etichette diverse in directory diverse. Si noti anche
+che nessuno di questi nomi viene ad assumere una particolare preferenza o
+originalità rispetto agli altri, in quanto tutti fanno comunque riferimento
+allo stesso inode\index{inode}.
Per aggiungere ad una directory una voce che faccia riferimento ad un
inode\index{inode} già esistente si utilizza la funzione \func{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 pagina di manuale, sono le seguenti:
+ link}). Il prototipo della funzione è:
\begin{prototype}{unistd.h}
{int link(const char *oldpath, const char *newpath)}
- Crea un nuovo collegamento diretto al file indicato da \param{oldpath}
- dandogli nome \param{newpath}.
+ Crea un nuovo collegamento diretto.
\bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di
errore nel qual caso \var{errno} viene impostata ai valori:
\errval{ENOSPC}, \errval{EIO}.}
\end{prototype}
-La creazione di un nuovo collegamento diretto non copia il contenuto del file,
-ma si limita a creare una voce nella directory specificata con \param{newpath}
-e ad aumentare di uno il numero di riferimenti al file (riportato nel campo
-\var{st\_nlink} della struttura \struct{stat}, vedi \secref{sec:file_stat})
-aggiungendo il nuovo nome ai precedenti. Si noti che uno stesso file può
-essere così chiamato con vari nomi in diverse directory.
+La funzione crea sul pathname \param{newpath} un collegamento diretto al file
+indicato da \param{oldpath}. Per quanto detto la creazione di un nuovo
+collegamento diretto non copia il contenuto del file, ma si limita a creare
+una voce nella directory specificata da \param{newpath} e ad aumentare di uno
+il numero di riferimenti al file (riportato nel campo \var{st\_nlink} della
+struttura \struct{stat}, vedi \secref{sec:file_stat}) aggiungendo il nuovo
+nome ai precedenti. Si noti che uno stesso file può essere così chiamato con
+vari nomi in diverse directory.
Per quanto dicevamo in \secref{sec:file_filesystem} la creazione di un
collegamento diretto è possibile solo se entrambi i pathname sono nello stesso
funzione restituisce l'errore \errcode{EPERM}.
La rimozione di un file (o più precisamente della voce che lo referenzia
-all'interno di una directory) si effettua con la funzione \func{unlink}; il
+all'interno di una directory) si effettua con la funzione \funcd{unlink}; il
suo prototipo è il seguente:
\begin{prototype}{unistd.h}{int unlink(const char *pathname)}
\errcode{EPERM} in caso l'operazione non sia consentita o il processo non
abbia privilegi sufficienti.}
-La funzione cancella il nome specificato dal pathname nella relativa directory
-e decrementa il numero di riferimenti nel relativo inode\index{inode}. Nel
-caso di link simbolico cancella il link simbolico; nel caso di
-socket\index{socket}, fifo o file di dispositivo\index{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 cancella il nome specificato da \param{pathname} nella relativa
+directory e decrementa il numero di riferimenti nel relativo
+inode\index{inode}. Nel caso di link simbolico cancella il link simbolico; nel
+caso di socket\index{socket}, fifo o file di dispositivo\index{file!di
+ dispositivo} rimuove il nome, ma come per i file i processi che hanno aperto
+uno di questi oggetti possono continuare ad utilizzarlo.
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
Al contrario di quanto avviene con altri Unix, in Linux non è possibile usare
\func{unlink} sulle directory; per cancellare una directory si può usare la
funzione \func{rmdir} (vedi \secref{sec:file_dir_creat_rem}), oppure la
-funzione \func{remove}.
+funzione \funcd{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
ancora in uso.
Per cambiare nome ad un file o a una directory (che devono comunque essere
-nello stesso filesystem) si usa invece la funzione \func{rename},\footnote{la
+nello stesso filesystem) si usa invece la funzione \funcd{rename},\footnote{la
funzione è definita dallo standard ANSI C, ma si applica solo per i file, lo
standard POSIX estende la funzione anche alle directory.} il cui prototipo
è:
sistema (come mount point).
\item[\errcode{EINVAL}] \param{newpath} contiene un prefisso di
\param{oldpath} o più in generale si è cercato di creare una directory come
- sottodirectory di se stessa.
+ sotto-directory di se stessa.
\item[\errcode{ENOTDIR}] Uno dei componenti dei pathname non è una directory
o \param{oldpath} è una directory e \param{newpath} esiste e non è una
directory.
funzioni di libreria (come \func{open} o \func{stat}) dare come parametro un
link simbolico comporta l'applicazione della funzione al file da esso
specificato. La funzione che permette di creare un nuovo link simbolico è
-\func{symlink}; il suo prototipo è:
+\funcd{symlink}; il suo prototipo è:
\begin{prototype}{unistd.h}
{int symlink(const char *oldpath, const char *newpath)}
Crea un nuovo link simbolico di nome \param{newpath} il cui 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
alle informazioni del link invece che a quelle del file a cui esso fa
riferimento. Quando si vuole leggere il contenuto di un link simbolico si usa
-la funzione \func{readlink}, il cui prototipo è:
+la funzione \funcd{readlink}, il cui prototipo è:
\begin{prototype}{unistd.h}
{int readlink(const char *path, char *buff, size\_t size)}
Legge il contenuto del link simbolico indicato da \param{path} nel buffer
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
\subsection{La creazione e la cancellazione delle directory}
\label{sec:file_dir_creat_rem}
-Per creare e cancellare delle directory si usano le due funzioni (omonime
-degli analoghi comandi di shell) \func{mkdir} e \func{rmdir}. Per poter
-accedere ai tipi usati da queste funzioni si deve includere il file
-\file{sys/types.h}, il prototipo della prima è:
-\begin{prototype}{sys/stat.h}
- {int mkdir(const char *dirname, mode\_t mode)} Crea una nuova directory.
+Benché in sostanza le directory non siano altro che dei file contenenti
+elenchi di nomi ed inode, non è possibile trattarle come file ordinari e
+devono essere create direttamente dal kernel attraverso una opportuna system
+call.\footnote{questo permette anche, attraverso l'uso del VFS, l'utilizzo di
+ diversi formati per la gestione dei suddetti elenchi.} La funzione usata
+per creare una directory è \funcd{mkdir}, ed il suo prototipo è:
+\begin{functions}
+ \headdecl{sys/stat.h}
+ \headdecl{sys/types.h}
+ \funcdecl{int mkdir(const char *dirname, mode\_t mode)}
+
+ Crea una nuova directory.
\bodydesc{La funzione restituisce zero in caso di successo e -1 per un
errore, nel qual caso \var{errno} assumerà i valori:
ed inoltre anche \errval{EPERM}, \errval{EFAULT}, \errval{ENAMETOOLONG},
\errval{ENOENT}, \errval{ENOTDIR}, \errval{ENOMEM}, \errval{ELOOP},
\errval{EROFS}.}
-\end{prototype}
+\end{functions}
La funzione crea una nuova directory vuota, che contiene cioè solo le due voci
-standard \file{.} e \file{..}, con il nome indicato dall'argomento
+standard (\file{.} e \file{..}), con il nome indicato dall'argomento
\param{dirname}. Il nome può essere indicato sia come pathname assoluto che
relativo.
nuova directory è impostata secondo quanto riportato in
\secref{sec:file_ownership}.
-La seconda funzione serve ad eliminare una directory già vuota (la directory
-deve cioè contenere soltanto le due voci standard \file{.} e \file{..}); il
-suo prototipo è:
+La funzione per la cancellazione di una directory è \funcd{rmdir}, il suo
+prototipo è:
\begin{prototype}{sys/stat.h}{int rmdir(const char *dirname)}
Cancella una directory.
\errval{ENOTDIR}, \errval{ENOMEM}, \errval{ELOOP}, \errval{EROFS}.}
\end{prototype}
-La funzione cancella la directory \param{dirname}, che deve essere vuota. Il
-nome può essere indicato con il pathname assoluto o relativo.
+La funzione cancella la directory \param{dirname}, che deve essere vuota (la
+directory deve cioè contenere soltanto le due voci standard \file{.} e
+\file{..}). Il nome può essere indicato con il pathname assoluto o relativo.
La modalità con cui avviene la cancellazione è analoga a quella di
\func{unlink}: fintanto che il numero di link all'inode\index{inode} della
il filesystem su cui si è cercato di creare \func{pathname} non supporta
l'operazione.
\item[\errcode{EINVAL}] Il valore di \param{mode} non indica un file, una
- fifo o un dipositivo.
+ fifo o un dispositivo.
\item[\errcode{EEXIST}] \param{pathname} esiste già o è un link simbolico.
\end{errlist}
ed inoltre anche \errval{EFAULT}, \errval{EACCES}, \errval{ENAMETOOLONG},
\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}.
\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}
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 contenente 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
+corrisponde a quello 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 è
+ definita 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 corrisponde 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}
\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 errato 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'inizio 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 dinamicamente 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}.)
+
A ciascun processo è associata 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, dove il ``relativa'' fa riferimento appunto a questa directory.
+relativa, dove il ``\textsl{relativa}'' fa riferimento appunto a questa
+directory.
Quando un utente effettua il login, questa directory viene impostata alla
\textit{home directory} del suo account. Il comando \cmd{cd} della shell
In genere il kernel tiene traccia per ciascun processo dell'inode\index{inode}
della directory di lavoro corrente, per ottenere il pathname occorre usare una
-apposita funzione di libreria, \func{getcwd}, il cui prototipo è:
+apposita funzione di libreria, \funcd{getcwd}, il cui prototipo è:
\begin{prototype}{unistd.h}{char *getcwd(char *buffer, size\_t size)}
- Restituisce il filename completo della directory di lavoro corrente nella
- stringa puntata da \param{buffer}, che deve essere precedentemente allocata,
- per una dimensione massima di \param{size}.
+ Legge il pathname della directory di lavoro corrente.
\bodydesc{La funzione restituisce il puntatore \param{buffer} se riesce,
\val{NULL} se fallisce, in quest'ultimo caso la variabile
\end{errlist}}
\end{prototype}
-Il buffer deve essere sufficientemente lungo da poter contenere il pathname
+La funzione restituisce il pathname completo della directory di lavoro
+corrente nella stringa puntata da \param{buffer}, che deve essere
+precedentemente allocata, per una dimensione massima di \param{size}. Il
+buffer deve essere sufficientemente lungo da poter contenere il pathname
completo più lo zero di terminazione della stringa. Qualora esso ecceda le
-dimensioni specificate con \param{size} la funzione restituisce un errore. Si
-può anche specificare un puntatore nullo come \param{buffer},\footnote{questa è
- un'estensione allo standard POSIX.1, supportata da Linux.} nel qual caso la
-stringa sarà allocata automaticamente per una dimensione pari a \param{size}
-qualora questa sia diversa da zero, o della lunghezza esatta del pathname
-altrimenti. In questo caso ci si deve ricordare di disallocare la stringa una
-volta cessato il suo utilizzo.
+dimensioni specificate con \param{size} la funzione restituisce un errore.
+
+Si può anche specificare un puntatore nullo come
+\param{buffer},\footnote{questa è un'estensione allo standard POSIX.1,
+ supportata da Linux.} nel qual caso la stringa sarà allocata automaticamente
+per una dimensione pari a \param{size} qualora questa sia diversa da zero, o
+della lunghezza esatta del pathname altrimenti. In questo caso ci si deve
+ricordare di disallocare la stringa una volta cessato il suo utilizzo.
Di questa funzione esiste una versione \code{char *getwd(char *buffer)}
fatta per compatibilità all'indietro con BSD, che non consente di specificare
passaggio attraverso eventuali link simbolici.
Per cambiare la directory di lavoro corrente si può usare la funzione
-\func{chdir} (equivalente del comando di shell \cmd{cd}) il cui nome sta
+\funcd{chdir} (equivalente del comando di shell \cmd{cd}) il cui nome sta
appunto per \textit{change directory}, il suo prototipo è:
\begin{prototype}{unistd.h}{int chdir(const char *pathname)}
Cambia la directory di lavoro corrente in \param{pathname}.
Dato che anche le directory sono file, è possibile riferirsi ad esse anche
tramite il file descriptor, e non solo tramite il filename, per fare questo si
-usa \func{fchdir}, il cui prototipo è:
+usa \funcd{fchdir}, il cui prototipo è:
\begin{prototype}{unistd.h}{int fchdir(int fd)}
Identica a \func{chdir}, ma usa il file descriptor \param{fd} invece del
pathname.
Le \acr{glibc} provvedono varie funzioni per generare nomi di file temporanei,
di cui si abbia certezza di unicità (al momento della generazione); la prima
-di queste funzioni è \func{tmpnam} il cui prototipo è:
+di queste funzioni è \funcd{tmpnam} il cui prototipo è:
\begin{prototype}{stdio.h}{char *tmpnam(char *string)}
Restituisce il puntatore ad una stringa contente un nome di file valido e
non esistente al momento dell'invocazione.
Di questa funzione esiste una versione rientrante, \func{tmpnam\_r}, che non
fa nulla quando si passa \val{NULL} come parametro. Una funzione simile,
-\func{tempnam}, permette di specificare un prefisso per il file
+\funcd{tempnam}, permette di specificare un prefisso per il file
esplicitamente, il suo prototipo è:
\begin{prototype}{stdio.h}{char *tempnam(const char *dir, const char *pfx)}
Restituisce il puntatore ad una stringa contente un nome di file valido e
esistente.
Per evitare di dovere effettuare a mano tutti questi controlli, lo standard
-POSIX definisce la funzione \func{tempfile}, il cui prototipo è:
+POSIX definisce la funzione \funcd{tempfile}, il cui prototipo è:
\begin{prototype}{stdio.h}{FILE *tmpfile (void)}
Restituisce un file temporaneo aperto in lettura/scrittura.
condition}\index{race condition}.
Alcune versioni meno recenti di Unix non supportano queste funzioni; in questo
-caso si possono usare le vecchie funzioni \func{mktemp} e \func{mkstemp} che
+caso si possono usare le vecchie funzioni \funcd{mktemp} e \func{mkstemp} che
modificano una stringa di input che serve da modello e che deve essere
conclusa da 6 caratteri \code{X} che verranno sostituiti da un codice
-unico. La prima delle due è analoga a \func{tmpnam} e genera un nome casuale,
+unico. La prima delle due è analoga a \funcd{tmpnam} e genera un nome casuale,
il suo prototipo è:
\begin{prototype}{stlib.h}{char *mktemp(char *template)}
Genera un filename univoco sostituendo le \code{XXXXXX} finali di
indovinare. Per tutti questi motivi la funzione è deprecata e non dovrebbe mai
essere usata.
-
-
-La seconda funzione, \func{mkstemp} è sostanzialmente equivalente a
+La seconda funzione, \funcd{mkstemp} è sostanzialmente equivalente a
\func{tmpfile}, ma restituisce un file descriptor invece di uno stream; il suo
prototipo è:
\begin{prototype}{stlib.h}{int mkstemp(char *template)}
-1 in caso di errore, nel qual caso \var{errno} assumerà i valori:
\begin{errlist}
\item[\errcode{EINVAL}] \param{template} non termina con \code{XXXXXX}.
- \item[\errcode{EEXIST}] non è riuscita a creare un file temporano, il
+ \item[\errcode{EEXIST}] non è riuscita a creare un file temporaneo, il
contenuto di \param{template} è indefinito.
\end{errlist}}
\end{prototype}
In OpenBSD è stata introdotta un'altra funzione\footnote{introdotta anche in
Linux a partire dalle \acr{glibc} 2.1.91.} simile alle precedenti,
-\func{mkdtemp}, che crea una directory temporanea; il suo prototipo è:
+\funcd{mkdtemp}, che crea una directory temporanea; il suo prototipo è:
\begin{prototype}{stlib.h}{char *mkdtemp(char *template)}
Genera una directory temporaneo il cui nome è ottenuto sostituendo le
\code{XXXXXX} finali di \param{template}.
\label{sec:file_utime}
I tempi di ultimo accesso e modifica possono essere cambiati usando la
-funzione \func{utime}, il cui prototipo è:
+funzione \funcd{utime}, il cui prototipo è:
\begin{prototype}{utime.h}
{int utime(const char *filename, struct utimbuf *times)}
del controllo di accesso ai file, che viene implementato per qualunque
filesystem standard.\footnote{per standard si intende che implementa le
caratteristiche previste dallo standard POSIX. In Linux sono disponibili
- anche una serie di altri filesystem, come quelli di Windiws e del Mac, che
+ anche una serie di altri filesystem, come quelli di Windows e del Mac, che
non supportano queste caratteristiche.} In questa sezione ne esamineremo i
concetti essenziali e le funzioni usate per gestirne i vari aspetti.
lettura, scrittura ed esecuzione e sono applicati rispettivamente
rispettivamente al proprietario, al gruppo, a tutti gli altri.
-I restanti tre bit (noti come \acr{suid}, \acr{sgid}, e \textsl{sticky}) sono
-usati per indicare alcune caratteristiche più complesse del meccanismo del
-controllo di accesso su cui torneremo in seguito (in
-\secref{sec:file_suid_sgid} e \secref{sec:file_sticky}); lo schema di
-allocazione dei bit è riportato in \figref{fig:file_perm_bit}.
-
\begin{figure}[htb]
\centering
\includegraphics[width=6cm]{img/fileperm}
\label{fig:file_perm_bit}
\end{figure}
+I restanti tre bit (noti come \acr{suid}, \acr{sgid}, e \textsl{sticky}) sono
+usati per indicare alcune caratteristiche più complesse del meccanismo del
+controllo di accesso su cui torneremo in seguito (in
+\secref{sec:file_suid_sgid} e \secref{sec:file_sticky}); lo schema di
+allocazione dei bit è riportato in \figref{fig:file_perm_bit}.
+
Anche i permessi, come tutte le altre informazioni pertinenti al file, sono
memorizzati nell'inode\index{inode}; in particolare essi sono contenuti in
alcuni bit del campo \var{st\_mode} della struttura \struct{stat} (si veda di
Per una directory infatti il permesso di esecuzione significa che essa può
essere attraversata nella risoluzione del pathname, ed è distinto dal permesso
di lettura che invece implica che si può leggere il contenuto della directory.
+
Questo significa che se si ha il permesso di esecuzione senza permesso di
lettura si potrà lo stesso aprire un file in una directory (se si hanno i
permessi opportuni per il medesimo) ma non si potrà vederlo con \cmd{ls}
Per una spiegazione dettagliata degli identificatori associati ai processi si
veda \secref{sec:proc_perms}; normalmente, a parte quanto vedremo in
-\secref{sec:file_suid_sgid}, l'userid effettivo e il groupid effectivo
+\secref{sec:file_suid_sgid}, l'userid effettivo e il groupid effettivo
corrispondono ai valori dell'\acr{uid} e del \acr{gid} dell'utente che ha
lanciato il processo, mentre i groupid supplementari sono quelli dei gruppi
cui l'utente appartiene.
\item l'utente è l'amministratore
\end{itemize*}
un classico esempio di directory che ha questo bit impostato è \file{/tmp}, i
-permessi infatti di solito sono impostati come:
+permessi infatti di solito sono i seguenti:
\begin{verbatim}
$ ls -ld /tmp
drwxrwxrwt 6 root root 1024 Aug 10 01:03 /tmp
\end{verbatim}%$
-in questo modo chiunque può creare file in questa directory (che infatti è
-normalmente utilizzata per la creazione di file temporanei), ma solo l'utente
-che ha creato un certo file potrà cancellarlo o rinominarlo. In questo modo si
-evita che un utente possa, più o meno consapevolmente, cancellare i file degli
-altri.
+quindi con lo \textsl{sticky bit} bit impostato. In questo modo qualunque
+utente nel sistema può creare dei file in questa directory (che, come
+suggerisce il nome, è normalmente utilizzata per la creazione di file
+temporanei), ma solo l'utente che ha creato un certo file potrà cancellarlo o
+rinominarlo. In questo modo si evita che un utente possa, più o meno
+consapevolmente, cancellare i file temporanei creati degli altri utenti.
\subsection{La titolarità di nuovi file e directory}
Usare la semantica BSD ha il vantaggio che il \acr{gid} viene sempre
automaticamente propagato, restando coerente a quello della directory di
-partenza, in tutte le sottodirectory. La semantica SVr4 offre la possibilità
-di scegliere, ma per ottenere lo stesso risultato di coerenza che si ha con
-BSD necessita che per le nuove directory venga anche propagato anche il bit
-\acr{sgid}. Questo è il comportamento predefinito di \cmd{mkdir}, ed è in
-questo modo ad esempio che Debian assicura che le sottodirectory create nella
-home di un utente restino sempre con il \acr{gid} del gruppo primario dello
-stesso.
+partenza, in tutte le sotto-directory.
+
+La semantica SVr4 offre la possibilità di scegliere, ma per ottenere lo stesso
+risultato di coerenza che si ha con BSD necessita che per le nuove directory
+venga anche propagato anche il bit \acr{sgid}. Questo è il comportamento
+predefinito del comando \cmd{mkdir}, ed è in questo modo ad esempio che Debian
+assicura che le sotto-directory create nella home di un utente restino sempre
+con il \acr{gid} del gruppo primario dello stesso.
\subsection{La funzione \func{access}}
ed il groupid reale, vale a dire usando i valori di \acr{uid} e \acr{gid}
relativi all'utente che ha lanciato il programma, e che, come accennato in
\secref{sec:file_suid_sgid} e spiegato in dettaglio in
-\secref{sec:proc_perms}, non è detto siano uguali a quelli effettivi. Per far
-questo si può usare la funzione \func{access}, il cui prototipo è:
+\secref{sec:proc_perms}, non è detto siano uguali a quelli effettivi.
+
+Per far questo si può usare la funzione \funcd{access}, il cui prototipo è:
\begin{prototype}{unistd.h}
{int access(const char *pathname, int mode)}
-Verifica i permessi di accesso, indicati da \param{mode}, per il file indicato
-da \param{pathname}.
+Verifica i permessi di accesso.
\bodydesc{La funzione ritorna 0 se l'accesso è consentito, -1 se l'accesso non
è consentito ed in caso di errore; nel qual caso la variabile \var{errno}
\errval{ENOTDIR}, \errval{ELOOP}, \errval{EIO}.}
\end{prototype}
-I valori possibili per l'argomento \param{mode} sono esprimibili come
-combinazione delle costanti numeriche riportate in
-\tabref{tab:file_access_mode_val} (attraverso un OR binario delle stesse). I
-primi tre valori implicano anche la verifica dell'esistenza del file, se si
-vuole verificare solo quest'ultima si può usare \const{F\_OK}, o anche
-direttamente \func{stat}. Nel caso in cui \param{pathname} si riferisca ad un
-link simbolico, questo viene seguito ed il controllo è fatto sul file a cui
-esso fa riferimento.
+La funzione verifica i permessi di accesso, indicati da \param{mode}, per il
+file indicato da \param{pathname}. I valori possibili per l'argomento
+\param{mode} sono esprimibili come combinazione delle costanti numeriche
+riportate in \tabref{tab:file_access_mode_val} (attraverso un OR binario delle
+stesse). I primi tre valori implicano anche la verifica dell'esistenza del
+file, se si vuole verificare solo quest'ultima si può usare \const{F\_OK}, o
+anche direttamente \func{stat}. Nel caso in cui \param{pathname} si riferisca
+ad un link simbolico, questo viene seguito ed il controllo è fatto sul file a
+cui esso fa riferimento.
La funzione controlla solo i bit dei permessi di accesso, si ricordi che il
fatto che una directory abbia permesso di scrittura non significa che ci si
Oltre che dai valori indicati in sede di creazione, i permessi assegnati ai
nuovi file sono controllati anche da una maschera di bit impostata con la
-funzione \func{umask}, il cui prototipo è:
+funzione \funcd{umask}, il cui prototipo è:
\begin{prototype}{stat.h}
{mode\_t umask(mode\_t mask)}
\acr{s}&\acr{s}&\acr{t}&r&w&x&r&w&x&r&w&x& \\
\hline
\hline
- 1&-&-&-&-&-&-&-&-&-&-&-&Se eseguito ha i permessi del propritario\\
- -&1&-&-&-&1&-&-&-&-&-&-&Se eseguito ha i permessi del gruppo propritario\\
+ 1&-&-&-&-&-&-&-&-&-&-&-&Se eseguito ha i permessi del proprietario\\
+ -&1&-&-&-&1&-&-&-&-&-&-&Se eseguito ha i permessi del gruppo proprietario\\
-&1&-&-&-&0&-&-&-&-&-&-&Il \textit{mandatory locking} è abilitato\\
-&-&1&-&-&-&-&-&-&-&-&-&Non utilizzato\\
-&-&-&1&-&-&-&-&-&-&-&-&Permesso di lettura per il proprietario\\
\label{sec:file_chroot}
Benché non abbia niente a che fare con permessi, utenti e gruppi, la funzione
-\func{chroot} viene usata spesso per restringere le capacità di acccesso di un
+\func{chroot} viene usata spesso per restringere le capacità di accesso di un
programma ad una sezione limitata del filesystem, per cui ne parleremo in
questa sezione.
\figref{fig:proc_task_struct}.} che è la directory che per il processo
costituisce la radice dell'albero dei file e rispetto alla quale vengono
risolti i pathname assoluti (si ricordi quanto detto in
-\secref{sec:file_organization}). La radice viene eredidata dal padre per ogni
+\secref{sec:file_organization}). La radice viene ereditata dal padre per ogni
processo figlio, e quindi di norma coincide con la \file{/} del sistema.
In certe situazioni però per motivi di sicurezza non si vuole che un processo
possa accedere a tutto il filesystem; per questo si può cambiare la directory
-radice con la funzione \func{chroot}, il cui prototipo è:
+radice con la funzione \funcd{chroot}, il cui prototipo è:
\begin{prototype}{unistd.h}{int chroot(const char *path)}
Cambia la directory radice del processo a quella specificata da
\param{path}.
Ma quando ad un processo restano i privilegi di root esso potrà sempre portare
la directory di lavoro corrente fuori dalla \textit{chroot jail} creando una
-sottodirectory ed eseguendo una \func{chroot} su di essa. Per questo motivo
+sotto-directory ed eseguendo una \func{chroot} su di essa. Per questo motivo
l'uso di questa funzione non ha molto senso quando un processo necessita dei
privilegi di root per le sue normali operazioni.
-Un caso tipico di uso di \func{chroot} è quello di un server ftp anonimo, in
+Un caso tipico di uso di \func{chroot} è quello di un server FTP anonimo, in
questo caso infatti si vuole che il server veda solo i file che deve
trasferire, per cui in genere si esegue una \func{chroot} sulla directory che
contiene i file. Si tenga presente però che in questo caso occorrerà