%% filestd.tex
%%
-%% Copyright (C) 2000-2006 Simone Piccardi. Permission is granted to
+%% Copyright (C) 2000-2009 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 "Un preambolo",
%% license is included in the section entitled "GNU Free Documentation
%% License".
%%
+
\chapter{I file: l'interfaccia standard ANSI C}
\label{cha:files_std_interface}
\label{sec:file_stream}
\index{file!stream|(}
+
Come più volte ribadito, l'interfaccia dei file descriptor è un'interfaccia di
basso livello, che non provvede nessuna forma di formattazione dei dati e
nessuna forma di bufferizzazione per ottimizzare le operazioni di I/O.
(sui quali sono basati), ed in particolare continua a valere quanto visto in
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|)}
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
+queste strutture (che sono dei \index{tipo!opaco} \textsl{tipi opachi}) ma
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
\texttt{r} & Il file viene aperto, l'accesso viene posto in sola
lettura, lo stream è posizionato all'inizio del file.\\
\texttt{r+}& Il file viene aperto, l'accesso viene posto in lettura e
- scrittura, lo stream è posizionato all'inizio del file. \\
+ scrittura, lo stream è posizionato all'inizio del file.\\
% \hline
\texttt{w} & Il file viene aperto e troncato a lunghezza nulla (o
creato se non esiste), l'accesso viene posto in sola
\itindex{append~mode} \textit{append mode}, l'accesso viene
posto in lettura e scrittura.\\
\hline
- \texttt{b} & specifica che il file è binario, non ha alcun effetto. \\
- \texttt{x} & l'apertura fallisce se il file esiste già. \\
+ \texttt{b} & Specifica che il file è binario, non ha alcun effetto. \\
+ \texttt{x} & L'apertura fallisce se il file esiste già. \\
\hline
\end{tabular}
\caption{Modalità di apertura di uno stream dello standard ANSI C che
file non viene duplicato e verrà chiuso alla chiusura dello stream.
I nuovi file saranno creati secondo quanto visto in
-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 sez.~\ref{sec:file_umask}).
+sez.~\ref{sec:file_ownership_management} 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 \itindex{umask} \textit{umask} per
+il processo (si veda sez.~\ref{sec:file_perm_management}).
In caso di file aperti in lettura e scrittura occorre ricordarsi che c'è
di mezzo una bufferizzazione; per questo motivo lo standard ANSI C
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 sez.~\ref{sec:file_stream_thread} per i
-dettagli), i loro prototipi sono:
+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}
\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.
+ \param{stream}. È una sempre una funzione.
\funcdecl{wint\_t getwchar(void)} Equivalente a \code{getwc(stdin)}.
\funcdecl{int putc(int c, FILE *stream)} Scrive il carattere \param{c}
su \param{stream}. In genere è implementata come una macro.
- \funcdecl{int fputc(FILE *stream)} Scrive il carattere \param{c} su
+ \funcdecl{int fputc(int c, FILE *stream)} Scrive il carattere \param{c} su
\param{stream}. È una sempre una funzione.
- \funcdecl{int putchar(void)} Equivalente a \code{putc(stdin)}.
+ \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
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}\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}.}
+stringa letta superi le dimensioni del buffer, si avrà un
+\itindex{buffer~overflow} \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 infatti inviare
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
+\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}).
puntatore all'inizio del testo della linea letta. Un esempio di codice può
essere il seguente:
\includecodesnip{listati/getline.c}
-e per evitare \textit{memory leak}\itindex{memory~leak} occorre ricordarsi di
+e per evitare \itindex{memory~leak} \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
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}\itindex{buffer~overflow}; per questo motivo
-si consiglia l'uso dell'alternativa \funcd{snprintf}, il cui prototipo è:
+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
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 \textit{variadic}\index{variadic},
+(si noti come tutte queste funzioni siano \index{variadic} \textit{variadic},
prendendo un numero di argomenti variabile che dipende appunto da quello che
si è specificato in \param{format}).
\hline
\hline
\cmd{\%d} &\ctyp{int} & Stampa un numero intero in formato decimale
- con segno \\
- \cmd{\%i} &\ctyp{int} & Identico a \cmd{\%i} in output, \\
- \cmd{\%o} &\ctyp{unsigned int}& Stampa un numero intero come ottale\\
+ con segno.\\
+ \cmd{\%i} &\ctyp{int} & Identico a \cmd{\%i} in output.\\
+ \cmd{\%o} &\ctyp{unsigned int}& Stampa un numero intero come ottale.\\
\cmd{\%u} &\ctyp{unsigned int}& Stampa un numero intero in formato
- decimale senza segno \\
+ decimale senza segno.\\
\cmd{\%x},
\cmd{\%X} &\ctyp{unsigned int}& Stampano un intero in formato esadecimale,
rispettivamente con lettere minuscole e
- maiuscole. \\
+ maiuscole.\\
\cmd{\%f} &\ctyp{double} & Stampa un numero in virgola mobile con la
- notazione a virgola fissa \\
+ notazione a virgola fissa.\\
\cmd{\%e},
\cmd{\%E} &\ctyp{double} & Stampano un numero in virgola mobile con la
notazione esponenziale, rispettivamente con
- lettere minuscole e maiuscole. \\
+ lettere minuscole e maiuscole.\\
\cmd{\%g},
\cmd{\%G} &\ctyp{double} & Stampano un numero in virgola mobile con la
notazione più appropriate delle due precedenti,
rispettivamente con lettere minuscole e
- maiuscole. \\
+ maiuscole.\\
\cmd{\%a},
\cmd{\%A} &\ctyp{double} & Stampano un numero in virgola mobile in
- notazione esadecimale frazionaria\\
- \cmd{\%c} &\ctyp{int} & Stampa un carattere singolo\\
- \cmd{\%s} &\ctyp{char *} & Stampa una stringa \\
- \cmd{\%p} &\ctyp{void *} & Stampa il valore di un puntatore\\
- \cmd{\%n} &\ctyp{\&int} & Prende il numero di caratteri stampati finora\\
- \cmd{\%\%}& & Stampa un \% \\
+ notazione esadecimale frazionaria.\\
+ \cmd{\%c} &\ctyp{int} & Stampa un carattere singolo.\\
+ \cmd{\%s} &\ctyp{char *} & Stampa una stringa.\\
+ \cmd{\%p} &\ctyp{void *} & Stampa il valore di un puntatore.\\
+ \cmd{\%n} &\ctyp{\&int} & Prende il numero di caratteri stampati finora.\\
+ \cmd{\%\%}& & Stampa un \%.\\
\hline
\end{tabular}
\caption{Valori possibili per gli specificatori di conversione in una
\val{0} & La conversione è riempita con zeri alla sinistra del valore.\\
\val{-} & La conversione viene allineata a sinistra sul bordo del campo.\\
\val{' '}& Mette uno spazio prima di un numero con segno di valore
- positivo\\
+ positivo.\\
\val{+} & Mette sempre il segno ($+$ o $-$) prima di un numero.\\
\hline
\end{tabular}
\textbf{Valore} & \textbf{Significato} \\
\hline
\hline
- \cmd{hh} & una conversione intera corrisponde a un \ctyp{char} con o senza
+ \cmd{hh} & Una conversione intera corrisponde a un \ctyp{char} con o senza
segno, o il puntatore per il numero dei parametri \cmd{n} è di
tipo \ctyp{char}.\\
- \cmd{h} & una conversione intera corrisponde a uno \ctyp{short} con o
+ \cmd{h} & Una conversione intera corrisponde a uno \ctyp{short} con o
senza segno, o il puntatore per il numero dei parametri \cmd{n}
è di tipo \ctyp{short}.\\
- \cmd{l} & una conversione intera corrisponde a un \ctyp{long} con o
+ \cmd{l} & Una conversione intera corrisponde a un \ctyp{long} con o
senza segno, o il puntatore per il numero dei parametri \cmd{n}
è di tipo \ctyp{long}, o il carattere o la stringa seguenti
sono in formato esteso.\\
- \cmd{ll} & una conversione intera corrisponde a un \ctyp{long long} con o
+ \cmd{ll} & Una conversione intera corrisponde a un \ctyp{long long} con o
senza segno, o il puntatore per il numero dei parametri \cmd{n}
è di tipo \ctyp{long long}.\\
- \cmd{L} & una conversione in virgola mobile corrisponde a un
+ \cmd{L} & Una conversione in virgola mobile corrisponde a un
\ctyp{double}.\\
- \cmd{q} & sinonimo di \cmd{ll}.\\
- \cmd{j} & una conversione intera corrisponde a un \type{intmax\_t} o
+ \cmd{q} & Sinonimo di \cmd{ll}.\\
+ \cmd{j} & Una conversione intera corrisponde a un \type{intmax\_t} o
\type{uintmax\_t}.\\
- \cmd{z} & una conversione intera corrisponde a un \type{size\_t} o
+ \cmd{z} & Una conversione intera corrisponde a un \type{size\_t} o
\type{ssize\_t}.\\
- \cmd{t} & una conversione intera corrisponde a un \type{ptrdiff\_t}.\\
+ \cmd{t} & Una conversione intera corrisponde a un \type{ptrdiff\_t}.\\
\hline
\end{tabular}
\caption{Il modificatore di tipo di dato per il formato di \func{printf}}
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\itindex{buffer~overflow}.
+\noindent in modo da evitare possibili \itindex{buffer~overflow} buffer
+overflow.
Per eliminare alla radice questi problemi, le \acr{glibc} supportano una
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 \itindex{value~result~argument}\textit{value result argument})
+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}.
+la stringa non serve più, onde evitare \itindex{memory~leak} \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
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
- vero.}
+ sistema Unix esistono vari tipi di file, come le fifo ed i
+ \index{file!di~dispositivo} 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 è
espressa da un intero positivo, rappresentato dal tipo \type{off\_t}, il
In Linux, a partire dalle glibc 2.1, sono presenti anche le due funzioni
\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}.
+\type{off\_t} anziché di tipo \ctyp{long int}. Dato che \ctyp{long} è nella
+gran parte dei casi un intero a 32 bit, questo diventa un problema quando la
+posizione sul file viene espressa con un valore a 64 bit come accade nei
+sistemi più moderni.
In questa sezione esamineremo alcune funzioni avanzate che permettono di
eseguire operazioni particolari sugli stream, come leggerne gli attributi,
controllarne le modalità di bufferizzazione, gestire direttamente i lock
-impliciti per la programmazione multi thread.
+impliciti per la programmazione \itindex{thread} \textit{multi-thread}.
\subsection{Le funzioni di controllo}
compresi gli eventuali caratteri rimandati indietro con \func{ungetc}.
-\subsection{Gli stream e i thread}
+\subsection{Gli \textit{stream} e i \textit{thread}}
\label{sec:file_stream_thread}
-Gli stream possono essere usati in applicazioni multi-thread allo stesso
-modo in cui sono usati nelle applicazioni normali, ma si deve essere
+\itindbeg{thread}
+
+Gli stream possono essere usati in applicazioni \textit{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 con i thread.
+\textit{thread}, dato che l'implementazione delle librerie è influenzata
+pesantemente dalle richieste necessarie per garantirne l'uso con i
+\textit{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
-libreria durante la lettura e la scrittura di uno stream devono essere
-opportunamente protette (in quanto il sistema assicura l'atomicità solo per le
-system call). Questo viene fatto associando ad ogni stream un opportuno blocco
-che deve essere implicitamente acquisito prima dell'esecuzione di qualunque
-operazione.
-
-Ci sono comunque situazioni in cui questo non basta, come quando un thread
-necessita di compiere più di una operazione sullo 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 stream; esse sono disponibili definendo
-\macro{\_POSIX\_THREAD\_SAFE\_FUNCTIONS} ed i loro prototipi sono:
+ai \textit{thread}, per questo le operazioni sui buffer effettuate dalle
+funzioni di libreria durante la lettura e la scrittura di uno stream devono
+essere opportunamente protette (in quanto il sistema assicura l'atomicità solo
+per le system call). Questo viene fatto associando ad ogni stream un opportuno
+blocco che deve essere implicitamente 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 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 stream; esse sono disponibili
+definendo \macro{\_POSIX\_THREAD\_SAFE\_FUNCTIONS} ed i loro prototipi sono:
\begin{functions}
\headdecl{stdio.h}
Ma, vista la complessità delle strutture di dati coinvolte, le operazioni di
blocco non sono del tutto indolori, e quando il locking dello stream non è
-necessario (come in tutti i programmi che non usano i thread), tutta la
-procedura può comportare dei costi pesanti in termini di prestazioni. Per
+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
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 thread è però un lavoro
-abbastanza noioso; per questo motivo le \acr{glibc} forniscono al
+\code{\_unlocked} in un programma che non usa i \textit{thread} è però un
+lavoro abbastanza noioso; per questo motivo le \acr{glibc} forniscono al
programmatore pigro un'altra via\footnote{anche questa mutuata da estensioni
introdotte in Solaris.} da poter utilizzare per disabilitare in blocco il
locking degli stream: l'uso della funzione \funcd{\_\_fsetlocking}, il cui
di blocco dello stream.
\end{basedescript}
+\itindend{thread}
+
+
%%% Local Variables:
%%% mode: latex