In questa sezione faremo una breve introduzione sulla architettura su cui è
basata dell'interfaccia dei \textit{file descriptor}, che, sia pure con
-differenze di implementazione, è comune ad ogni implementazione di unix.
+differenze nella realizzazione pratica, resta sostanzialmente la stessa in
+ogni implementazione di unix.
\subsection{L'architettura dei \textit{file descriptor}}
La funzione ritorna il file descriptor in caso di successo e -1 in caso di
errore. In questo caso la variabile \var{errno} viene settata ad uno dei
valori:
-
\begin{errlist}
\item \macro{EEXIST} \var{pathname} esiste e si è specificato
\macro{O\_CREAT} e \macro{O\_EXCL}.
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
-restare aperto attraverso una \func{exec} (come accennato in
-\secref{sec:proc_exec}) ed l'offset è settato all'inizio del file.
-Il parametro \var{mode} specifica i permessi con cui il file viene
-eventualmente creato; i valori possibili sono gli stessi già visti in
-\secref{sec:file_perm_overview} e possono essere specificati come OR binario
-delle costanti descritte in \tabref{tab:file_bit_perm}. Questi permessi
-filtrati dal valore di \file{umask} (vedi \secref{sec:file_umask}) per il
-processo.
-
-La funzione prevede diverse opzioni, che vengono specificate usando vari bit
-del parametro \var{flags}. Alcuni di questi bit vanno anche a costituire il
-flag di stato del file (o \textit{file status flag}), che è mantenuto nel
-campo \var{f\_flags} della struttura \var{file} (al solito si veda lo schema
-di \curfig). Essi sono divisi in tre categorie principali:
-\begin{itemize}
-\item \textsl{i bit delle modalità di accesso}: specificano con quale modalità
- si accederà al file: i valori possibili sono lettura, scrittura o
- lettura/scrittura. Uno di questi bit deve essere sempre specificato quando
- si apre un file. Vengono settati alla chiamata da \func{open}, e possono
- essere riletti con una \func{fcntl} (fanno parte del \textit{file status
- flag}), ma non modificati.
-\item \textsl{i bit delle modalità di apertura}: permettono di specificare
- alcune delle caratteristiche del comportamento di \func{open} quando viene
- eseguita. Hanno effetto solo al momento della chiamata della funzione e non
- sono memorizzati nè possono essere riletti.
-\item \textsl{i bit delle modalità di operazione}: permettono di specificare
- alcune caratteristiche del comportamento delle future operazioni sul file
- (come la \func{read} o la \func{write}). Anch'essi fanno parte del
- \textit{file status flag}. Il loro valore è settato alla chiamata di
- \func{open}, ma possono essere riletti e modificati (insieme alle
- caratteristiche operative che controllano) con una \func{fcntl}.
-\end{itemize}
-
-In \ntab\ si sono riportate, ordinate e divise fra loro secondo le tre
-modalità appena elencate, le costanti mnemoniche associate a 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.
-
-\begin{table}[!htbp]
+\begin{table}[!htb]
\centering
\footnotesize
\begin{tabular}[c]{|l|p{12cm}|}
\label{tab:file_open_flags}
\end{table}
+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
+restare aperto attraverso una \func{exec} (come accennato in
+\secref{sec:proc_exec}) ed l'offset è settato all'inizio del file.
+
+Il parametro \var{mode} specifica i permessi con cui il file viene
+eventualmente creato; i valori possibili sono gli stessi già visti in
+\secref{sec:file_perm_overview} e possono essere specificati come OR binario
+delle costanti descritte in \tabref{tab:file_bit_perm}. Questi permessi
+filtrati dal valore di \file{umask} (vedi \secref{sec:file_umask}) per il
+processo.
+
+La funzione prevede diverse opzioni, che vengono specificate usando vari bit
+del parametro \var{flags}. Alcuni di questi bit vanno anche a costituire il
+flag di stato del file (o \textit{file status flag}), che è mantenuto nel
+campo \var{f\_flags} della struttura \var{file} (al solito si veda lo schema
+di \curfig). Essi sono divisi in tre categorie principali:
+\begin{itemize}
+\item \textsl{i bit delle modalità di accesso}: specificano con quale modalità
+ si accederà al file: i valori possibili sono lettura, scrittura o
+ lettura/scrittura. Uno di questi bit deve essere sempre specificato quando
+ si apre un file. Vengono settati alla chiamata da \func{open}, e possono
+ essere riletti con una \func{fcntl} (fanno parte del \textit{file status
+ flag}), ma non modificati.
+\item \textsl{i bit delle modalità di apertura}: permettono di specificare
+ alcune delle caratteristiche del comportamento di \func{open} quando viene
+ eseguita. Hanno effetto solo al momento della chiamata della funzione e non
+ sono memorizzati nè possono essere riletti.
+\item \textsl{i bit delle modalità di operazione}: permettono di specificare
+ alcune caratteristiche del comportamento delle future operazioni sul file
+ (come la \func{read} o la \func{write}). Anch'essi fanno parte del
+ \textit{file status flag}. Il loro valore è settato alla chiamata di
+ \func{open}, ma possono essere riletti e modificati (insieme alle
+ caratteristiche operative che controllano) con una \func{fcntl}.
+\end{itemize}
+
+In \tabref{tab:file_open_flags} si sono riportate, ordinate e divise fra loro
+secondo le tre modalità appena elencate, le costanti mnemoniche associate a
+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.
+
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
creare un nuovo file c'era una system call apposita, \func{creat}, il cui
adesso questa funzione resta solo per compatibilità con i vecchi programmi.
+\subsection{La funzione \func{close}}
+\label{sec:file_close}
+La funzione \func{close} permette di chiudere un file, in questo modo il file
+descriptor ritorna disponibile; il suo prototipo è:
+\begin{prototype}{unistd.h}{int close(int fd)}
+ Chiude il descrittore \var{fd}.
+
+ La funzione ritorna 0 in caso di successo e -1 n caso di errore. In questo
+ caso \var{errno} è settata ai valori:
+ \begin{errlist}
+ \item \macro{EBADF} \var{fd} non è un descrittore valido.
+ \item \macro{EINTR} la funzione è stata interrotta da un segnale.
+ \end{errlist}
+ ed \macro{EIO}.
+\end{prototype}
+La chiusura di un file rilascia ogni blocco (il \textit{file locking} è
+trattato in \secref{sec:file_locking}) che il processo poteva avere acquisito
+su di esso; se \var{fd} è ultimo (di eventuali copie) riferimento ad un file
+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
+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
+implementano la tecnica del \textit{write-behind}, per cui una \func{write}
+può avere successo anche se i dati non sono stati scritti, un eventuale errore
+di I/O allora può sfuggire, ma verrà riportato alla chiusura del file: per
+questo motivo non effettuare il controllo può portare ad una perdita di dati
+inavvertita; in Linux questo comportamento è stato osservato con NFS e le
+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).
-\subsection{La funzione \func{close}}
-\label{sec:file_close}
\subsection{La funzione \func{lseek}}
\label{sec:file_lseek}
+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
+lettura e scrittura avvengono a partire da questa posizione che viene
+automaticamente spostata in avanti del numero di byte letti o scritti.
+
+In genere (a meno di non avere richiesto la modalità \macro{O\_APPEND}) questa
+posizione viene settata a zero all'apertura del file. È possibile settarla ad
+un valore qualsiasi con la funzione \func{lseek}, il cui prototipo è:
+\begin{functions}
+ \headdecl{sys/types.h}
+ \headdecl{unistd.h}
+ \funcdecl{off\_t lseek(int fd, off\_t offset, int whence)}
+ La funzione setta la posizione attuale nel file.
+
+ La funzione ritorna valore della posizione corrente 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{ESPIPE} \var{fd} è una pipe, un socket o una fifo.
+ \item \macro{EINVAL} \var{whence} non è un valore valido.
+ \end{errlist}
+ e \macro{EBADF}.
+\end{functions}
+
+La nuova posizione è settata usando il valore specificato da \var{offset},
+sommato al riferimento dato da \var{whence}; quest'ultimo può assumere i
+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
+ \var{offset} è la nuova posizione.
+\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
+ \var{offset} può essere negativo e positivo.
+\end{description}
+
+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
+successiva scrittura il file sarà esteso. La chiamata non causa nessuna
+attività di input/output, si limita a modificare la posizione corrente nel
+kernel (cioè \var{f\_pos} in \var{file}, vedi \figref{fig:file_proc_file}).
+
+Dato che la funzione ritorna la nuova posizione, usando il valore zero per
+\func{offset} si può riottenere la posizione corrente nel file chiamando la
+funzione con \func{lseek(fd, 0, SEEK\_CUR}.
+
+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}.
+
+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
+ 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.
+
+
\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 è:
+\begin{prototype}
+ \headdecl{unistd.h}
+ \funcdecl{ssize\_t read(int fd, void * buf, size\_t count)}
+
+ La funzione cerca di leggere \var{count} bytes 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 letto quasiasi 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}
+ ed inoltre \macro{EBADF}, \macro{EIO}, \macro{EISDIR}, \macro{EBADF},
+ \macro{EINVAL} e \macro{EFAULT}.
+\end{prototype}
+
+
\subsection{La funzione \func{write}}
\label{sec:file_write}