X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=filestd.tex;h=3fde1d701e18309337d44b05337ecb1789341d97;hp=9d06757cd1d02302f4a8ff1c372a2c31913308f8;hb=6f8e0ca42d3d0b97b5e5747798a1eaffb44e8521;hpb=c474f4307db945bc45287edd0ea4c2c29374d0ee diff --git a/filestd.tex b/filestd.tex index 9d06757..3fde1d7 100644 --- a/filestd.tex +++ b/filestd.tex @@ -1,9 +1,9 @@ %% filestd.tex %% -%% Copyright (C) 2000-2004 Simone Piccardi. Permission is granted to +%% Copyright (C) 2000-2005 Simone Piccardi. Permission is granted to %% copy, distribute and/or modify this document under the terms of the GNU Free %% Documentation License, Version 1.1 or any later version published by the -%% Free Software Foundation; with the Invariant Sections being "Prefazione", +%% Free Software Foundation; with the Invariant Sections being "Un preambolo", %% with no Front-Cover Texts, and with no Back-Cover Texts. A copy of the %% license is included in the section entitled "GNU Free Documentation %% License". @@ -42,7 +42,7 @@ basso livello, che non provvede nessuna forma di formattazione dei dati e nessuna forma di bufferizzazione per ottimizzare le operazioni di I/O. In \cite{APUE} Stevens descrive una serie di test sull'influenza delle -dimensioni del blocco di dati (il parametro \param{buf} di \func{read} e +dimensioni del blocco di dati (l'argomento \param{buf} di \func{read} e \func{write}) nell'efficienza nelle operazioni di I/O con i file descriptor, evidenziando come le prestazioni ottimali si ottengano a partire da dimensioni del buffer dei dati pari a quelle dei blocchi del filesystem (il valore dato @@ -72,21 +72,22 @@ sez.~\ref{sec:file_access_control} per il controllo di accesso. \index{file!stream|)} -\subsection{Gli oggetti \ctyp{FILE}} +\subsection{Gli oggetti \type{FILE}} \label{sec:file_FILE} + Per ragioni storiche la struttura di dati che rappresenta uno stream è stata -chiamata \ctyp{FILE}, questi oggetti sono creati dalle funzioni di libreria e +chiamata \type{FILE}, questi oggetti sono creati dalle funzioni di libreria e contengono tutte le informazioni necessarie a gestire le operazioni sugli stream, come la posizione corrente, lo stato del buffer e degli indicatori di stato e di fine del file. Per questo motivo gli utenti non devono mai utilizzare direttamente o allocare queste strutture (che sono dei \textsl{tipi opachi}\index{tipo!opaco}) ma -usare sempre puntatori del tipo \ctyp{FILE *} ottenuti dalla libreria stessa +usare sempre puntatori del tipo \texttt{FILE *} ottenuti dalla libreria stessa (tanto che in certi casi il termine di puntatore a file è diventato sinonimo di stream). Tutte le funzioni della libreria che operano sui file accettano -come parametri solo variabili di questo tipo, che diventa accessibile +come argomenti solo variabili di questo tipo, che diventa accessibile includendo l'header file \file{stdio.h}. @@ -113,14 +114,13 @@ definiti nell'header \file{stdio.h} che sono: sullo schermo. \end{basedescript} -Nelle \acr{glibc} \var{stdin}, \var{stdout} e \var{stderr} sono -effettivamente tre variabili di tipo \ctyp{FILE *} che possono essere -usate come tutte le altre, ad esempio si può effettuare una redirezione -dell'output di un programma con il semplice codice: -\includecodesnip{listati/redir_stdout.c} -ma in altri sistemi queste variabili possono essere definite da macro, e -se si hanno problemi di portabilità e si vuole essere sicuri, diventa -opportuno usare la funzione \func{freopen}. +Nelle \acr{glibc} \var{stdin}, \var{stdout} e \var{stderr} sono effettivamente +tre variabili di tipo \type{FILE}\texttt{ *} che possono essere usate come +tutte le altre, ad esempio si può effettuare una redirezione dell'output di un +programma con il semplice codice: \includecodesnip{listati/redir_stdout.c} ma +in altri sistemi queste variabili possono essere definite da macro, e se si +hanno problemi di portabilità e si vuole essere sicuri, diventa opportuno +usare la funzione \func{freopen}. \subsection{Le modalità di bufferizzazione} @@ -422,7 +422,7 @@ funzionamento di \var{errno}). Per questo motivo tutte le implementazioni delle librerie standard mantengono per ogni stream almeno due flag all'interno dell'oggetto -\ctyp{FILE}, il flag di \textit{end-of-file}, che segnala che si è +\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 @@ -585,11 +585,11 @@ pi meccanismo visto in sez.~\ref{sec:proc_var_passing}; per questo motivo se si passa un'espressione si possono avere effetti indesiderati. -Invece \func{fgetc} è assicurata essere sempre una funzione, per questo -motivo la sua esecuzione normalmente è più lenta per via dell'overhead -della chiamata, ma è altresì possibile ricavarne l'indirizzo, che può -essere passato come parametro ad un altra funzione (e non si hanno i -problemi accennati in precedenza nel tipo di argomento). +Invece \func{fgetc} è assicurata essere sempre una funzione, per questo motivo +la sua esecuzione normalmente è più lenta per via dell'overhead della +chiamata, ma è altresì possibile ricavarne l'indirizzo, che può essere passato +come argomento ad un altra funzione (e non si hanno i problemi accennati in +precedenza nel tipo di argomento). Le tre funzioni restituiscono tutte un \ctyp{unsigned char} convertito ad \ctyp{int} (si usa \ctyp{unsigned char} in modo da evitare @@ -636,11 +636,10 @@ loro prototipi sono: fine del file il valore di ritorno è \val{EOF}.} \end{functions} -Tutte queste funzioni scrivono sempre un byte alla volta, anche se -prendono come parametro 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}. +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, @@ -747,18 +746,17 @@ viene restituito un \val{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}\index{buffer overflow}, con sovrascrittura della memoria del + overflow}\itindex{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 -infatti inviare una stringa sufficientemente lunga ed opportunamente -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 -che lancia una shell). +Questa è una delle vulnerabilità più sfruttate per guadagnare accessi non +autorizzati al sistema (i cosiddetti \textit{exploit}), basta infatti inviare +una stringa sufficientemente lunga ed opportunamente forgiata per +sovrascrivere gli indirizzi di ritorno nello \itindex{stack} 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 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 @@ -856,28 +854,28 @@ newline, esattamente allo stesso modo di \func{fgets}, il suo prototipo 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 +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 parametro la funzione vuole l'indirizzo della 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 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é -i valori delle variabili, secondo la tecnica spiegata in +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 restituiti indietro (si noti infatti +come per entrambi gli argomenti si siano usati dei +\itindex{value~result~argument}\textit{value result argument}, passando dei +puntatori anziché i valori delle variabili, secondo la tecnica spiegata in sez.~\ref{sec:proc_var_passing}). -Se si passa alla funzione l'indirizzo di un puntatore impostato a \val{NULL} -e \var{*n} è zero, la funzione provvede da sola all'allocazione della memoria +Se si passa alla funzione l'indirizzo di un puntatore impostato a \val{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: -\includecodesnip{listati/getline.c} -e per evitare memory leak\index{memory leak} occorre ricordarsi di liberare -\var{ptr} con una \func{free}. +essere il seguente: +\includecodesnip{listati/getline.c} +e per evitare \textit{memory leak}\itindex{memory~leak} occorre ricordarsi di +liberare \var{ptr} con una \func{free}. Il valore di ritorno della funzione indica il numero di caratteri letti dallo stream (quindi compreso il newline, ma non lo zero di @@ -926,12 +924,12 @@ L'output formattato viene eseguito con una delle 13 funzioni della famiglia \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 +\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 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 \textit{buffer overflow}\index{buffer overflow}; per questo motivo +possibili \textit{buffer overflow}\itindex{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, ...)} @@ -941,8 +939,8 @@ si consiglia l'uso dell'alternativa \funcd{snprintf}, il cui prototipo 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 dei parametri che dovranno essere passati a seguire (si -noti come tutte queste funzioni siano \textit{variadic}\index{variadic}, +deriva anche il numero degli argomenti che dovranno essere passati a seguire +(si noti come tutte queste funzioni siano \textit{variadic}\index{variadic}, prendendo un numero di argomenti variabile che dipende appunto da quello che si è specificato in \param{format}). @@ -1102,8 +1100,8 @@ sez.~\ref{sec:proc_variadic}), sono \funcd{vprintf}, \funcd{vfprintf} e \end{functions} \noindent con queste funzioni diventa possibile selezionare gli argomenti che si vogliono passare ad una routine di stampa, passando direttamente la lista -tramite il parametro \param{ap}. Per poter far questo ovviamente la lista dei -parametri dovrà essere opportunamente trattata (l'argomento è esaminato in +tramite l'argomento \param{ap}. Per poter far questo ovviamente la lista degli +argomenti dovrà essere opportunamente trattata (l'argomento è esaminato in sez.~\ref{sec:proc_variadic}), e dopo l'esecuzione della funzione l'argomento \param{ap} non sarà più utilizzabile (in generale dovrebbe essere eseguito un \code{va\_end(ap)} ma in Linux questo non è necessario). @@ -1116,7 +1114,8 @@ scritti sulla stringa di destinazione: Identica a \func{vsprintf}, ma non scrive su \param{str} più di \param{size} caratteri. \end{prototype} -\noindent in modo da evitare possibili buffer overflow\index{buffer overflow}. +\noindent in modo da evitare possibili buffer +overflow\itindex{buffer~overflow}. Per eliminare alla radice questi problemi, le \acr{glibc} supportano una @@ -1138,13 +1137,15 @@ sono: \bodydesc{Le funzioni ritornano il numero di caratteri stampati.} \end{functions} -Entrambe le funzioni prendono come parametro \param{strptr} che deve essere + +Entrambe le funzioni prendono come argomento \param{strptr} che deve essere l'indirizzo di un puntatore ad una stringa di caratteri, in cui verrà restituito (si ricordi quanto detto in sez.~\ref{sec:proc_var_passing} a -proposito dei \textit{value result argument}) l'indirizzo della stringa -allocata automaticamente dalle funzioni. Occorre inoltre ricordarsi di -invocare \func{free} per liberare detto puntatore quando la stringa non serve -più, onde evitare memory leak\index{memory leak}. +proposito dei \itindex{value~result~argument}\textit{value result argument}) +l'indirizzo della stringa allocata automaticamente dalle funzioni. Occorre +inoltre ricordarsi di invocare \func{free} per liberare detto puntatore quando +la stringa non serve più, onde evitare \textit{memory + leak}\itindex{memory~leak}. Infine una ulteriore estensione GNU definisce le due funzioni \func{dprintf} e \func{vdprintf}, che prendono un file descriptor al posto dello stream. Altre @@ -1161,7 +1162,7 @@ famiglia \func{scanf}; fra queste le tre pi \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 nei parametri seguenti. + 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}. @@ -1185,11 +1186,11 @@ caratteristica. Le funzioni leggono i caratteri dallo stream (o dalla stringa) di input ed eseguono un confronto con quanto indicato in \param{format}, la sintassi di -questo parametro è simile a quella usata per l'analogo di \func{printf}, ma ci +questo argomento è simile a quella usata per l'analogo di \func{printf}, ma ci sono varie differenze. Le funzioni di input infatti sono più orientate verso la lettura di testo libero che verso un input formattato in campi fissi. Uno spazio in \param{format} corrisponde con un numero qualunque di caratteri di -separazione (che possono essere spazi, tabulatori, virgole etc.), mentre +separazione (che possono essere spazi, tabulatori, virgole ecc.), mentre caratteri diversi richiedono una corrispondenza esatta. Le direttive di conversione sono analoghe a quelle di \func{printf} e si trovano descritte in dettaglio nelle pagine di manuale e nel manuale delle \acr{glibc}. @@ -1227,7 +1228,7 @@ 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 file di - dispositivo\index{file!di dispositivo}, non è scontato che questo sia sempre + dispositivo\index{file!di~dispositivo}, non è scontato che questo sia sempre vero.} In GNU/Linux ed in generale in ogni sistema unix-like la posizione nel file è @@ -1240,7 +1241,7 @@ esempio in VMS pu rispetto al record corrente). Tutto questo comporta la presenza di diverse funzioni che eseguono -sostanzialmente le stesse operazioni, ma usano parametri di tipo diverso. Le +sostanzialmente le stesse operazioni, ma usano argomenti di tipo diverso. Le funzioni tradizionali usate per il riposizionamento della posizione in uno stream sono \funcd{fseek} e \funcd{rewind} i cui prototipi sono: \begin{functions} @@ -1255,7 +1256,7 @@ stream sono \funcd{fseek} e \funcd{rewind} i cui prototipi sono: \end{functions} L'uso di \func{fseek} è del tutto analogo a quello di \func{lseek} per i file -descriptor, ed i parametri, a parte il tipo, hanno lo stesso significato; in +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 @@ -1434,13 +1435,13 @@ coincidano con quelle su cui viene effettuato l'I/O. \const{\_IOFBF} & \textit{fully buffered}\\ \hline \end{tabular} - \caption{Valori del parametro \param{mode} di \func{setvbuf} - per l'impostazione delle modalità di bufferizzazione.} + \caption{Valori dell'argomento \param{mode} di \func{setvbuf} + per l'impostazione delle modalità di bufferizzazione.} \label{tab:file_stream_buf_mode} \end{table} Per evitare che \func{setvbuf} imposti il buffer basta passare un valore -\val{NULL} per \param{buf} e la funzione ignorerà il parametro \param{size} +\val{NULL} per \param{buf} e la funzione ignorerà l'argomento \param{size} usando il buffer allocato automaticamente dal sistema. Si potrà comunque modificare la modalità di bufferizzazione, passando in \param{mode} uno degli opportuni valori elencati in tab.~\ref{tab:file_stream_buf_mode}. Qualora si