From 1add1cb54c1754ed030033b994a68c6678d7d275 Mon Sep 17 00:00:00 2001 From: Simone Piccardi Date: Sat, 4 Feb 2012 21:47:10 +0000 Subject: [PATCH] Risistemazione definizioni delle funzioni per I/O su file e riorganizzazione delle sezioni con risistemazioni dei riferimenti. --- fileadv.tex | 59 +- filedir.tex | 48 +- fileio.tex | 1993 ++++++++++++++++++++++++++++---------------------- ipc.tex | 19 +- process.tex | 2 +- session.tex | 25 +- sockctrl.tex | 12 +- system.tex | 4 +- tcpsock.tex | 28 +- 9 files changed, 1218 insertions(+), 972 deletions(-) diff --git a/fileadv.tex b/fileadv.tex index 240c058..1de6aeb 100644 --- a/fileadv.tex +++ b/fileadv.tex @@ -934,18 +934,18 @@ nel peggiore dei casi (quando la conclusione della operazione bloccata dipende da quanto si otterrebbe dal file descriptor ``\textsl{disponibile}'') si potrebbe addirittura arrivare ad un \itindex{deadlock} \textit{deadlock}. -Abbiamo già accennato in sez.~\ref{sec:file_open} che è possibile prevenire -questo tipo di comportamento delle funzioni di I/O aprendo un file in -\textsl{modalità non-bloccante}, attraverso l'uso del flag \const{O\_NONBLOCK} -nella chiamata di \func{open}. In questo caso le funzioni di input/output -eseguite sul file che si sarebbero bloccate, ritornano immediatamente, -restituendo l'errore \errcode{EAGAIN}. L'utilizzo di questa modalità di I/O -permette di risolvere il problema controllando a turno i vari file descriptor, -in un ciclo in cui si ripete l'accesso fintanto che esso non viene garantito. -Ovviamente questa tecnica, detta \itindex{polling} \textit{polling}, è -estremamente inefficiente: si tiene costantemente impiegata la CPU solo per -eseguire in continuazione delle system call che nella gran parte dei casi -falliranno. +Abbiamo già accennato in sez.~\ref{sec:file_open_close} che è possibile +prevenire questo tipo di comportamento delle funzioni di I/O aprendo un file +in \textsl{modalità non-bloccante}, attraverso l'uso del flag +\const{O\_NONBLOCK} nella chiamata di \func{open}. In questo caso le funzioni +di input/output eseguite sul file che si sarebbero bloccate, ritornano +immediatamente, restituendo l'errore \errcode{EAGAIN}. L'utilizzo di questa +modalità di I/O permette di risolvere il problema controllando a turno i vari +file descriptor, in un ciclo in cui si ripete l'accesso fintanto che esso non +viene garantito. Ovviamente questa tecnica, detta \itindex{polling} +\textit{polling}, è estremamente inefficiente: si tiene costantemente +impiegata la CPU solo per eseguire in continuazione delle system call che +nella gran parte dei casi falliranno. Per superare questo problema è stato introdotto il concetto di \textit{I/O multiplexing}, una nuova modalità di operazioni che consente di tenere sotto @@ -1547,7 +1547,7 @@ maschera binaria in fase di creazione del file descriptor. Al momento l'unico valore legale per \param{flags} (a parte lo zero) è \const{EPOLL\_CLOEXEC}, che consente di impostare in maniera atomica sul file descriptor il flag di \itindex{close-on-exec} \textit{close-on-exec} (si veda il significato di -\const{O\_CLOEXEC} in sez.~\ref{sec:file_open}), senza che sia +\const{O\_CLOEXEC} in sez.~\ref{sec:file_open_close}), senza che sia necessaria una successiva chiamata a \func{fcntl}. Una volta ottenuto un file descriptor per \textit{epoll} il passo successivo è @@ -2478,19 +2478,19 @@ operazioni di I/O volute. \itindbeg{signal~driven~I/O} -Abbiamo accennato in sez.~\ref{sec:file_open} che è possibile, attraverso -l'uso del flag \const{O\_ASYNC},\footnote{l'uso del flag di \const{O\_ASYNC} e - dei comandi \const{F\_SETOWN} e \const{F\_GETOWN} per \func{fcntl} è - specifico di Linux e BSD.} aprire un file in modalità asincrona, così come è -possibile attivare in un secondo tempo questa modalità impostando questo flag -attraverso l'uso di \func{fcntl} con il comando \const{F\_SETFL} (vedi -sez.~\ref{sec:file_fcntl}). In realtà parlare di apertura in modalità -asincrona non significa che le operazioni di lettura o scrittura del file -vengono eseguite in modo asincrono (tratteremo questo, che è ciò che più +Abbiamo accennato in sez.~\ref{sec:file_open_close} che è definito un flag +\const{O\_ASYNC}, che consentirebbe di aprire un file in modalità asincrona, +anche se in realtà è opportuno attivare in un secondo tempo questa modalità +impostando questo flag attraverso l'uso di \func{fcntl} con il comando +\const{F\_SETFL} (vedi sez.~\ref{sec:file_fcntl}).\footnote{l'uso del flag di + \const{O\_ASYNC} e dei comandi \const{F\_SETOWN} e \const{F\_GETOWN} per + \func{fcntl} è specifico di Linux e BSD.} In realtà parlare di apertura in +modalità asincrona non significa che le operazioni di lettura o scrittura del +file vengono eseguite in modo asincrono (tratteremo questo, che è ciò che più propriamente viene chiamato \textsl{I/O asincrono}, in sez.~\ref{sec:file_asyncronous_io}), quanto dell'attivazione un meccanismo di notifica asincrona delle variazione dello stato del file descriptor aperto in -questo modo. +questo modo. Quello che succede è che per tutti i file posti in questa modalità\footnote{si tenga presente però che essa non è utilizzabile con i file ordinari ma solo @@ -3314,7 +3314,9 @@ raggruppati in un solo evento. \subsection{L'interfaccia POSIX per l'I/O asincrono} \label{sec:file_asyncronous_io} -% vedere anche http://davmac.org/davpage/linux/async-io.html +% vedere anche http://davmac.org/davpage/linux/async-io.html e +% http://www.ibm.com/developerworks/linux/library/l-async/ + Una modalità alternativa all'uso dell'\textit{I/O multiplexing} per gestione dell'I/O simultaneo su molti file è costituita dal cosiddetto \textsl{I/O @@ -3425,8 +3427,9 @@ richiesta, o in caso di errore. Non è detto che gli errori \errcode{EBADF} ed potrebbero anche emergere nelle fasi successive delle operazioni. Lettura e scrittura avvengono alla posizione indicata da \var{aio\_offset}, a meno che il file non sia stato aperto in \itindex{append~mode} \textit{append mode} -(vedi sez.~\ref{sec:file_open}), nel qual caso le scritture vengono effettuate -comunque alla fine de file, nell'ordine delle chiamate a \func{aio\_write}. +(vedi sez.~\ref{sec:file_open_close}), nel qual caso le scritture vengono +effettuate comunque alla fine de file, nell'ordine delle chiamate a +\func{aio\_write}. Si tenga inoltre presente che deallocare la memoria indirizzata da \param{aiocbp} o modificarne i valori prima della conclusione di una @@ -5408,10 +5411,6 @@ livello di kernel. % vedi http://lwn.net/Articles/226710/ e http://lwn.net/Articles/240571/ % http://kernelnewbies.org/Linux_2_6_23 - - - - % TODO non so dove trattarli, ma dal 2.6.39 ci sono i file handle, vedi % http://lwn.net/Articles/432757/ diff --git a/filedir.tex b/filedir.tex index 0bae59c..7720071 100644 --- a/filedir.tex +++ b/filedir.tex @@ -213,7 +213,7 @@ tab.~\ref{tab:file_inode_operations} le più rilevanti. \hline \hline \textsl{\code{create}} & Chiamata per creare un nuovo file (vedi - sez.~\ref{sec:file_open}).\\ + sez.~\ref{sec:file_open_close}).\\ \textsl{\code{link}} & Crea un \textit{hard link} (vedi sez.~\ref{sec:link_symlink_rename}).\\ \textsl{\code{unlink}} & Cancella un \textit{hard link} (vedi @@ -304,7 +304,8 @@ tab.~\ref{tab:file_file_operations} le più significative. \textbf{Funzione} & \textbf{Operazione} \\ \hline \hline - \textsl{\code{open}} & Apre il file (vedi sez.~\ref{sec:file_open}).\\ + \textsl{\code{open}} & Apre il file (vedi + sez.~\ref{sec:file_open_close}).\\ \textsl{\code{read}} & Legge dal file (vedi sez.~\ref{sec:file_read}).\\ \textsl{\code{write}} & Scrive sul file (vedi sez.~\ref{sec:file_write}).\\ @@ -1031,7 +1032,7 @@ nell'elenco seguente: \item[\const{MS\_SYNCHRONOUS}] Abilita la scrittura sincrona richiedendo che ogni modifica al contenuto del filesystem venga immediatamente registrata su disco. Lo stesso comportamento può essere ottenuto con il flag - \const{O\_SYNC} di \func{open} (vedi sez.~\ref{sec:file_open}). + \const{O\_SYNC} di \func{open} (vedi sez.~\ref{sec:file_open_close}). Questa opzione consente di ridurre al minimo il rischio di perdita dei dati in caso di crollo improvviso del sistema, al costo di una pesante perdita di @@ -1546,8 +1547,8 @@ Si noti che non si è specificato il comportamento delle funzioni che operano con i file descriptor (che tratteremo nel prossimo capitolo), in quanto la risoluzione del collegamento simbolico viene in genere effettuata dalla funzione che restituisce il file descriptor (normalmente la \func{open}, vedi -sez.~\ref{sec:file_open}) e tutte le operazioni seguenti fanno riferimento -solo a quest'ultimo. +sez.~\ref{sec:file_open_close}) e tutte le operazioni seguenti fanno +riferimento solo a quest'ultimo. Dato che, come indicato in tab.~\ref{tab:file_symb_effect}, funzioni come la \func{open} seguono i collegamenti simbolici, occorrono funzioni apposite per @@ -1988,11 +1989,12 @@ 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 sez.~\ref{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 tab.~\ref{tab:file_file_operations}, il \itindex{Virtual~File~System} VFS -prevede una apposita funzione per la lettura delle directory. +in sez.~\ref{sec:file_open_close} 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 tab.~\ref{tab:file_file_operations}, il +\itindex{Virtual~File~System} VFS prevede una apposita funzione per la lettura +delle directory. \itindbeg{directory~stream} @@ -3012,8 +3014,8 @@ prototipo è: Come per \func{mktemp} anche in questo caso \param{template} non può essere una stringa costante. La funzione apre un file in lettura/scrittura con la funzione \func{open}, usando l'opzione \const{O\_EXCL} (si veda -sez.~\ref{sec:file_open}), in questo modo al ritorno della funzione si ha la -certezza di essere stati i creatori del file, i cui permessi (si veda +sez.~\ref{sec:file_open_close}), in questo modo al ritorno della funzione si +ha la certezza di essere stati i creatori del file, i cui permessi (si veda sez.~\ref{sec:file_perm_overview}) sono impostati al valore \code{0600} (lettura e scrittura solo per il proprietario).\footnote{questo è vero a partire dalla \acr{glibc} 2.0.7, le versioni precedenti della \acr{glibc} e @@ -3984,8 +3986,8 @@ crearlo o rinominarlo o cancellarlo invece occorrerà avere anche il permesso di scrittura per la directory. Avere il permesso di lettura per un file consente di aprirlo con le opzioni -(si veda quanto riportato in sez.~\ref{sec:file_open}) di sola lettura o di -lettura/scrittura e leggerne il contenuto. Avere il permesso di scrittura +(si veda quanto riportato in sez.~\ref{sec:file_open_close}) di sola lettura o +di lettura/scrittura e leggerne il contenuto. Avere il permesso di scrittura consente di aprire un file in sola scrittura o lettura/scrittura e modificarne il contenuto, lo stesso permesso è necessario per poter troncare il file o per aggiornare il suo tempo di ultima modifica al tempo corrente, ma non per @@ -4465,11 +4467,11 @@ un'eventuale modifica comporterà la perdita di questo privilegio. Le funzioni \func{chmod} e \func{fchmod} ci permettono di modificare i permessi di un file, resta però il problema di quali sono i permessi assegnati quando il file viene creato. Le funzioni dell'interfaccia nativa di Unix, come -vedremo in sez.~\ref{sec:file_open}, permettono di indicare esplicitamente i -permessi di creazione di un file, ma questo non è possibile per le funzioni -dell'interfaccia standard ANSI C che non prevede l'esistenza di utenti e -gruppi, ed inoltre il problema si pone anche per l'interfaccia nativa quando i -permessi non vengono indicati esplicitamente. +vedremo in sez.~\ref{sec:file_open_close}, permettono di indicare +esplicitamente i permessi di creazione di un file, ma questo non è possibile +per le funzioni dell'interfaccia standard ANSI C che non prevede l'esistenza +di utenti e gruppi, ed inoltre il problema si pone anche per l'interfaccia +nativa quando i permessi non vengono indicati esplicitamente. \itindbeg{umask} @@ -4517,8 +4519,8 @@ utenti non hanno motivi per modificarlo. \subsection{La gestione della titolarità dei file} \label{sec:file_ownership_management} -Vedremo in sez.~\ref{sec:file_open} con quali funzioni si possono creare nuovi -file, in tale occasione vedremo che è possibile specificare in sede di +Vedremo in sez.~\ref{sec:file_open_close} con quali funzioni si possono creare +nuovi file, in tale occasione vedremo che è possibile specificare in sede di creazione quali permessi applicare ad un file, però non si può indicare a quale utente e gruppo esso deve appartenere. Lo stesso problema si presenta per la creazione di nuove directory (procedimento descritto in @@ -5275,7 +5277,7 @@ file) tutti quelli non presenti in \const{ACL\_MASK}.\footnote{questo diverso Un secondo aspetto dell'incidenza delle ACL sul comportamento del sistema è quello relativo alla creazione di nuovi file,\footnote{o oggetti sul filesystem, il comportamento discusso vale per le funzioni \func{open} e - \func{creat} (vedi sez.~\ref{sec:file_open}), \func{mkdir} (vedi + \func{creat} (vedi sez.~\ref{sec:file_open_close}), \func{mkdir} (vedi sez.~\ref{sec:file_dir_creat_rem}), \func{mknod} e \func{mkfifo} (vedi sez.~\ref{sec:file_mknod}).} che come accennato può essere modificato dalla presenza di una \textit{Default ACL} sulla directory che andrà a contenerli. @@ -6995,7 +6997,7 @@ sez.~\ref{sec:file_xattr} e \ref{sec:file_ACL}), poter ignorare lo \itindex{sticky~bit} \textit{sticky bit} nella cancellazione dei file (vedi sez.~\ref{sec:file_special_perm}), la possibilità di impostare il flag di \const{O\_NOATIME} con \func{open} e \func{fcntl} (vedi -sez.~\ref{sec:file_open} e sez.~\ref{sec:file_fcntl}) senza restrizioni. +sez.~\ref{sec:file_open_close} e sez.~\ref{sec:file_fcntl}) senza restrizioni. Una seconda capacità che copre diverse operazioni, in questo caso riguardanti la rete, è \const{CAP\_NET\_ADMIN}, che consente di impostare le opzioni diff --git a/fileio.tex b/fileio.tex index 601d98b..481d210 100644 --- a/fileio.tex +++ b/fileio.tex @@ -51,13 +51,13 @@ chiamata l'interfaccia dei \textit{file descriptor}. Per poter accedere al contenuto di un file occorre creare un canale di comunicazione con il kernel che renda possibile operare su di esso. Questo si -fa aprendo il file con la funzione \func{open} (vedi sez.~\ref{sec:file_open}) -che provvederà a localizzare \itindex{inode} l'inode del file e inizializzare -i puntatori che rendono disponibili le funzioni che il -\itindex{Virtual~File~System} VFS mette a disposizione (quelle di -tab.~\ref{tab:file_file_operations}). Una volta terminate le operazioni, il -file dovrà essere chiuso, e questo chiuderà il canale di comunicazione -impedendo ogni ulteriore operazione. +fa aprendo il file con la funzione \func{open} (vedi +sez.~\ref{sec:file_open_close}) che provvederà a localizzare \itindex{inode} +l'\textit{inode} del file e inizializzare i puntatori che rendono disponibili +le funzioni che il \itindex{Virtual~File~System} VFS mette a disposizione +(quelle di tab.~\ref{tab:file_file_operations}). Una volta terminate le +operazioni, il file dovrà essere chiuso, e questo chiuderà il canale di +comunicazione impedendo ogni ulteriore operazione. All'interno di ogni processo i file aperti sono identificati da un numero intero non negativo, che viene chiamato \textit{file descriptor}. Quando un @@ -216,8 +216,8 @@ sez.~\ref{sec:sys_limits}). -\subsection{Apertura e creazione di un file} -\label{sec:file_open} +\subsection{Apertura, creazione e chiusura di un file} +\label{sec:file_open_close} La funzione di sistema \funcd{open} è la principale funzione dell'interfaccia di gestione dei file, quella che dato un \textit{pathname} consente di @@ -256,7 +256,7 @@ corrispondente,\footnote{è \func{open} che alloca \kstruct{file}, la inserisce \const{O\_CREAT}, o non esiste un suo componente. \item[\errcode{ENOTDIR}] si è specificato \const{O\_DIRECTORY} e \param{pathname} non è una directory. - \item[\errcode{ENXIO}] si sono impostati \const{O\_NOBLOCK} o + \item[\errcode{ENXIO}] si sono impostati \const{O\_NONBLOCK} o \const{O\_WRONLY} ed il file è una fifo che non viene letta da nessun processo o \param{pathname} è un file di dispositivo ma il dispositivo è assente. @@ -265,7 +265,7 @@ corrispondente,\footnote{è \func{open} che alloca \kstruct{file}, la inserisce \item[\errcode{ETXTBSY}] si è cercato di accedere in scrittura all'immagine di un programma in esecuzione. \item[\errcode{EWOULDBLOCK}] la funzione si sarebbe bloccata ma si è - richiesto \const{O\_NOBLOCK}. + richiesto \const{O\_NONBLOCK}. \end{errlist} ed inoltre \errval{EACCES}, \errval{EFAULT}, \errval{EMFILE}, \errval{ENAMETOOLONG}, \errval{ENFILE}, \errval{ENOMEM}, \errval{ENOSPC}, @@ -312,11 +312,16 @@ anche in fig.~\ref{fig:file_proc_file}). Ciascun flag viene identificato da una apposita costante, ed il valore di \param{flags} deve essere specificato come OR aritmetico di queste -costanti. I vari bit che si possono usare come componenti di \param{flags} -sono divisi in tre gruppi principali. Il primo gruppo è quello dei cosiddetti -flag delle \textsl{modalità di accesso} (o \textit{access mode flags}), che -specificano che tipo di accesso si effettuerà sul file, fra lettura, scrittura -e lettura/scrittura. Questa modalità deve essere indicata usando una delle +costanti. Inoltre per evitare problemi di compatibilità con funzionalità che +non sono previste o non ancora supportate in versioni meno recenti del kernel, +la \func{open} di Linux ignora i flag che non riconosce, pertanto +l'indicazione di un flag inesistente non provoca una condizione di errore. + +I vari bit che si possono usare come componenti di \param{flags} sono divisi +in tre gruppi principali. Il primo gruppo è quello dei cosiddetti flag delle +\textsl{modalità di accesso} (o \textit{access mode flags}), che specificano +che tipo di accesso si effettuerà sul file, fra lettura, scrittura e +lettura/scrittura. Questa modalità deve essere indicata usando una delle costanti di tab.~\ref{tab:open_access_mode_flag}. \begin{table}[htb] @@ -472,7 +477,7 @@ tab.~\ref{tab:file_file_times} vengono impostati al tempo corrente. Se invece si tronca il file con \const{O\_TRUNC} verranno impostati soltanto il \textit{modification time} e lo \textit{status change time}. -\begin{table}[htb] +\begin{table}[!htb] \centering \footnotesize \begin{tabular}[c]{|l|p{10 cm}|} @@ -496,7 +501,11 @@ si tronca il file con \const{O\_TRUNC} verranno impostati soltanto il tutte le volte che il file è pronto per le operazioni di lettura o scrittura. Questo flag si può usare solo terminali, pseudo-terminali e socket - e, a partire dal kernel 2.6, anche sulle fifo.\\ + e, a partire dal kernel 2.6, anche sulle fifo. Per + un bug dell'implementazione non è opportuno usarlo + in fase di apertura del file, deve + invece essere attivato successivamente con + \func{fcntl}.\\ \const{O\_CLOEXEC}& Attiva la modalità di \itindex{close-on-exec} \textit{close-on-exec} (vedi sez.~\ref{sec:proc_exec}) sul file. Il flag è @@ -517,7 +526,10 @@ si tronca il file con \const{O\_TRUNC} verranno impostati soltanto il file (vedi sez.~\ref{sec:file_file_times}). Per molti filesystem questa funzionalità non è disponibile per il singolo file ma come opzione - generale da specificare in fase di montaggio.\\ + generale da specificare in fase di + montaggio. Introdotto con il kernel 2.6.8 ed + utilizzabile soltanto se si è definita la + macro \macro{\_GNU\_SOURCE}.\\ \const{O\_NONBLOCK}& Apre il file in \textsl{modalità non bloccante} per le operazioni di I/O (vedi sez.~\ref{sec:file_noblocking}). Questo significa @@ -563,9 +575,21 @@ mantenuto per ogni singolo file descriptor, vengono salvati nel campo \var{f\_flags} della struttura \kstruct{file} insieme al valore della \textsl{modalità di accesso} andando far parte dei cosiddetti \textit{file status flags}. Il loro valore viene impostato alla chiamata di \func{open}, -ma possono essere riletti ed in alcuni di essi anche modificati, con -conseguente effetto sulle caratteristiche operative che controllano, con -\func{fcntl} (vedi sez.~\ref{sec:file_fcntl}). +ma possono venire riletti in un secondo tempo con \func{fcntl}, inoltre alcuni +di essi possono anche essere modificati tramite questa funzione, con +conseguente effetto sulle caratteristiche operative che controllano (torneremo +sull'argomento in sez.~\ref{sec:file_fcntl}). + +Il flag \const{O\_ASYNC} (che, per per compatibilità con BSD, si può indicare +anche con la costante \const{FASYNC}) è definito come possibile valore per +\func{open}, ma per un bug dell'implementazione,\footnote{segnalato come + ancora presente nella pagina di manuale almeno fino al Settembre 2011.} non +solo non attiva il comportamento citato, ma se usato richiede di essere +esplicitamente disattivato prima di essere attivato in maniera effettiva con +l'uso di \func{fcntl}. Per questo motivo, non essendovi nessuna necessità +specifica di definirlo in fase di apertura del file, è sempre opportuno +attivarlo in un secondo tempo con \func{fcntl} (vedi +sez.~\ref{sec:file_fcntl}). Il flag \const{O\_DIRECT} non è previsto da nessuno standard, anche se è presente in alcuni kernel unix-like.\footnote{il flag è stato introdotto dalla @@ -574,8 +598,9 @@ presente in alcuni kernel unix-like.\footnote{il flag è stato introdotto dalla \textit{user space} da cui si effettua il trasferimento diretto dei dati siano allineati alle dimensioni dei blocchi del filesystem. Con il kernel 2.6 in genere basta che siano allineati a multipli di 512 byte, ma le restrizioni -possono variare a seconda del filesystem, ed inoltre su alcuni filesystem può -non essere supportato, nel qual caso si avrà un errore di \errval{EINVAL}. +possono variare a seconda del filesystem, ed inoltre su alcuni filesystem +questo flag può non essere supportato, nel qual caso si avrà un errore di +\errval{EINVAL}. Lo scopo di \const{O\_DIRECT} è consentire un completo controllo sulla bufferizzazione dei propri dati per quelle applicazioni (in genere database) @@ -588,28 +613,30 @@ ordinario, in quante le esigenze di mantenere coerenti i dati porterebbero ad un peggioramento delle prestazioni. Lo stesso dicasi per l'interazione con eventuale mappatura in memoria del file (vedi sez.~\ref{sec:file_memory_map}). -Si tenga presente infine che anche se l'uso di \const{O\_DIRECT} comporta -sostanzialmente solo una scrittura sincrona dei dati dei buffer in -\textit{user space}, questo non è completamente equivalente all'uso di -\const{O\_SYNC} che garantisce anche sulla scrittura sincrona dei metadati -associati alla scrittura dei dati del file. Per questo in genere è opportuno -se si usa \const{O\_DIRECT} è opportuno richiedere anche \const{O\_SYNC}. +Si tenga presente infine che anche se l'uso di \const{O\_DIRECT} comporta una +scrittura sincrona dei dati dei buffer in \textit{user space}, questo non è +completamente equivalente all'uso di \const{O\_SYNC} che garantisce anche +sulla scrittura sincrona dei metadati associati alla scrittura dei dati del +file.\footnote{la situazione si complica ulteriormente per NFS, in cui l'uso + del flag disabilita la bufferizzazione solo dal lato del client, e può + causare problemi di prestazioni.} Per questo in genere è opportuno se si usa +\const{O\_DIRECT} è opportuno richiedere anche \const{O\_SYNC}. Si tenga presente infine che la implementazione di \const{O\_SYNC} di Linux differisce da quanto previsto dallo standard POSIX.1 che prevede, oltre a questo flag che dovrebbe indicare la sincronizzazione completa di tutti i dati -e di tutti i metadati, altri due flag \const{O\_DSYNC} e \const{O\_RSYNC}. Il -primo dei due richiede la scrittura sincrona di tutti i dati del file e dei +e di tutti i metadati, altri due flag \const{O\_DSYNC} e \const{O\_RSYNC}. + +Il primo dei due richiede la scrittura sincrona di tutti i dati del file e dei metadati che ne consentono l'immediata rilettura, ma non di tutti i metadati, per evitare la perdita di prestazioni relativa alla sincronizzazione di -informazioni ausiliarie come i tempi dei file. - -Il secondo, da usare in combinazione con \const{O\_SYNC} o \const{O\_DSYNC} ne -sospende l'effetto, consentendo al kernel di bufferizzare le scritture, ma -soltanto finché non avviene una lettura, in quel caso i dati ed i metadati -dovranno essere sincronizzati immediatamente (secondo le modalità indicate da -\const{O\_SYNC} e \const{O\_DSYNC}) e la lettura verrà bloccata fintanto che -detta sincronizzazione non sia completata. +informazioni ausiliarie come i tempi dei file. Il secondo, da usare in +combinazione con \const{O\_SYNC} o \const{O\_DSYNC} ne sospende l'effetto, +consentendo al kernel di bufferizzare le scritture, ma soltanto finché non +avviene una lettura, in quel caso i dati ed i metadati dovranno essere +sincronizzati immediatamente (secondo le modalità indicate da \const{O\_SYNC} +e \const{O\_DSYNC}) e la lettura verrà bloccata fintanto che detta +sincronizzazione non sia completata. Nel caso di Linux, fino al kernel 2.6.33, esisteva solo \const{O\_SYNC}, ma con il comportamento previsto dallo standard per \const{O\_DSYNC}, e sia @@ -617,7 +644,11 @@ questo che \const{O\_RSYNC} erano definiti (fin dal kernel 2.1.130) come sinonimi di \const{O\_SYNC}. Con il kernel 2.6.33 il significato di \const{O\_SYNC} è diventato quello dello standard, ma gli è stato assegnato un valore diverso, mantenendo quello originario, con il comportamento -corrispondete, per \const{O\_DSYNC}. +corrispondete, per \const{O\_DSYNC} in modo che applicazioni compilate con +versioni precedenti delle librerie e del kernel non trovassero un +comportamento diverso. Inoltre il nuovo \const{O\_SYNC} è stato definito in +maniera opportuna in modo che su versioni del kernel precedenti la 2.6.33 +torni a corrispondere al valore di \const{O\_DSYNC}. % NOTE: per le differenze fra O_DSYNC, O_SYNC e O_RSYNC introdotte nella % nello sviluppo del kernel 2.6.33, vedi http://lwn.net/Articles/350219/ @@ -644,10 +675,6 @@ dall'argomento \param{mode}. È del tutto equivalente a \code{open(filedes, O\_CREAT|O\_WRONLY|O\_TRUNC, mode)} e resta solo per compatibilità con i vecchi programmi. - -\subsection{La funzione \func{close}} -\label{sec:file_close} - Una volta che l'accesso ad un file non sia più necessario la funzione di sistema \funcd{close} permette di ``\textsl{chiuderlo}'', in questo modo il file non sarà più accessibile ed il relativo file descriptor ritornerà @@ -668,9 +695,9 @@ disponibile; il suo prototipo è: ed inoltre \errval{EIO} nel suo significato generico.} \end{funcproto} -La funzione chiude il file descriptor \param{fd}, la chiusura rilascia ogni -blocco (il \textit{file locking} \itindex{file~locking} è trattato in -sez.~\ref{sec:file_locking}) che il processo poteva avere acquisito su di +La funzione chiude il file descriptor \param{fd}. La chiusura rilascia ogni +eventuale blocco (il \textit{file locking} \itindex{file~locking} è trattato +in sez.~\ref{sec:file_locking}) che il processo poteva avere acquisito su di esso. Se \param{fd} è l'ultimo riferimento (di eventuali copie, vedi sez.~\ref{sec:file_sharing} e \ref{sec:file_dup}) ad un file aperto, tutte le risorse nella \itindex{file~table} \textit{file table} vengono @@ -694,9 +721,10 @@ 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} (vedi sez.~\ref{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 che ritardano la scrittura dei dati, da cui l'abitudine -di ripetere tre volte il comando prima di eseguire lo shutdown). +comportamento dell'hardware, che a sua volta può introdurre ottimizzazioni +dell'accesso al disco che ritardano la scrittura dei dati. Da questo deriva +l'abitudine di alcuni sistemisti di ripetere tre volte il comando omonimo +prima di eseguire lo shutdown di una macchina. \subsection{La gestione della posizione nel file} @@ -712,13 +740,13 @@ viene automaticamente spostata in avanti del numero di byte letti o scritti. In genere, a meno di non avere richiesto la modalità \itindex{append~mode} di \textit{append} con \const{O\_APPEND}, questa posizione viene impostata a zero all'apertura del file. È possibile impostarla ad un valore qualsiasi con la -funzione si sistema \funcd{lseek}, il cui prototipo è: +funzione di sistema \funcd{lseek}, il cui prototipo è: \begin{funcproto}{ \fhead{sys/types.h} \fhead{unistd.h} \fdecl{off\_t lseek(int fd, off\_t offset, int whence)} -\fdesc{Imposta la posizione sul file..} +\fdesc{Imposta la posizione sul file.} } {La funzione ritorna il valore della posizione sul file in caso di successo e @@ -732,18 +760,23 @@ funzione si sistema \funcd{lseek}, il cui prototipo è: ed inoltre \errval{EBADF} nel suo significato generico.} \end{funcproto} -La funzione imposta la nuova posizione sul file usando il valore specificato +La funzione imposta la nuova posizione sul file usando il valore indicato da \param{offset}, che viene sommato al riferimento dato -dall'argomento \param{whence}. Quest'ultimo deve essere indicato con una delle -costanti riportate in tab.~\ref{tab:lseek_whence_values}.\footnote{per - compatibilità con alcune vecchie notazioni questi valori possono essere - rimpiazzati rispettivamente con 0, 1 e 2 o con \const{L\_SET}, - \const{L\_INCR} e \const{L\_XTND}.} +dall'argomento \param{whence}, che deve essere indicato con una delle costanti +riportate in tab.~\ref{tab:lseek_whence_values}.\footnote{per compatibilità + con alcune vecchie notazioni questi valori possono essere rimpiazzati + rispettivamente con 0, 1 e 2 o con \const{L\_SET}, \const{L\_INCR} e + \const{L\_XTND}.} Si tenga presente che la chiamata a \func{lseek} non causa +nessun accesso al file, si limita a modificare la posizione corrente (cioè il +campo \var{f\_pos} della struttura \kstruct{file}, vedi +fig.~\ref{fig:file_proc_file}). Dato che la funzione ritorna la nuova +posizione, usando il valore zero per \param{offset} si può riottenere la +posizione corrente nel file con \code{lseek(fd, 0, SEEK\_CUR)}. \begin{table}[htb] \centering \footnotesize - \begin{tabular}[c]{|l|p{8cm}|} + \begin{tabular}[c]{|l|p{10cm}|} \hline \textbf{Costante} & \textbf{Significato} \\ \hline @@ -762,15 +795,17 @@ costanti riportate in tab.~\ref{tab:lseek_whence_values}.\footnote{per \hline \const{SEEK\_DATA}& Sposta la posizione nel file sull'inizio del primo blocco di dati dopo un \textit{hole} che segue (o - coincide) con la posizione indicata da \param{offset}.\\ + coincide) con la posizione indicata da \param{offset} + (dal kernel 3.1).\\ \const{SEEK\_HOLE}& Sposta la posizione sul file all'inizio del primo \textit{hole} nel file che segue o inizia - con \param{offset}, oppure \param{offset} se questo è - all'interno di un \textit{hole} o alla fine del file - se non ci sono \textit{hole} dopo \param{offset}.\\ + con \param{offset}, oppure si porta su \param{offset} + se questo è all'interno di un \textit{hole}, oppure si + porta alla fine del file se non ci sono \textit{hole} + dopo \param{offset} (dal kernel 3.1).\\ \hline - \end{tabular} - \caption{Possibili valori per l'argomento \param{whence} di \func{lseek}.} + \end{tabular} \caption{Possibili valori per l'argomento \param{whence} di + \func{lseek}.} \label{tab:lseek_whence_values} \end{table} @@ -778,13 +813,6 @@ costanti riportate in tab.~\ref{tab:lseek_whence_values}.\footnote{per % NOTE: per SEEK_HOLE e SEEK_DATA, inclusi nel kernel 3.1, vedi % http://lwn.net/Articles/439623/ -Si tenga presente che la chiamata a \func{lseek} non causa nessun accesso al -file, si limita a modificare la posizione corrente (cioè il campo \var{f\_pos} -della struttura \kstruct{file}, vedi fig.~\ref{fig:file_proc_file}). Dato che -la funzione ritorna la nuova posizione, usando il valore zero -per \param{offset} si può riottenere la posizione corrente nel file chiamando -la funzione con \code{lseek(fd, 0, SEEK\_CUR)}. - Si tenga presente inoltre che usare \const{SEEK\_END} non assicura affatto che la 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ò @@ -807,24 +835,23 @@ un errore ma restituiscono un valore indefinito. Infine si tenga presente che, come accennato in sez.~\ref{sec:file_file_size}, con \func{lseek} è possibile impostare una posizione anche oltre la corrente fine del file. In tal caso alla successiva scrittura il file sarà esteso a -partire da detta posizione, ed in questo si ha quella che viene chiamata la -creazione di un \index{file!\textit{hole}} \textsl{buco} nel file. Il nome -deriva dal fatto che nonostante la dimensione del file sia cresciuta in -seguito alla scrittura effettuata, lo spazio vuoto fra la precedente fine del -file ed la nuova parte scritta dopo lo spostamento non corrisponde ad una -allocazione effettiva di spazio su disco, che sarebbe inutile dato che quella -zona è effettivamente vuota. +partire da detta posizione, con la creazione di quello che viene chiamato +\index{file!\textit{hole}} ``\textsl{buco}'' (in gergo \textit{hole}) nel +file. Il nome deriva dal fatto che nonostante la dimensione del file sia +cresciuta in seguito alla scrittura effettuata, lo spazio vuoto fra la +precedente fine del file ed la nuova parte scritta dopo lo spostamento non +corrisponde ad una allocazione effettiva di spazio su disco, che sarebbe +inutile dato che quella zona è effettivamente vuota. Questa è una delle caratteristiche specifiche della gestione dei file di un -sistema unix-like, ed in questo caso si ha appunto quello che in gergo si -chiama un \index{file!\textit{hole}} \textit{hole} nel file e si dice che il -file in questione è uno \textit{sparse file}. In sostanza, se si ricorda la -struttura di un filesystem illustrata in fig.~\ref{fig:file_filesys_detail}, -quello che accade è che nell'\textit{inode} del file viene segnata -l'allocazione di un blocco di dati a partire dalla nuova posizione, ma non -viene allocato nulla per le posizioni intermedie; in caso di lettura -sequenziale del contenuto del file il kernel si accorgerà della presenza del -buco, e restituirà degli zeri come contenuto di quella parte del file. +sistema unix-like e si dice che il file in questione è uno \textit{sparse + file}. In sostanza, se si ricorda la struttura di un filesystem illustrata +in fig.~\ref{fig:file_filesys_detail}, quello che accade è che \itindex{inode} +nell'\textit{inode} del file viene segnata l'allocazione di un blocco di dati +a partire dalla nuova posizione, ma non viene allocato nulla per le posizioni +intermedie; in caso di lettura sequenziale del contenuto del file il kernel si +accorgerà della presenza del buco, e restituirà degli zeri come contenuto di +quella parte del file. Questa funzionalità comporta una delle caratteristiche della gestione dei file su Unix che spesso genera più confusione in chi non la conosce, per cui @@ -836,18 +863,19 @@ effettivamente allocati per il file. Questo avviene proprio perché in un sistema unix-like la dimensione di un file è una caratteristica del tutto indipendente dalla quantità di spazio disco -effettivamente allocato, e viene registrata sull'\textit{inode} come le altre -proprietà del file. La dimensione viene aggiornata automaticamente quando si -estende un file scrivendoci, e viene riportata dal campo \var{st\_size} di una -struttura \struct{stat} quando si effettua la chiamata ad una delle funzioni -\texttt{*stat} viste in sez.~\ref{sec:file_stat}. +effettivamente allocato, e viene registrata \itindex{inode} +sull'\textit{inode} come le altre proprietà del file. La dimensione viene +aggiornata automaticamente quando si estende un file scrivendoci, e viene +riportata dal campo \var{st\_size} di una struttura \struct{stat} quando si +effettua la chiamata ad una delle funzioni \texttt{*stat} viste in +sez.~\ref{sec:file_stat}. Questo comporta che in generale, fintanto che lo si è scritto sequenzialmente, la dimensione di un file sarà più o meno corrispondente alla quantità di spazio disco da esso occupato, ma esistono dei casi, come questo in cui ci si sposta in una posizione oltre la fine corrente del file, o come quello accennato in in sez.~\ref{sec:file_file_size} in cui si estende la dimensione -di un file con una \func{truncate}, in cui in sostanza di modifica il valore +di un file con una \func{truncate}, in cui in sostanza si modifica il valore della dimensione di \var{st\_size} senza allocare spazio su disco. Questo consente di creare inizialmente file di dimensioni anche molto grandi, senza dover occupare da subito dello spazio disco che in realtà sarebbe @@ -855,13 +883,38 @@ inutilizzato. \itindend{sparse~file} - -\subsection{Le funzioni per la lettura} +A partire dal kernel 3.1, riprendendo una interfaccia adottata su Solaris, +sono state aggiunti due nuovi valori per l'argomento \param{whence}, riportati +nella seconda sezione di tab.~\ref{tab:lseek_whence_values}, che consentono di +riconoscere la presenza di \index{file!\textit{hole}} \textit{hole} +all'interno dei file ad uso di quelle applicazioni (come i programmi di +backup) che possono salvare spazio disco nella copia degli \textit{sparse + file}. Una applicazione può così determinare la presenza di un +\index{file!\textit{hole}} \textit{hole} usando \const{SEEK\_HOLE} all'inizio +del file e determinare poi l'inizio della successiva sezione di dati usando +\const{SEEK\_DATA}. Per compatibilità con i filesystem che non supportano +questa funzionalità è previsto comunque che in tal caso \const{SEEK\_HOLE} +riporti sempre la fine del file e \const{SEEK\_DATA} il valore +di \param{offset}. + +Inoltre la decisione di come riportare (o di non riportare) la presenza di un +\index{file!\textit{hole}} buco in un file è lasciata all'implementazione del +filesystem, dato che esistono vari motivi per cui una sezione di un file può +non contenere dati ed essere riportata come tale (ad esempio può essere stata +preallocata con \func{fallocate}, vedi sez.~\ref{sec:file_fadvise}) oltre a +quelle classiche appena esposte. Questo significa che l'uso di questi nuovi +valori non garantisce la mappatura della effettiva allocazione dello spazio +disco di un file, per il quale esiste una specifica operazione di controllo +(vedi sez.~\ref{sec:file_ioctl}). + + + +\subsection{Le funzioni per la lettura di un file} \label{sec:file_read} Una volta che un file è stato aperto (con il permesso in lettura) si possono -leggere i dati che contiene utilizzando la funzione \funcd{read}, il cui -prototipo è: +leggere i dati che contiene utilizzando la funzione di sistema \funcd{read}, +il cui prototipo è: \begin{funcproto}{ \fhead{unistd.h} @@ -872,37 +925,29 @@ prototipo è: {La funzione ritorna $0$ in caso di successo e $-1$ per un errore, nel qual caso \var{errno} assumerà uno dei valori: \begin{errlist} + \item[\errcode{EAGAIN}] la funzione non ha nessun dato da restituire e si è + aperto il file con \const{O\_NONBLOCK}. + \item[\errcode{EINTR}] la funzione è stata interrotta da un segnale. + \item[\errcode{EINVAL}] \param{fd} è associato ad un oggetto non leggibile, + o lo si è ottenuto da \func{timerfd\_create} (vedi + sez.~\ref{sec:sig_signalfd_eventfd}) e si è usato un valore sbagliato + per \param{size} o si è usato \const{O\_DIRECT} ed il buffer non è + allineato. + \item[\errval{EIO}] si è tentata la lettura dal terminale di controllo + essendo in background (vedi sez.~\ref{sec:term_io_design}). \end{errlist} - ed inoltre - nel loro significato generico.} + ed inoltre \errval{EBADF}, \errval{EFAULT} e \errval{EISDIR}, nel loro + significato generico.} \end{funcproto} -\begin{prototype}{unistd.h}{ssize\_t read(int fd, void * buf, size\_t count)} - - Cerca di leggere \param{count} byte dal file \param{fd} al buffer - \param{buf}. - - \bodydesc{La funzione ritorna il numero di byte letti in caso di successo e - $-1$ in caso di errore, nel qual caso \var{errno} assumerà uno dei valori: - \begin{errlist} - \item[\errcode{EINTR}] la funzione è stata interrotta da un segnale prima di - aver potuto leggere qualsiasi dato. - \item[\errcode{EAGAIN}] la funzione non aveva nessun dato da restituire e si - era aperto il file in modalità \const{O\_NONBLOCK}. - \end{errlist} - ed inoltre \errval{EBADF}, \errval{EIO}, \errval{EISDIR}, \errval{EBADF}, - \errval{EINVAL} e \errval{EFAULT} ed eventuali altri errori dipendenti dalla - natura dell'oggetto connesso a \param{fd}.} -\end{prototype} - -La funzione tenta di leggere \param{count} byte a partire dalla posizione -corrente nel file. Dopo la lettura la posizione sul file è spostata -automaticamente in avanti del numero di byte letti. Se \param{count} è zero la -funzione restituisce zero senza nessun altro risultato. Si deve sempre tener -presente che non è detto che la funzione \func{read} restituisca sempre il +La funzione tenta di leggere \param{count} byte dal file \param{fd} a partire +dalla posizione corrente, scrivendoli nel buffer \param{buf}. Dopo la lettura +la posizione sul file è spostata automaticamente in avanti del numero di byte +letti. Se \param{count} è zero la funzione restituisce zero senza nessun altro +risultato. Inoltre che non è detto che la funzione \func{read} restituisca il numero di byte richiesto, ci sono infatti varie ragioni per cui la funzione -può restituire un numero di byte inferiore; questo è un comportamento normale, -e non un errore, che bisogna sempre tenere presente. +può restituire un numero di byte inferiore: questo è un comportamento normale, +e non un errore, che bisogna sempre tenere presente. 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 @@ -927,20 +972,25 @@ Lo stesso comportamento avviene caso di lettura dalla rete (cioè su un socket, come vedremo in sez.~\ref{sec:sock_io_behav}), o per la lettura da certi file di dispositivo, come le unità a nastro, che restituiscono sempre i dati ad un singolo blocco alla volta, o come le linee seriali, che restituiscono solo i -dati ricevuti fino al momento della lettura. +dati ricevuti fino al momento della lettura, o i terminali, per i quali si +applicano inoltre ulteriori condizioni che approfondiremo in +sez.~\ref{sec:sess_terminal_io}. Infine anche le due condizioni segnalate dagli errori \errcode{EINTR} ed \errcode{EAGAIN} non sono propriamente degli errori. La prima si verifica quando la \func{read} è bloccata in attesa di dati in ingresso e viene -interrotta da un segnale; in tal caso l'azione da intraprendere è quella di -rieseguire la funzione. Torneremo in dettaglio sull'argomento in +interrotta da un segnale. In tal caso l'azione da intraprendere è quella di +rieseguire la funzione, torneremo in dettaglio sull'argomento in sez.~\ref{sec:sig_gen_beha}. La seconda si verifica quando il file è aperto -in modalità non bloccante (vedi sez.~\ref{sec:file_noblocking}) e non ci sono -dati in ingresso: la funzione allora ritorna immediatamente con un errore +in modalità non bloccante (con \const{O\_NONBLOCK}) e non ci sono dati in +ingresso: la funzione allora ritorna immediatamente con un errore \errcode{EAGAIN}\footnote{in BSD si usa per questo errore la costante - \errcode{EWOULDBLOCK}, in Linux, con le \acr{glibc}, questa è sinonima di - \errcode{EAGAIN}.} che indica soltanto che non essendoci al momento dati -disponibili occorre provare a ripetere la lettura in un secondo tempo. + \errcode{EWOULDBLOCK}, in Linux, con la \acr{glibc}, questa è sinonima di + \errcode{EAGAIN}, ma se si vuole essere completamente portabili occorre + verificare entrambi i valori, dato che POSIX.1-2001 non richiede che siano + coincidenti.} che indica soltanto che non essendoci al momento dati +disponibili occorre provare a ripetere la lettura in un secondo tempo, +torneremo sull'argomento in sez.~\ref{sec:file_noblocking}. La funzione \func{read} è una delle \textit{system call} fondamentali, esistenti fin dagli albori di Unix, ma nella seconda versione delle @@ -951,17 +1001,18 @@ esistenti fin dagli albori di Unix, ma nella seconda versione delle precedenti sia del kernel che delle librerie la funzione non è disponibile.} (quello che viene chiamato normalmente Unix98, vedi sez.~\ref{sec:intro_xopen}) è stata introdotta la definizione di un'altra -funzione di lettura, \funcd{pread}, il cui prototipo è: -\begin{prototype}{unistd.h} -{ssize\_t pread(int fd, void * buf, size\_t count, off\_t offset)} - -Cerca di leggere \param{count} byte dal file \param{fd}, a partire dalla -posizione \param{offset}, nel buffer \param{buf}. - -\bodydesc{La funzione ritorna il numero di byte letti in caso di successo e - $-1$ in caso di errore, nel qual caso \var{errno} assumerà i valori già - visti per \func{read} e \func{lseek}.} -\end{prototype} +funzione di sistema, \funcd{pread}, il cui prototipo è: + +\begin{funcproto}{ +\fhead{unistd.h} +\fdecl{ssize\_t pread(int fd, void * buf, size\_t count, off\_t offset)} +\fdesc{Legge a partire da una posizione sul file.} +} + +{La funzione ritorna il numero di byte letti in caso di successo e $-1$ per un + errore, nel qual caso \var{errno} assumerà i valori già visti per + \func{read} e \func{lseek}.} +\end{funcproto} La funzione prende esattamente gli stessi argomenti di \func{read} con lo stesso significato, a cui si aggiunge l'argomento \param{offset} che indica @@ -979,45 +1030,48 @@ importante quando la posizione sul file viene condivisa da processi diversi La funzione \func{pread} è disponibile anche in Linux, però diventa accessibile solo attivando il supporto delle estensioni previste dalle \textit{Single Unix Specification} con la definizione della macro: -\begin{verbatim} +\begin{Example} #define _XOPEN_SOURCE 500 -\end{verbatim} +\end{Example} e si ricordi di definire questa macro prima dell'inclusione del file di dichiarazioni \headfile{unistd.h}. -\subsection{Le funzioni per la scrittura} +\subsection{Le funzioni per la scrittura di un file} \label{sec:file_write} Una volta che un file è stato aperto (con il permesso in scrittura) si può -scrivere su di esso utilizzando la funzione \funcd{write}, il cui prototipo è: -\begin{prototype}{unistd.h}{ssize\_t write(int fd, void * buf, size\_t count)} - - Scrive \param{count} byte dal buffer \param{buf} sul file \param{fd}. - - \bodydesc{La funzione ritorna il numero di byte scritti in caso di successo - e $-1$ in caso di errore, nel qual caso \var{errno} assumerà uno dei - valori: +scrivere su di esso utilizzando la funzione di sistema \funcd{write}, il cui +prototipo è: + +\begin{funcproto}{ +\fhead{unistd.h} +\fdecl{ssize\_t write(int fd, void * buf, size\_t count)} +\fdesc{Scrive i dati su un file.} +} + +{La funzione ritorna il numero di byte scritti in caso di successo e $-1$ per + un errore, nel qual caso \var{errno} assumerà uno dei valori: \begin{errlist} - \item[\errcode{EINVAL}] \param{fd} è connesso ad un oggetto che non consente - la scrittura. + \item[\errcode{EAGAIN}] ci si sarebbe bloccati, ma il file era aperto in + modalità \const{O\_NONBLOCK}. \item[\errcode{EFBIG}] si è cercato di scrivere oltre la dimensione massima consentita dal filesystem o il limite per le dimensioni dei file del processo o su una posizione oltre il massimo consentito. + \item[\errcode{EINTR}] si è stati interrotti da un segnale prima di aver + potuto scrivere qualsiasi dato. + \item[\errcode{EINVAL}] \param{fd} è connesso ad un oggetto che non consente + la scrittura o si è usato \const{O\_DIRECT} ed il buffer non è allineato. \item[\errcode{EPIPE}] \param{fd} è connesso ad una pipe il cui altro capo è chiuso in lettura; in questo caso viene anche generato il segnale \signal{SIGPIPE}, se questo viene gestito (o bloccato o ignorato) la funzione ritorna questo errore. - \item[\errcode{EINTR}] si è stati interrotti da un segnale prima di aver - potuto scrivere qualsiasi dato. - \item[\errcode{EAGAIN}] ci si sarebbe bloccati, ma il file era aperto in - modalità \const{O\_NONBLOCK}. \end{errlist} - ed inoltre \errval{EBADF}, \errval{EIO}, \errval{EISDIR}, \errval{EBADF}, - \errval{ENOSPC}, \errval{EINVAL} e \errval{EFAULT} ed eventuali altri errori - dipendenti dalla natura dell'oggetto connesso a \param{fd}.} -\end{prototype} + ed inoltre \errval{EBADF}, \errval{EFAULT}, \errval{EIO}, \errval{EISDIR}, + \errval{ENOSPC} nel loro significato generico.} +\end{funcproto} + Come nel caso di \func{read} la funzione tenta di scrivere \param{count} byte a partire dalla posizione corrente nel file e sposta automaticamente la @@ -1036,16 +1090,18 @@ stesso comportamento di \func{read}. Anche per \func{write} lo standard Unix98 definisce un'analoga \funcd{pwrite} per scrivere alla posizione indicata senza modificare la posizione corrente nel file, il suo prototipo è: -\begin{prototype}{unistd.h} -{ssize\_t pwrite(int fd, void * buf, size\_t count, off\_t offset)} - -Cerca di scrivere sul file \param{fd}, a partire dalla posizione -\param{offset}, \param{count} byte dal buffer \param{buf}. - -\bodydesc{La funzione ritorna il numero di byte letti in caso di successo e - $-1$ in caso di errore, nel qual caso \var{errno} assumerà i valori già - visti per \func{write} e \func{lseek}.} -\end{prototype} + +\begin{funcproto}{ +\fhead{unistd.h} +\fdecl{ssize\_t pwrite(int fd, void * buf, size\_t count, off\_t offset)} +\fdesc{Scrive a partire da una posizione sul file.} +} + +{La funzione ritorna il numero di byte letti in caso di successo e $-1$ per un + errore, nel qual caso \var{errno} assumerà i valori già visti per + \func{write} e \func{lseek}.} +\end{funcproto} + \noindent e per essa valgono le stesse considerazioni fatte per \func{pread}. @@ -1070,7 +1126,7 @@ confronti dell'accesso allo stesso file da parte di processi diversi. \begin{figure}[!htb] \centering - \includegraphics[width=15cm]{img/filemultacc} + \includegraphics[width=12cm]{img/filemultacc} \caption{Schema dell'accesso allo stesso file da parte di due processi diversi} \label{fig:file_mult_acc} @@ -1082,7 +1138,7 @@ situazione come quella illustrata in fig.~\ref{fig:file_mult_acc}: ciascun processo avrà una sua voce nella \textit{file table} referenziata da un diverso file descriptor nella sua \kstruct{file\_struct}. Entrambe le voci nella \itindex{file~table} \textit{file table} faranno però riferimento allo -stesso \itindex{inode} inode su disco. +stesso \itindex{inode} \textit{inode} su disco. Questo significa che ciascun processo avrà la sua posizione corrente sul file, la sua modalità di accesso e versioni proprie di tutte le proprietà che @@ -1095,21 +1151,21 @@ che: \func{write} la posizione corrente sarà cambiata solo nel processo. Se la scrittura eccede la dimensione corrente del file questo verrà esteso automaticamente con l'aggiornamento del campo \var{i\_size} \itindex{inode} - nell'inode. + nell'\textit{inode}. \item se un file è in modalità \itindex{append~mode} \const{O\_APPEND} tutte le volte che viene effettuata una scrittura la posizione corrente viene prima impostata alla dimensione corrente del file letta \itindex{inode} - dall'inode. Dopo la scrittura il file viene automaticamente esteso. + dall'\textit{inode}. Dopo la scrittura il file viene automaticamente esteso. \item l'effetto di \func{lseek} è solo quello di cambiare il campo \var{f\_pos} nella struttura \kstruct{file} della \itindex{file~table} \textit{file table}, non c'è nessuna operazione sul file su disco. Quando la si usa per porsi alla fine del file la posizione viene impostata leggendo la - dimensione corrente \itindex{inode} dall'inode. + dimensione corrente \itindex{inode} dall'\textit{inode}. \end{itemize} \begin{figure}[!htb] \centering - \includegraphics[width=15cm]{img/fileshar} + \includegraphics[width=12cm]{img/fileshar} \caption{Schema dell'accesso ai file da parte di un processo figlio} \label{fig:file_acc_child} \end{figure} @@ -1132,14 +1188,13 @@ corrente nel file varierà per entrambi i processi (in quanto verrà modificato Si noti inoltre che anche i \itindex{file~status~flag} flag di stato del file (quelli impostati dall'argomento \param{flag} di \func{open}) essendo tenuti -nella voce della \textit{file table}\footnote{per la precisione nel campo - \var{f\_flags} di \kstruct{file}, vedi fig.~\ref{fig:kstruct_file}.}, -vengono in questo caso condivisi. Ai file però sono associati anche altri -flag, dei quali l'unico usato al momento è \const{FD\_CLOEXEC}, detti -\index{file~descriptor~flags} \textit{file descriptor flags}. Questi ultimi -sono tenuti invece in \kstruct{file\_struct}, e perciò sono specifici di -ciascun processo e non vengono modificati dalle azioni degli altri anche in -caso di condivisione della stessa voce della \textit{file table}. +nella voce della \textit{file table}, vengono in questo caso condivisi. Ai +file però sono associati anche altri flag, dei quali l'unico usato al momento +è \const{FD\_CLOEXEC}, detti \itindex{file~descriptor~flags} \textit{file + descriptor flags}. Questi ultimi sono tenuti invece in +\kstruct{file\_struct}, e perciò sono specifici di ciascun processo e non +vengono modificati dalle azioni degli altri anche in caso di condivisione +della stessa voce della \textit{file table}. @@ -1200,10 +1255,11 @@ caratteristica si veda sez.~\ref{sec:ipc_file_lock}). % TODO, aggiungere syncfs, introdotta con il 2.6.39 -Come accennato in sez.~\ref{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}. +Come accennato in sez.~\ref{sec:file_open_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 @@ -1213,12 +1269,16 @@ scarico dei dati dai buffer del kernel.\footnote{come già accennato neanche ottimizzazione per l'accesso al disco che può ritardare ulteriormente la scrittura effettiva.} La prima di queste funzioni è \funcd{sync} il cui prototipo è: -\begin{prototype}{unistd.h}{int sync(void)} - - Sincronizza il buffer della cache dei file col disco. - - \bodydesc{La funzione ritorna sempre zero.} -\end{prototype} + +\begin{funcproto}{ +\fhead{unistd.h} +\fdecl{int sync(void)} +\fdesc{Sincronizza il buffer della cache dei file col disco.} +} + +{La funzione ritorna sempre $0$ ed ha sempre successo.} +\end{funcproto} + \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 @@ -1238,28 +1298,31 @@ in \file{Documentation/sysctl/vm.txt}). 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 \funcd{fsync} e \funcd{fdatasync}, i cui prototipi sono: -\begin{functions} - \headdecl{unistd.h} - \funcdecl{int fsync(int fd)} - Sincronizza dati e meta-dati del file \param{fd} - \funcdecl{int fdatasync(int fd)} - Sincronizza i dati del file \param{fd}. - - \bodydesc{La funzione ritorna 0 in caso di successo e $-1$ in caso di - errore, nel qual caso \var{errno} assume i valori: + +\begin{funcproto}{ +\fhead{unistd.h} +\fdecl{int fsync(int fd)} +\fdesc{Sincronizza dati e metadati di un file.} +\fdecl{int fdatasync(int fd)} +\fdesc{Sincronizza i dati di un file.} +} + +{Le funzioni ritornano $0$ in caso di successo e $-1$ per un errore, nel qual + caso \var{errno} assumerà uno dei valori: \begin{errlist} \item[\errcode{EINVAL}] \param{fd} è un \index{file!speciali} file speciale che non supporta la sincronizzazione. \end{errlist} - ed inoltre \errval{EBADF}, \errval{EROFS} e \errval{EIO}.} -\end{functions} + ed inoltre \errval{EBADF}, \errval{EROFS} e \errval{EIO} nel loro + significato generico.} +\end{funcproto} 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 meta-dati del file (che riguardano sia le modifiche alle tabelle di allocazione dei settori, che gli -altri dati contenuti \itindex{inode} nell'inode che si leggono con \func{fstat}, -come i tempi del file). +altri dati contenuti \itindex{inode} nell'\textit{inode} che si leggono con +\func{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 @@ -1277,18 +1340,22 @@ 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 \funcd{dup} il cui prototipo è: -\begin{prototype}{unistd.h}{int dup(int oldfd)} - Crea una copia del file descriptor \param{oldfd}. - - \bodydesc{La funzione ritorna il nuovo file descriptor in caso di successo e - $-1$ in caso di errore, nel qual caso \var{errno} assumerà uno dei - valori: + +\begin{funcproto}{ +\fhead{unistd.h} +\fdecl{int dup(int oldfd)} +\fdesc{Crea un file descriptor duplicato.} +} + +{La funzione ritorna il nuovo file descriptor in caso di successo e $-1$ per + un errore, nel qual caso \var{errno} assumerà uno dei valori: \begin{errlist} \item[\errcode{EBADF}] \param{oldfd} non è un file aperto. \item[\errcode{EMFILE}] si è raggiunto il numero massimo consentito di file descriptor aperti. - \end{errlist}} -\end{prototype} + \end{errlist} +} +\end{funcproto} La funzione ritorna, come \func{open}, il primo file descriptor libero. Il file descriptor è una copia esatta del precedente ed entrambi possono essere @@ -1300,7 +1367,7 @@ alla stessa voce nella \textit{file table}; per questo si dice che il nuovo file descriptor è \textsl{duplicato}, da cui il nome della funzione. \begin{figure}[!htb] - \centering \includegraphics[width=14cm]{img/filedup} + \centering \includegraphics[width=12cm]{img/filedup} \caption{Schema dell'accesso ai file duplicati} \label{fig:file_dup} \end{figure} @@ -1330,19 +1397,25 @@ Dato che questa è l'operazione più comune, è prevista una diversa versione della funzione, \funcd{dup2}, che permette di specificare esplicitamente qual è il valore di file descriptor che si vuole avere come duplicato; il suo prototipo è: -\begin{prototype}{unistd.h}{int dup2(int oldfd, int newfd)} - - Rende \param{newfd} una copia del file descriptor \param{oldfd}. - - \bodydesc{La funzione ritorna il nuovo file descriptor in caso di successo e - $-1$ in caso di errore, nel qual caso \var{errno} assumerà uno dei valori: + +\begin{funcproto}{ +\fhead{unistd.h} +\fdecl{int dup2(int oldfd, int newfd)} +\fdesc{Duplica un file descriptor su un altro.} +} + +{La funzione ritorna il nuovo file descriptor in caso di successo e $-1$ per + un errore, nel qual caso \var{errno} assumerà uno dei valori: \begin{errlist} \item[\errcode{EBADF}] \param{oldfd} non è un file aperto o \param{newfd} ha un valore fuori dall'intervallo consentito per i file descriptor. \item[\errcode{EMFILE}] si è raggiunto il numero massimo consentito di file descriptor aperti. - \end{errlist}} -\end{prototype} + \end{errlist} +} +\end{funcproto} + + \noindent e qualora il file descriptor \param{newfd} sia già aperto (come avviene ad esempio nel caso della duplicazione di uno dei file standard) esso sarà prima chiuso e poi duplicato (così che il file duplicato sarà connesso @@ -1426,24 +1499,25 @@ argomento il file descriptor della directory da usare come base, mentre gli argomenti successivi restano identici a quelli della corrispondente funzione ordinaria; ad esempio nel caso di \funcd{openat} avremo che essa è definita come: -\begin{functions} - \headdecl{fcntl.h} - \funcdecl{int openat(int dirfd, const char *pathname, int flags)} - \funcdecl{int openat(int dirfd, const char *pathname, int flags, mode\_t - mode))} - - Apre un file usando come directory di \index{directory~di~lavoro} lavoro - corrente \param{dirfd}. - - \bodydesc{la funzione restituisce gli stessi valori e gli stessi codici di - errore di \func{open}, ed in più: + +\begin{funcproto}{ +\fhead{fcntl.h} +\fdecl{int openat(int dirfd, const char *pathname, int flags)} +\fdecl{int openat(int dirfd, const char *pathname, int flags, mode\_t + mode))} +\fdesc{Apre un file a partire da una directory di \index{directory~di~lavoro} + lavoro.} +} + +{La funzione ritorna gli stessi valori e gli stessi codici di errore di + \func{open}, ed in più: \begin{errlist} \item[\errcode{EBADF}] \param{dirfd} non è un file descriptor valido. \item[\errcode{ENOTDIR}] \param{pathname} è un \itindsub{pathname}{relativo} - \textit{pathname} relativo, ma - \param{dirfd} fa riferimento ad un file. - \end{errlist}} -\end{functions} + \textit{pathname} relativo, ma \param{dirfd} fa riferimento ad un file. + \end{errlist} +} +\end{funcproto} Il comportamento delle nuove funzioni è del tutto analogo a quello delle corrispettive classiche, con la sola eccezione del fatto che se fra i loro @@ -1532,23 +1606,25 @@ binaria, ed impostato usando i valori delle appropriate costanti Come esempio di questo secondo tipo di funzioni possiamo considerare \funcd{fchownat}, che può essere usata per sostituire sia \func{chown} che \func{lchown}; il suo prototipo è: -\begin{functions} - \headdecl{unistd.h} \headdecl{fcntl.h} - \funcdecl{int fchownat(int dirfd, const char *pathname, uid\_t owner, gid\_t +\begin{funcproto}{ +\fhead{unistd.h} +\fhead{fcntl.h} +\fdecl{int fchownat(int dirfd, const char *pathname, uid\_t owner, gid\_t group, int flags)} +\fdesc{Modifica il proprietario di un file.} +} - Modifica la proprietà di un file. - - \bodydesc{la funzione restituisce gli stessi valori e gli stessi codici di - errore di \func{chown}, ed in più: +{La funzione ritorna gli stessi valori e gli stessi codici di errore di + \func{chown}, ed in più: \begin{errlist} \item[\errcode{EBADF}] \param{dirfd} non è un file descriptor valido. \item[\errcode{EINVAL}] \param{flags} non ha un valore valido. \item[\errcode{ENOTDIR}] \param{pathname} è un \itindsub{pathname}{relativo} \textit{pathname} relativo, ma \param{dirfd} fa riferimento ad un file. - \end{errlist}} -\end{functions} + \end{errlist} +} +\end{funcproto} In questo caso il valore di \param{flags} stabilisce il comportamento della funzione quando la si applica ad un collegamento simbolico, e l'unico valore @@ -1564,21 +1640,23 @@ Come accennato fra tutte quelle marcate in tab.~\ref{tab:file_atfunc_corr} solo due funzioni possono usare l'argomento \param{flags} con valori diversi da \const{AT\_SYMLINK\_NOFOLLOW}, la prima di queste è \funcd{faccessat}, ed il suo prototipo è: -\begin{functions} - \headdecl{unistd.h} - \funcdecl{int faccessat(int dirfd, const char *path, int mode, int flags)} - - Controlla i permessi di accesso. - - \bodydesc{la funzione restituisce gli stessi valori e gli stessi codici di - errore di \func{access}, ed in più: + +\begin{funcproto}{ +\fhead{unistd.h} +\fdecl{int faccessat(int dirfd, const char *path, int mode, int flags)} +\fdesc{Controlla i permessi di accesso.} +} + +{La funzione ritorna gli stessi valori e gli stessi codici di errore di + \func{access}, ed in più: \begin{errlist} \item[\errcode{EBADF}] \param{dirfd} non è un file descriptor valido. \item[\errcode{EINVAL}] \param{flags} non ha un valore valido. \item[\errcode{ENOTDIR}] \param{pathname} è un \itindsub{pathname}{relativo} \textit{pathname} relativo, ma \param{dirfd} fa riferimento ad un file. - \end{errlist}} -\end{functions} + \end{errlist} +} +\end{funcproto} La funzione esegue lo stesso controllo di accesso effettuabile con \func{access}, ma si può utilizzare l'argomento \param{flags} per modificarne @@ -1597,22 +1675,24 @@ La seconda eccezione è \func{unlinkat}, in questo caso l'ulteriore argomento \param{flags} viene utilizzato perché tramite esso la funzione possa comportarsi sia come analogo di \func{unlink} che di \func{rmdir}; il suo prototipo è: -\begin{functions} - \headdecl{fcntl.h} - \funcdecl{int unlinkat(int dirfd, const char *pathname, int flags)} - - Rimuove una voce da una directory. - - \bodydesc{la funzione restituisce gli stessi valori e gli stessi codici di - errore di \func{unlink} o di \func{rmdir} a seconda del valore di - \param{flags}, ed in più: + +\begin{funcproto}{ +\fhead{fcntl.h} +\fdecl{int unlinkat(int dirfd, const char *pathname, int flags)} +\fdesc{Rimuove una voce da una directory.} +} + +{La funzione ritorna gli stessi valori e gli stessi codici di errore di + \func{unlink} o di \func{rmdir} a seconda del valore di \param{flags}, ed in + più: \begin{errlist} \item[\errcode{EBADF}] \param{dirfd} non è un file descriptor valido. \item[\errcode{EINVAL}] \param{flags} non ha un valore valido. \item[\errcode{ENOTDIR}] \param{pathname} è un \itindsub{pathname}{relativo} \textit{pathname} relativo, ma \param{dirfd} fa riferimento ad un file. - \end{errlist}} -\end{functions} + \end{errlist} +} +\end{funcproto} Di default il comportamento di \func{unlinkat} è equivalente a quello che avrebbe \func{unlink} applicata a \param{pathname}, fallendo in tutti i casi @@ -1648,24 +1728,25 @@ funzionalità che il kernel può mettere a disposizione.\footnote{ad esempio si Per queste operazioni di manipolazione e di controllo delle varie proprietà e caratteristiche di un file descriptor, viene usata la funzione \funcd{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)} - Esegue una delle possibili operazioni specificate da \param{cmd} - sul file \param{fd}. - - \bodydesc{La funzione ha valori di ritorno diversi a seconda - dell'operazione. In caso di errore il valore di ritorno è sempre $-1$ ed - il codice dell'errore è restituito nella variabile \var{errno}; i codici - possibili dipendono dal tipo di operazione, l'unico valido in generale è: + +\begin{funcproto}{ +\fhead{unistd.h} +\fhead{fcntl.h} +\fdecl{int fcntl(int fd, int cmd)} +\fdecl{int fcntl(int fd, int cmd, long arg)} +\fdecl{int fcntl(int fd, int cmd, struct flock * lock)} +\fdesc{Esegue una operazione di controllo sul file.} +} + +{La funzione ha valori di ritorno diversi a seconda dell'operazione richiesta + in caso di successo mentre ritorna sempre $-1$ per un errore, nel qual caso + \var{errno} assumerà valori diversi che dipendono dal tipo di operazione, + l'unico valido in generale è: \begin{errlist} \item[\errcode{EBADF}] \param{fd} non è un file aperto. - \end{errlist}} -\end{functions} - + \end{errlist} +} +\end{funcproto} Il primo argomento della funzione è sempre il numero di file descriptor \var{fd} su cui si vuole operare. Il comportamento di questa funzione, il @@ -1832,15 +1913,17 @@ Per questo motivo nell'architettura del sistema è stata prevista l'esistenza di una funzione apposita, \funcd{ioctl}, con cui poter compiere le operazioni specifiche di ogni dispositivo particolare, usando come riferimento il solito file descriptor. Il prototipo di questa funzione è: -\begin{prototype}{sys/ioctl.h}{int ioctl(int fd, int request, ...)} - - Esegue l'operazione di controllo specificata da \param{request} sul file - descriptor \param{fd}. - - \bodydesc{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$ ed \var{errno} assumerà uno dei - valori: + +\begin{funcproto}{ +\fhead{sys/ioctl.h} +\fdecl{int ioctl(int fd, int request, ...)} +\fdesc{Esegue una operazione speciale.} +} + +{La funzione ritorna $0$ in caso di successo nella maggior parte dei casi, ma + alcune operazioni possono restituire un valore positivo, mentre ritorna + sempre $-1$ per un errore, nel qual caso \var{errno} assumerà uno dei + valori: \begin{errlist} \item[\errcode{ENOTTY}] il file \param{fd} non è associato con un dispositivo, o la richiesta non è applicabile all'oggetto a cui fa @@ -1848,17 +1931,18 @@ file descriptor. Il prototipo di questa funzione è: \item[\errcode{EINVAL}] gli argomenti \param{request} o \param{argp} non sono validi. \end{errlist} - ed inoltre \errval{EBADF} e \errval{EFAULT}.} -\end{prototype} - -La funzione serve in sostanza come meccanismo generico per fare tutte quelle -operazioni che non rientrano nell'interfaccia ordinaria della gestione dei -file e che non è possibile effettuare con le funzioni esaminate finora. La -funzione richiede che si passi come primo argomento un file descriptor -regolarmente aperto, e l'operazione da compiere viene selezionata attraverso -il valore dell'argomento \param{request}. Il terzo argomento dipende -dall'operazione prescelta; tradizionalmente è specificato come \code{char * - argp}, da intendersi come puntatore ad un area di memoria + ed inoltre \errval{EBADF} e \errval{EFAULT} nel loro significato generico.} +\end{funcproto} + +La funzione esegue l'operazione di controllo specificata da \param{request} +sul file descriptor \param{fd} e serve in sostanza come meccanismo generico +per fare tutte quelle operazioni che non rientrano nell'interfaccia ordinaria +della gestione dei file e che non è possibile effettuare con le funzioni +esaminate finora. La funzione richiede che si passi come primo argomento un +file descriptor regolarmente aperto, e l'operazione da compiere viene +selezionata attraverso il valore dell'argomento \param{request}. Il terzo +argomento dipende dall'operazione prescelta; tradizionalmente è specificato +come \code{char * argp}, da intendersi come puntatore ad un area di memoria generica,\footnote{all'epoca della creazione di questa funzione infatti ancora non era stato introdotto il tipo \ctyp{void}.} ma per certe operazioni può essere omesso, e per altre è un semplice intero. @@ -1953,7 +2037,9 @@ operazioni che sono predefinite per qualunque file,\footnote{in particolare (cioè di tipo \texttt{int *}) su cui sarà restituito il valore. \end{basedescript} -% TODO aggiungere FIBMAP e FIEMAP, vedi http://lwn.net/Articles/260832 +% TODO aggiungere FIBMAP e FIEMAP, vedi http://lwn.net/Articles/260795/, +% http://lwn.net/Articles/429345/ + Si noti però come la gran parte di queste operazioni specifiche dei file (per essere precisi le prime sei dell'elenco) siano effettuabili in maniera @@ -2039,10 +2125,6 @@ sez.~\ref{sec:file_access_control} per il controllo di accesso. \itindend{file~stream} -\subsection{Gli oggetti \type{FILE}} -\label{sec:file_FILE} - - Per ragioni storiche la struttura di dati che rappresenta uno \textit{stream} è stata chiamata \type{FILE}, questi oggetti sono creati dalle funzioni di libreria e contengono tutte le informazioni necessarie a gestire le operazioni @@ -2057,10 +2139,6 @@ di \textit{stream}). Tutte le funzioni della libreria che operano sui file accettano come argomenti solo variabili di questo tipo, che diventa accessibile includendo l'header file \headfile{stdio.h}. - -\subsection{Gli \textit{stream standard}} -\label{sec:file_std_stream} - Ai tre file descriptor standard (vedi tab.~\ref{tab:file_std_files}) aperti per ogni processo, corrispondono altrettanti \textit{stream}, che rappresentano i canali standard di input/output prestabiliti; anche questi tre @@ -2184,35 +2262,37 @@ Le funzioni che si possono usare per aprire uno \textit{stream} sono solo tre: \funcd{fopen}, \funcd{fdopen} e \funcd{freopen},\footnote{\func{fopen} e \func{freopen} fanno parte dello standard ANSI C, \func{fdopen} è parte dello standard POSIX.1.} i loro prototipi sono: -\begin{functions} - \headdecl{stdio.h} - \funcdecl{FILE *fopen(const char *path, const char *mode)} - Apre il file specificato da \param{path}. - \funcdecl{FILE *fdopen(int fildes, const char *mode)} - Associa uno \textit{stream} al file descriptor \param{fildes}. - \funcdecl{FILE *freopen(const char *path, const char *mode, FILE *stream)} - Apre il file specificato da \param{path} associandolo allo \textit{stream} - specificato da \param{stream}, se questo è già aperto prima lo chiude. - - \bodydesc{Le funzioni ritornano un puntatore valido in caso di successo e - \val{NULL} in caso di errore, in tal caso \var{errno} assumerà il valore - ricevuto dalla funzione sottostante di cui è fallita l'esecuzione. - - Gli errori pertanto possono essere quelli di \func{malloc} per tutte - e tre le funzioni, quelli \func{open} per \func{fopen}, quelli di - \func{fcntl} per \func{fdopen} e quelli di \func{fopen}, - \func{fclose} e \func{fflush} per \func{freopen}.} -\end{functions} + +\begin{funcproto}{ +\fhead{stdio.h} +\fdecl{FILE *fopen(const char *path, const char *mode)} +\fdesc{Apre uno \textit{stream} da un \texttt{pathname}.} +\fdecl{FILE *fdopen(int fildes, const char *mode)} +\fdesc{Associa uno \textit{stream} a un file descriptor.} +\fdecl{FILE *freopen(const char *path, const char *mode, FILE *stream)} +\fdesc{Chiude uno \textit{stream} e lo riapre su un file diverso.} +} + +{Le funzioni ritornano un puntatore ad un oggetto \type{FILE} in caso di + successo e \val{NULL} per un errore, nel qual caso \var{errno} assumerà il + valore ricevuto dalla funzione sottostante di cui è fallita l'esecuzione, + gli errori pertanto possono essere quelli di \func{malloc} per tutte e tre + le funzioni, quelli \func{open} per \func{fopen}, quelli di \func{fcntl} per + \func{fdopen} e quelli di \func{fopen}, \func{fclose} e \func{fflush} per + \func{freopen}.} +\end{funcproto} + Normalmente la funzione che si usa per aprire uno \textit{stream} è -\func{fopen}, essa apre il file specificato nella modalità specificata da -\param{mode}, che è una stringa che deve iniziare con almeno uno dei valori -indicati in tab.~\ref{tab:file_fopen_mode} (sono possibili varie estensioni -che vedremo in seguito). - -L'uso più comune di \func{freopen} è per redirigere uno dei tre file -standard (vedi sez.~\ref{sec:file_std_stream}): il file \param{path} viene -associato a \param{stream} e se questo è uno \textit{stream} già aperto viene +\func{fopen}, essa apre il file specificato dal \textit{pathname} \param{path} +nella modalità specificata da \param{mode}, che è una stringa che deve +iniziare con almeno uno dei valori indicati in tab.~\ref{tab:file_fopen_mode} +(sono possibili varie estensioni che vedremo in seguito). + +L'uso più comune di \func{freopen} è per redirigere uno dei tre file standard +(vedi sez.~\ref{sec:file_stream}): il file \param{path} viene aperto nella +modalità indicata da \param{mode} ed associato allo \textit{stream} +a \param{stream}, e se questo era uno \textit{stream} già aperto viene preventivamente chiuso. Infine \func{fdopen} viene usata per associare uno \textit{stream} ad un file @@ -2320,103 +2400,126 @@ si è effettuato alcuna operazione di I/O sul file. Uno \textit{stream} viene chiuso con la funzione \funcd{fclose} il cui prototipo è: -\begin{prototype}{stdio.h}{int fclose(FILE *stream)} - Chiude lo \textit{stream} \param{stream}. - - \bodydesc{Restituisce 0 in caso di successo e \val{EOF} in caso di errore, - nel qual caso imposta \var{errno} a \errval{EBADF} se il file descriptor - indicato da \param{stream} non è valido, o uno dei valori specificati - dalla sottostante funzione che è fallita (\func{close}, \func{write} o - \func{fflush}).} -\end{prototype} - -La funzione effettua lo scarico di tutti i dati presenti nei buffer di uscita -e scarta tutti i dati in ingresso; se era stato allocato un buffer per lo -\textit{stream} questo verrà rilasciato. La funzione effettua lo scarico solo -per i dati presenti nei buffer in user space usati dalle \acr{glibc}; se si -vuole essere sicuri che il kernel forzi la scrittura su disco occorrerà -effettuare una \func{sync} (vedi sez.~\ref{sec:file_sync}). + +\begin{funcproto}{ +\fhead{stdio.h} +\fdecl{int fclose(FILE *stream)} +\fdesc{Chiude uno \textit{stream}.} +} + +{La funzione ritorna $0$ in caso di successo e \val{EOF} per un errore, nel + qual caso \var{errno} assumerà il valore \errval{EBADF} se il file + descriptor indicato da \param{stream} non è valido, o uno dei valori + specificati dalla sottostante funzione che è fallita (\func{close}, + \func{write} o \func{fflush}). +} +\end{funcproto} + +La funzione chiude lo \textit{stream} \param{stream} ed effettua lo scarico di +tutti i dati presenti nei buffer di uscita e scarta tutti i dati in ingresso; +se era stato allocato un buffer per lo \textit{stream} questo verrà +rilasciato. La funzione effettua lo scarico solo per i dati presenti nei +buffer in \textit{user space} usati dalle \acr{glibc}; se si vuole essere +sicuri che il kernel forzi la scrittura su disco occorrerà effettuare una +\func{sync} (vedi sez.~\ref{sec:file_sync}). Linux supporta anche una altra funzione, \funcd{fcloseall}, come estensione GNU implementata dalle \acr{glibc}, accessibile avendo definito \macro{\_GNU\_SOURCE}, il suo prototipo è: -\begin{prototype}{stdio.h}{int fcloseall(void)} - Chiude tutti gli \textit{stream}. - - \bodydesc{Restituisce 0 se non ci sono errori ed \val{EOF} altrimenti.} -\end{prototype} -\noindent la funzione esegue lo scarico dei dati bufferizzati in uscita -e scarta quelli in ingresso, chiudendo tutti i file. Questa funzione è -provvista solo per i casi di emergenza, quando si è verificato un errore -ed il programma deve essere abortito, ma si vuole compiere qualche altra -operazione dopo aver chiuso i file e prima di uscire (si ricordi quanto -visto in sez.~\ref{sec:proc_conclusion}). - - -\subsection{Lettura e scrittura su uno \textit{stream}} -\label{sec:file_io} - -Una delle caratteristiche più utili dell'interfaccia degli \textit{stream} è -la ricchezza delle funzioni disponibili per le operazioni di lettura e -scrittura sui file. Sono infatti previste ben tre diverse modalità modalità di -input/output non formattato: -\begin{enumerate*} -\item\textsl{binario} in cui legge/scrive un blocco di dati alla - volta, vedi sez.~\ref{sec:file_binary_io}. -\item\textsl{a caratteri} in cui si legge/scrive un carattere alla - volta (con la bufferizzazione gestita automaticamente dalla libreria), - vedi sez.~\ref{sec:file_char_io}. -\item\textsl{di linea} in cui si legge/scrive una linea alla volta (terminata - dal carattere di newline \verb|'\n'|), vedi sez.~\ref{sec:file_line_io}. -\end{enumerate*} -ed inoltre la modalità di input/output formattato. - -A differenza dell'interfaccia dei file descriptor, con gli \textit{stream} il -raggiungimento della fine del file è considerato un errore, e viene -notificato come tale dai valori di uscita delle varie funzioni. Nella -maggior parte dei casi questo avviene con la restituzione del valore -intero (di tipo \ctyp{int}) \val{EOF}\footnote{la costante deve essere - negativa, le \acr{glibc} usano -1, altre implementazioni possono avere - valori diversi.} definito anch'esso nell'header \headfile{stdlib.h}. - -Dato che le funzioni dell'interfaccia degli \textit{stream} sono funzioni di -libreria che si appoggiano a delle \textit{system call}, esse non impostano -direttamente la variabile \var{errno}, che mantiene il valore impostato dalla -\textit{system call} che ha riportato l'errore. - -Siccome la condizione di end-of-file è anch'essa segnalata come errore, nasce -il problema di come distinguerla da un errore effettivo; basarsi solo sul -valore di ritorno della funzione e controllare il valore di \var{errno} -infatti non basta, dato che quest'ultimo potrebbe essere stato impostato in -una altra occasione, (si veda sez.~\ref{sec:sys_errno} per i dettagli del -funzionamento di \var{errno}). - -Per questo motivo tutte le implementazioni delle librerie standard mantengono -per ogni \textit{stream} almeno due flag all'interno dell'oggetto \type{FILE}, -il flag di \textit{end-of-file}, che segnala che si è raggiunta la fine del -file in lettura, e quello di errore, che segnala la presenza di un qualche -errore nelle operazioni di input/output; questi due flag possono essere -riletti dalle funzioni \funcd{feof} e \funcd{ferror}, i cui prototipi sono: -\begin{functions} - \headdecl{stdio.h} - \funcdecl{int feof(FILE *stream)} - Controlla il flag di end-of-file di \param{stream}. - \funcdecl{int ferror(FILE *stream)} - Controlla il flag di errore di \param{stream}. - - \bodydesc{Entrambe le funzioni ritornano un valore diverso da zero se - i relativi flag sono impostati.} -\end{functions} + +\begin{funcproto}{ +\fhead{stdio.h} +\fdecl{int fcloseall(void)} +\fdesc{Chiude tutti gli \textit{stream}.} +} + +{La funzione ritorna $0$ in caso di successo e \val{EOF} per un errore, nel + qual caso \var{errno} assumerà gli stessi valori di \func{fclose}.} +\end{funcproto} + + La funzione esegue lo scarico dei dati bufferizzati in uscita + e scarta quelli in ingresso, chiudendo tutti i file. Questa funzione è + provvista solo per i casi di emergenza, quando si è verificato un errore + ed il programma deve essere abortito, ma si vuole compiere qualche altra + operazione dopo aver chiuso i file e prima di uscire (si ricordi quanto + visto in sez.~\ref{sec:proc_conclusion}). + + + \subsection{Lettura e scrittura su uno \textit{stream}} + \label{sec:file_io} + + Una delle caratteristiche più utili dell'interfaccia degli \textit{stream} è + la ricchezza delle funzioni disponibili per le operazioni di lettura e + scrittura sui file. Sono infatti previste ben tre diverse modalità modalità di + input/output non formattato: + \begin{enumerate*} + \item\textsl{binario} in cui legge/scrive un blocco di dati alla + volta, vedi sez.~\ref{sec:file_binary_io}. + \item\textsl{a caratteri} in cui si legge/scrive un carattere alla + volta (con la bufferizzazione gestita automaticamente dalla libreria), + vedi sez.~\ref{sec:file_char_io}. + \item\textsl{di linea} in cui si legge/scrive una linea alla volta (terminata + dal carattere di newline \verb|'\n'|), vedi sez.~\ref{sec:file_line_io}. + \end{enumerate*} + ed inoltre la modalità di input/output formattato. + + A differenza dell'interfaccia dei file descriptor, con gli \textit{stream} il + raggiungimento della fine del file è considerato un errore, e viene + notificato come tale dai valori di uscita delle varie funzioni. Nella + maggior parte dei casi questo avviene con la restituzione del valore + intero (di tipo \ctyp{int}) \val{EOF}\footnote{la costante deve essere + negativa, le \acr{glibc} usano -1, altre implementazioni possono avere + valori diversi.} definito anch'esso nell'header \headfile{stdlib.h}. + + Dato che le funzioni dell'interfaccia degli \textit{stream} sono funzioni di + libreria che si appoggiano a delle \textit{system call}, esse non impostano + direttamente la variabile \var{errno}, che mantiene il valore impostato dalla + \textit{system call} che ha riportato l'errore. + + Siccome la condizione di end-of-file è anch'essa segnalata come errore, nasce + il problema di come distinguerla da un errore effettivo; basarsi solo sul + valore di ritorno della funzione e controllare il valore di \var{errno} + infatti non basta, dato che quest'ultimo potrebbe essere stato impostato in + una altra occasione, (si veda sez.~\ref{sec:sys_errno} per i dettagli del + funzionamento di \var{errno}). + + Per questo motivo tutte le implementazioni delle librerie standard mantengono + per ogni \textit{stream} almeno due flag all'interno dell'oggetto \type{FILE}, + il flag di \textit{end-of-file}, che segnala che si è raggiunta la fine del + file in lettura, e quello di errore, che segnala la presenza di un qualche + errore nelle operazioni di input/output; questi due flag possono essere + riletti dalle funzioni \funcd{feof} e \funcd{ferror}, i cui prototipi sono: + +\begin{funcproto}{ +\fhead{stdio.h} +\fdecl{int feof(FILE *stream)} +\fdesc{Controlla il flag di \textit{end-of-file} di uno \textit{stream}.} +\fdecl{int ferror(FILE *stream)} +\fdesc{Controlla il flag di errore di uno \textit{stream}.} +} + +{Le funzioni ritornano un valore diverso da zero se i relativi flag sono + impostati, e non prevedono condizioni di errore.} +\end{funcproto} + \noindent si tenga presente comunque che la lettura di questi flag segnala soltanto che c'è stato un errore, o che si è raggiunta la fine del file in una qualunque operazione sullo \textit{stream}, il controllo quindi deve essere effettuato ogni volta che si chiama una funzione di libreria. -Entrambi i flag (di errore e di end-of-file) possono essere cancellati usando -la funzione \funcd{clearerr}, il cui prototipo è: -\begin{prototype}{stdio.h}{void clearerr(FILE *stream)} - Cancella i flag di errore ed \textit{end-of-file} di \param{stream}. -\end{prototype} +Entrambi i flag (di errore e di \textit{end-of-file}) possono essere +cancellati usando la funzione \funcd{clearerr}, il cui prototipo è: + +\begin{funcproto}{ +\fhead{stdio.h} +\fdecl{void clearerr(FILE *stream)} +\fdesc{Cancella i flag di errore ed \textit{end-of-file} di uno + \textit{stream}.} +} + +{La funzione non ritorna nulla e prevede condizioni di errore.} +\end{funcproto} + \noindent in genere si usa questa funzione una volta che si sia identificata e corretta la causa di un errore per evitare di mantenere i flag attivi, così da poter rilevare una successiva ulteriore condizione di errore. Di questa @@ -2433,27 +2536,27 @@ lettura dei dati da un buffer verso un file e viceversa. In generale questa è la modalità che si usa quando si ha a che fare con dati non formattati. Le due funzioni che si usano per l'I/O binario sono \funcd{fread} ed \funcd{fwrite}; i loro prototipi sono: -\begin{functions} - \headdecl{stdio.h} - - \funcdecl{size\_t fread(void *ptr, size\_t size, size\_t nmemb, FILE - *stream)} - - \funcdecl{size\_t fwrite(const void *ptr, size\_t size, size\_t - nmemb, FILE *stream)} - - Rispettivamente leggono e scrivono \param{nmemb} elementi di dimensione - \param{size} dal buffer \param{ptr} al file \param{stream}. - - \bodydesc{Entrambe le funzioni ritornano il numero di elementi letti o - scritti, in caso di errore o fine del file viene restituito un numero di - elementi inferiore al richiesto.} -\end{functions} - -In genere si usano queste funzioni quando si devono trasferire su file -blocchi di dati binari in maniera compatta e veloce; un primo caso di uso -tipico è quello in cui si salva un vettore (o un certo numero dei suoi -elementi) con una chiamata del tipo: + +\begin{funcproto}{ +\fhead{stdio.h} +\fdecl{size\_t fread(void *ptr, size\_t size, size\_t nmemb, FILE *stream)} +\fdesc{Legge i dati da uno \textit{stream}.} +\fdecl{size\_t fwrite(const void *ptr, size\_t size, size\_t nmemb, + FILE *stream)} +\fdesc{Scrive i dati su uno \textit{stream}.} +} + +{Le funzioni ritornano il numero di elementi letti o scritti, in caso di + errore o fine del file viene restituito un numero di elementi inferiore al + richiesto.} +\end{funcproto} + +Le funzioni rispettivamente leggono e scrivono \param{nmemb} elementi di +dimensione \param{size} dal buffer \param{ptr} al file \param{stream}. In +genere si usano queste funzioni quando si devono trasferire su file blocchi di +dati binari in maniera compatta e veloce; un primo caso di uso tipico è quello +in cui si salva un vettore (o un certo numero dei suoi elementi) con una +chiamata del tipo: \includecodesnip{listati/WriteVect.c} in questo caso devono essere specificate le dimensioni di ciascun elemento ed il numero di quelli che si vogliono scrivere. Un secondo @@ -2507,20 +2610,22 @@ Le \acr{glibc} definiscono altre due funzioni per l'I/O binario, implicito dello \textit{stream}, usato per dalla librerie per la gestione delle applicazioni \itindex{thread} \textit{multi-thread} (si veda sez.~\ref{sec:file_stream_thread} per i dettagli), i loro prototipi sono: -\begin{functions} - \headdecl{stdio.h} - - \funcdecl{size\_t fread\_unlocked(void *ptr, size\_t size, size\_t + +\begin{funcproto}{ +\fhead{stdio.h} +\fdecl{size\_t fread\_unlocked(void *ptr, size\_t size, size\_t nmemb, FILE *stream)} - - \funcdecl{size\_t fwrite\_unlocked(const void *ptr, size\_t size, +\fdecl{size\_t fwrite\_unlocked(const void *ptr, size\_t size, size\_t nmemb, FILE *stream)} - - \bodydesc{Le funzioni sono identiche alle analoghe \func{fread} e - \func{fwrite} ma non acquisiscono il lock implicito sullo \textit{stream}.} -\end{functions} -\noindent entrambe le funzioni sono estensioni GNU previste solo dalle -\acr{glibc}. +\fdesc{Leggono o scrivono dati su uno \textit{stream} senza acquisire il lock + implicito sullo stesso.} +} + +{Le funzioni ritornano gli stessi valori delle precedenti \func{fread} e + \func{fwrite}.} +\end{funcproto} + +% TODO: trattare in generale le varie *_unlocked \subsection{Input/output a caratteri} @@ -2530,21 +2635,25 @@ La seconda modalità di input/output è quella a caratteri, in cui si trasferisce un carattere alla volta. Le funzioni per la lettura a caratteri sono tre, \funcd{fgetc}, \funcd{getc} e \funcd{getchar}, i rispettivi prototipi sono: -\begin{functions} - \headdecl{stdio.h} - - \funcdecl{int getc(FILE *stream)} Legge un byte da \param{stream} e lo - restituisce come intero. In genere è implementata come una macro. - - \funcdecl{int fgetc(FILE *stream)} Legge un byte da \param{stream} e lo - restituisce come intero. È sempre una funzione. - - \funcdecl{int getchar(void)} Equivalente a \code{getc(stdin)}. - - \bodydesc{Tutte queste funzioni leggono un byte alla volta, che viene - restituito come intero; in caso di errore o fine del file il valore - di ritorno è \val{EOF}.} -\end{functions} + +\begin{funcproto}{ +\fhead{stdio.h} +\fdecl{int getc(FILE *stream)} +\fdecl{int fgetc(FILE *stream)} +\fdesc{Leggono un singolo byte da uno \textit{stream}.} +\fdecl{int getchar(void)} +\fdesc{Legge un byte dallo \textit{standard input}.} +} + +{Le funzioni ritornano il byte letto in caso di successo e \val{EOF} per un + errore o se si arriva alla fine del file.} +\end{funcproto} + +La funzione \func{getc} legge un byte da \param{stream} e lo restituisce come +intero, ed in genere è implementata come una macro per cui può avere +\itindex{side~effects} \textit{side effects}, mentre \func{fgetc} è assicurato +essere sempre una funzione. Infine \func{getchar} è equivalente a +\code{getc(stdin)}. A parte \func{getchar}, che si usa in genere per leggere un carattere da tastiera, le altre due funzioni sono sostanzialmente equivalenti. La @@ -2571,45 +2680,52 @@ funzioni equivalenti alle precedenti, \funcd{getwc}, \funcd{fgetwc} e \funcd{getwchar}, che invece di un carattere di un byte restituiscono un carattere in formato esteso (cioè di tipo \ctyp{wint\_t}), il loro prototipo è: -\begin{functions} - \headdecl{stdio.h} - \headdecl{wchar.h} - - \funcdecl{wint\_t getwc(FILE *stream)} Legge un carattere esteso da - \param{stream}. In genere è implementata come una macro. - - \funcdecl{wint\_t fgetwc(FILE *stream)} Legge un carattere esteso da - \param{stream}. È una sempre una funzione. - - \funcdecl{wint\_t getwchar(void)} Equivalente a \code{getwc(stdin)}. - - \bodydesc{Tutte queste funzioni leggono un carattere alla volta, in - caso di errore o fine del file il valore di ritorno è \const{WEOF}.} -\end{functions} + +\begin{funcproto}{ +\fhead{stdio.h} +\fhead{wchar.h} +\fdecl{wint\_t getwc(FILE *stream)} +\fdecl{wint\_t fgetwc(FILE *stream)} +\fdesc{Leggono un carattere da uno \textit{stream}.} +\fdecl{wint\_t getwchar(void)} +\fdesc{Legge un carattere dallo \textit{standard input}.} +} + +{Le funzioni ritornano il carattere letto in caso di successo e \val{WEOF} per + un errore o se si arriva alla fine del file.} +\end{funcproto} + +La funzione \func{getwc} legge un carattere esteso da \param{stream} e lo +restituisce come intero, ed in genere è implementata come una macro, mentre +\func{fgetwc} è assicurata essere sempre una funzione. Infine \func{getwchar} +è equivalente a \code{getwc(stdin)}. + Per scrivere un carattere si possono usare tre funzioni, analoghe alle precedenti usate per leggere: \funcd{putc}, \funcd{fputc} e \funcd{putchar}; i loro prototipi sono: -\begin{functions} - \headdecl{stdio.h} - - \funcdecl{int putc(int c, FILE *stream)} Scrive il carattere \param{c} - su \param{stream}. In genere è implementata come una macro. - - \funcdecl{int fputc(int c, FILE *stream)} Scrive il carattere \param{c} su - \param{stream}. È una sempre una funzione. - - \funcdecl{int putchar(int c)} Equivalente a \code{putc(stdout)}. - - \bodydesc{Le funzioni scrivono sempre un carattere alla volta, il cui - valore viene restituito in caso di successo; in caso di errore o - fine del file il valore di ritorno è \val{EOF}.} -\end{functions} - -Tutte queste funzioni scrivono sempre un byte alla volta, anche se prendono -come argomento un \ctyp{int} (che pertanto deve essere ottenuto con un cast da -un \ctyp{unsigned char}). Anche il valore di ritorno è sempre un intero; in -caso di errore o fine del file il valore di ritorno è \val{EOF}. + +\begin{funcproto}{ +\fhead{stdio.h} +\fdecl{int putc(int c, FILE *stream)} +\fdecl{int fputc(int c, FILE *stream)} +\fdesc{Scrive un byte su uno \textit{stream}.} +\fdecl{int putchar(int c)} +\fdesc{Scrive un byte sullo \textit{standard output}.} +} + +{Le funzioni ritornano il valore del byte scritto in caso di successo e + \val{EOF} per un errore.} +\end{funcproto} + +La funzione \func{putc} scrive un byte su \param{stream} e lo restituisce come +intero, ed in genere è implementata come una macro, mentre \func{fputc} è +assicurata essere sempre una funzione. Infine \func{putchar} è equivalente a +\code{putc(stdout)}. Tutte queste funzioni scrivono sempre un byte alla +volta, anche se prendono come argomento un \ctyp{int} (che pertanto deve +essere ottenuto con un cast da un \ctyp{unsigned char}). Anche il valore di +ritorno è sempre un intero; in caso di errore o fine del file il valore di +ritorno è \val{EOF}. Come nel caso dell'I/O binario con \func{fread} e \func{fwrite} le \acr{glibc} provvedono come estensione, per ciascuna delle funzioni precedenti, @@ -2620,16 +2736,18 @@ il lock implicito dello \textit{stream}. Per compatibilità con SVID sono inoltre provviste anche due funzioni, \funcd{getw} e \funcd{putw}, da usare per leggere e scrivere una \textit{word} (cioè due byte in una volta); i loro prototipi sono: -\begin{functions} - \headdecl{stdio.h} - - \funcdecl{int getw(FILE *stream)} Legge una parola da \param{stream}. - \funcdecl{int putw(int w, FILE *stream)} Scrive la parola \param{w} su - \param{stream}. - - \bodydesc{Le funzioni restituiscono la parola \param{w}, o \val{EOF} - in caso di errore o di fine del file.} -\end{functions} + +\begin{funcproto}{ +\fhead{stdio.h} +\fdecl{getw(FILE *stream)} +\fdesc{Legge una parola da uno \textit{stream}.} +\fdecl{int putw(int w, FILE *stream)} +\fdesc{Scrive una parola su uno \textit{stream}.} +} + +{Le funzioni ritornano la parola letta o scritta in caso di successo e + \val{EOF} per un errore.} +\end{funcproto} Le funzioni leggono e scrivono una \textit{word} di due byte, usando comunque una variabile di tipo \ctyp{int}; il loro uso è deprecato in favore dell'uso @@ -2647,17 +2765,22 @@ Nel nostro caso questo tipo di comportamento può essere realizzato prima leggendo il carattere, e poi rimandandolo indietro, cosicché ridiventi disponibile per una lettura successiva; la funzione che inverte la lettura si chiama \funcd{ungetc} ed il suo prototipo è: -\begin{prototype}{stdio.h}{int ungetc(int c, FILE *stream)} - Rimanda indietro il carattere \param{c}, con un cast a \ctyp{unsigned - char}, sullo \textit{stream} \param{stream}. - - \bodydesc{La funzione ritorna \param{c} in caso di successo e - \val{EOF} in caso di errore.} -\end{prototype} -\noindent benché lo standard ANSI C preveda che l'operazione possa -essere ripetuta per un numero arbitrario di caratteri, alle -implementazioni è richiesto di garantire solo un livello; questo è -quello che fa la \acr{glibc}, che richiede che avvenga un'altra + +\begin{funcproto}{ +\fhead{stdio.h} +\fdecl{int ungetc(int c, FILE *stream)} +\fdesc{Manda indietro un byte su uno \textit{stream}.} +} + +{La funzione ritorna il byte inviato in caso di successo e \val{EOF} per un + errore.} +\end{funcproto} + +La funzione rimanda indietro il carattere \param{c}, con un cast a +\ctyp{unsigned char}, sullo \textit{stream} \param{stream}. Benché lo standard +ANSI C preveda che l'operazione possa essere ripetuta per un numero arbitrario +di caratteri, alle implementazioni è richiesto di garantire solo un livello; +questo è quello che fa la \acr{glibc}, che richiede che avvenga un'altra operazione fra due \func{ungetc} successive. Non è necessario che il carattere che si manda indietro sia l'ultimo che @@ -2692,19 +2815,18 @@ caratteristiche più controverse. Le funzioni previste dallo standard ANSI C per leggere una linea sono sostanzialmente due, \funcd{gets} e \funcd{fgets}, i cui rispettivi prototipi sono: -\begin{functions} - \headdecl{stdio.h} - - \funcdecl{char *gets(char *string)} Scrive su \param{string} una - linea letta da \var{stdin}. - - \funcdecl{char *fgets(char *string, int size, FILE *stream)} - Scrive su \param{string} la linea letta da \param{stream} per un - massimo di \param{size} byte. - - \bodydesc{Le funzioni restituiscono l'indirizzo \param{string} in caso - di successo o \val{NULL} in caso di errore.} -\end{functions} + +\begin{funcproto}{ +\fhead{stdio.h} +\fdecl{char *gets(char *string)} +\fdesc{Legge una linea di testo dallo \textit{standard input}.} +\fdecl{char *fgets(char *string, int size, FILE *stream)} +\fdesc{Legge una linea di testo da uno \textit{stream}.} +} + +{Le funzioni ritornano l'indirizzo della stringa con la linea di testo letta o + scritta in caso di successo e \val{NULL} per un errore.} +\end{funcproto} Entrambe le funzioni effettuano la lettura (dal file specificato \func{fgets}, dallo standard input \func{gets}) di una linea di caratteri (terminata dal @@ -2742,18 +2864,22 @@ successiva. Per la scrittura di una linea lo standard ANSI C prevede altre due funzioni, \funcd{fputs} e \funcd{puts}, analoghe a quelle di lettura, i rispettivi prototipi sono: -\begin{functions} - \headdecl{stdio.h} - - \funcdecl{int puts(const char *string)} Scrive su \var{stdout} la - linea \param{string}. - - \funcdecl{int fputs(const char *string, FILE *stream)} Scrive su - \param{stream} la linea \param{string}. - - \bodydesc{Le funzioni restituiscono un valore non negativo in caso di - successo o \val{EOF} in caso di errore.} -\end{functions} + +\begin{funcproto}{ +\fhead{stdio.h} +\fdecl{int puts(char *string)} +\fdesc{Scrive una linea di testo sullo \textit{standard output}.} +\fdecl{int fputs(char *string, int size, FILE *stream)} +\fdesc{Scrive una linea di testo su uno \textit{stream}.} +} + +{Le funzioni ritornano un valore non negativo in caso di successo e \val{EOF} + per un errore.} +\end{funcproto} + +La funzione \func{puts} scrive una linea di testo mantenuta +all'indirizzo \param{string} sullo \textit{standard output} mentre \func{puts} +la scrive sul file indicato da \param{stream}. Dato che in questo caso si scrivono i dati in uscita \func{puts} non ha i problemi di \func{gets} ed è in genere la forma più immediata per scrivere @@ -2767,21 +2893,25 @@ Come per le analoghe funzioni di input/output a caratteri, anche per l'I/O di linea esistono delle estensioni per leggere e scrivere linee di caratteri estesi, le funzioni in questione sono \funcd{fgetws} e \funcd{fputws} ed i loro prototipi sono: -\begin{functions} - \headdecl{wchar.h} - \funcdecl{wchar\_t *fgetws(wchar\_t *ws, int n, FILE *stream)} - Legge un massimo di \param{n} caratteri estesi dal file - \param{stream} al buffer \param{ws}. - - \funcdecl{int fputws(const wchar\_t *ws, FILE *stream)} Scrive la - linea \param{ws} di caratteri estesi sul file \param{stream}. - - \bodydesc{Le funzioni ritornano rispettivamente \param{ws} o un numero - non negativo in caso di successo e \val{NULL} o \val{EOF} in - caso di errore o fine del file.} -\end{functions} - -Il comportamento di queste due funzioni è identico a quello di \func{fgets} e + +\begin{funcproto}{ +\fhead{wchar.h} +\fdecl{wchar\_t *fgetws(wchar\_t *ws, int n, FILE *stream)} +\fdesc{Legge una stringa di carattere estesi da uno \textit{stream}.} +\fdecl{int fputws(const wchar\_t *ws, FILE *stream)} +\fdesc{Scrive una stringa di carattere estesi da uno \textit{stream}.} +} + +{Le funzioni ritornano rispettivamente l'indirizzo della stringa o un non + negativo in caso di successo e \val{NULL} o \val{EOF} per un errore o per la + fine del file.} +\end{funcproto} + + +La funzione \func{fgetws} legge un massimo di \param{n} caratteri estesi dal +file \param{stream} al buffer \param{ws}, mentre la funzione \func{fputws} +scrive la linea \param{ws} di caratteri estesi sul file \param{stream}. Il +comportamento di queste due funzioni è identico a quello di \func{fgets} e \func{fputs}, a parte il fatto che tutto (numero di caratteri massimo, terminatore della stringa, newline) è espresso in termini di caratteri estesi anziché di normali caratteri ASCII. @@ -2813,24 +2943,27 @@ definendo la macro \macro{\_GNU\_SOURCE} prima di includere \headfile{stdio.h}. La prima delle due, \funcd{getline}, serve per leggere una linea terminata da un newline, esattamente allo stesso modo di \func{fgets}, il suo prototipo è: -\begin{prototype}{stdio.h} - {ssize\_t getline(char **buffer, size\_t *n, FILE *stream)} Legge una linea - dal file \param{stream} copiandola sul buffer indicato da \param{buffer} - riallocandolo se necessario (l'indirizzo del buffer e la sua dimensione - vengono sempre riscritte). - - \bodydesc{La funzione ritorna il numero di caratteri letti in caso di - successo e -1 in caso di errore o di raggiungimento della fine del - file.} -\end{prototype} - -La funzione permette di eseguire una lettura senza doversi preoccupare della -eventuale lunghezza eccessiva della stringa da leggere. Essa prende come primo -argomento l'indirizzo del puntatore al buffer su cui si vuole copiare la -linea. Quest'ultimo \emph{deve} essere stato allocato in precedenza con una -\func{malloc} (non si può passare l'indirizzo di un puntatore ad una variabile -locale); come secondo argomento la funzione vuole l'indirizzo della variabile -contenente le dimensioni del buffer suddetto. + +\begin{funcproto}{ +\fhead{stdio.h} +\fdecl{ssize\_t getline(char **buffer, size\_t *n, FILE *stream)} +\fdesc{Legge una riga da uno \textit{stream}.} +} + +{La funzione ritorna il numero di caratteri letti in caso di successo e $-1$ + per un errore o per il raggiungimento della fine del file.} +\end{funcproto} + +La funzione legge una linea dal file \param{stream} copiandola sul buffer +indicato da \param{buffer} riallocandolo se necessario (l'indirizzo del buffer +e la sua dimensione vengono sempre riscritte). Permette così di eseguire una +lettura senza doversi preoccupare della eventuale lunghezza eccessiva della +stringa da leggere. Essa prende come primo argomento l'indirizzo del puntatore +al buffer su cui si vuole copiare la linea. Quest'ultimo \emph{deve} essere +stato allocato in precedenza con una \func{malloc} (non si può passare +l'indirizzo di un puntatore ad una variabile locale); come secondo argomento +la funzione vuole l'indirizzo della variabile contenente le dimensioni del +buffer suddetto. Se il buffer di destinazione è sufficientemente ampio la stringa viene scritta subito, altrimenti il buffer viene allargato usando \func{realloc} e la nuova @@ -2859,14 +2992,22 @@ un errore la funzione restituisce -1. La seconda estensione GNU è una generalizzazione di \func{getline} per poter usare come separatore un carattere qualsiasi, la funzione si chiama \funcd{getdelim} ed il suo prototipo è: -\begin{prototype}{stdio.h} -{ssize\_t getdelim(char **buffer, size\_t *n, int delim, FILE *stream)} - Identica a \func{getline} solo che usa \param{delim} al posto del - carattere di newline come separatore di linea. -\end{prototype} - -Il comportamento di \func{getdelim} è identico a quello di \func{getline} (che -può essere implementata da questa passando \verb|'\n'| come valore di + +\begin{funcproto}{ +\fhead{stdio.h} +\fdecl{size\_t getdelim(char **buffer, size\_t *n, int delim, FILE *stream)} +\fdesc{Legge da uno \textit{stream} una riga delimitata da un carattere + scelto.} +} + +{La funzione ha gli stessi valori di ritorno e gli stessi errori di + \func{getline}.} +\end{funcproto} + +La funzione è identica a \func{getline} solo che usa \param{delim} al posto +del carattere di newline come separatore di linea. Il comportamento di +\func{getdelim} è identico a quello di \func{getline} (che può essere +implementata da questa passando \verb|'\n'| come valore di \param{delim}). @@ -2881,41 +3022,53 @@ permette di stampare in maniera facile e veloce dati, tabelle e messaggi. L'output formattato viene eseguito con una delle 13 funzioni della famiglia \func{printf}; le tre più usate sono \funcd{printf}, \funcd{fprintf} e \funcd{sprintf}, i cui prototipi sono: -\begin{functions} - \headdecl{stdio.h} - \funcdecl{int printf(const char *format, ...)} Stampa su \file{stdout} - gli argomenti, secondo il formato specificato da \param{format}. - - \funcdecl{int fprintf(FILE *stream, const char *format, ...)} Stampa - su \param{stream} gli argomenti, secondo il formato specificato da - \param{format}. - - \funcdecl{int sprintf(char *str, const char *format, ...)} Stampa - sulla stringa \param{str} gli argomenti, secondo il formato - specificato da \param{format}. - - \bodydesc{Le funzioni ritornano il numero di caratteri stampati.} -\end{functions} -\noindent le prime due servono per stampare su file (lo standard output o -quello specificato) la terza permette di stampare su una stringa, in genere + +\begin{funcproto}{ +\fhead{stdio.h} +\fdecl{int printf(const char *format, ...)} +\fdesc{Scrive una stringa formattata sullo \textit{standard output}.} +\fdecl{int fprintf(FILE *stream, const char *format, ...)} +\fdesc{Scrive una stringa formattata su uno \textit{stream}.} +\fdecl{int sprintf(char *str, const char *format, ...)} +\fdesc{Scrive una stringa formattata su un buffer.} +} + +{Le funzioni ritornano il numero di caratteri scritti in caso di successo e un + valore negativo per un errore.} +\end{funcproto} + + +Le funzioni usano la stringa \param{format} come indicatore del formato con +cui dovrà essere scritto il contenuto degli argomenti, il cui numero +\index{funzioni!variadic} è variabile e dipende dal formato stesso. + +Le prime due servono per scrivere su file (lo \textit{standard output} o +quello specificato) la terza permette di scrivere su una stringa, in genere l'uso di \func{sprintf} è sconsigliato in quanto è possibile, se non si ha la sicurezza assoluta sulle dimensioni del risultato della stampa, eccedere le dimensioni di \param{str}, con conseguente sovrascrittura di altre variabili e possibili \itindex{buffer~overflow} \textit{buffer overflow}; per questo motivo si consiglia l'uso dell'alternativa \funcd{snprintf}, il cui prototipo è: -\begin{prototype}{stdio.h} -{snprintf(char *str, size\_t size, const char *format, ...)} - Identica a \func{sprintf}, ma non scrive su \param{str} più di - \param{size} caratteri. -\end{prototype} - -La parte più complessa delle funzioni di scrittura formattata è il formato -della stringa \param{format} che indica le conversioni da fare, e da cui -deriva anche il numero degli argomenti che dovranno essere passati a seguire -(si noti come tutte queste funzioni siano \index{funzioni!variadic} -\textit{variadic}, prendendo un numero di argomenti variabile che dipende -appunto da quello che si è specificato in \param{format}). + +\begin{funcproto}{ +\fhead{stdio.h} +\fdecl{snprintf(char *str, size\_t size, const char *format, ...)} +\fdesc{Scrive una stringa formattata su un buffer.} +} + +{La funzione ha lo stesso valore di ritorno e gli stessi errori di + \func{sprintf}.} +\end{funcproto} + +La funzione è identica a \func{sprintf}, ma non scrive su \param{str} più di +\param{size} caratteri. La parte più complessa delle funzioni di scrittura +formattata è il formato della stringa \param{format} che indica le conversioni +da fare, e da cui deriva anche il numero degli argomenti che dovranno essere +passati a seguire (si noti come tutte queste funzioni siano +\index{funzioni!variadic} \textit{variadic}, prendendo un numero di argomenti +variabile che dipende appunto da quello che si è specificato +in \param{format}). \begin{table}[htb] \centering @@ -3051,28 +3204,26 @@ manuale di \func{printf} e nella documentazione delle \acr{glibc}. \end{table} Una versione alternativa delle funzioni di output formattato, che permettono -di usare il puntatore ad una lista variabile \index{funzioni!variadic} di -argomenti (vedi sez.~\ref{sec:proc_variadic}), sono \funcd{vprintf}, -\funcd{vfprintf} e \funcd{vsprintf}, i cui prototipi sono: -\begin{functions} - \headdecl{stdio.h} - - \funcdecl{int vprintf(const char *format, va\_list ap)} Stampa su - \var{stdout} gli argomenti della lista \param{ap}, secondo il formato - specificato da \param{format}. - - \funcdecl{int vfprintf(FILE *stream, const char *format, va\_list ap)} - Stampa su \param{stream} gli argomenti della lista \param{ap}, secondo il - formato specificato da \param{format}. - - \funcdecl{int vsprintf(char *str, const char *format, va\_list ap)} Stampa - sulla stringa \param{str} gli argomenti della lista \param{ap}, secondo il - formato specificato da \param{format}. - - \bodydesc{Le funzioni ritornano il numero di caratteri stampati.} -\end{functions} -\noindent con queste funzioni diventa possibile selezionare gli argomenti che -si vogliono passare ad una funzione di stampa, passando direttamente la lista +di usare il puntatore ad una lista variabile di argomenti (vedi +sez.~\ref{sec:proc_variadic}), sono \funcd{vprintf}, \funcd{vfprintf} e +\funcd{vsprintf}, i cui prototipi sono: + +\begin{funcproto}{ +\fhead{stdio.h} +\fdecl{int vprintf(const char *format, va\_list ap)} +\fdesc{Scrive una stringa formattata sullo \textit{standard output}.} +\fdecl{int vfprintf(FILE *stream, const char *format, va\_list ap)} +\fdesc{Scrive una stringa formattata su un \textit{stream}.} +\fdecl{int vsprintf(char *str, const char *format, va\_list ap)} +\fdesc{Scrive una stringa formattata su un buffer.} +} + +{Le funzioni ritornano il numero di caratteri scritti in caso di successo e un + valore negativo per un errore.} +\end{funcproto} + +Con queste funzioni diventa possibile selezionare gli argomenti che si +vogliono passare ad una funzione di stampa, passando direttamente la lista tramite l'argomento \param{ap}. Per poter far questo ovviamente la lista variabile\index{funzioni!variadic} degli argomenti dovrà essere opportunamente trattata (l'argomento è esaminato in sez.~\ref{sec:proc_variadic}), e dopo @@ -3083,34 +3234,38 @@ l'esecuzione della funzione l'argomento Come per \func{sprintf} anche per \func{vsprintf} esiste una analoga \funcd{vsnprintf} che pone un limite sul numero di caratteri che vengono scritti sulla stringa di destinazione: -\begin{prototype}{stdio.h} -{vsnprintf(char *str, size\_t size, const char *format, va\_list ap)} - Identica a \func{vsprintf}, ma non scrive su \param{str} più di - \param{size} caratteri. -\end{prototype} + +\begin{funcproto}{ +\fhead{stdio.h} +\fdecl{vsnprintf(char *str, size\_t size, const char *format, va\_list ap)} +\fdesc{Scrive una stringa formattata su un buffer.} +} + +{La funzione ha lo stesso valore di ritorno e gli stessi errori di + \func{vsprintf}.} +\end{funcproto} + \noindent in modo da evitare possibili \itindex{buffer~overflow} buffer overflow. -Per eliminare alla radice questi problemi, le \acr{glibc} supportano una +Per eliminare alla radice questi problemi, la \acr{glibc} supporta una specifica estensione GNU che alloca dinamicamente tutto lo spazio necessario; l'estensione si attiva al solito definendo \macro{\_GNU\_SOURCE}, le due funzioni sono \funcd{asprintf} e \funcd{vasprintf}, ed i rispettivi prototipi sono: -\begin{functions} - \headdecl{stdio.h} - - \funcdecl{int asprintf(char **strptr, const char *format, ...)} Stampa gli - argomenti specificati secondo il formato specificato da \param{format} su - una stringa allocata automaticamente all'indirizzo \param{*strptr}. - - \funcdecl{int vasprintf(char **strptr, const char *format, va\_list ap)} - Stampa gli argomenti della lista \param{ap} secondo il formato specificato - da \param{format} su una stringa allocata automaticamente all'indirizzo - \param{*strptr}. - - \bodydesc{Le funzioni ritornano il numero di caratteri stampati.} -\end{functions} + +\begin{funcproto}{ +\fhead{stdio.h} +\fdecl{int asprintf(char **strptr, const char *format, ...)} +\fdecl{int vasprintf(char **strptr, const char *format, va\_list ap)} +\fdesc{Scrive una stringa formattata su un buffer.} +} + +{Le funzioni hanno lo stesso valore di ritorno e gli stessi errori di + \func{vsprintf}.} +\end{funcproto} + Entrambe le funzioni prendono come argomento \param{strptr} che deve essere l'indirizzo di un puntatore ad una stringa di caratteri, in cui verrà @@ -3134,26 +3289,31 @@ In corrispondenza alla famiglia di funzioni \func{printf} che si usano per l'output formattato, l'input formattato viene eseguito con le funzioni della famiglia \func{scanf}; fra queste le tre più importanti sono \funcd{scanf}, \funcd{fscanf} e \funcd{sscanf}, i cui prototipi sono: -\begin{functions} - \headdecl{stdio.h} \funcdecl{int scanf(const char *format, ...)} Esegue una - scansione di \file{stdin} cercando una corrispondenza di quanto letto con il - formato dei dati specificato da \param{format}, ed effettua le relative - conversione memorizzando il risultato negli argomenti seguenti. - - \funcdecl{int fscanf(FILE *stream, const char *format, ...)} Analoga alla - precedente, ma effettua la scansione su \param{stream}. - - \funcdecl{int sscanf(char *str, const char *format, ...)} Analoga alle - precedenti, ma effettua la scansione dalla stringa \param{str}. - - \bodydesc{Le funzioni ritornano il numero di elementi assegnati. Questi - possono essere in numero inferiore a quelli specificati, ed anche zero. - Quest'ultimo valore significa che non si è trovata corrispondenza. In caso - di errore o fine del file viene invece restituito \val{EOF}.} -\end{functions} -\noindent e come per le analoghe funzioni di scrittura esistono le relative -\funcm{vscanf}, \funcm{vfscanf} e \funcm{vsscanf} che usano un puntatore ad -una lista di argomenti. + +\begin{funcproto}{ +\fhead{stdio.h} +\fdecl{int scanf(const char *format, ...)} +\fdesc{Esegue la scansione di dati dallo \textit{standard input}.} +\fdecl{int fscanf(FILE *stream, const char *format, ...)} +\fdesc{Esegue la scansione di dati da uno \textit{stream}. } +\fdecl{int sscanf(char *str, const char *format, ...)} +\fdesc{Esegue la scansione di dati da un buffer.} +} + +{La funzione ritorna il numero di elementi assegnati in caso di successo e + \val{EOF} per un errore o se si raggiunta la fine del file.} +\end{funcproto} + +Le funzioni eseguono una scansione della rispettiva fonte di input cercando +una corrispondenza di quanto letto con il formato dei dati specificato +da \param{format}, ed effettua le relative conversione memorizzando il +risultato negli argomenti seguenti, il cui numero è variabile e dipende dal +valore di \param{format}. Come per le analoghe funzioni di scrittura esistono +le relative \funcm{vscanf}, \funcm{vfscanf} e \funcm{vsscanf} che usano un +puntatore ad una lista di argomenti. Le funzioni ritornano il numero di +elementi assegnati. Questi possono essere in numero inferiore a quelli +specificati, ed anche zero. Quest'ultimo valore significa che non si è trovata +corrispondenza. Tutte le funzioni della famiglia delle \func{scanf} vogliono come argomenti i puntatori alle variabili che dovranno contenere le conversioni; questo è un @@ -3221,57 +3381,63 @@ Tutto questo comporta la presenza di diverse funzioni che eseguono sostanzialmente le stesse operazioni, ma usano argomenti di tipo diverso. Le funzioni tradizionali usate per il riposizionamento della posizione in uno \textit{stream} sono \funcd{fseek} e \funcd{rewind} i cui prototipi sono: -\begin{functions} - \headdecl{stdio.h} - - \funcdecl{int fseek(FILE *stream, long offset, int whence)} Sposta la - posizione nello \textit{stream} secondo quanto specificato - tramite \param{offset} e \param{whence}. - \funcdecl{void rewind(FILE *stream)} Riporta la posizione nello - \textit{stream} all'inizio del file. -\end{functions} +\begin{funcproto}{ +\fhead{stdio.h} +\fdecl{int fseek(FILE *stream, long offset, int whence)} +\fdesc{Sposta la posizione nello \textit{stream}.} +\fdecl{void rewind(FILE *stream)} +\fdesc{Riporta la posizione nello \textit{stream} all'inizio del file.} +} + +{La funzione \func{fseek} ritorna $0$ in caso di successo e $-1$ per un + errore, nel qual caso \var{errno} assumerà i valori di \func{lseek}, + \func{rewind} non ritorna nulla e non ha condizioni di errore.} +\end{funcproto} L'uso di \func{fseek} è del tutto analogo a quello di \func{lseek} per i file descriptor, e gli argomenti, a parte il tipo, hanno lo stesso significato; in particolare \param{whence} assume gli stessi valori già visti in sez.~\ref{sec:file_lseek}. La funzione restituisce 0 in caso di successo e -1 in caso di errore. La funzione \func{rewind} riporta semplicemente la -posizione corrente all'inizio dello \textit{stream}, ma non esattamente +posizione corrente all'inizio dello \textit{stream}, ma non è esattamente equivalente ad una \code{fseek(stream, 0L, SEEK\_SET)} in quanto vengono cancellati anche i flag di errore e fine del file. Per ottenere la posizione corrente si usa invece la funzione \funcd{ftell}, il cui prototipo è: -\begin{prototype}{stdio.h}{long ftell(FILE *stream)} - Legge la posizione attuale nello \textit{stream} \param{stream}. - - \bodydesc{La funzione restituisce la posizione corrente, o -1 in caso - di fallimento, che può esser dovuto sia al fatto che il file non - supporta il riposizionamento che al fatto che la posizione non può - essere espressa con un \ctyp{long int}} -\end{prototype} -\noindent la funzione restituisce la posizione come numero di byte -dall'inizio dello \textit{stream}. + +\begin{funcproto}{ +\fhead{stdio.h} +\fdecl{long ftell(FILE *stream)} +\fdesc{Legge la posizione attuale nello \textit{stream}.} +} + +{La funzione ritorna la posizione corrente in caso di successo e $-1$ per un + errore, nel qual caso \var{errno} assumerà i valori di \func{lseek}.} +\end{funcproto} + + +La funzione restituisce la posizione come numero di byte dall'inizio dello +\textit{stream}. Queste funzioni esprimono tutte la posizione nel file come un \ctyp{long int}. Dato che (ad esempio quando si usa un filesystem indicizzato a 64 bit) questo può non essere possibile lo standard POSIX ha introdotto le nuove funzioni \funcd{fgetpos} e \funcd{fsetpos}, che invece usano il nuovo tipo \type{fpos\_t}, ed i cui prototipi sono: -\begin{functions} - \headdecl{stdio.h} - - \funcdecl{int fsetpos(FILE *stream, fpos\_t *pos)} Imposta la posizione - corrente nello \textit{stream} \param{stream} al valore specificato - da \param{pos}. - - \funcdecl{int fgetpos(FILE *stream, fpos\_t *pos)} Legge la posizione - corrente nello \textit{stream} \param{stream} e la scrive in \param{pos}. - - \bodydesc{Le funzioni ritornano 0 in caso di successo e -1 in caso di - errore.} -\end{functions} + +\begin{funcproto}{ +\fhead{stdio.h} +\fdecl{int fsetpos(FILE *stream, fpos\_t *pos)} +\fdesc{.} +\fdecl{int fgetpos(FILE *stream, fpos\_t *pos)} +\fdesc{.} +} + +{La funzione ritorna $0$ in caso di successo e $-1$ per un errore, nel qual + caso \var{errno} assumerà i valori di \func{lseek}.} +\end{funcproto} In Linux, a partire dalle glibc 2.1, sono presenti anche le due funzioni \func{fseeko} e \func{ftello}, che sono assolutamente identiche alle @@ -3301,13 +3467,18 @@ C non prevedono nessuna funzione come la \func{fcntl} per il controllo degli attributi dei file. Però, dato che ogni \textit{stream} si appoggia ad un file descriptor, si può usare la funzione \funcd{fileno} per ottenere quest'ultimo, il prototipo della funzione è: -\begin{prototype}{stdio.h}{int fileno(FILE *stream)} - Legge il file descriptor sottostante lo \textit{stream} \param{stream}. - - \bodydesc{Restituisce il numero del file descriptor in caso di successo, e - -1 qualora \param{stream} non sia valido, nel qual caso imposta - \var{errno} a \errval{EBADF}.} -\end{prototype} + +\begin{funcproto}{ +\fhead{stdio.h} +\fdecl{int fileno(FILE *stream)} +\fdesc{Legge il file descriptor sottostante lo \textit{stream}.} +} + +{La funzione ritorna il numero del file descriptor in caso di successo e $-1$ + per un errore, nel qual caso \var{errno} assumerà il valore \errval{EBADF} + se \param{stream} non è valido.} +\end{funcproto} + \noindent ed in questo modo diventa possibile usare direttamente \func{fcntl}. Questo permette di accedere agli attributi del file descriptor sottostante lo @@ -3323,31 +3494,43 @@ una subroutine, che a questo punto necessiterà di informazioni aggiuntive rispetto al semplice puntatore allo \textit{stream}; questo può essere evitato con le due funzioni \funcd{\_\_freadable} e \funcd{\_\_fwritable} i cui prototipi sono: -\begin{functions} - \headdecl{stdio\_ext.h} - \funcdecl{int \_\_freadable(FILE *stream)} - Restituisce un valore diverso da zero se \param{stream} consente la lettura. - - \funcdecl{int \_\_fwritable(FILE *stream)} - Restituisce un valore diverso da zero se \param{stream} consente la - scrittura. -\end{functions} + +\begin{funcproto}{ +\fhead{stdio\_ext.h} +\fdecl{int \_\_freadable(FILE *stream)} +\fdesc{Controlla se uno \textit{stream} consente la lettura.} +\fdecl{int \_\_fwritable(FILE *stream)} +\fdesc{Controlla se uno \textit{stream} consente la scrittura.} +} + +{Le funzioni ritornano un valore diverso da $0$ se l'operazione richiesta è + consentita, non sono previste condizioni di errore.} +\end{funcproto} + \noindent che permettono di ottenere questa informazione. La conoscenza dell'ultima operazione effettuata su uno \textit{stream} aperto è utile in quanto permette di trarre conclusioni sullo stato del buffer e del suo contenuto. Altre due funzioni, \funcd{\_\_freading} e \funcd{\_\_fwriting} servono a tale scopo, il loro prototipo è: -\begin{functions} - \headdecl{stdio\_ext.h} - \funcdecl{int \_\_freading(FILE *stream)} - Restituisce un valore diverso da zero se \param{stream} è aperto in sola - lettura o se l'ultima operazione è stata di lettura. - \funcdecl{int \_\_fwriting(FILE *stream)} - Restituisce un valore diverso da zero se \param{stream} è aperto in sola - scrittura o se l'ultima operazione è stata di scrittura. -\end{functions} +\begin{funcproto}{ +\fhead{stdio\_ext.h} +\fdecl{int \_\_freading(FILE *stream)} +\fdesc{Controlla l'ultima operazione di lettura.} +\fdecl{int \_\_fwriting(FILE *stream)} +\fdesc{Controlla l'ultima operazione di scrittura.} +} + +{Le funzioni ritornano un valore diverso da $0$ se l'operazione richiesta è + consentita, non sono previste condizioni di errore.} +\end{funcproto} + +La funzione \func{\_\_freading} restituisce un valore diverso da zero +se \param{stream} è aperto in sola lettura o se l'ultima operazione è stata di +lettura mentre \func{\_\_fwriting} restituisce un valore diverso da zero +se \param{stream} è aperto in sola scrittura o se l'ultima operazione è stata +di scrittura. Le due funzioni permettono di determinare di che tipo è stata l'ultima operazione eseguita su uno \textit{stream} aperto in lettura/scrittura; @@ -3370,22 +3553,24 @@ Però una volta che si sia aperto lo \textit{stream} (ma prima di aver compiuto operazioni su di esso) è possibile intervenire sulle modalità di buffering; la funzione che permette di controllare la bufferizzazione è \funcd{setvbuf}, il suo prototipo è: -\begin{prototype}{stdio.h}{int setvbuf(FILE *stream, char *buf, int mode, - size\_t size)} - - Imposta la bufferizzazione dello \textit{stream} \param{stream} nella - modalità indicata da \param{mode}, usando \param{buf} come buffer di - lunghezza - \param{size}. - - \bodydesc{Restituisce zero in caso di successo, ed un valore qualunque in - caso di errore, nel qual caso \var{errno} viene impostata opportunamente.} -\end{prototype} - -La funzione permette di controllare tutti gli aspetti della bufferizzazione; -l'utente può specificare un buffer da usare al posto di quello allocato dal -sistema passandone alla funzione l'indirizzo in \param{buf} e la dimensione in -\param{size}. + +\begin{funcproto}{ +\fhead{stdio.h} +\fdecl{int setvbuf(FILE *stream, char *buf, int mode, size\_t size)} +\fdesc{Imposta la bufferizzazione dello \textit{stream}.} +} + +{La funzione ritorna $0$ in caso di successo e un altro valore qualunque per + un errore, nel qual caso \var{errno} assumerà un valore appropriato.} +\end{funcproto} + + +La funzione imposta la bufferizzazione dello \textit{stream} \param{stream} +nella modalità indicata da \param{mode}, usando \param{buf} come buffer di +lunghezza \param{size} e permette di controllare tutti gli aspetti della +bufferizzazione; l'utente può specificare un buffer da usare al posto di +quello allocato dal sistema passandone alla funzione l'indirizzo +in \param{buf} e la dimensione in \param{size}. Ovviamente se si usa un buffer specificato dall'utente questo deve essere stato allocato e rimanere disponibile per tutto il tempo in cui si opera sullo @@ -3436,49 +3621,63 @@ vengono sempre ignorati. Oltre a \func{setvbuf} le \acr{glibc} definiscono altre tre funzioni per la gestione della bufferizzazione di uno \textit{stream}: \funcd{setbuf}, \funcd{setbuffer} e \funcd{setlinebuf}; i loro prototipi sono: -\begin{functions} - \headdecl{stdio.h} - - \funcdecl{void setbuf(FILE *stream, char *buf)} Disabilita la - bufferizzazione se \param{buf} è \val{NULL}, altrimenti usa \param{buf} - come buffer di dimensione \const{BUFSIZ} in modalità \textit{fully buffered}. - - \funcdecl{void setbuffer(FILE *stream, char *buf, size\_t size)} Disabilita - la bufferizzazione se \param{buf} è \val{NULL}, altrimenti usa \param{buf} - come buffer di dimensione \param{size} in modalità \textit{fully buffered}. - - \funcdecl{void setlinebuf(FILE *stream)} Pone lo \textit{stream} in modalità - \textit{line buffered}. -\end{functions} -\noindent tutte queste funzioni sono realizzate con opportune chiamate a -\func{setvbuf} e sono definite solo per compatibilità con le vecchie librerie -BSD. Infine le \acr{glibc} provvedono le funzioni non standard\footnote{anche - queste funzioni sono originarie di Solaris.} \funcd{\_\_flbf} e + +\begin{funcproto}{ +\fhead{stdio.h} +\fdecl{void setbuf(FILE *stream, char *buf)} +\fdecl{void setbuffer(FILE *stream, char *buf, size\_t size)} +\fdesc{Impostano il buffer per uno \textit{stream}.} +\fdecl{void setlinebuf(FILE *stream)} +\fdesc{Porta uno \textit{stream} in modalità \textit{line buffered}.} +} + +{Le funzioni non ritornano niente e non hanno condizioni di errore.} +\end{funcproto} + + +La funzione \func{setbuf} disabilita la bufferizzazione se \param{buf} è +\val{NULL}, altrimenti usa \param{buf} come buffer di dimensione +\const{BUFSIZ} in modalità \textit{fully buffered}, mentre \func{setbuffer} +disabilita la bufferizzazione se \param{buf} è \val{NULL}, altrimenti +usa \param{buf} come buffer di dimensione \param{size} in modalità +\textit{fully buffered}. Tutte queste funzioni sono realizzate con opportune +chiamate a \func{setvbuf} e sono definite solo per compatibilità con le +vecchie librerie BSD. + +Infine le \acr{glibc} provvedono le funzioni non standard\footnote{anche + queste funzioni sono originarie di Solaris.} \funcd{\_\_flbf} e \funcd{\_\_fbufsize} che permettono di leggere le proprietà di bufferizzazione di uno \textit{stream}; i cui prototipi sono: -\begin{functions} - \headdecl{stdio\_ext.h} - - \funcdecl{int \_\_flbf(FILE *stream)} Restituisce un valore diverso da zero - se \param{stream} è in modalità \textit{line buffered}. - - \funcdecl{size\_t \_\_fbufsize(FILE *stream)} Restituisce le dimensioni del - buffer di \param{stream}. -\end{functions} + +\begin{funcproto}{ +\fhead{stdio\_ext.h} +\fdecl{size\_t \_\_fbufsize(FILE *stream)} +\fdesc{Restituisce le dimensioni del buffer di uno \textit{stream}.} +\fdecl{int \_\_flbf(FILE *stream)} +\fdesc{Controlla la modalità di bufferizzazione di uno \textit{stream}.} +} + +{Le funzioni ritornano rispettivamente la dimensione del buffer o un valore + non nullo se lo \textit{stream} è in modalità \textit{line-buffered}, non + sono previste condizioni di errore.} +\end{funcproto} Come già accennato, indipendentemente dalla modalità di bufferizzazione scelta, si può forzare lo scarico dei dati sul file con la funzione \funcd{fflush}, il suo prototipo è: -\begin{prototype}{stdio.h}{int fflush(FILE *stream)} - - Forza la scrittura di tutti i dati bufferizzati dello - \textit{stream} \param{stream}. - - \bodydesc{Restituisce zero in caso di successo, ed \val{EOF} in caso di - errore, impostando \var{errno} a \errval{EBADF} se \param{stream} non è - aperto o non è aperto in scrittura, o ad uno degli errori di - \func{write}.} -\end{prototype} + +\begin{funcproto}{ +\fhead{stdio.h} +\fdecl{int fflush(FILE *stream)} +\fdesc{Forza la scrittura dei dati bufferizzati di uno \textit{stream}.} +} + +{La funzione ritorna $0$ in caso di successo e \val{EOF} per un errore, nel + qual caso \var{errno} assumerà il valore \errval{EBADF} se \param{stream} + non è aperto o non è aperto in scrittura, o ad uno degli errori di + \func{write}.} +\end{funcproto} + \noindent anche di questa funzione esiste una analoga \func{fflush\_unlocked}\footnote{accessibile definendo \macro{\_BSD\_SOURCE} o \macro{\_SVID\_SOURCE} o \macro{\_GNU\_SOURCE}.} che non effettua il blocco @@ -3492,10 +3691,16 @@ essere sicuri che sia stato eseguito tutto l'output su terminale, in cui serve poter effettuare lo scarico dei dati solo per gli \textit{stream} in modalità line buffered; per questo motivo le \acr{glibc} supportano una estensione di Solaris, la funzione \funcd{\_flushlbf}, il cui prototipo è: -\begin{prototype}{stdio-ext.h}{void \_flushlbf(void)} - Forza la scrittura di tutti i dati bufferizzati degli \textit{stream} in - modalità line buffered. -\end{prototype} + +\begin{funcproto}{ +\fhead{stdio-ext.h} +\fdecl{void \_flushlbf(void)} +\fdesc{Forza la scrittura dei dati bufferizzati degli \textit{stream} in + modalità \textit{line buffered}.} +} + +{La funzione non ritorna nulla e non presenta condizioni di errore.} +\end{funcproto} Si ricordi comunque che lo scarico dei dati dai buffer effettuato da queste funzioni non comporta la scrittura di questi su disco; se si vuole che il @@ -3504,13 +3709,15 @@ usare \func{sync} o \func{fsync} (si veda~sez.~\ref{sec:file_sync}). Infine esistono anche circostanze in cui si vuole scartare tutto l'output pendente; per questo si può usare \funcd{fpurge}, il cui prototipo è: -\begin{prototype}{stdio.h}{int fpurge(FILE *stream)} - - Cancella i buffer di input e di output dello \textit{stream} \param{stream}. - - \bodydesc{Restituisce zero in caso di successo, ed \val{EOF} in caso di - errore.} -\end{prototype} + +\begin{funcproto}{ +\fhead{stdio.h} +\fdecl{int fpurge(FILE *stream)} +\fdesc{Cancella i buffer di uno \textit{stream}.} +} + +{La funzione ritorna $0$ in caso di successo e \val{EOF} per un errore.} +\end{funcproto} La funzione scarta tutti i dati non ancora scritti (se il file è aperto in scrittura), e tutto l'input non ancora letto (se è aperto in lettura), @@ -3540,40 +3747,51 @@ acquisito prima dell'esecuzione di qualunque operazione. Ci sono comunque situazioni in cui questo non basta, come quando un \textit{thread} necessita di compiere più di una operazione sullo \textit{stream} atomicamente, per questo motivo le librerie provvedono anche -delle funzioni \funcd{flockfile}, \funcd{ftrylockfile} e \funcd{funlockfile}, -che permettono la gestione esplicita dei blocchi sugli \textit{stream}; esse -sono disponibili definendo \macro{\_POSIX\_THREAD\_SAFE\_FUNCTIONS} ed i loro -prototipi sono: -\begin{functions} - \headdecl{stdio.h} - - \funcdecl{void flockfile(FILE *stream)} Esegue l'acquisizione del lock dello - \textit{stream} \param{stream}, bloccandosi se il lock non è disponibile. - - \funcdecl{int ftrylockfile(FILE *stream)} Tenta l'acquisizione del lock - dello \textit{stream} \param{stream}, senza bloccarsi se il lock non è - disponibile. Ritorna zero in caso di acquisizione del lock, diverso da zero - altrimenti. - - \funcdecl{void funlockfile(FILE *stream)} Rilascia il lock dello - \textit{stream} \param{stream}. -\end{functions} -\noindent con queste funzioni diventa possibile acquisire un blocco ed -eseguire tutte le operazioni volute, per poi rilasciarlo. - -Ma, vista la complessità delle strutture di dati coinvolte, le operazioni di -blocco non sono del tutto indolori, e quando il locking dello \textit{stream} -non è necessario (come in tutti i programmi che non usano i \textit{thread}), -tutta la procedura può comportare dei costi pesanti in termini di -prestazioni. Per questo motivo abbiamo visto come alle usuali funzioni di I/O -non formattato siano associate delle versioni \code{\_unlocked} (alcune -previste dallo stesso standard POSIX, altre aggiunte come estensioni dalle -\acr{glibc}) che possono essere usate quando il locking non serve\footnote{in - certi casi dette funzioni possono essere usate, visto che sono molto più - efficienti, anche in caso di necessità di locking, una volta che questo sia - stato acquisito manualmente.} con prestazioni molto più elevate, dato che -spesso queste versioni (come accade per \func{getc} e \func{putc}) sono -realizzate come macro. +delle funzioni \funcd{flockfile} e \funcd{funlockfile}, che permettono la +gestione esplicita dei blocchi sugli \textit{stream}; esse sono disponibili +definendo \macro{\_POSIX\_THREAD\_SAFE\_FUNCTIONS} ed i loro prototipi sono: + +\begin{funcproto}{ +\fhead{stdio.h} +\fdecl{void flockfile(FILE *stream)} +\fdesc{Acquisisce il lock su uno \textit{stream}.} +\fdecl{void funlockfile(FILE *stream)} +\fdesc{Rilascia il lock su uno \textit{stream}.} +} +{Le funzioni non ritornano nulla e non sono previste condizioni di errore.} +\end{funcproto} + +La funzione \func{flockfile} esegue l'acquisizione del lock dello +\textit{stream} \param{stream}, bloccandosi se il lock non è disponibile, +mentre \func{funlockfile} rilascia il lock. + +Si può poi provare ad acquisire un lock senza bloccarsi con +\funcd{ftrylockfile}, il cui prototipo è: + +\begin{funcproto}{ +\fhead{stdio.h} +\fdecl{int ftrylockfile(FILE *stream)} +\fdesc{Tenta l'acquisizione del lock di uno \textit{stream}.} +} + +{La funzione ritorna $0$ in caso di acquisizione del lock ed un altro valore + qualunque altrimenti, non sono previste condizioni di errore.} +\end{funcproto} + +Con queste funzioni diventa possibile acquisire un blocco ed eseguire tutte le +operazioni volute, per poi rilasciarlo. Ma, vista la complessità delle +strutture di dati coinvolte, le operazioni di blocco non sono del tutto +indolori, e quando il locking dello \textit{stream} non è necessario (come in +tutti i programmi che non usano i \textit{thread}), tutta la procedura può +comportare dei costi pesanti in termini di prestazioni. Per questo motivo +abbiamo visto come alle usuali funzioni di I/O non formattato siano associate +delle versioni \code{\_unlocked} (alcune previste dallo stesso standard POSIX, +altre aggiunte come estensioni dalle \acr{glibc}) che possono essere usate +quando il locking non serve\footnote{in certi casi dette funzioni possono + essere usate, visto che sono molto più efficienti, anche in caso di + necessità di locking, una volta che questo sia stato acquisito manualmente.} +con prestazioni molto più elevate, dato che spesso queste versioni (come +accade per \func{getc} e \func{putc}) sono realizzate come macro. La sostituzione di tutte le funzioni di I/O con le relative versioni \code{\_unlocked} in un programma che non usa i \textit{thread} è però un @@ -3582,19 +3800,21 @@ programmatore pigro un'altra via\footnote{anche questa mutuata da estensioni introdotte in Solaris.} da poter utilizzare per disabilitare in blocco il locking degli \textit{stream}: l'uso della funzione \funcd{\_\_fsetlocking}, il cui prototipo è: -\begin{prototype}{stdio\_ext.h}{int \_\_fsetlocking (FILE *stream, int type)} - Specifica o richiede a seconda del valore di \param{type} la modalità in cui - le operazioni di I/O su \param{stream} vengono effettuate rispetto - all'acquisizione implicita del blocco sullo \textit{stream}. - - \bodydesc{Restituisce lo stato di locking interno dello \textit{stream} con - uno dei valori \const{FSETLOCKING\_INTERNAL} o - \const{FSETLOCKING\_BYCALLER}.} -\end{prototype} - -La funzione imposta o legge lo stato della modalità di operazione di uno -\textit{stream} nei confronti del locking a seconda del valore specificato -con \param{type}, che può essere uno dei seguenti: + +\begin{funcproto}{ +\fhead{stdio\_ext.h} +\fdecl{int \_\_fsetlocking (FILE *stream, int type)} +\fdesc{Specifica se abilitare il locking su uno \textit{stream}.} +} + +{La funzione ritorna stato di locking interno dello \textit{stream}, non sono + previste condizioni di errore.} +\end{funcproto} + +La funzione imposta o legge lo stato della modalità in cui le operazioni di +I/O su \param{stream} vengono effettuate rispetto all'acquisizione implicita +del locking a seconda del valore specificato con \param{type}, che può essere +uno dei seguenti: \begin{basedescript}{\desclabelwidth{4.0cm}} \item[\const{FSETLOCKING\_INTERNAL}] Lo \textit{stream} userà da ora in poi il blocco implicito predefinito. @@ -3604,6 +3824,12 @@ con \param{type}, che può essere uno dei seguenti: di blocco dello \textit{stream}. \end{basedescript} +La funzione, se usata con \const{FSETLOCKING\_QUERY}, non modifica la modalità +di operazione ma restituisce lo stato di locking interno dello \textit{stream} +con uno dei valori \const{FSETLOCKING\_INTERNAL} o +\const{FSETLOCKING\_BYCALLER}. + + % TODO trattare \func{clearerr\_unlocked} @@ -3621,12 +3847,12 @@ con \param{type}, che può essere uno dei seguenti: % LocalWords: nell'header stdin shell stdout stderr error freopen flush line % LocalWords: unbuffered buffered newline fully SVr fopen fdopen POSIX const % LocalWords: char path int fildes NULL errno malloc fcntl fclose fflush tab -% LocalWords: dup fifo socket append EXCL ccs IRUSR IWUSR IRGRP IWGRP +% LocalWords: dup fifo socket append EXCL ccs IRUSR IWUSR IRGRP IWGRP inode fd % LocalWords: IROTH IWOTH umask fseek fsetpos rewind SEEK CUR EOF EBADF close -% LocalWords: sync fcloseall void stdlib of feof ferror clearerr ws +% LocalWords: sync fcloseall void stdlib of feof ferror clearerr ws VFS table % LocalWords: unlocked fread fwrite size ptr nmemb nelem gcc padding point str -% LocalWords: lock thread fgetc getc getchar dell'overhead unsigned ap -% LocalWords: getwc fgetwc getwchar wint wchar WEOF putc fputc putchar +% LocalWords: lock thread fgetc getc getchar dell'overhead unsigned ap process +% LocalWords: getwc fgetwc getwchar wint wchar WEOF putc fputc putchar struct % LocalWords: SVID getw putw parsing peeking ahead ungetc gets fgets string Di % LocalWords: overflow Aleph stack fputs puts fgetws fputws getline ssize leak % LocalWords: realloc value result argument memory getdelim delim printf short @@ -3637,14 +3863,31 @@ con \param{type}, che può essere uno dei seguenti: % LocalWords: lseek ftell fgetpos fpos fseeko ftello fileno Solaris freadable % LocalWords: fwritable ext freading fwriting buffering setvbuf BUFSIZ setbuf % LocalWords: IONBF IOLBF IOFBF setbuffer setlinebuf flbf fbufsize flushlbf hh -% LocalWords: fsync fpurge flockfile ftrylockfile funlockfile -% LocalWords: locking fsetlocking type Virtual operation -% LocalWords: modification hole functions FSETSIG - - - +% LocalWords: fsync fpurge flockfile ftrylockfile funlockfile files fig flags +% LocalWords: locking fsetlocking type Virtual operation dentry unistd sys AT +% LocalWords: modification hole functions FSETSIG pathname EEXIST CREAT EINTR +% LocalWords: EISDIR EFBIG EOVERFLOW ELOOP NOFOLLOW ENODEV ENOENT ENOTDIR fork %%% Local Variables: %%% mode: latex %%% TeX-master: "gapil" %%% End: +% LocalWords: ENXIO NONBLOCK WRONLY EPERM NOATIME ETXTBSY EWOULDBLOCK EACCES% LocalWords: EFAULT +% LocalWords: EMFILE ENAMETOOLONG ENFILE ENOMEM ENOSPC EROFS exec access RDWR +% LocalWords: RDONLY ioctl AND ACCMODE creation Denial Service DoS opendir NFS +% LocalWords: SOURCE LARGEFILE BITS NOCTTY TRUNC SHLOCK shared EXLOCK race SGI +% LocalWords: exclusive condition change ASYNC SIGIO CLOEXEC DIRECT NDELAY EIO +% LocalWords: DSYNC FASYNC IRIX FreeBSD EINVAL client RSYNC creat filedes INCR +% LocalWords: behind shutdown ESPIPE XTND truncate fallocate count EAGAIN log +% LocalWords: timerfd Specification pwrite pread define XOPEN EPIPE SIGPIPE at +% LocalWords: caching cache update bdflush fdatasync fstat oldfd newfd DUPFD +% LocalWords: openat mkdirat mkdir proc ATFILE dirfd FDCWD utimes lutimes uid +% LocalWords: utimensat faccessat fchmodat chmod fchownat chown lchown fstatat +% LocalWords: lstat linkat mknodat mknod readlinkat readlink renameat rename +% LocalWords: symlinkat symlink unlinkat unlink rmdir mkfifoat mkfifo owner is +% LocalWords: gid group FOLLOW REMOVEDIR cmd arg flock SETFD GETFD GETFL SETFL +% LocalWords: GETLK SETLK SETLKW GETOWN PID Signal SIGURG SETOWN GETSIG SETSIG +% LocalWords: sigaction SIGINFO siginfo SETLEASE lease GETLEASE NOTIFY request +% LocalWords: everything framebuffer ENOTTY argp CDROM lsattr chattr magic +% LocalWords: number FIOCLEX FIONCLEX FIOASYNC FIONBIO FIOSETOWN FIOGETOWN +% LocalWords: FIONREAD epoll FIOQSIZE side effects SAFE BYCALLER QUERY diff --git a/ipc.tex b/ipc.tex index 3d567b5..59c7f83 100644 --- a/ipc.tex +++ b/ipc.tex @@ -185,10 +185,9 @@ duplicazione dei file descriptor che abbiamo trattato in sez.~\ref{sec:file_dup}, in particolare di \func{dup2}. È attraverso queste funzioni infatti che è possibile dirottare gli stream standard dei processi (che abbiamo visto in tab.~\ref{tab:file_std_files} e -sez.~\ref{sec:file_std_stream}) sulla pipe. In -fig.~\ref{fig:ipc_barcodepage_code} abbiamo riportato il corpo del programma, -il cui codice completo è disponibile nel file \file{BarCodePage.c} che si -trova nella directory dei sorgenti. +sez.~\ref{sec:file_stream}) sulla pipe. In fig.~\ref{fig:ipc_barcodepage_code} +abbiamo riportato il corpo del programma, il cui codice completo è disponibile +nel file \file{BarCodePage.c} che si trova nella directory dei sorgenti. \begin{figure}[!htbp] \footnotesize \centering @@ -3053,7 +3052,7 @@ La prima possibilità, utilizzata fin dalle origini di Unix, è quella di usare dei \textsl{file di lock} (per i quali esiste anche una opportuna directory, \file{/var/lock}, nel filesystem standard). Per questo si usa la caratteristica della funzione \func{open} (illustrata in -sez.~\ref{sec:file_open}) che prevede\footnote{questo è quanto dettato dallo +sez.~\ref{sec:file_open_close}) che prevede\footnote{questo è quanto dettato dallo standard POSIX.1, ciò non toglie che in alcune implementazioni questa tecnica possa non funzionare; in particolare per Linux, nel caso di NFS, si è comunque soggetti alla possibilità di una \itindex{race~condition} @@ -3085,7 +3084,7 @@ cancella con \func{unlink}. \end{figure} Uno dei limiti di questa tecnica è che, come abbiamo già accennato in -sez.~\ref{sec:file_open}, questo comportamento di \func{open} può non +sez.~\ref{sec:file_open_close}, questo comportamento di \func{open} può non funzionare (la funzione viene eseguita, ma non è garantita l'atomicità dell'operazione) se il filesystem su cui si va ad operare è su NFS; in tal caso si può adottare una tecnica alternativa che prevede l'uso della @@ -3419,7 +3418,7 @@ diversi. La funzione è del tutto analoga ad \func{open} ed analoghi sono i valori che possono essere specificati per \param{oflag}, che deve essere specificato come maschera binaria; i valori possibili per i vari bit sono quelli visti in -sez.~\ref{sec:file_open} dei quali però \func{mq\_open} riconosce solo i +sez.~\ref{sec:file_open_close} dei quali però \func{mq\_open} riconosce solo i seguenti: \begin{basedescript}{\desclabelwidth{2.2cm}\desclabelstyle{\nextlinelabel}} \item[\const{O\_RDONLY}] Apre la coda solo per la ricezione di messaggi. Il @@ -3849,7 +3848,7 @@ La funzione è del tutto analoga ad \func{open} ed analoghi sono i valori che possono essere specificati per \param{oflag}, che deve essere specificato come maschera binaria comprendente almeno uno dei due valori \const{O\_RDONLY} e \const{O\_RDWR}; i valori possibili per i vari bit sono quelli visti in -sez.~\ref{sec:file_open} dei quali però \func{shm\_open} riconosce solo +sez.~\ref{sec:file_open_close} dei quali però \func{shm\_open} riconosce solo i seguenti: \begin{basedescript}{\desclabelwidth{2.0cm}\desclabelstyle{\nextlinelabel}} \item[\const{O\_RDONLY}] Apre il file descriptor associato al segmento di @@ -3871,7 +3870,7 @@ In caso di successo la funzione restituisce un file descriptor associato al segmento di memoria condiviso con le stesse modalità di \func{open}\footnote{in realtà, come accennato, \func{shm\_open} è un semplice wrapper per \func{open}, usare direttamente quest'ultima avrebbe lo stesso - effetto.} viste in sez.~\ref{sec:file_open}; in particolare viene impostato + effetto.} viste in sez.~\ref{sec:file_open_close}; in particolare viene impostato il flag \const{FD\_CLOEXEC}. Chiamate effettuate da diversi processi usando lo stesso nome, restituiranno file descriptor associati allo stesso segmento (così come, nel caso di file di dati, essi sono associati allo stesso @@ -4037,7 +4036,7 @@ automaticamente un nome nella forma \texttt{sem.qualchenome}.\footnote{si ha L'argomento \param{oflag} è quello che controlla le modalità con cui opera la funzione, ed è passato come maschera binaria; i bit corrispondono a quelli utilizzati per l'analogo argomento di \func{open}, anche se dei possibili -valori visti in sez.~\ref{sec:file_open} sono utilizzati soltanto +valori visti in sez.~\ref{sec:file_open_close} sono utilizzati soltanto \const{O\_CREAT} e \const{O\_EXCL}. Se si usa \const{O\_CREAT} si richiede la creazione del semaforo qualora diff --git a/process.tex b/process.tex index e99d198..4eb8d72 100644 --- a/process.tex +++ b/process.tex @@ -1018,7 +1018,7 @@ come quello dei \itindex{double~free} \textit{double~free} o i \begin{itemize*} \item se la variabile è posta a $0$ gli errori vengono ignorati; \item se la variabile è posta a $1$ viene stampato un avviso sullo - \textit{standard error} (vedi sez.~\ref{sec:file_std_stream}); + \textit{standard error} (vedi sez.~\ref{sec:file_fd}); \item se la variabile è posta a $2$ viene chiamata la funzione \func{abort} (vedi sez.~\ref{sec:sig_alarm_abort}), che in genere causa l'immediata terminazione del programma; diff --git a/session.tex b/session.tex index 12e2beb..6fd9027 100644 --- a/session.tex +++ b/session.tex @@ -336,13 +336,13 @@ divenuto un nuovo leader di sessione dovrà riottenere\footnote{solo quando ciò sempre vera.}, un terminale di controllo. In generale questo viene fatto automaticamente dal sistema\footnote{a meno di non avere richiesto esplicitamente che questo non diventi un terminale di controllo con il flag - \const{O\_NOCTTY} (vedi sez.~\ref{sec:file_open}). In questo Linux segue la - semantica di SVr4; BSD invece richiede che il terminale venga allocato - esplicitamente con una \func{ioctl} con il comando \const{TIOCSCTTY}.} -quando viene aperto il primo terminale (cioè uno dei vari file di dispositivo -\file{/dev/tty*}) che diventa automaticamente il terminale di controllo, -mentre il processo diventa il \textsl{processo di controllo} di quella -sessione. + \const{O\_NOCTTY} (vedi sez.~\ref{sec:file_open_close}). In questo Linux + segue la semantica di SVr4; BSD invece richiede che il terminale venga + allocato esplicitamente con una \func{ioctl} con il comando + \const{TIOCSCTTY}.} quando viene aperto il primo terminale (cioè uno dei +vari file di dispositivo \file{/dev/tty*}) che diventa automaticamente il +terminale di controllo, mentre il processo diventa il \textsl{processo di + controllo} di quella sessione. In genere (a meno di redirezioni) nelle sessioni di lavoro questo terminale è associato ai file standard (di input, output ed error) dei processi nella @@ -1193,8 +1193,8 @@ disco e agli altri dispositivi. -\subsection{L'architettura} -\label{sec:term_design} +\subsection{L'architettura dell'I/O su terminale} +\label{sec:term_io_design} I terminali sono una classe speciale di dispositivi a caratteri (si ricordi la classificazione di sez.~\ref{sec:file_file_types}); un terminale ha infatti una @@ -1232,6 +1232,9 @@ una delle principali infatti è che essi prevedono due modalità di operazione, dette rispettivamente ``\textsl{modo canonico}'' e ``\textsl{modo non canonico}'', che hanno dei comportamenti nettamente diversi. +% TODO: inserire qui il comportamento di read relativo all'errore EIO sulla +% lettura in background??? + La modalità preimpostata all'apertura del terminale è quella canonica, in cui le operazioni di lettura vengono sempre effettuate assemblando i dati in una linea;\footnote{per cui eseguendo una \func{read} su un terminale in modo @@ -1641,7 +1644,7 @@ valore. e che le linee di controllo del modem devono essere ignorate. Se non impostato effettuando una chiamata ad \func{open} senza aver specificato il flag di - \const{O\_NOBLOCK} si bloccherà il processo finché + \const{O\_NONBLOCK} si bloccherà il processo finché non si è stabilita una connessione con il modem; inoltre se viene rilevata una disconnessione viene inviato un segnale di \signal{SIGHUP} al processo di controllo del @@ -2396,7 +2399,7 @@ Qui vanno le cose su \func{openpty} e compagnia. % LocalWords: BRKINT IGNCR carriage return newline ICRNL INLCR IUCLC IXON NL % LocalWords: IXANY IXOFF IMAXBEL iflag OPOST CR OCRNL OLCUC ONLCR ONOCR OFILL % LocalWords: ONLRET OFDEL NLDLY CRDLY TABDLY BSDLY backspace BS VTDLY FFDLY -% LocalWords: form feed FF oflag CLOCAL NOBLOCK of HUPCL CREAD CSTOPB PARENB +% LocalWords: form feed FF oflag CLOCAL of HUPCL CREAD CSTOPB PARENB % LocalWords: PARODD CSIZE CS CBAUD CBAUDEX CIBAUD CRTSCTS RTS CTS cflag ECHO % LocalWords: ICANON ECHOE ERASE ECHOPRT ECHOK ECHOKE ECHONL ECHOCTL ctrl ISIG % LocalWords: INTR QUIT SUSP IEXTEN EOL LNEXT REPRINT WERASE NOFLSH and TOSTOP diff --git a/sockctrl.tex b/sockctrl.tex index 9bc9336..8d0f5b9 100644 --- a/sockctrl.tex +++ b/sockctrl.tex @@ -2386,12 +2386,12 @@ avuto un crollo del sistema ed è stata riavviata, per cui dopo il riavvio la connessione non esiste più.\footnote{si ricordi che un normale riavvio o il crollo dell'applicazione non ha questo effetto, in quanto in tal caso si passa sempre per la chiusura del processo, e questo, come illustrato in - sez.~\ref{sec:file_close}, comporta anche la regolare chiusura del socket - con l'invio di un segmento FIN all'altro capo della connessione.} In questo -caso all'invio del messaggio di \textit{keep-alive} si otterrà come risposta -un segmento RST che indica che l'altro capo non riconosce più l'esistenza -della connessione ed il socket verrà chiuso riportando un errore di -\errcode{ECONNRESET}. + sez.~\ref{sec:file_open_close}, comporta anche la regolare chiusura del + socket con l'invio di un segmento FIN all'altro capo della connessione.} In +questo caso all'invio del messaggio di \textit{keep-alive} si otterrà come +risposta un segmento RST che indica che l'altro capo non riconosce più +l'esistenza della connessione ed il socket verrà chiuso riportando un errore +di \errcode{ECONNRESET}. Se invece non viene ricevuta nessuna risposta (indice che la macchina non è più raggiungibile) l'emissione dei messaggi viene ripetuta ad intervalli di 75 diff --git a/system.tex b/system.tex index 9859062..e745a7c 100644 --- a/system.tex +++ b/system.tex @@ -407,10 +407,10 @@ riportate in tab.~\ref{tab:sys_file_macro}. \const{PIPE\_BUF}&4096 & Byte scrivibili atomicamente in una pipe (vedi sez.~\ref{sec:ipc_pipes}).\\ \const{MAX\_CANON}&255 & Dimensione di una riga di terminale in modo - canonico (vedi sez.~\ref{sec:term_design}).\\ + canonico (vedi sez.~\ref{sec:term_io_design}).\\ \const{MAX\_INPUT}&255 & Spazio disponibile nella coda di input del terminale (vedi - sez.~\ref{sec:term_design}).\\ + sez.~\ref{sec:term_io_design}).\\ \hline \end{tabular} \caption{Costanti per i limiti sulle caratteristiche dei file.} diff --git a/tcpsock.tex b/tcpsock.tex index 8450373..fb63b0b 100644 --- a/tcpsock.tex +++ b/tcpsock.tex @@ -1222,9 +1222,9 @@ socket BSD fanno questa assunzione. \subsection{La funzione \func{close}} \label{sec:TCP_func_close} -La funzione standard Unix \func{close} (vedi sez.~\ref{sec:file_close}) che si -usa sui file può essere usata con lo stesso effetto anche sui file descriptor -associati ad un socket. +La funzione standard Unix \func{close} (vedi sez.~\ref{sec:file_open_close}) +che si usa sui file può essere usata con lo stesso effetto anche sui file +descriptor associati ad un socket. L'azione di questa funzione quando applicata a socket è di marcarlo come chiuso e ritornare immediatamente al processo. Una volta chiamata il socket @@ -3303,17 +3303,17 @@ con il ciclo (\texttt{\small 8--10}) in cui si impostano i socket trovati attivi. Per far questo si usa la caratteristica dei file descriptor, descritta in -sez.~\ref{sec:file_open}, per cui il kernel associa sempre ad ogni nuovo file -il file descriptor con il valore più basso disponibile. Questo fa sì che si -possa eseguire il ciclo (\texttt{\small 8}) a partire da un valore minimo, che -sarà sempre quello del socket in ascolto, mantenuto in \var{list\_fd}, fino al -valore massimo di \var{max\_fd} che dovremo aver cura di tenere aggiornato. -Dopo di che basterà controllare (\texttt{\small 9}) nella nostra tabella se il -file descriptor è in uso o meno,\footnote{si tenga presente che benché il - kernel assegni sempre il primo valore libero, dato che nelle operazioni i - socket saranno aperti e chiusi in corrispondenza della creazione e - conclusione delle connessioni, si potranno sempre avere dei \textsl{buchi} - nella nostra tabella.} e impostare \var{fset} di conseguenza. +sez.~\ref{sec:file_open_close}, per cui il kernel associa sempre ad ogni nuovo +file il file descriptor con il valore più basso disponibile. Questo fa sì che +si possa eseguire il ciclo (\texttt{\small 8}) a partire da un valore minimo, +che sarà sempre quello del socket in ascolto, mantenuto in \var{list\_fd}, +fino al valore massimo di \var{max\_fd} che dovremo aver cura di tenere +aggiornato. Dopo di che basterà controllare (\texttt{\small 9}) nella nostra +tabella se il file descriptor è in uso o meno,\footnote{si tenga presente che + benché il kernel assegni sempre il primo valore libero, dato che nelle + operazioni i socket saranno aperti e chiusi in corrispondenza della + creazione e conclusione delle connessioni, si potranno sempre avere dei + \textsl{buchi} nella nostra tabella.} e impostare \var{fset} di conseguenza. Una volta inizializzato con i socket aperti il nostro \textit{file descriptor set} potremo chiamare \func{select} per fargli osservare lo stato degli -- 2.30.2