Come visto in sez.~\ref{sec:file_vfs_work} il kernel mette a disposizione
-tramite il \itindex{Virtual~File~System} \textit{Virtual File System} una
-serie di \textit{system call} che consentono di operare sui file in maniera
-generale. Abbiamo trattato quelle relative alla gestione delle proprietà dei
-file nel precedente capitolo, vedremo quelle che si applicano al contenuto dei
-file in questa sezione, iniziando con una breve introduzione sull'architettura
-dei \textit{file descriptor} per poi trattare le funzioni di base e le
-modalità con cui consentono di gestire i dati memorizzati sui file.
+tramite il \textit{Virtual File System} una serie di \textit{system call} che
+consentono di operare sui file in maniera generale. Abbiamo trattato quelle
+relative alla gestione delle proprietà dei file nel precedente capitolo,
+vedremo quelle che si applicano al contenuto dei file in questa sezione,
+iniziando con una breve introduzione sull'architettura dei \textit{file
+ descriptor} per poi trattare le funzioni di base e le modalità con cui
+consentono di gestire i dati memorizzati sui file.
\subsection{I \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_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.
+sez.~\ref{sec:file_open_close}) che provvederà a localizzare l'\textit{inode}
+del file e inizializzare i puntatori che rendono disponibili le funzioni che
+il 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
ulteriori operazioni dovranno essere compiute specificando questo stesso
numero come argomento alle varie funzioni dell'interfaccia.
+\itindbeg{process~table}
+\itindbeg{file~table}
+
Per capire come funziona il meccanismo occorre spiegare a grandi linee come il
kernel gestisce l'interazione fra processi e file. Abbiamo già accennato in
sez.~\ref{sec:proc_hierarchy} come il kernel mantenga un elenco di tutti
-processi nella cosiddetta \itindex{process~table} \textit{process table}. Lo
-stesso, come accennato in sez.~\ref{sec:file_vfs_work}, vale anche per tutti i
-file aperti, il cui elenco viene mantenuto nella cosiddetta
-\itindex{file~table} \textit{file table}.
-
-La \itindex{process~table} \textit{process table} è una tabella che contiene
-una voce per ciascun processo attivo nel sistema. Ciascuna voce è costituita
-dal puntatore a una struttura di tipo \kstruct{task\_struct} nella quale sono
-raccolte tutte le informazioni relative al processo, fra queste informazioni
-c'è anche il puntatore ad una ulteriore struttura di tipo
+processi nella cosiddetta \textit{process table}. Lo stesso, come accennato in
+sez.~\ref{sec:file_vfs_work}, vale anche per tutti i file aperti, il cui
+elenco viene mantenuto nella cosiddetta \textit{file table}.
+
+La \textit{process table} è una tabella che contiene una voce per ciascun
+processo attivo nel sistema. Ciascuna voce è costituita dal puntatore a una
+struttura di tipo \kstruct{task\_struct} nella quale sono raccolte tutte le
+informazioni relative al processo, fra queste informazioni c'è anche il
+puntatore ad una ulteriore struttura di tipo
\kstruct{files\_struct},\footnote{la definizione corrente di questa struttura
si trova nel file \texttt{include/linux/fdtable.h} dei sorgenti del kernel,
quella mostrata in fig.~\ref{fig:file_proc_file} è una versione pesantemente
semplificata.} che contiene le informazioni relative ai file che il processo
ha aperto.
-La \itindex{file~table} \textit{file table} è una tabella che contiene una
-voce per ciascun file che è stato aperto nel sistema. Come accennato in
-sez.~\ref{sec:file_vfs_work} per ogni file aperto viene allocata una struttura
-\kstruct{file} e la \textit{file table} è costituita da un elenco di puntatori
-a ciascuna di queste strutture, che, come illustrato in
-fig.~\ref{fig:kstruct_file}, contengono le informazioni necessarie per la
-gestione dei file, ed in particolare:
+La \textit{file table} è una tabella che contiene una voce per ciascun file
+che è stato aperto nel sistema. Come accennato in sez.~\ref{sec:file_vfs_work}
+per ogni file aperto viene allocata una struttura \kstruct{file} e la
+\textit{file table} è costituita da un elenco di puntatori a ciascuna di
+queste strutture, che, come illustrato in fig.~\ref{fig:kstruct_file},
+contengono le informazioni necessarie per la gestione dei file, ed in
+particolare:
\begin{itemize*}
\item i flag di stato \itindex{file~status~flag} del file nel campo
\var{f\_flags}.
\item la posizione corrente nel file, il cosiddetto \textit{offset}, nel campo
\var{f\_pos}.
\item un puntatore alla struttura \kstruct{inode} che identifica
- \itindex{inode} l'\textit{inode} del file.\footnote{nel kernel 2.4.x si è in
- realtà passati ad un puntatore ad una struttura \kstruct{dentry} che punta
- a sua volta \itindex{inode} all'\textit{inode} passando per la nuova
- struttura del VFS.}
+ l'\textit{inode} del file.\footnote{nel kernel 2.4.x si è in realtà passati
+ ad un puntatore ad una struttura \kstruct{dentry} che punta a sua volta
+ all'\textit{inode} passando per la nuova struttura del VFS.}
\item un puntatore \var{f\_op} alla tabella delle funzioni che si possono
usare sul file.\footnote{quelle della struttura \kstruct{file\_operation},
descritte sommariamente in tab.~\ref{tab:file_file_operations}.}
In fig.~\ref{fig:file_proc_file} si è riportato uno schema semplificato in cui
è illustrata questa architettura, ed in cui si sono evidenziate le
-interrelazioni fra la \itindex{file~table} \textit{file table}, la
-\itindex{process~table} \textit{process table} e le varie strutture di dati
-che il kernel mantiene per ciascun file e ciascun processo.
+interrelazioni fra la \textit{file table}, la \textit{process table} e le
+varie strutture di dati che il kernel mantiene per ciascun file e ciascun
+processo.
+\itindend{process~table}
Come si può notare alla fine il collegamento che consente di porre in
relazione i file ed i processi è effettuato attraverso i dati mantenuti nella
\item il numero di file aperti dal processo.
\item la \itindex{file~descriptor~table} \textit{file descriptor table}, una
tabella con i puntatori, per ciascun file aperto, alla relativa voce nella
- \itindex{file~table} \textit{file table}.
+ \textit{file table}.
\end{itemize*}
In questa infrastruttura un \textit{file descriptor} non è altro che l'intero
positivo che indicizza quest'ultima tabella, e che consente di recuperare il
puntatore alla struttura \kstruct{file} corrispondente al file aperto dal
-processo a cui era stato assegnato questo indice. Una volta ottenuta grazie
-al \textit{file descriptor} la struttura \kstruct{file} corrispondente al file
-voluto nella \itindex{file~table} \textit{file table}, il kernel potrà usare
-le funzioni messe disposizione dal VFS per eseguire sul file tutte le
-operazioni necessarie.
+processo a cui era stato assegnato questo indice. Una volta ottenuta grazie al
+\textit{file descriptor} la struttura \kstruct{file} corrispondente al file
+voluto nella \textit{file table}, il kernel potrà usare le funzioni messe
+disposizione dal VFS per eseguire sul file tutte le operazioni necessarie.
Il meccanismo dell'apertura dei file prevede che venga sempre fornito il primo
\textit{file descriptor} libero nella tabella, e per questo motivo essi
vengono assegnati in successione tutte le volte che si apre un nuovo file,
posto che non ne sia stato chiuso nessuno in precedenza.
+\itindbeg{standard~input}
+\itindbeg{standard~output}
+\itindbeg{standard~error}
+
In tutti i sistemi unix-like esiste una convenzione generale per cui ogni
processo si aspetta di avere sempre tre file aperti che, per quanto appena
detto, avranno come \itindex{file~descriptor} \textit{file descriptor} i
valori 0, 1 e 2. Il primo file è sempre associato al cosiddetto
-\itindex{standard~input} \textit{standard input}, è cioè il file da cui un
-processo si aspetta di dover leggere i dati in ingresso. Il secondo file è il
-cosiddetto \itindex{standard~output} \textit{standard output}, cioè quello su
-cui ci si aspetta di dover scrivere i dati in uscita. Il terzo è lo
-\itindex{standard~error} \textit{standard error}, su cui vengono scritti i
-dati relativi agli errori.
+\textit{standard input}, è cioè il file da cui un processo si aspetta di dover
+leggere i dati in ingresso. Il secondo file è il cosiddetto \textit{standard
+ output}, cioè quello su cui ci si aspetta di dover scrivere i dati in
+uscita. Il terzo è lo \textit{standard error}, su cui
+vengono scritti i dati relativi agli errori.
Benché questa sia soltanto una convenzione, essa è seguita dalla gran parte
delle applicazioni, e non aderirvi potrebbe portare a problemi di
\label{tab:file_std_files}
\end{table}
+\itindend{standard~input}
+\itindend{standard~output}
+\itindend{standard~error}
+
In fig.~\ref{fig:file_proc_file} si è rappresentata una situazione diversa
rispetto a quella usuale della shell, in cui tutti e tre questi file fanno
riferimento al terminale su cui si opera. Nell'esempio invece viene illustrata
-la situazione di un programma in cui lo \itindex{standard~input}
-\textit{standard input} è associato ad un file mentre lo
-\itindex{standard~output} \textit{standard output} e lo
-\itindex{standard~error} \textit{standard error} sono associati ad un altro
-file. Si noti poi come per questi ultimi le strutture \kstruct{file} nella
-\itindex{file~table} \textit{file table}, pur essendo distinte, fanno
-riferimento allo stesso \itindex{inode} \textit{inode}, dato che il file che è
-stato aperto lo stesso. Questo è quello che avviene normalmente quando si apre
-più volte lo stesso file.
-
-Si ritrova quindi anche con le voci della \itindex{file~table} \textit{file
- table} una situazione analoga di quella delle voci di una directory, con la
-possibilità di avere più voci che fanno riferimento allo stesso
-\itindex{inode} \textit{inode}. L'analogia è in realtà molto stretta perché
-quando si cancella un file, il kernel verifica anche che non resti nessun
-riferimento in una una qualunque voce della \itindex{file~table} \textit{file
+la situazione di un programma in cui lo \textit{standard input} è associato ad
+un file mentre lo \textit{standard output} e lo \textit{standard error} sono
+associati ad un altro file. Si noti poi come per questi ultimi le strutture
+\kstruct{file} nella \textit{file table}, pur essendo distinte, fanno
+riferimento allo stesso \textit{inode}, dato che il file che è stato aperto lo
+stesso. Questo è quello che avviene normalmente quando si apre più volte lo
+stesso file.
+
+Si ritrova quindi anche con le voci della \textit{file table} una situazione
+analoga di quella delle voci di una directory, con la possibilità di avere più
+voci che fanno riferimento allo stesso \textit{inode}. L'analogia è in realtà
+molto stretta perché quando si cancella un file, il kernel verifica anche che
+non resti nessun riferimento in una una qualunque voce della \textit{file
table} prima di liberare le risorse ad esso associate e disallocare il
-relativo \itindex{inode} \textit{inode}.
+relativo \textit{inode}.
Nelle vecchie versioni di Unix (ed anche in Linux fino al kernel 2.0.x) il
numero di file aperti era anche soggetto ad un limite massimo dato dalle
lista, ma restano i limiti imposti dall'amministratore (vedi
sez.~\ref{sec:sys_limits}).
+\itindend{file~table}
\subsection{Apertura, creazione e chiusura di un file}
supportata su NFS solo a partire da NFSv3 e con il kernel 2.6, nelle versioni
precedenti la funzionalità viene emulata controllando prima l'esistenza del
file per cui usarla per creare \index{file!di lock} un file di lock potrebbe
-dar luogo a una \itindex{race~condition} \textit{race condition}.\footnote{un
- file potrebbe venir creato fra il controllo la successiva apertura con
- \const{O\_CREAT}, la cosa si può risolvere comunque creando un file con un
- nome univoco ed usando la funzione \func{link} per creare il \index{file!di
- lock} file di lock, (vedi sez.~\ref{sec:ipc_file_lock}).}
+dar luogo a una \textit{race condition}.\footnote{un file potrebbe venir
+ creato fra il controllo la successiva apertura con \const{O\_CREAT}, la cosa
+ si può risolvere comunque creando un file con un nome univoco ed usando la
+ funzione \func{link} per creare il \index{file!di lock} file di lock, (vedi
+ sez.~\ref{sec:ipc_file_lock}).}
Se si usa \const{O\_EXCL} senza \const{O\_CREAT} il comportamento è
indefinito. Nella creazione di un file con \const{O\_CREAT} occorre sempre
viene sempre aggiunto al contenuto precedente. Con
NFS questa funzionalità non è supportata
e viene emulata, per questo possono verificarsi
- \itindex{race~condition} \textit{race
- condition} con una sovrapposizione dei dati se
- più di un processo scrive allo stesso tempo.\\
+ \textit{race condition} con una sovrapposizione dei
+ dati se più di un processo scrive allo stesso
+ tempo.\\
\const{O\_ASYNC} & Apre il file per l'I/O in modalità asincrona (vedi
sez.~\ref{sec:signal_driven_io}). Quando è
impostato viene generato il segnale \signal{SIGIO}
sez.~\ref{sec:proc_exec}) sul file. Il flag è
previsto dallo standard POSIX.1-2008, ed è stato
introdotto con il kernel 2.6.23 per evitare una
- \itindex{race~condition} \textit{race condition}
- che si potrebbe verificare con i \textit{thread}
- fra l'apertura del file e l'impostazione della
- suddetta modalità con \func{fcntl} (vedi
- sez.~\ref{sec:file_fcntl_ioctl}).\\
+ \textit{race condition} che si potrebbe verificare
+ con i \textit{thread} fra l'apertura del file e
+ l'impostazione della suddetta modalità con
+ \func{fcntl} (vedi
+ sez.~\ref{sec:file_fcntl_ioctl}).\\
\const{O\_DIRECT} & Esegue l'I/O direttamente dalla memoria in
\textit{user space} in maniera sincrona, in modo da
scavalcare i meccanismi di bufferizzazione del
non supportano questa funzione, come ad esempio per i file di
terminale.\footnote{altri sistemi, usando \const{SEEK\_SET}, in questo caso
ritornano il numero di caratteri che vi sono stati scritti.} Lo standard
-POSIX però non specifica niente in proposito. Inoltre alcuni
-\index{file!speciali} file speciali, ad esempio \file{/dev/null}, non causano
-un errore ma restituiscono un valore indefinito.
+POSIX però non specifica niente in proposito. Inoltre alcuni file speciali, ad
+esempio \file{/dev/null}, non causano un errore ma restituiscono un valore
+indefinito.
\itindbeg{sparse~file}
\index{file!\textit{hole}|(}
Un caso tipico di necessità di accesso condiviso in scrittura è quello in cui
vari processi devono scrivere alla fine di un file (ad esempio un file di
log). Come accennato in sez.~\ref{sec:file_lseek} impostare la posizione alla
-fine del file e poi scrivere può condurre ad una \itindex{race~condition}
-\textit{race condition}l infatti può succedere che un secondo processo scriva
-alla fine del file fra la \func{lseek} e la \func{write}. In questo caso, come
-abbiamo appena visto, il file sarà esteso, ma il primo processo, che avrà la
-posizione corrente che aveva impostato con la \func{lseek} che non corrisponde
-più alla fine del file, e la sua successiva \func{write} sovrascriverà i dati
-del secondo processo.
+fine del file e poi scrivere può condurre ad una \textit{race condition};
+infatti può succedere che un secondo processo scriva alla fine del file fra la
+\func{lseek} e la \func{write}. In questo caso, come abbiamo appena visto, il
+file sarà esteso, ma il primo processo, avrà una posizione corrente che aveva
+impostato con la \func{lseek} che non corrisponde più alla fine del file, e la
+sua successiva \func{write} sovrascriverà i dati del secondo processo.
Il problema deriva dal fatto che usare due \textit{system call} in successione
non è mai un'operazione atomica dato che il kernel può interrompere
\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{EBUSY}] si è rilevata la possibilità di una
- \itindex{race~condition} \textit{race condition}.
+ \item[\errcode{EBUSY}] si è rilevata la possibilità di una \textit{race
+ condition}.
\item[\errcode{EINTR}] la funzione è stata interrotta da un segnale.
\item[\errcode{EMFILE}] si è raggiunto il numero massimo consentito di file
descriptor aperti.
L'uso di \func{dup2} ha vari vantaggi rispetto alla combinazione di
\func{close} e \func{dup}; anzitutto se \param{oldfd} è uguale \param{newfd}
questo verrebbe chiuso e \func{dup} fallirebbe, ma soprattutto l'operazione è
-atomica e consente di evitare una \itindex{race~condition} \textit{race
- condition} in cui dopo la chiusura del file si potrebbe avere la ricezione
-di un segnale il cui gestore (vedi sez.~\ref{sec:sig_signal_handler}) potrebbe
-a sua volta aprire un file, per cui alla fine \func{dup} restituirebbe un file
-descriptor diverso da quello voluto.
+atomica e consente di evitare una \textit{race condition} in cui dopo la
+chiusura del file si potrebbe avere la ricezione di un segnale il cui gestore
+(vedi sez.~\ref{sec:sig_signal_handler}) potrebbe a sua volta aprire un file,
+per cui alla fine \func{dup} restituirebbe un file descriptor diverso da
+quello voluto.
Con Linux inoltre la funzione prevede la possibilità di restituire l'errore
\errcode{EBUSY}, che non è previsto dallo standard, quando viene rilevata la
-possibilità di una \itindex{race~condition} \textit{race condition} interna in
-cui si cerca di duplicare un file descriptor che è stato allocato ma per il
-quale non sono state completate le operazioni di apertura.\footnote{la
- condizione è abbastanza peculiare e non attinente al tipo di utilizzo
- indicato, quanto piuttosto ad un eventuale tentativo di duplicare file
- descriptor non ancora aperti, la condizione di errore non è prevista dallo
- standard, ma in condizioni simili FreeBSD risponde con un errore di
- \errval{EBADF}, mentre OpenBSD elimina la possibilità di una \textit{race
- condition} al costo di una perdita di prestazioni.} In tal caso occorre
-ritentare l'operazione.
+possibilità di una \textit{race condition} interna in cui si cerca di
+duplicare un file descriptor che è stato allocato ma per il quale non sono
+state completate le operazioni di apertura.\footnote{la condizione è
+ abbastanza peculiare e non attinente al tipo di utilizzo indicato, quanto
+ piuttosto ad un eventuale tentativo di duplicare file descriptor non ancora
+ aperti, la condizione di errore non è prevista dallo standard, ma in
+ condizioni simili FreeBSD risponde con un errore di \errval{EBADF}, mentre
+ OpenBSD elimina la possibilità di una \textit{race condition} al costo di
+ una perdita di prestazioni.} In tal caso occorre ritentare l'operazione.
La duplicazione dei file descriptor può essere effettuata anche usando la
funzione di controllo dei file \func{fcntl} (che esamineremo in
{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.
+ \item[\errcode{EINVAL}] \param{fd} è un file speciale che non supporta la
+ sincronizzazione.
\end{errlist}
ed inoltre \errval{EBADF}, \errval{EIO} e \errval{EROFS} nel loro
significato generico.}
come per le altre funzioni che prendono come argomenti dei
\itindsub{pathname}{relativo} \textit{pathname} relativi, è la possibilità,
quando un \textit{pathname} relativo non fa riferimento ad un file posto
-direttamente nella \index{directory~di~lavoro} directory di lavoro corrente,
-che alcuni dei componenti del \textit{pathname} vengano modificati in
-parallelo alla chiamata a \func{open}, cosa che lascia aperta la possibilità
-di una \itindex{race~condition} \textit{race condition} in cui c'è spazio per
-un \itindex{symlink~attack} \textit{symlink attack} (si ricordi quanto visto
-per \func{access} in sez.~\ref{sec:file_perm_management}).
-
-Inoltre come già accennato, la \index{directory~di~lavoro} directory di lavoro
-corrente è una proprietà del singolo processo; questo significa che quando si
-lavora con i \itindex{thread} \textit{thread} essa sarà la stessa per tutti,
-ma esistono molti casi in cui sarebbe invece utile che ogni singolo
-\itindex{thread} \textit{thread} avesse la sua \index{directory~di~lavoro}
-directory di lavoro.
+direttamente nella directory di lavoro corrente, che alcuni dei componenti del
+\textit{pathname} vengano modificati in parallelo alla chiamata a \func{open},
+cosa che lascia aperta la possibilità di una \textit{race condition} in cui
+c'è spazio per un \textit{symlink attack} (si ricordi quanto visto per
+\func{access} in sez.~\ref{sec:file_perm_management}).
+
+Inoltre come già accennato, la directory di lavoro corrente è una proprietà
+del singolo processo; questo significa che quando si lavora con i
+\textit{thread} essa sarà la stessa per tutti, ma esistono molti casi in cui
+sarebbe invece utile che ogni singolo \textit{thread} avesse la sua directory
+di lavoro.
Per risolvere questi problemi, riprendendo una interfaccia già presente in
Solaris, a fianco delle normali funzioni che operano sui file (come
passare il relativo file descriptor alle varie funzioni che useranno quella
directory come punto di partenza per la risoluzione. In questo modo, anche
quando si lavora con i \itindex{thread} \textit{thread}, si può mantenere una
-\index{directory~di~lavoro} directory di lavoro diversa per ciascuno di essi.
+directory di lavoro diversa per ciascuno di essi.
-Questo metodo, oltre a risolvere i problemi di \itindex{race~condition}
-\textit{race condition}, consente anche di ottenere aumenti di prestazioni
-significativi quando si devono eseguire molte operazioni su sezioni
-dell'albero dei file che prevedono delle gerarchie di sottodirectory molto
-profonde. Infatti in questo caso basta eseguire la risoluzione del
-\textit{pathname} della directory di partenza una sola volta (nell'apertura
-iniziale) e non tutte le volte che si deve accedere a ciascun file che essa
-contiene.
+Questo metodo, oltre a risolvere i problemi di \textit{race condition},
+consente anche di ottenere aumenti di prestazioni significativi quando si
+devono eseguire molte operazioni su sezioni dell'albero dei file che prevedono
+delle gerarchie di sottodirectory molto profonde. Infatti in questo caso basta
+eseguire la risoluzione del \textit{pathname} della directory di partenza una
+sola volta (nell'apertura iniziale) e non tutte le volte che si deve accedere
+a ciascun file che essa contiene.
La sintassi generale di queste nuove funzioni è che esse prevedono come primo
argomento il file descriptor della directory da usare come base per la
\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.}
+\fdesc{Apre un file a partire da una directory di lavoro.}
}
{La funzione ritorna gli stessi valori e gli stessi codici di errore di
da \param{dirfd}. Qualora invece si usi un \itindsub{pathname}{assoluto}
\textit{pathname} assoluto \param{dirfd} verrà semplicemente ignorato. Infine
se per \param{dirfd} si usa il valore speciale \const{AT\_FDCWD}, la
-risoluzione sarà effettuata rispetto alla directory di
-\index{directory~di~lavoro} lavoro corrente del processo. Si tenga presente
-però che questa, come le altre costanti \texttt{AT\_*}, è definita in
-\headfile{fcntl.h}, pertanto se la si vuole usare occorrerà includere comunque
-questo file, anche per le funzioni che non sono definite in esso.
+risoluzione sarà effettuata rispetto alla directory di lavoro corrente del
+processo. Si tenga presente però che questa, come le altre costanti
+\texttt{AT\_*}, è definita in \headfile{fcntl.h}, pertanto se la si vuole
+usare occorrerà includere comunque questo file, anche per le funzioni che non
+sono definite in esso.
Così come il comportamento, anche i valori di ritorno e le condizioni di
errore delle nuove funzioni sono gli stessi delle funzioni classiche, agli
Come per i file descriptor anche per gli \textit{stream} è possibile spostarsi
all'interno di un file per effettuare operazioni di lettura o scrittura in un
punto prestabilito, sempre che l'operazione di riposizionamento sia supportata
-dal file sottostante lo \textit{stream}, nel caso cioè in cui si ha a che
-fare con quello che viene detto un file ad \textsl{accesso casuale}. Dato che
-in un sistema Unix esistono vari tipi di file, come le fifo ed i
-\index{file!di~dispositivo} file di dispositivo (ad esempio i terminali), non
-è scontato che questo sia vero in generale, pur essendolo sempre nel caso di
-file di dati.
+dal file sottostante lo \textit{stream}, nel caso cioè in cui si ha a che fare
+con quello che viene detto un file ad \textsl{accesso casuale}. Dato che in un
+sistema Unix esistono vari tipi di file, come le fifo ed i file di dispositivo
+(ad esempio i terminali), non è scontato che questo sia vero in generale, pur
+essendolo sempre nel caso di file di dati.
Con Linux ed in generale in ogni sistema unix-like la posizione nel file, come
abbiamo già visto in sez.~\ref{sec:file_lseek}, è espressa da un intero
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)}.
+\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
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} \textit{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, che in
-genere contiene uno \textit{shell code}, cioè una sezione di programma che
-lancia una shell da cui si potranno poi eseguire altri programmi.
+sovrascrivere gli indirizzi di ritorno nello \textit{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, che in genere contiene
+uno \textit{shell code}, cioè una sezione di programma che lancia una shell da
+cui si potranno poi eseguire altri programmi.
La funzione \func{fgets} non ha i precedenti problemi di \func{gets} in quanto
prende in ingresso la dimensione del buffer \param{size}, che non verrà mai
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 entrambi gli argomenti siano dei \itindex{value~result~argument}
-\textit{value result argument}, per i quali vengono passati dei puntatori
-anziché i valori delle variabili, secondo quanto abbiamo descritto in
-sez.~\ref{sec:proc_var_passing}).
+come entrambi gli argomenti siano dei \textit{value result argument}, per i
+quali vengono passati dei puntatori anziché i valori delle variabili, secondo
+quanto abbiamo descritto 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
puntatore all'inizio del testo della linea letta. Un esempio di codice può
essere il seguente:
\includecodesnip{listati/getline.c}
-e per evitare \itindex{memory~leak} \textit{memory leak} occorre ricordarsi di
-liberare la memoria allocata dalla funzione eseguendo una \func{free} su
-\var{ptr}.
+e per evitare \textit{memory leak} occorre ricordarsi di liberare la memoria
+allocata dalla funzione eseguendo una \func{free} su \var{ptr}.
Il valore di ritorno di \func{getline} indica il numero di caratteri letti
dallo \textit{stream}, quindi compreso il \textit{newline}, ma non lo zero di
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.
+cui dovrà essere scritto il contenuto degli argomenti, il cui numero è
+variabile e dipende dal formato stesso.
Le prime due servono per scrivere su file (lo \itindex{standard~output}
\textit{standard output} o quello specificato) la terza permette di scrivere
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}.
+si noti come tutte queste funzioni siano ``\textit{variadic}'', prendendo un
+numero di argomenti variabile che dipende appunto da quello che si è
+specificato in \param{format}.
La stringa di formato è costituita da caratteri normali (tutti eccetto
-``\texttt{\%}''), che vengono passati invariati all'output, e da direttive di
+``\texttt{\%}''), che vengono passati invariati in uscita, 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 tab.~\ref{tab:file_format_spec}) che la conclude.
\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
- \type{uintmax\_t}.\\
- \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{j} & Una conversione intera corrisponde a un \ctyp{intmax\_t} o
+ \ctyp{uintmax\_t}.\\
+ \cmd{z} & Una conversione intera corrisponde a un \ctyp{size\_t} o
+ \ctyp{ssize\_t}.\\
+ \cmd{t} & Una conversione intera corrisponde a un \ctyp{ptrdiff\_t}.\\
\hline
\end{tabular}
\caption{Il modificatore di tipo di dato per il formato di \func{printf}}
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
-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).
+variabile 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).
Come per \func{sprintf} anche per \func{vsprintf} esiste una analoga
\funcd{vsnprintf} che pone un limite sul numero di caratteri che vengono
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})
-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 \itindex{memory~leak} \textit{memory
- leak}.
+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 \textit{memory leak}.
% TODO verificare se mettere prototipi di \func{dprintf} e \func{vdprintf}
stato allocato e rimanere disponibile per tutto il tempo in cui si opera sullo
\textit{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 \index{variabili!automatiche} variabile
-automatica. In \headfile{stdio.h} è definita la macro \const{BUFSIZ}, che
-indica le dimensioni generiche del buffer di uno \textit{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).
+funzione, può anche essere usata una variabile automatica. In
+\headfile{stdio.h} è definita la macro \const{BUFSIZ}, che indica le
+dimensioni generiche del buffer di uno \textit{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, come delle scritture accidentali sul buffer, e non assicura la scelta