%% filestd.tex
%%
-%% Copyright (C) 2000-2003 Simone Piccardi. Permission is granted to
+%% Copyright (C) 2000-2004 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".
\section{Introduzione}
\label{sec:file_stream_intro}
-Come visto in \capref{cha:file_unix_interface} le operazioni di I/O sui file
+Come visto in cap.~\ref{cha:file_unix_interface} le operazioni di I/O sui file
sono gestibili a basso livello con l'interfaccia standard unix, che ricorre
direttamente alle system call messe a disposizione dal kernel.
scrittura (sia per quel che riguarda la bufferizzazione, che le
formattazioni), i file stream restano del tutto equivalenti ai file descriptor
(sui quali sono basati), ed in particolare continua a valere quanto visto in
-\secref{sec:file_sharing} a proposito dell'accesso condiviso ed in
-\secref{sec:file_access_control} per il controllo di accesso.
+sez.~\ref{sec:file_sharing} a proposito dell'accesso condiviso ed in
+sez.~\ref{sec:file_access_control} per il controllo di accesso.
\index{file!stream|)}
\subsection{Gli stream standard}
\label{sec:file_std_stream}
-Ai tre file descriptor standard (vedi \secref{sec:file_std_descr})
+Ai tre file descriptor standard (vedi sez.~\ref{sec:file_std_descr})
aperti per ogni processo, corrispondono altrettanti stream, che
rappresentano i canali standard di input/output prestabiliti; anche
questi tre stream sono identificabili attraverso dei nomi simbolici
legge è in modalità \textit{unbuffered}.} viene anche eseguito lo scarico di
tutti i buffer degli stream in scrittura.
-In \secref{sec:file_buffering_ctrl} vedremo come la libreria definisca delle
+In sez.~\ref{sec:file_buffering_ctrl} vedremo come la libreria definisca delle
opportune funzioni per controllare le modalità di bufferizzazione e lo scarico
dei dati.
\label{sec:file_ansi_base_func}
Esamineremo in questa sezione le funzioni base dell'interfaccia degli stream,
-analoghe a quelle di \secref{sec:file_base_func} per i file descriptor. In
+analoghe a quelle di sez.~\ref{sec:file_base_func} per i file descriptor. In
particolare vedremo come aprire, leggere, scrivere e cambiare la posizione
corrente in uno stream.
Normalmente la funzione che si usa per aprire uno 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 \tabref{tab:file_fopen_mode} (sono possibili varie
+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 \secref{sec:file_std_stream}): il file \param{path} viene
+standard (vedi sez.~\ref{sec:file_std_stream}): il file \param{path} viene
associato a \param{stream} e se questo è uno stream già aperto viene
preventivamente chiuso.
\end{table}
In realtà lo standard ANSI C prevede un totale di 15 possibili valori
-diversi per \param{mode}, ma in \tabref{tab:file_fopen_mode} si sono
+diversi per \param{mode}, ma in tab.~\ref{tab:file_fopen_mode} si sono
riportati solo i sei valori effettivi, ad essi può essere aggiunto pure
il carattere \texttt{b} (come ultimo carattere o nel mezzo agli altri per
le stringhe di due caratteri) che in altri sistemi operativi serve a
Le \acr{glibc} supportano alcune estensioni, queste devono essere sempre
indicate dopo aver specificato il \param{mode} con uno dei valori di
-\tabref{tab:file_fopen_mode}. L'uso del carattere \texttt{x} serve per
+tab.~\ref{tab:file_fopen_mode}. L'uso del carattere \texttt{x} serve per
evitare di sovrascrivere un file già esistente (è analoga all'uso
dell'opzione \const{O\_EXCL} in \func{open}), se il file specificato già
esiste e si aggiunge questo carattere a \param{mode} la \func{fopen}
Nel caso si usi \func{fdopen} i valori specificati da \param{mode} devono
essere compatibili con quelli con cui il file descriptor è stato aperto.
Inoltre i modi \cmd{w} e \cmd{w+} non troncano il file. La posizione nello
-stream viene impostata a quella corrente nel file descriptor, e le variabili di
-errore e di fine del file (vedi \secref{sec:file_io}) sono cancellate. Il file
-non viene duplicato e verrà chiuso alla chiusura dello stream.
+stream viene impostata a quella corrente nel file descriptor, e le variabili
+di errore e di fine del file (vedi sez.~\ref{sec:file_io}) sono cancellate. Il
+file non viene duplicato e verrà chiuso alla chiusura dello stream.
I nuovi file saranno creati secondo quanto visto in
-\secref{sec:file_ownership} ed avranno i permessi di accesso impostati al
+sez.~\ref{sec:file_ownership} ed avranno i permessi di accesso impostati al
valore \code{S\_IRUSR|S\_IWUSR|S\_IRGRP|S\_IWGRP|S\_IROTH|S\_IWOTH} (pari a
\val{0666}) modificato secondo il valore di \acr{umask} per il processo (si
-veda \secref{sec:file_umask}).
+veda sez.~\ref{sec:file_umask}).
In caso di file aperti in lettura e scrittura occorre ricordarsi che c'è
di mezzo una bufferizzazione; per questo motivo lo standard ANSI C
sufficiente a garantire la sincronizzazione.
Una volta aperto lo stream, si può cambiare la modalità di bufferizzazione
-(si veda \secref{sec:file_buffering_ctrl}) fintanto che non si è effettuato
+(si veda sez.~\ref{sec:file_buffering_ctrl}) fintanto che non si è effettuato
alcuna operazione di I/O sul file.
Uno stream viene chiuso con la funzione \funcd{fclose} il cui prototipo è:
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 \secref{sec:file_sync}).
+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
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 \secref{sec:proc_exit}).
+visto in sez.~\ref{sec:proc_exit}).
\subsection{Lettura e scrittura su uno stream}
modalità di input/output non formattato:
\begin{enumerate*}
\item\textsl{binario} in cui legge/scrive un blocco di dati alla
- volta, vedi \secref{sec:file_binary_io}.
+ 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 \secref{sec:file_char_io}.
+ 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 \secref{sec:file_line_io}.
+ dal carattere di newline \verb|'\n'|), vedi sez.~\ref{sec:file_line_io}.
\end{enumerate*}
ed inoltre la modalità di input/output formattato.
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 \secref{sec:sys_errno} per i dettagli del
+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
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
funzione esiste una analoga \func{clearerr\_unlocked} che non esegue il blocco
-dello stream (vedi \secref{sec:file_stream_thread}).
+dello stream (vedi sez.~\ref{sec:file_stream_thread}).
\subsection{Input/output binario}
Le \acr{glibc} definiscono altre due funzioni per l'I/O binario,
\funcd{fread\_unlocked} e \funcd{fwrite\_unlocked} che evitano il lock
implicito dello stream, usato per dalla librerie per la gestione delle
-applicazioni multi-thread (si veda \secref{sec:file_stream_thread} per i
+applicazioni multi-thread (si veda sez.~\ref{sec:file_stream_thread} per i
dettagli), i loro prototipi sono:
\begin{functions}
\headdecl{stdio.h}
viene implementata con una macro, per cui occorre stare attenti a cosa
le si passa come argomento, infatti \param{stream} può essere valutato
più volte nell'esecuzione, e non viene passato in copia con il
-meccanismo visto in \secref{sec:proc_var_passing}; per questo motivo se
+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
Infine si tenga presente che \func{ungetc} non altera il contenuto del
file, ma opera esclusivamente sul buffer interno. Se si esegue una
qualunque delle operazioni di riposizionamento (vedi
-\secref{sec:file_fseek}) i caratteri rimandati indietro vengono
+sez.~\ref{sec:file_fseek}) i caratteri rimandati indietro vengono
scartati.
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
-processo adiacente al buffer.\footnote{questa tecnica è spiegata in dettaglio
- e con molta efficacia nell'ormai famoso articolo di Aleph1 \cite{StS}.}
+ overflow}\index{\textit{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
\acr{glibc} supportano una serie di altre funzioni, estensioni di tutte quelle
illustrate finora (eccetto \func{gets} e \func{puts}), che eseguono
esattamente le stesse operazioni delle loro equivalenti, evitando però il lock
-implicito dello stream (vedi \secref{sec:file_stream_thread}). Come per le
+implicito dello stream (vedi sez.~\ref{sec:file_stream_thread}). Come per le
altre forma di I/O, dette funzioni hanno lo stesso nome della loro analoga
normale, con l'aggiunta dell'estensione \code{\_unlocked}.
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é
-i valori delle variabili, secondo la tecnica spiegata in
-\secref{sec:proc_var_passing}).
+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
+\index{\textit{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 memory leak\index{\textit{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
\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
-si consiglia l'uso dell'alternativa \funcd{snprintf}, il cui prototipo è:
+possibili \textit{buffer overflow}\index{\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
vengono passati invariati all'output, e da direttive di conversione, in cui
devono essere sempre presenti il carattere \texttt{\%}, che introduce la
direttiva, ed uno degli specificatori di conversione (riportati in
-\tabref{tab:file_format_spec}) che la conclude.
+tab.~\ref{tab:file_format_spec}) che la conclude.
\begin{table}[htb]
\centering
\begin{itemize*}
\item uno specificatore del parametro da usare (terminato da un \val{\$}),
\item uno o più flag (i cui valori possibili sono riassunti in
- \tabref{tab:file_format_flag}) che controllano il formato di stampa della
+ tab.~\ref{tab:file_format_flag}) che controllano il formato di stampa della
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),
\item uno specificatore del tipo di dato, che ne indica la dimensione (i cui
- valori possibili sono riassunti in \tabref{tab:file_format_type}).
+ valori possibili sono riassunti in tab.~\ref{tab:file_format_type}).
\end{itemize*}
Una versione alternativa delle funzioni di output formattato, che permettono
di usare il puntatore ad una lista di argomenti (vedi
-\secref{sec:proc_variadic}), sono \funcd{vprintf}, \funcd{vfprintf} e
+sez.~\ref{sec:proc_variadic}), sono \funcd{vprintf}, \funcd{vfprintf} e
\funcd{vsprintf}, i cui prototipi sono:
\begin{functions}
\headdecl{stdio.h}
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
-\secref{sec:proc_variadic}), e dopo l'esecuzione della funzione l'argomento
+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).
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\index{\textit{buffer~overflow}}.
Per eliminare alla radice questi problemi, le \acr{glibc} supportano una
\end{functions}
Entrambe le funzioni prendono come parametro \param{strptr} che deve essere
l'indirizzo di un puntatore ad una stringa di caratteri, in cui verrà
-restituito (si ricordi quanto detto in \secref{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}.
+restituito (si ricordi quanto detto in sez.~\ref{sec:proc_var_passing} a
+proposito dei \index{\textit{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 memory
+leak\index{\textit{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
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 è
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
particolare \param{whence} assume gli stessi valori già visti in
-\secref{sec:file_lseek}. La funzione restituisce 0 in caso di successo e -1
+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 stream, ma non esattamente equivalente ad
una \code{fseek(stream, 0L, SEEK\_SET)} in quanto vengono cancellati anche i
\subsection{Il controllo della bufferizzazione}
\label{sec:file_buffering_ctrl}
-Come accennato in \secref{sec:file_buffering} le librerie definiscono una
+Come accennato in sez.~\ref{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
autonomamente sulla base del tipo di file sottostante, ed i buffer vengono
\val{NULL} per \param{buf} e la funzione ignorerà il parametro \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 \tabref{tab:file_stream_buf_mode}. Qualora si
+opportuni valori elencati in tab.~\ref{tab:file_stream_buf_mode}. Qualora si
specifichi la modalità non bufferizzata i valori di \param{buf} e \param{size}
vengono sempre ignorati.
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
kernel dia effettivamente avvio alle operazioni di scrittura su disco occorre
-usare \func{sync} o \func{fsync} (si veda~\secref{sec:file_sync}).
+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 è: