Completato I/O binario
[gapil.git] / fileunix.tex
index 258eae0adcc24fa0041238985bd5a4794e44e0a0..17a68ed645e5a2fc4ad033a422e7ecaf9b40f105 100644 (file)
@@ -1,12 +1,12 @@
-\chapter{L'interfaccia unix di I/O con i file}
+\chapter{I file: l'interfaccia standard unix}
 \label{cha:file_unix_interface}
 
 Esamineremo in questo capitolo la prima delle due interfacce di programmazione
 per i file, quella dei \textit{file descriptor}, nativa di unix. Questa è
-l'interfaccia di basso livello, che non prevede funzioni evolute come la
-bufferizzazione o funzioni di lettura o scrittura formattata, ma è su questa
-che è costruita anche l'interfaccia standard dei file definita dallo standard
-ANSI C.
+l'interfaccia di basso livello provvista direttamente dalle system call, che
+non prevede funzionalità evolute come la bufferizzazione o funzioni di lettura
+o scrittura formattata, e sulla quale è costruita anche l'interfaccia definita
+dallo standard ANSI C che affronteremo in \capref{cha:files_std_interface}.
 
 
 
@@ -34,7 +34,7 @@ ogni ulteriore operazione.
 All'interno di ogni processo i file aperti sono identificati da un intero non
 negativo, chiamato appunto \textit{file descriptor}, quando un file viene
 aperto la funzione restituisce il file descriptor, e tutte le successive
-operazioni devono passare il \textit{file descriptors} come argomento.
+operazioni devono passare il \textit{file descriptor} come argomento.
 
 Per capire come funziona il meccanismo occorre spiegare a grandi linee come è
 che il kernel gestisce l'interazione fra processi e file.  Il kernel mantiene
@@ -78,7 +78,7 @@ questa architettura, in cui si sono evidenziate le interrelazioni fra le varie
 strutture di dati sulla quale essa è basata. 
 \begin{figure}[htb]
   \centering
-  \includegraphics[width=14cm]{img/procfile.eps}
+  \includegraphics[width=14cm]{img/procfile}
   \caption{Schema della architettura dell'accesso ai file attraverso
   l'interfaccia dei \textit{file descriptor}}
   \label{fig:file_proc_file}
@@ -194,7 +194,7 @@ prototipo 
     che non esiste.  
   \item \macro{ETXTBSY} si è cercato di accedere in scrittura all'immagine di
     un programma in esecuzione.
-  \item \macro{ELOOP} si sono incotrati troppi link simbolici nel risolvere
+  \item \macro{ELOOP} si sono incontrati troppi link simbolici nel risolvere
     pathname o si è indicato \macro{O\_NOFOLLOW} e \var{pathname} è un link
     simbolico.
   \end{errlist}
@@ -205,12 +205,7 @@ prototipo 
 
 La funzione apre il file, usando il primo file descriptor libero, e crea
 l'opportuna voce (cioè la struttura \var{file}) nella file table.  Viene usato
-sempre il file descriptor con il valore più basso, questa caratteristica
-permette di prevedere qual'è il valore che si otterrà e viene talvolta usata
-da alcune applicazioni per sostituire i file corrispondenti ai file standard
-di \secref{sec:file_std_descr}: se ad esempio si chiude lo standard input e si
-apre subito dopo un nuovo file questo diventerà il nuovo standard input (avrà
-cioè il file descriptor 0).
+sempre il file descriptor con il valore più basso. 
 
 \begin{table}[!htb]
   \centering
@@ -219,22 +214,18 @@ cio
     \hline
     \textbf{Flag} & \textbf{Descrizione} \\
     \hline
-    \hline % modailtà di accesso al file
+    \hline % modalità di accesso al file
     \macro{O\_RDONLY} & apre il file in sola lettura. \\
     \macro{O\_WRONLY} & apre il file in sola scrittura. \\
     \macro{O\_RDWR} & apre il file lettura/scrittura. \\
-    \hline % modalita di apertura del file
+    \hline % modalità di apertura del file
     \hline
     \macro{O\_CREAT} & se il file non esiste verrà creato, con le regole di
     titolarità del file viste in \secref{sec:file_ownership}. Il parametro
     \var{mode} deve essere specificato. \\
     \macro{O\_EXCL} & usato in congiunzione con \macro{O\_CREAT} fa sì che
-    l'esistenza del file diventi un errore\protect\footnote{la man page di 
-      \func{open} segnala che questa opzione è difettosa su NFS, e che i 
-      programmi che la usano per stabilire un file di lock possono incorrere 
-      in una race condition.  Si consiglia come alternativa di usare un file 
-      con un nome univoco e la funzione \func{link} per verificarne 
-      l'esistenza.} che fa fallire \func{open} con \macro{EEXIST}. \\
+    l'esistenza del file diventi un errore\protect\footnotemark\ che fa fallire
+    \func{open} con \macro{EEXIST}. \\
     \macro{O\_NONBLOCK} & apre il file in modalità non bloccante. Questo
     valore specifica anche una modalità di operazione (vedi sotto), e 
     comporta che \func{open} ritorni immediatamente (torneremo su
@@ -256,10 +247,8 @@ cio
     opzione è ignorata. \\
     \macro{O\_DIRECTORY} & se \var{pathname} non è una directory la chiamata
     fallisce. Questo flag è specifico di Linux ed è stato introdotto con il
-    kernel 2.1.126 per evitare dei DoS\protect\footnote{Denial of Service, si 
-      chiamano così attacchi miranti ad impedire un servizio causando una 
-      qualche forma di carico eccessivo per il sistema, che resta bloccato 
-      nelle risposte all'attacco} quando \func{opendir} viene chiamata su una 
+    kernel 2.1.126 per evitare dei DoS\protect\footnotemark\ quando 
+    \func{opendir} viene chiamata su una 
     fifo o su un device di unità a nastri, non deve essere utilizzato al di 
     fuori dell'implementazione di \func{opendir}. \\
     \macro{O\_LARGEFILE} & nel caso di sistemi a 32 bit che supportano file di
@@ -270,21 +259,17 @@ cio
     \macro{O\_APPEND} & il file viene aperto in append mode. Prima di ciascuna
     scrittura la posizione corrente viene sempre settata alla fine del
     file. Può causare corruzione del file con NFS se più di un processo scrive
-    allo stesso tempo\footnote{il problema è che NFS non supporta la scrittura
-    in append, ed il kernel deve simularla, ma questo comporta la possibilità
-    di una race condition}.\\
+    allo stesso tempo\footnotemark.\\
     \macro{O\_NONBLOCK} & il file viene aperto in modalità non bloccante per
     le operazioni di I/O: questo significa il fallimento di una \func{read} in
     assenza di dati da leggere e quello di una \func{write} in caso di 
     impossibilità di scrivere immediatamente. L'opzione è effettiva solo per
     le fifo e per alcuni file di dispositivo. \\
-    \macro{O\_NDELAY} & in Linux\footnote{l'opzione origina da SVr4, dove però
-    causava il ritorno da una \func{read} con un valore nullo e non con un
-    errore, questo introduce una ambiguità, dato che come vedremo in
-    \secref{sec:file_read} il ritorno di zero da parte di \func{read} ha il
-    significato di una end-of-file} è sinonimo di \macro{O\_NONBLOCK}.\\
+    \macro{O\_NDELAY} & in Linux\footnotemark\ è sinonimo di 
+    \macro{O\_NONBLOCK}.\\
     \macro{O\_ASYNC} & apre il file per l'input/output in modalità
-    asincrona. Non è supportato in Linux. \\
+    asincrona. Quando è settato viene generato un segnale di \macro{SIGIO}
+    tutte le volte che è disponibile dell'input sul file. \\
     \macro{O\_SYNC} & apre il file per l'input/output sincrono, ogni
     \func{write} bloccherà fino al completamento della scrittura di tutti dati
     sul sull'hardware sottostante.\\
@@ -295,11 +280,37 @@ cio
     di montaggio.\\
     \hline
   \end{tabular}
-  \caption{Costanti definite in \file{fcntl.h} per indicare i vari bit 
-    usabili per il specificare parametro \var{flags} di \func{open}.}
+  \caption{Valori e significato dei vari bit del \textit{file status flag}.}
   \label{tab:file_open_flags}
 \end{table}
 
+\footnotetext[2]{la man page di \func{open} segnala che questa opzione è
+  difettosa su NFS, e che i programmi che la usano per stabilire un file di
+  lock possono incorrere in una race condition.  Si consiglia come alternativa
+  di usare un file con un nome univoco e la funzione \func{link} per
+  verificarne l'esistenza.}  
+
+\footnotetext[3]{Denial of Service, si chiamano così attacchi miranti ad
+  impedire un servizio causando una qualche forma di carico eccessivo per il
+  sistema, che resta bloccato nelle risposte all'attacco.}
+
+\footnotetext[4]{il problema è che NFS non supporta la scrittura in append, ed
+  il kernel deve simularla, ma questo comporta la possibilità di una race
+  condition, vedi \secref{sec:file_atomic}.}
+
+\footnotetext[5]{l'opzione origina da SVr4, dove però causava il ritorno da
+  una \func{read} con un valore nullo e non con un errore, questo introduce
+  una ambiguità, dato che come vedremo in \secref{sec:file_read} il ritorno di
+  zero da parte di \func{read} ha il significato di una end-of-file.}
+
+Questa caratteristica permette di prevedere qual'è il valore del file
+descriptor che si otterrà al ritorno di \func{open}, e viene talvolta usata da
+alcune applicazioni per sostituire i file corrispondenti ai file standard di
+\secref{sec:file_std_descr}: se ad esempio si chiude lo standard input e si
+apre subito dopo un nuovo file questo diventerà il nuovo standard input (avrà
+cioè il file descriptor 0).
+
+
 Il nuovo file descriptor non è condiviso con nessun altro processo, (torneremo
 sulla condivisione dei file, in genere accessibile dopo una \func{fork}, in
 \secref{sec:file_sharing}). Il nuovo file descriptor è settato di default per
@@ -342,7 +353,9 @@ secondo le tre modalit
 ciascuno di questi bit, dette costanti possono essere combinate fra di loro
 con un OR aritmetico per costruire il valore (in forma di maschera binaria)
 del parametro \var{flags} da passare alla \func{open} per specificarne il
-comportamento.
+comportamento. I due flag \macro{O\_NOFOLLOW} e \macro{O\_DIRECTORY} sono
+estensioni specifiche di Linux, e deve essere usata definita la macro
+\macro{\_GNU\_SOURCE} per poterli usare.
 
 Nelle prime versioni di unix i flag specificabili per \func{open} erano solo
 quelli relativi alle modalità di accesso del file.  Per questo motivo per
@@ -353,8 +366,8 @@ prototipo 
   Crea un nuovo file vuoto, con i permessi specificati da \var{mode}. É del
   tutto equivalente a \func{open(filedes, O\_CREAT|O\_WRONLY|O\_TRUNC, mode)}. 
 \end{prototype}
-
-adesso questa funzione resta solo per compatibilità con i vecchi programmi.
+\noindent adesso questa funzione resta solo per compatibilità con i vecchi 
+programmi.
 
 
 \subsection{La funzione \func{close}}
@@ -371,7 +384,7 @@ descriptor ritorna disponibile; il suo prototipo 
     \item \macro{EBADF}  \var{fd} non è un descrittore valido.
     \item \macro{EINTR} la funzione è stata interrotta da un segnale.
   \end{errlist}
-  ed \macro{EIO}.
+  ed inoltre \macro{EIO}.
 \end{prototype}
 
 La chiusura di un file rilascia ogni blocco (il \textit{file locking} è
@@ -381,7 +394,7 @@ aperto, tutte le risorse nella file table vengono rilasciate. Infine se il
 file descriptor era l'ultimo riferimento ad un file su disco quest'ultimo
 viene cancellato.
 
-Si ricordi che quando un processo termina anche tutti i sui file descriptor
+Si ricordi che quando un processo termina anche tutti i suoi file descriptor
 vengono chiusi, molti programmi sfruttano questa caratteristica e non usano
 esplicitamente \func{close}. In genere comunque chiudere un file senza
 controllarne lo stato di uscita è errore; infatti molti filesystem
@@ -395,9 +408,10 @@ quote su disco.
 In ogni caso una \func{close} andata a buon fine non garantisce che i dati
 siano stati effettivamente scritti su disco, perché il kernel può decidere di
 ottimizzare l'accesso a disco ritardandone la scrittura. L'uso della funzione
-\func{sync} effettua esplicitamente il \emph{flush} dei dati, ma anche in
-questo caso resta l'incertezza dovuta al comportamento dell'hardware (che a
-sua volta può introdurre ottimizzazioni dell'accesso al disco).
+\func{sync} (vedi \secref{sec:file_sync}) effettua esplicitamente il
+\emph{flush} dei dati, ma anche in questo caso resta l'incertezza dovuta al
+comportamento dell'hardware (che a sua volta può introdurre ottimizzazioni
+dell'accesso al disco).
 
 
 \subsection{La funzione \func{lseek}}
@@ -406,7 +420,7 @@ sua volta pu
 Come già accennato in \secref{sec:file_fd} a ciascun file aperto è associata
 una \textsl{posizione corrente nel file} (il cosiddetto \textit{file offset},
 mantenuto nel campo \var{f\_pos} di \var{file}) espressa da un numero intero
-positivo come numero di bytes dall'inizio del file. Tutte le operazioni di
+positivo come numero di byte dall'inizio del file. Tutte le operazioni di
 lettura e scrittura avvengono a partire da questa posizione che viene
 automaticamente spostata in avanti del numero di byte letti o scritti.
 
@@ -425,7 +439,7 @@ un valore qualsiasi con la funzione \func{lseek}, il cui prototipo 
     \item \macro{ESPIPE} \var{fd} è una pipe, un socket o una fifo.
     \item \macro{EINVAL} \var{whence} non è un valore valido.
   \end{errlist}
-  e \macro{EBADF}.
+  ed inoltre \macro{EBADF}.
 \end{functions}
 
 La nuova posizione è settata usando il valore specificato da \var{offset},
@@ -433,14 +447,14 @@ sommato al riferimento dato da \var{whence}; quest'ultimo pu
 seguenti valori\footnote{per compatibilità con alcune vecchie notazioni
   questi valori possono essere rimpiazzati rispettivamente con 0, 1 e 2 o con
   \macro{L\_SET}, \macro{L\_INCR} e \macro{L\_XTND}}:
-\begin{description}
-\item \macro{SEEK\_SET} si fa riferimento all'inizio del file: il valore di
+\begin{basedescript}{\desclabelwidth{2.0cm}}
+\item[\macro{SEEK\_SET}] si fa riferimento all'inizio del file: il valore di
   \var{offset} è la nuova posizione.
-\item \macro{SEEK\_CUR} si fa riferimento alla posizione corrente del file:
+\item[\macro{SEEK\_CUR}] si fa riferimento alla posizione corrente del file:
   \var{offset} che può essere negativo e positivo.
-\item \macro{SEEK\_END} si fa riferimento alla fine del file: il valore di
+\item[\macro{SEEK\_END}] si fa riferimento alla fine del file: il valore di
   \var{offset} può essere negativo e positivo.
-\end{description}
+\end{basedescript}
 
 Come accennato in \secref{sec:file_file_size} con \func{lseek} è possibile
 settare la posizione corrente anche al di la della fine del file, e alla
@@ -456,15 +470,14 @@ Si tenga presente inoltre che usare \macro{SEEK\_END} non assicura affatto che
 successiva scrittura avvenga alla fine del file, infatti se questo è stato
 aperto anche da un altro processo che vi ha scritto, la fine del file può
 essersi spostata, ma noi scriveremo alla posizione settata in precedenza.
-Questa è una potenziale sorgente di \textit{race condition}, e quando si vuole
-essere sicuri di scrivere alla fine del file questo deve essere posto in
-modalità \macro{O\_APPEND}.
+(questa è una potenziale sorgente di \textit{race condition}, vedi
+\secref{sec:file_atomic}).
 
 Non tutti i file supportano la capacità di eseguire una \func{lseek}, in
 questo caso la funzione ritorna l'errore \macro{EPIPE}. Questo, oltre che per
 i tre casi citati nel prototipo, vale anche per tutti quei dispositivi che non
 supportano questa funzione, come ad esempio per le \acr{tty}\footnote{altri
-  sistemi, usando \macro{SEEK\_SET} in questo caso ritornano il numero di
+  sistemi, usando \macro{SEEK\_SET}, in questo caso ritornano il numero di
   caratteri che vi sono stati scritti}. Lo standard POSIX però non specifica
 niente al proposito. Infine alcuni device, ad esempio \file{/dev/null}, non
 causano un errore ma restituiscono un valore indefinito.
@@ -473,18 +486,19 @@ causano un errore ma restituiscono un valore indefinito.
 \subsection{La funzione \func{read}}
 \label{sec:file_read}
 
-Per leggere da un file precedentemente aperto, si può la funzione \func{read},
-il cui prototipo è:
+
+Una volta che un file è stato aperto su possono leggere i dati che contiene
+utilizzando la funzione \func{read}, il cui prototipo è:
 \begin{prototype}{unistd.h}{ssize\_t read(int fd, void * buf, size\_t count)}
   
-  La funzione cerca di leggere \var{count} bytes dal file \var{fd} al buffer
+  La funzione cerca di leggere \var{count} byte dal file \var{fd} al buffer
   \var{buf}.
   
   La funzione ritorna il numero di byte letti in caso di successo e -1 in
   caso di errore, nel qual caso \var{errno} viene settata ad uno dei valori:
   \begin{errlist}
   \item \macro{EINTR} la funzione è stata interrotta da un segnale prima di
-    aver potuto leggere quasiasi dato.
+    aver potuto leggere qualsiasi dato.
     \item \macro{EAGAIN} la funzione non aveva nessun dato da restituire e si
       era aperto il file in modalità \macro{O\_NONBLOCK}.
   \end{errlist}
@@ -495,7 +509,7 @@ il cui prototipo 
 
 La funzione tenta di leggere \var{count} byte a partire dalla posizione
 corrente nel file; dopo la lettura la posizione è spostata automaticamente in
-avanti del numero di bytes letti. Se \var{count} è zero la funzione
+avanti del numero di byte letti. Se \var{count} è zero la funzione
 restituisce zero senza nessun altro risultato.
 
 Si deve sempre tener presente che non è detto che la funzione \func{read}
@@ -504,7 +518,7 @@ la funzione pu
 comportamento normale e non un errore, che però bisogna sempre tenere
 presente.
 
-La prima e più ovvia di queste ragioni è che si è chiesto di leggere più bytes
+La prima e più ovvia di queste ragioni è che si è chiesto di leggere più byte
 di quanto il file ne contenga. In questo caso il file viene letto fino alla
 sua fine, e la funzione ritorna regolarmente il numero di byte letti
 effettivamente. Se ripetessimo la lettura \func{read} restituirebbe uno zero.
@@ -540,7 +554,7 @@ sono dati in ingresso: la funzione allora ritorna immediatamente con un errore
 Lo standard Unix98\footnote{questa funzione, e l'analoga \func{pwrite} sono
   state aggiunte nel kernel 2.1.60, il supporto nelle \acr{glibc}, compresa
   l'emulazione per i vecchi kernel che non hanno la system call, è stato
-  aggiutno con la versione 2.1} (vedi \secref{sec:intro_opengroup}) prevede la
+  aggiunto con la versione 2.1} (vedi \secref{sec:intro_opengroup}) prevede la
 definizione di un'altra funzione di lettura, \func{pread}, che diventa
 accessibile con la definizione:
 \begin{verbatim}
@@ -550,7 +564,7 @@ il prototipo di questa funzione 
 \begin{prototype}{unistd.h}
 {ssize\_t pread(int fd, void * buf, size\_t count, off\_t offset)}
   
-La funzione cerca di leggere \var{count} bytes dal file \var{fd}, a partire
+La funzione cerca di leggere \var{count} byte dal file \var{fd}, a partire
 dalla posizione \var{offset}, nel buffer \var{buf}.
   
 La funzione ritorna il numero di byte letti in caso di successo e -1 in caso
@@ -559,20 +573,21 @@ per \func{read} e \func{lseek}.
 \end{prototype}
 
 Questa funzione serve quando si vogliono leggere dati dal file senza
-modificarne la posizione corrente. È equivalente alla esecuzione di una
-\func{read} e una \func{lseek}, ma dato che la posizione sul file può essere
-condivisa fra vari processi (vedi \secref{sec:file_sharing}), essa permette di
-eseguire l'operazione atomicamente. Il valore di \var{offset} fa riferimento
-all'inizio del file.
+modificarne la posizione corrente. È sostanzialmente equivalente alla
+esecuzione di una \func{read} e una \func{lseek}, ma dato che la posizione sul
+file può essere condivisa fra vari processi (vedi \secref{sec:file_sharing}),
+essa permette di eseguire l'operazione atomicamente. Il valore di \var{offset}
+fa sempre riferimento all'inizio del file.
 
 
 \subsection{La funzione \func{write}}
 \label{sec:file_write}
 
-Per scrivere su un file si usa la funzione \func{write}, il cui prototipo è:
+Una volta che un file è stato aperto su può scrivere su di esso utilizzando la
+funzione \func{write}, il cui prototipo è:
 \begin{prototype}{unistd.h}{ssize\_t write(int fd, void * buf, size\_t count)}
   
-  La funzione scrive \var{count} bytes dal buffer \var{buf} sul file \var{fd}.
+  La funzione scrive \var{count} byte dal buffer \var{buf} sul file \var{fd}.
   
   La funzione ritorna il numero di byte scritti in caso di successo e -1 in
   caso di errore, nel qual caso \var{errno} viene settata ad uno dei valori:
@@ -587,7 +602,7 @@ Per scrivere su un file si usa la funzione \func{write}, il cui prototipo 
     \macro{SIGPIPE}, se questo viene gestito (o bloccato o ignorato) la
     funzione ritorna questo errore.
   \item \macro{EINTR} la funzione è stata interrotta da un segnale prima di
-    aver potuto scerivere quasiasi dato.
+    aver potuto scrivere qualsiasi dato.
   \item \macro{EAGAIN} la funzione non aveva nessun dato da restituire e si
     era aperto il file in modalità \macro{O\_NONBLOCK}.
   \end{errlist}
@@ -598,7 +613,7 @@ Per scrivere su un file si usa la funzione \func{write}, il cui prototipo 
 
 Come nel caso di \func{read} la funzione tenta di scrivere \var{count} byte a
 partire dalla posizione corrente nel file e sposta automaticamente la
-posizione in avanti del numero di bytes scritti. Se il file è aperto in
+posizione in avanti del numero di byte scritti. Se il file è aperto in
 modalità \macro{O\_APPEND} i dati vengono sempre scritti alla fine del file.
 Lo standard POSIX richiede che i dati scritti siano immediatamente disponibili
 ad una \func{read} chiamata dopo che la \func{write} che li ha scritti è
@@ -606,7 +621,7 @@ ritornata; ma dati i meccanismi di caching non 
 supportino questa capacità.
 
 Se \var{count} è zero la funzione restituisce zero senza fare nient'altro. Per
-i file ordinari il numero di bytes scritti è sempre uguale a quello indicato
+i file ordinari il numero di byte scritti è sempre uguale a quello indicato
 da \var{count}, a meno di un errore. Negli altri casi si ha lo stesso
 comportamento di \func{read}.
 
@@ -617,7 +632,7 @@ suo prototipo 
 {ssize\_t pwrite(int fd, void * buf, size\_t count, off\_t offset)}
   
 La funzione cerca di scrivere sul file \var{fd}, a partire dalla posizione
-\var{offset}, \var{count} bytes dal buffer \var{buf}.
+\var{offset}, \var{count} byte dal buffer \var{buf}.
   
 La funzione ritorna il numero di byte letti in caso di successo e -1 in caso
 di errore, nel qual caso \var{errno} viene settata secondo i valori già visti
@@ -629,7 +644,7 @@ per \func{write} e \func{lseek}.
 \section{Caratteristiche avanzate}
 \label{sec:file_adv_func}
 
-In questa sezione approfondireme alcune delle caratteristiche più sottili
+In questa sezione approfondiremo alcune delle caratteristiche più sottili
 della gestione file in un sistema unix-like, esaminando in dettaglio il
 comportamento delle funzioni base, inoltre tratteremo alcune funzioni che
 permettono di eseguire operazioni avanzate con i file.
@@ -646,7 +661,7 @@ confronti dell'accesso allo stesso file da parte di processi diversi.
 
 \begin{figure}[htb]
   \centering
-  \includegraphics[width=14cm]{img/filemultacc.eps}
+  \includegraphics[width=14cm]{img/filemultacc}
   \caption{Schema dell'accesso allo stesso file da parte di due processi 
     diversi}
   \label{fig:file_mult_acc}
@@ -681,14 +696,14 @@ stesso file, in particolare occorre tenere presente che:
 
 \begin{figure}[htb]
   \centering
-  \includegraphics[width=14cm]{img/fileshar.eps}
+  \includegraphics[width=14cm]{img/fileshar}
   \caption{Schema dell'accesso ai file da parte di un processo figlio}
   \label{fig:file_acc_child}
 \end{figure}
 
 È comunque possibile che due file descriptor di due processi diversi puntino
 alla stessa voce nella \textit{file table}; questo è ad esempio il caso dei
-file aperti che venfono ereditati dal processo figlio all'esecuzione di una
+file aperti che vengono ereditati dal processo figlio all'esecuzione di una
 \func{fork} (si ricordi quanto detto in \secref{sec:proc_fork}). La situazione
 è illustrata in \figref{fig:file_acc_child}; dato che il processo figlio
 riceve una copia dello spazio di indirizzi del padre, riceverà anche una copia
@@ -696,7 +711,7 @@ di \var{file\_struct} e relativa tabella dei file aperti.
 
 In questo modo padre e figlio avranno gli stessi file descriptor che faranno
 riferimento alla stessa voce nella \textit{file table}, condividendo così la
-posizione corrente sul file. Questo ha le cosenguenze descritte a suo tempo in
+posizione corrente sul file. Questo ha le conseguenze descritte a suo tempo in
 \secref{sec:proc_fork}: in caso di scrittura contemporanea la posizione
 corrente nel file varierà per entrambi i processi (in quanto verrà modificato
 \var{f\_pos} che è la stesso per entrambi).
@@ -717,30 +732,329 @@ vengono toccati anche in caso di condivisione della voce della \textit{file
 
 Come si è visto in un sistema unix è sempre possibile per più processi
 accedere in contemporanea allo stesso file, e che le operazioni di lettura e
-scrittura saranno fatte in base alla posizione corrente nel file. Ovviamente
-senza prevedere opportuni meccanismi di sincronizzazione le operazioni
-potranno mescolarsi in maniera imprevedibile. L'unica garanzia è che se si è
-in modalità \macro{O\_APPEND} il sistema assicura che si scriva (con il
-procedimento appena esposto) sempre alla fine del file.
+scrittura possono essere fatte da ogni processo in maniera autonoma in base
+ad una posizione corrente nel file che è locale a ciascuno di essi.
+
+Se dal punto di vista della lettura dei dati questo non comporta nessun
+problema, quando si andrà a scrivere le operazioni potranno mescolarsi in
+maniera imprevedibile.  Il sistema però fornisce in alcuni casi la possibilità
+di eseguire alcune operazioni di scrittura in maniera coordinata anche senza
+utilizzare meccanismi di sincronizzazione più complessi (come il \textit{file
+  locking}, che esamineremo in \secref{cha:file_advanced}).
+
+Un caso tipico di necessità di accesso condiviso in scrittura è quello in cui
+vari processi devono scrivere alla fine di un file (ad esempio un file di
+log). Come accennato in \secref{sec:file_lseek} settare la posizione alla fine
+del file e poi scrivere può condurre ad una \textit{race condition}: infatti
+può succedere che un secondo processo scriva alla fine del file fra la
+\func{lseek} e la \func{write}; in questo caso, come abbiamo appena visto, il
+file sarà esteso, ma il nostro primo processo avrà ancora la posizione
+corrente settata con la \func{lseek} che non corrisponde più alla fine del
+file, e la successiva \func{write} sovrascriverà i dati del secondo processo.
+
+Il problema è che usare due system call in successione non è una operazione
+atomica; il problema è stato risolto introducendo la modalità
+\macro{O\_APPEND}, in questo caso infatti, come abbiamo visto, è il kernel che
+aggiorna automaticamente la posizione alla fine del file prima di effettuare
+la scrittura, e poi estende il file. Tutto questo avviene all'interno di una
+singola system call (la \func{write}) che non essendo interrompibile da un
+altro processo costituisce una operazione atomica.
+
+Un altro caso tipico in cui è necessaria l'atomicità è quello in cui si vuole
+creare un file di lock, bloccandosi se il file esiste. In questo caso la
+sequenza logica porterebbe a verificare prima l'esistenza del file con una
+\func{stat} per poi crearlo con una \func{creat}; di nuovo avremmo la
+possibilità di una race condition da parte di un altro processo che crea lo
+stesso file fra il controllo e la creazione. 
+
+Per questo motivo sono stati introdotti i due flag \macro{O\_CREAT} e
+\macro{O\_EXCL}, in questo modo l'operazione di controllo dell'esistenza del
+file (con relativa uscita dalla funzione con un errore) e creazione in caso di
+assenza, diventa atomica essendo svolta tutta all'interno di una singola
+\func{open}.
+
+
+\subsection{La funzioni \func{sync} e \func{fsync}}
+\label{sec:file_sync}
+
+Come accennato in \secref{sec:file_close} tutte le operazioni di scrittura
+sono in genere bufferizzate dal kernel, che provvede ad effettuarle in maniera
+asincrona (ad esempio accorpando gli accessi alla stessa zona del disco) in un
+secondo tempo rispetto al momento della esecuzione della \func{write}.
+
+Per questo motivo, quando è necessaria una sincronizzazione dei dati, il
+sistema mette a disposizione delle funzioni che provvedono a forzare lo
+scarico dei dati dai buffer del kernel\footnote{come già accennato neanche
+  questo da la garanzia assoluta che i dati siano integri dopo la chiamata,
+  l'hardware dei dischi è in genere dotato di un suo meccanismo interno che
+  può ritardare ulteriormente la scrittura effettiva.}. La prima di queste
+funzioni è \func{sync} il cui prototipo è:
+\begin{prototype}{unistd.h}{int sync(void)}
+  
+  La funzione sincronizza buffer della cache dei file col disco.
+  
+  La funzione ritorna sempre zero.
+\end{prototype}
+\noindent  i vari standard prevedono che la funzione si limiti a far partire
+le operazioni, ritornando immediatamente; in Linux (dal kernel 1.3.20) invece
+la funzione aspetta la conclusione delle operazioni di sincronizzazione del
+kernel.
+
+La funzione viene usata dal comando \cmd{sync} quando si vuole forzare
+esplicitamente lo scarico dei dati su disco, o dal demone di sistema
+\cmd{update} che esegue lo scarico dei dati ad intervalli di tempo fissi: il
+valore tradizionale per l'update dei dati è ogni 30 secondi, ma in Linux era
+di 5 secondi; con le nuove versioni poi, è il kernel che si occupa
+direttamente di tutto quanto.
+
+Quando si vogliono scaricare soltanto i dati di un file (ad esempio essere
+sicuri che i dati di un database sono stati registrati su disco) si possono
+usare le due funzioni \func{fsync} e \func{fdatasync}, i cui prototipi sono:
+\begin{functions}
+  \headdecl{unistd.h}
+  \funcdecl{int fsync(int fd)}
+  Sincronizza dati e metadati del file \param{fd}
+  \funcdecl{int fdatasync(int fd)}
+  Sincronizza i dati del file \param{fd}.
+  
+  La funzione ritorna 0 in caso di successo e -1 in caso di errore, nel qual
+  caso i codici restituiti in \var{errno} sono:
+  \begin{errlist}
+  \item \macro{EINVAL} \param{fd} è un file speciale che non supporta la
+    sincronizzazione.
+  \end{errlist}
+  ed inoltre \macro{EBADF}, \macro{EROFS} e \macro{EIO}.
+\end{functions}
 
+Entrambe le funzioni forzano la sincronizzazione col disco di tutti i dati del
+file specificato, ed attendono fino alla conclusione delle operazioni;
+\func{fsync} forza anche la sincronizzazione dei metadata dell'inode (i dati
+di \var{fstat} come i tempi del file). 
 
 
+Si tenga presente che questo non comporta la sincronizzazione della
+directory che contiene il file (e scrittura della relativa voce su
+disco) che deve essere effettuata esplicitamente\footnote{in realtà per
+  il filesystem \acr{ext2}, quando lo si monta con l'opzione \cmd{sync},
+  il kernel provvede anche alla sincronizzazione automatica delle voci
+  delle directory.}.
+
 
 \subsection{La funzioni \func{dup} e \func{dup2}}
 \label{sec:file_dup}
 
+Abbiamo già visto in \secref{sec:file_sharing} come un processo figlio
+condivida gli stessi file descriptor del padre; è possibile però ottenere un
+comportamento analogo all'interno di uno stesso processo \textit{duplicando}
+un file descriptor. Per far questo si usa la funzione \func{dup} il cui
+prototipo è:
+\begin{prototype}{unistd.h}{int dup(int oldfd)}
+  
+  La funzione crea una copia del file descriptor \param{oldfd}.
+  
+  La funzione ritorna il nuovo file descriptor in caso di successo e -1 in
+  caso di errore, nel qual caso \var{errno} viene settata ad uno dei valori:
+  \begin{errlist}
+  \item \macro{EBADF} \param{oldfd} non è un file aperto.
+  \item \macro{EMFILE} si è raggiunto il numero massimo consentito di file
+    descriptor aperti.
+  \end{errlist}
+\end{prototype}
 
+La funzione ritorna, come \func{open}, il primo file descriptor libero. Il
+file descriptor è una copia esatta del precedente ed entrambi possono essere
+interscambiati nell'uso. Per capire meglio il funzionamento della funzione si
+può fare riferimento a \figref{fig:file_dup}: l'effetto della funzione è
+semplicemente quello di copiare il valore nella struttura \var{file\_struct},
+cosicché anche il nuovo file descriptor fa riferimento alla stessa voce
+nella \textit{file table}.
 
 \begin{figure}[htb]
-  \centering \includegraphics[width=14cm]{img/filedup.eps}
+  \centering \includegraphics[width=14cm]{img/filedup}
   \caption{Schema dell'accesso ai file duplicati}
   \label{fig:file_dup}
 \end{figure}
 
+In questo modo entrambi i file condivideranno eventuali lock, \textit{file
+  status flag}, e posizione corrente: se ad esempio \func{lseek} modifica la
+posizione su uno dei due file descriptor essa sarà modificata anche sull'altro
+(al solito viene modificato lo stesso campo nella voce della \textit{file
+  table} a cui entrambi fanno riferimento).
+
+L'unica differenza fra i due file descriptor è che ciascuno avrà il suo
+\textit{file descriptor flag}; nel caso di \func{dup} il flag di \textit{close
+  on exec} viene sempre cancellato nella copia.  
+
+Una diversa versione della funzione, \func{dup2} viene utilizzata per
+specificare esplicitamente il nuovo file descriptor; il suo prototipo è:
+\begin{prototype}{unistd.h}{int dup2(int oldfd, int newfd)}
+  
+  La funzione rende \param{newfd} una copia del file descriptor \param{oldfd}.
+  
+  La funzione ritorna il nuovo file descriptor in caso di successo e -1 in
+  caso di errore, nel qual caso \var{errno} viene settata ad uno dei valori:
+  \begin{errlist}
+  \item \macro{EBADF} \param{oldfd} non è un file aperto o \param{newfd} ha un
+    valore fuori dall'intervallo consentito per i file descriptor.
+  \item \macro{EMFILE} si è raggiunto il numero massimo consentito di file
+    descriptor aperti.
+  \end{errlist}
+\end{prototype}
+\noindent la funzione chiude il file descriptor \param{newfd} se è aperto.
+
+La duplicazione dei file descriptor può essere effettuata anche usando la
+funzione di controllo dei file \func{fnctl} (che esamineremo in
+\secref{sec:file_fcntl}) con il parametro \macro{F\_DUPFD}. 
+
+L'operazione ha la sintassi \func{fnctl(oldfd, F\_DUPFD, newfd)} e se si usa 0
+come valore per \param{newfd} diventa equivalente a \func{dup}. La sola
+differenza, a parte i codici di errore, è che \func{dup2} chiude il nuovo file
+se è già aperto mentre \func{fcntl} apre il primo disponibile con un valore
+superiore, per cui per poterla usare come \func{dup2} occorrerebbe prima
+effettuare una \func{close}, perdendo l'atomicità dell'operazione.
+
+L'uso principale di queste funzioni è per la redirezione dell'input e
+dell'output fra l'esecuzione di una \func{fork} e la successiva \func{exec};
+diventa così possibile associare un file (o una pipe) allo standard input o
+allo standard output, torneremo su questo uso più avanti quando tratteremo le
+pipe.
+
 
 \subsection{La funzione \func{fcntl}}
 \label{sec:file_fcntl}
 
+Oltre alle operazioni base esaminate in \secref{sec:file_base_func} esistono
+tutta una serie di operazioni ausiliarie che è possibile eseguire su un file
+descriptor. Per queste operazioni di manipolazione delle varie proprietà di un
+file descriptor viene usata la funzione \func{fcntl} il cui prototipo è:
+\begin{functions}
+  \headdecl{unistd.h}
+  \headdecl{fcntl.h}
+  \funcdecl{int fcntl(int fd, int cmd)}
+  \funcdecl{int fcntl(int fd, int cmd, long arg)}
+  \funcdecl{int fcntl(int fd, int cmd, struct flock * lock)}
+  La funzione esegue una delle possibili operazioni specificate da \param{cmd}
+  sul file \param{fd}.
+  
+  La funzione ha valori di ritorno diversi a seconda dell'operazione. In caso
+  di errore il valore di ritorno è -1 e la variabile \var{errno} viene settata
+  ad un opportuno codice, quelli validi in generale sono:
+  \begin{errlist}
+  \item \macro{EBADF} \param{oldfd} non è un file aperto.
+  \end{errlist}
+\end{functions}
+
+Il comportamento di questa funzione è determinato dal valore del comando
+\param{cmd} che le viene fornito; in \secref{sec:file_dup} abbiamo incontrato
+un esempio per la duplicazione dei file descriptor, una lista dei possibili
+valori è riportata di seguito:
+\begin{basedescript}{\desclabelwidth{2.0cm}}
+\item[\macro{F\_DUPFD}] trova il primo file descriptor disponibile di valore
+  maggiore o uguale ad \param{arg} e ne fa una copia di \var{fd}. In caso di
+  successo ritorna il nuovo file descriptor. Gli errori possibili sono
+  \macro{EINVAL} se \param{arg} è negativo o maggiore del massimo consentito o
+  \macro{EMFILE} se il processo ha già raggiunto il massimo numero di
+  descrittori consentito.
+\item[\macro{F\_SETFD}] setta il valore del \textit{file descriptor flag}
+  al valore specificato con \param{arg}. Al momento l'unico bit usato è
+  quello di \textit{close on exec}, identificato dalla costante
+  \macro{FD\_CLOEXEC}.
+\item[\macro{F\_GETFD}] ritorna il valore del \textit{file descriptor flag} di
+  \var{fd}, se \macro{FD\_CLOEXEC} è settato i file descriptor aperti vengono
+  chiusi attraverso una \func{exec} altrimenti (il default) restano aperti.
+\item[\macro{F\_GETFL}] ritorna il valore del \textit{file status flag},
+  permette cioè di rileggere quei bit settati da \func{open} all'apertura del
+  file che vengono memorizzati (quelli riportati nella prima e terza sezione
+  di \tabref{tab:file_open_flags}). 
+\item[\macro{F\_SETFL}] setta il \textit{file status flag} al valore
+  specificato da \param{arg}, possono essere settati solo i bit riportati
+  nella terza sezione di \tabref{tab:file_open_flags} (da verificare).
+\item[\macro{F\_GETLK}] se un file lock è attivo restituisce nella struttura
+  \param{lock} la struttura \type{flock} che impedisce l'acquisizione del
+  blocco, altrimenti setta il campo \var{l\_type} a \macro{F\_UNLCK} (per i
+  dettagli sul \textit{file locking} vedi \secref{sec:file_locking}).
+\item[\macro{F\_SETLK}] richiede il file lock specificato da \param{lock} se
+  \var{l\_type} è \macro{F\_RDLCK} o \macro{F\_WRLLCK} o lo rilascia se
+  \var{l\_type} è \macro{F\_UNLCK}. Se il lock è tenuto da qualcun'altro
+  ritorna immediatamente restituendo -1 e setta \var{errno} a \macro{EACCES} o
+  \macro{EAGAIN} (per i dettagli sul \textit{file locking} vedi
+  \secref{sec:file_locking}).
+\item[\macro{F\_SETLKW}] identica a \macro{F\_SETLK} eccetto per il fatto che
+  la funzione non ritorna subito ma attende che il blocco sia rilasciato. Se
+  l'attesa viene interrotta da un segnale la funzione restituisce -1 e setta
+  \var{errno} a \macro{EINTR} (per i dettagli sul \textit{file locking} vedi
+  \secref{sec:file_locking}).
+\item[\macro{F\_GETOWN}] restituisce il \acr{pid} del processo o il process
+  group che è preposto alla ricezione dei segnali \macro{SIGIO} e
+  \macro{SIGURG} per gli eventi associati al file descriptor \var{fd}. Il
+  process group è restituito come valore negativo.
+\item[\macro{F\_SETOWN}] setta il processo o process group che riceverà i
+  segnali \macro{SIGIO} e \macro{SIGURG} per gli eventi associati al file
+  descriptor \var{fd}.  I process group sono settati usando valori negativi.
+\item[\macro{F\_GETSIG}] restituisce il segnale mandato quando ci sono dati
+  disponibili in input sul file descriptor. Il valore 0 indica il default (che
+  è \macro{SIGIO}), un valore diverso da zero indica il segnale richiesto,
+  (che può essere lo stesso \macro{SIGIO}), nel qual caso al manipolatore del
+  segnale, se installato con \macro{SA\_SIGINFO}, vengono rese disponibili
+  informazioni ulteriori informazioni.
+\item[\macro{F\_SETSIG}] setta il segnale da inviare quando diventa possibile
+  effettuare I/O sul file descriptor. Il valore zero indica il default
+  (\macro{SIGIO}), ogni altro valore permette di rendere disponibile al
+  manipolatore del segnale ulteriori informazioni se si è usata
+  \macro{SA\_SIGINFO}.
+\end{basedescript}
+
+La maggior parte delle funzionalità di \func{fcntl} sono troppo avanzate per
+poter essere affrontate in dettaglio a questo punto; saranno riprese più
+avanti quando affronteremo le problematiche ad esse relative.
+
+Per determinare le modalità di accesso inoltre è necessario estrarre i bit di
+accesso (ottenuti con il comando \macro{F\_GETFL}); infatti la definizione
+corrente non assegna bit separati a \macro{O\_RDONLY}, \macro{O\_WRONLY} e
+\macro{O\_RDWR}\footnote{posti rispettivamente ai valori 0, 1 e 2}, per cui il
+valore si ottiene eseguendo un AND binario del valore di ritorno di
+\func{fcntl} con la maschera \macro{O\_ACCMODE} anch'essa definita in
+\file{fcntl.h}.
+
+
+
 \subsection{La funzione \func{ioctl}}
 \label{sec:file_ioctl}
 
+Benché il concetto di \textit{everything is a file} si sia dimostratato molto
+valido anche per l'interazione con i più vari dispositivi, con cui si può
+interagire con le stesse funzioni usate per i normali file di dati,
+esisteranno sempre caratteristiche peculiari, specifiche dell'hardware e della
+funzionalità che ciascuno di essi provvede, che non possono venire comprese in
+questa interfaccia astratta (un caso tipico è il settaggio della velocità di
+una porta seriale, o le dimensioni di un framebuffer).
+
+Per questo motivo l'architettura del sistema ha previsto l'esistenza di una
+funzione speciale, \func{ioctl}, con cui poter compiere operazioni specifiche
+per ogni singolo dispositivo.  Il prototipo di questa funzione è:
+
+\begin{prototype}{sys/ioctl.h}{int ioctl(int fd, int request, ...)}
+  
+  La funzione manipola il sottostante dispositivo, usando il parametro
+  \param{request} per specificare l'operazione richiesta e il terzo parametro
+  (che usualmente è di tipo \param{char * argp}) per passare o ricevere
+  l'informazione necessaria al dispositivo.
+  
+  La funzione nella maggior parte dei casi ritorna 0, alcune operazioni usano
+  però il valore di ritorno per restituire informazioni. In caso di errore
+  viene sempre restituito -1 e \var{errno} viene settata ad uno dei valori
+  seguenti:
+  \begin{errlist}
+  \item \macro{ENOTTY} il file \param{fd} non è associato con un device.
+  \item \macro{EINVAL} gli argomenti \param{request} o \param{argp} non sono
+    validi.
+  \end{errlist}
+  ed inoltre \macro{EBADF} e \macro{EFAULT}.
+\end{prototype}
+
+La funzione serve in sostanza per fare tutte quelle operazioni che non si
+adattano all'architettura di I/O di unix e che non è possibile effettuare con
+le funzioni esaminate finora. Per questo motivo non è possibile fare altro che
+una descrizione generica; torneremo ad esaminarla in seguito, quando si
+tratterà di applicarla ad alcune problematiche specifiche.
+