Correzioni e aggiunte secondo le indicazioni di D. Masini, terza e
[gapil.git] / filestd.tex
index aa4ecff..8ab8956 100644 (file)
@@ -531,21 +531,20 @@ lo svantaggio di dipendere strettamente dalla piattaforma di sviluppo
 usata ed in genere possono essere riletti senza problemi solo dallo
 stesso programma che li ha prodotti.
 
-Infatti diversi compilatori possono eseguire ottimizzazioni diverse
-delle strutture dati e alcuni compilatori (come il \cmd{gcc}) possono
-anche scegliere se ottimizzare l'occupazione di spazio, impacchettando
-più strettamente i dati, o la velocità inserendo opportuni
-\textit{padding} per l'allineamento dei medesimi generando quindi output
-binari diversi. Inoltre altre incompatibilità si possono presentare
-quando entrano in gioco differenze di architettura hardware, come la
-dimensione del bus o la modalità di ordinamento dei bit o il formato
-delle variabili in floating point.
-
-Per questo motivo quando si usa l'input/output binario occorre sempre
-essere prendere le opportune precauzioni (in genere usare un formato di
-più alto livello che permetta di recuperare l'informazione completa),
-per assicurarsi che versioni diverse del programma siano in grado di
-rileggere i dati tenendo conto delle eventuali differenze.
+Infatti diversi compilatori possono eseguire ottimizzazioni diverse delle
+strutture dati e alcuni compilatori (come il \cmd{gcc}) possono anche
+scegliere se ottimizzare l'occupazione di spazio, impacchettando più
+strettamente i dati, o la velocità inserendo opportuni \textit{padding} per
+l'allineamento dei medesimi generando quindi output binari diversi. Inoltre
+altre incompatibilità si possono presentare quando entrano in gioco differenze
+di architettura hardware, come la dimensione del bus o la modalità di
+ordinamento dei bit o il formato delle variabili in floating point.
+
+Per questo motivo quando si usa l'input/output binario occorre sempre prendere
+le opportune precauzioni (in genere usare un formato di più alto livello che
+permetta di recuperare l'informazione completa), per assicurarsi che versioni
+diverse del programma siano in grado di rileggere i dati tenendo conto delle
+eventuali differenze.
 
 Le \acr{glibc} definiscono altre due funzioni per l'I/O binario, che
 evitano il lock implicito dello stream, usato per dalla librerie per la
@@ -613,7 +612,7 @@ positivo, tranne in caso di errore o fine del file.
 Nelle estensioni GNU che provvedono la localizzazione sono definite tre
 funzioni equivalenti alle precedenti che invece di un carattere di un
 byte restituiscono un carattere in formato esteso (cioè di tipo
-\ctyp{wint\_t}, il loro prototipo è:
+\ctyp{wint\_t}), il loro prototipo è:
 \begin{functions}
   \headdecl{stdio.h} 
   \headdecl{wchar.h} 
@@ -678,12 +677,12 @@ loro prototipi sono:
 \func{fread} e \func{fwrite}, in quanto non è possibile distinguere il
 valore -1 da una condizione di errore che restituisce \macro{EOF}.
 
-Una degli usi più frequenti dell'input/output a caratteri è nei
-programmi di \textit{parsing} in cui si analizza il testo; in questo
-contesto diventa utile poter analizzare il carattere successivo da uno
-stream senza estrarlo effettivamente (la tecnica è detta \textit{peeking
-  ahead}) in modo che il programma possa regolarsi sulla base avendo
-dato una \textsl{sbirciatina} a quello che viene dopo. 
+Uno degli usi più frequenti dell'input/output a caratteri è nei programmi di
+\textit{parsing} in cui si analizza il testo; in questo contesto diventa utile
+poter analizzare il carattere successivo da uno stream senza estrarlo
+effettivamente (la tecnica è detta \textit{peeking ahead}) in modo che il
+programma possa regolarsi avendo dato una \textsl{sbirciatina} a quello che
+viene dopo.
 
 Nel nostro caso questo tipo di comportamento può essere realizzato prima
 leggendo il carattere, e poi rimandandolo indietro, cosicché ridiventi
@@ -726,10 +725,10 @@ scartati.
 \subsection{Input/output di linea}
 \label{sec:file_line_io}
 
-La terza ed ultima modalità di input/output non formattato è quella di
-linea, in cui legge o scrive una riga alla volta; questa è una modalità
-molto usata per l'I/O da terminale, ma che presenta le caratteristiche
-più controverse.
+La terza ed ultima modalità di input/output non formattato è quella di linea,
+in cui si legge o si scrive una riga alla volta; questa è una modalità molto
+usata per l'I/O da terminale, ma che presenta le caratteristiche più
+controverse.
 
 Le funzioni previste dallo standard ANSI C per leggere una linea sono
 sostanzialmente due, \func{gets} e \func{fgets}, i cui rispettivi
@@ -750,16 +749,17 @@ prototipi sono:
 
 Entrambe le funzioni effettuano la lettura (dal file specificato \func{fgets},
 dallo standard input \func{gets}) di una linea di caratteri (terminata dal
-carattere \textit{newline}, \verb|\n|, quello mappato sul tasto di ritorno a
-capo della tastiera), ma \func{gets} sostituisce \verb|\n| con uno zero,
+carattere \textit{newline}, \verb|'\n'|, quello mappato sul tasto di ritorno a
+capo della tastiera), ma \func{gets} sostituisce \verb|'\n'| con uno zero,
 mentre \func{fgets} aggiunge uno zero dopo il \textit{newline}, che resta
 dentro la stringa. Se la lettura incontra la fine del file (o c'è un errore)
 viene restituito un \macro{NULL}, ed il buffer \param{buf} non viene toccato.
 L'uso di \func{gets} è deprecato e deve essere assolutamente evitato; la
-funzione infatti non controlla il numero di byte letti, per cui nel caso
-la stringa letta superi le dimensioni del buffer, si avrà un
-\textit{buffer overflow}, con sovrascrittura della memoria del processo
-adiacente al buffer. 
+funzione infatti non controlla il numero di byte letti, per cui nel caso la
+stringa letta superi le dimensioni del buffer, si avrà un \textit{buffer
+  overflow}\index{buffer overflow}, con sovrascrittura della memoria del
+processo adiacente al buffer.\footnote{questa tecnica è spiegata in dettaglio
+  e con molta efficacia nell'ormai famoso articolo di Aleph1 \cite{StS}.}
 
 Questa è una delle vulnerabilità più sfruttate per guadagnare accessi
 non autorizzati al sistema (i cosiddetti \textit{exploit}), basta
@@ -768,17 +768,17 @@ forgiata per sovrascrivere gli indirizzi di ritorno nello stack
 (supposto che la \func{gets} sia stata chiamata da una subroutine), in
 modo da far ripartire l'esecuzione nel codice inviato nella stringa
 stessa (in genere uno \textit{shell code} cioè una sezione di programma
-lancia una shell).
-
-La funzione \func{fgets} non ha i precedenti problemi di \func{gets} in
-quanto prende in input la dimensione del buffer \param{size}, che non
-verrà mai ecceduta in lettura. La funzione legge fino ad un massimo di
-\param{size} caratteri (newline compreso), ed aggiunge uno zero di
-terminazione; questo comporta che la stringa possa essere al massimo di
-\var{size-1} caratteri.  Se la linea eccede la dimensione del buffer
-verranno letti solo \var{size-1} caratteri, ma la stringa sarà sempre
-terminata correttamente con uno zero finale; sarà possibile leggere i
-restanti caratteri in una chiamata successiva.
+che lancia una shell).
+
+La funzione \func{fgets} non ha i precedenti problemi di \func{gets} in quanto
+prende in input la dimensione del buffer \param{size}, che non verrà mai
+ecceduta in lettura. La funzione legge fino ad un massimo di \param{size}
+caratteri (newline compreso), ed aggiunge uno zero di terminazione; questo
+comporta che la stringa possa essere al massimo di \code{size-1} caratteri.  Se
+la linea eccede la dimensione del buffer verranno letti solo \code{size-1}
+caratteri, ma la stringa sarà sempre terminata correttamente con uno zero
+finale; sarà possibile leggere i rimanenti caratteri in una chiamata
+successiva.
 
 Per la scrittura di una linea lo standard ANSI C prevede altre due
 funzioni, \func{fputs} e \func{puts}, analoghe a quelle di lettura, i
@@ -819,9 +819,9 @@ per leggere e scrivere caratteri estesi, i loro prototipi sono:
     non negativo in caso di successo e \macro{NULL} o \macro{EOF} in
     caso di errore o fine del file.}
 \end{functions}
-\noindent il comportamento è identico a quello di \func{fgets} e
-\func{fputs} solo che tutto (numero di caratteri massimo, terminatore
-della stringa, newline) è espresso in termini di caratteri estesi
+\noindent il cui comportamento è 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 caratteri ASCII.
 
 Come nel caso dell'I/O binario e a caratteri nelle \acr{glibc} sono
@@ -851,38 +851,37 @@ includere \file{stdio.h}. La prima delle due, \func{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} sul buffer indicato da \param{buffer}
-  riallocandolo se necessario (l'indirizzo del buffer e la sua
-  dimensione vengono sempre riscritte).
+  {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 parametro l'indirizzo del puntatore al buffer su cui
-si vuole leggere 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
-parametro la funzione vuole l'indirizzo della variabile contenente le
-dimensioni del buffer suddetto.
+La funzione permette di eseguire una lettura senza doversi preoccupare della
+eventuale lunghezza eccessiva della stringa da leggere. Essa prende come primo
+parametro 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 parametro 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 dimensione ed il nuovo puntatore vengono
 passata indietro (si noti infatti come per entrambi i parametri si siano
-usati dei \textit{value result argument}, passando dei puntatori anzichè
+usati dei \textit{value result argument}, passando dei puntatori anziché
 i valori delle variabili, secondo la tecnica spiegata in
 \secref{sec:proc_var_passing}).
 
-Se si passa alla funzione l'indirizzo ad un puntatore impostato a
-\macro{NULL} e \var{*n} è zero, la funzione provvede da sola
-all'allocazione della memoria necessaria a contenere la linea. In tutti
-i casi si ottiene dalla funzione un puntatore all'inizio del testo della
-linea. Un esempio di codice può essere il seguente:
+Se si passa alla funzione l'indirizzo di un puntatore impostato a \macro{NULL}
+e \var{*n} è zero, la funzione provvede da sola all'allocazione della memoria
+necessaria a contenere la linea. In tutti i casi si ottiene dalla funzione un
+puntatore all'inizio del testo della linea letta. Un esempio di codice può
+essere il seguente:
 \begin{lstlisting}[labelstep=0,frame=,indent=1cm]{}
     size_t n = 0; 
     char *ptr = NULL;
@@ -1043,7 +1042,7 @@ questo ordine:
 \item uno specificatore del parametro da usare (terminato da un \cmd{\$}),
 \item uno o più flag (i cui valori possibili sono riassunti in
   \tabref{tab:file_format_flag}) che controllano il formato di stampa della
-  conversione
+  conversione,
 \item uno specificatore di larghezza (un numero decimale), eventualmente
   seguito (per i numeri in virgola mobile) da un specificatore di precisione
   (un altro numero decimale),
@@ -1130,7 +1129,7 @@ scritti sulla stringa di destinazione:
 
 
 Per eliminare alla radice questi problemi, le \acr{glibc} supportano una
-estensione specifica GNU che alloca dinamicamente tutto lo spazio necessario;
+specifica estensione GNU che alloca dinamicamente tutto lo spazio necessario;
 l'estensione si attiva al solito definendo \macro{\_GNU\_SOURCE}, le due
 funzioni sono:
 \begin{functions}
@@ -1217,27 +1216,34 @@ recuperare in caso di fallimento nelle corrispondenze, l'input formattato non
 relativamente semplice si preferisce usare l'input di linea ed effettuare
 scansione e conversione di quanto serve direttamente con una delle funzioni di
 conversione delle stringhe; se invece il formato è più complesso diventa più
-facile utilizzare uno strumento come il \cmd{flex} per generare un
-analizzatore lessicale o il \cmd{bison} per generare un parser.
+facile utilizzare uno strumento come \cmd{flex}\footnote{il programma
+  \cmd{flex}, è una implementazione libera di \cmd{lex} un generatore di
+  analizzatori lessicali, per i dettagli si può fare riferimento al manuale
+  \cite{flex}.} per generare un analizzatore lessicale o il
+\cmd{bison}\footnote{il programma \cmd{bison} è un clone del generatore di
+  parser \cmd{yacc}, maggiori dettagli possono essere trovati nel relativo
+  manuale \cite{bison}.} per generare un parser.
 
 
 \subsection{Posizionamento su uno stream}
 \label{sec:file_fseek}
 
-Come per i file descriptor è possibile anche con gli stream spostarsi
+Come per i file descriptor anche per gli stream è possibile spostarsi
 all'interno di un file per effettuare operazioni di lettura o scrittura in un
-punto prestabilito; questo fintanto che l'operazione di riposizionamento è
-supportata dal file sottostante lo stream, quando cioè si ha a che fare con
-quello che viene detto un file ad \textsl{accesso casuale}.
+punto prestabilito; sempre che l'operazione di riposizionamento sia supportata
+dal file sottostante lo stream, quando cioè si ha a che fare con quello che
+viene detto un file ad \textsl{accesso casuale}.\footnote{dato che in un
+  sistema Unix esistono vari tipi di file, come le fifo ed i dispositivi, non
+  è scontato che questo sia sempre vero.}
 
 In GNU/Linux ed in generale in ogni sistema unix-like la posizione nel file è
 espressa da un intero positivo, rappresentato dal tipo \type{off\_t}, il
-problema è alcune delle funzioni usate per il riposizionamento sugli stream
-originano dalle prime versioni di Unix, in cui questo tipo non era ancora
-stato definito, e che in altri sistemi non è detto che la posizione su un file
-venga sempre rappresentata con il numero di caratteri dall'inizio (ad esempio
-in VMS può essere rappresentata come numero di record, e offset rispetto al
-record corrente).
+problema è che alcune delle funzioni usate per il riposizionamento sugli
+stream originano dalle prime versioni di Unix, in cui questo tipo non era
+ancora stato definito, e che in altri sistemi non è detto che la posizione su
+un file venga sempre rappresentata con il numero di caratteri dall'inizio (ad
+esempio in VMS può essere rappresentata come numero di record, più l'offset
+rispetto al record corrente).
 
 Tutto questo comporta la presenza di diverse funzioni che eseguono
 sostanzialmente le stesse operazioni, ma usano parametri di tipo
@@ -1276,8 +1282,8 @@ cui prototipo 
 \noindent la funzione restituisce la posizione come numero di byte
 dall'inizio dello stream. 
 
-Queste funzioni esprimono tutte la posizione nel file come un \func{long int},
-dato che (ad esempio quando si usa un filesystem indicizzato a 64 bit) questo
+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
 \func{fgetpos} e \func{fsetpos}, che invece usano il nuovo tipo
 \type{fpos\_t}, ed i cui prototipi sono:
@@ -1287,17 +1293,17 @@ pu
   \funcdecl{int fsetpos(FILE *stream, fpos\_t *pos)} Imposta la posizione
   corrente nello stream \param{stream} al valore specificato da \param{pos}.
   
-  \funcdecl{int fgetpos(FILE *stream, fpos\_t *pos)} Scrive la posizione
-  corrente nello stream \param{stream} in \param{pos}.
+  \funcdecl{int fgetpos(FILE *stream, fpos\_t *pos)} Legge la posizione
+  corrente nello 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}
 
 In Linux, a partire dalle glibc 2.1, sono presenti anche le due funzioni
-\func{fseeko} e \func{ftello}, che assolutamente identiche alle precedenti
-\func{fseek} e \func{ftell} ma hanno argomenti di tipo \type{off\_t} anziché
-di tipo \ctyp{long int}.
+\func{fseeko} e \func{ftello}, che sono assolutamente identiche alle
+precedenti \func{fseek} e \func{ftell} ma hanno argomenti di tipo
+\type{off\_t} anziché di tipo \ctyp{long int}.
 
 
 
@@ -1313,11 +1319,11 @@ impliciti per la programmazione multi thread.
 \subsection{Le funzioni di controllo}
 \label{sec:file_stream_cntrl}
 
-Al contrario di quanto avviene con i file descriptor le librerie standard del
+Al contrario di quanto avviene con i file descriptor, le librerie standard del
 C non prevedono nessuna funzione come la \func{fcntl} per il controllo degli
-attributi dei file. Però siccome ogni stream si appoggia ad un file descriptor
-si può usare la funzione \func{fileno} per ottenere quest'ultimo, il prototipo
-della funzione è:
+attributi dei file. Però, dato che ogni stream si appoggia ad un file
+descriptor, si può usare la funzione \func{fileno} per ottenere quest'ultimo,
+il prototipo della funzione è:
 \begin{prototype}{stdio.h}{int fileno(FILE *stream)}
   Legge il file descriptor sottostante lo stream \param{stream}.
   
@@ -1328,7 +1334,7 @@ della funzione 
 \noindent ed in questo modo diventa possibile usare direttamente \func{fcntl}.
 
 Questo permette di accedere agli attributi del file descriptor sottostante lo
-stream, ma non ci da nessuna informazione riguardo alle proprietà dello stream
+stream, ma non ci dà nessuna informazione riguardo alle proprietà dello stream
 medesimo.  Le \acr{glibc} però supportano alcune estensioni derivate da
 Solaris, che permettono di ottenere informazioni utili.
 
@@ -1378,7 +1384,7 @@ operazione ci fosse comunque stata.
 
 Come accennato in \secref{sec:file_buffering} le librerie definiscono una
 serie di funzioni che permettono di controllare il comportamento degli stream;
-se non si è specificato nulla la modalità di buffering viene decisa
+se non si è specificato nulla, la modalità di buffering viene decisa
 autonomamente sulla base del tipo di file sottostante, ed i buffer vengono
 allocati automaticamente.
 
@@ -1403,13 +1409,13 @@ 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 restare disponibile per tutto il tempo in cui si opera sullo
+stato allocato e rimanere disponibile per tutto il tempo in cui si opera sullo
 stream. In genere conviene allocarlo con \func{malloc} e disallocarlo dopo la
 chiusura del file; ma fintanto che il file è usato all'interno di una
-funzione, può anche essere usata una variabile automatica. In \file{stdio.h}
+funzione, può anche essere usata una variabile automatica. In \file{stdio.h} è
 definita la macro \macro{BUFSIZ}, che indica le dimensioni generiche del
-buffer di uno stream; queste vengono usate dalla funzione \func{setbuf},
-questa però non è detto corrisponda in tutti i casi al valore ottimale (che
+buffer di uno stream; queste vengono usate dalla funzione \func{setbuf}.  Non
+è detto però che tale dimensione corrisponda sempre al valore ottimale (che
 può variare a seconda del dispositivo).
 
 Dato che la procedura di allocazione manuale è macchinosa, comporta dei rischi
@@ -1449,7 +1455,7 @@ vengono sempre ignorati.
 
 Oltre a \func{setvbuf} le \acr{glibc} definiscono altre tre funzioni per la
 gestione della bufferizzazione di uno stream: \func{setbuf}, \func{setbuffer}
-e \func{setlinebuf}, i loro prototipi sono:
+e \func{setlinebuf}; i loro prototipi sono:
 \begin{functions}
   \headdecl{stdio.h} 
   
@@ -1514,7 +1520,7 @@ kernel dia effettivamente avvio alle operazioni di scrittura su disco occorre
 usare \func{sync} o \func{fsync} (si veda~\secref{sec:file_sync}).
 
 Infine esistono anche circostanze in cui si vuole scartare tutto l'output
-pendente, per questo si può usare \func{fpurge}, il cui prototipo è:
+pendente; per questo si può usare \func{fpurge}, il cui prototipo è:
 \begin{prototype}{stdio.h}{int fpurge(FILE *stream)}
  
   Cancella i buffer di input e di output dello stream \param{stream}.
@@ -1535,7 +1541,7 @@ Gli stream possono essere usati in applicazioni multi-thread allo stesso
 modo in cui sono usati nelle applicazioni normali, ma si deve essere
 consapevoli delle possibili complicazioni anche quando non si usano i
 thread, dato che l'implementazione delle librerie è influenzata
-pesantemente dalle richieste necessarie per garantirne l'uso coi thread.
+pesantemente dalle richieste necessarie per garantirne l'uso coi thread.
 
 Lo standard POSIX richiede che le operazioni sui file siano atomiche rispetto
 ai thread, per questo le operazioni sui buffer effettuate dalle funzioni di
@@ -1553,14 +1559,12 @@ 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 stream \param{stream}, bloccandosi in caso il lock non
-  disponibile. 
+  \funcdecl{void flockfile(FILE *stream)} Esegue l'acquisizione del lock dello
+  stream \param{stream}, bloccandosi se il lock non è disponibile.
   
-  \funcdecl{int ftrylockfile(FILE *stream)} Tenta l'acquisizione del
-  lock dello stream \param{stream}, senza bloccarsi in caso il lock non sia
-  disponibile. Ritorna zero in caso di acquisizione del lock, diverso da
-  zero altrimenti.
+  \funcdecl{int ftrylockfile(FILE *stream)} Tenta l'acquisizione del lock
+  dello 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
   stream \param{stream}.