\chapter{La gestione dell'I/O su file}
\label{cha:file_IO_interface}
-Esamineremo in questo capitol le due interfacce di programmazione che
+Esamineremo in questo capitolo le due interfacce di programmazione che
consentono di gestire i dati mantenuti nei file. Cominceremo con quella nativa
del sistema, detta dei \textit{file descriptor}, che viene fornita
direttamente dalle \textit{system call} e che non prevede funzionalità evolute
\itindend{file~descriptor}
-Benché questa sia soltanto una convenzione, essa è seguita dalla gran parte
-delle applicazioni, e non aderirvi potrebbe portare a problemi di
+Benché questa sia alla fine soltanto una convenzione, essa è seguita dalla
+totalità delle applicazioni, e non aderirvi potrebbe portare a problemi di
interoperabilità. Nel caso della shell tutti questi file sono associati al
terminale di controllo, e corrispondono quindi alla lettura della tastiera per
l'ingresso e alla scrittura sul terminale per l'uscita. Lo standard POSIX.1
\const{O\_CREAT} e \const{O\_EXCL}.
\item[\errcode{EINTR}] la funzione era bloccata ed è stata interrotta da un
segnale (vedi sez.~\ref{sec:sig_gen_beha}).
- \item[\errcode{EISDIR}] \param{pathname} indica una directory e si è tentato
- l'accesso in scrittura o in lettura/scrittura.
- \item[\errcode{EFBIG}] il file è troppo grande per essere aperto (lo
- standard richiederebbe \errval{EOVERFLOW}).
+ \item[\errcode{EINVAL}] si è usato \const{O\_CREAT} indicando un pathname
+ con caratteri non supportati dal filesystem sottostante o si è richiesto
+ \const{O\_TMPFILE} senza indicare \const{O\_WRONLY} o \const{O\_RDWR} o si
+ è usato \const{O\_DIRECT} per un filesystem che non lo supporta.
+ \item[\errcode{EISDIR}] \param{pathname} indica una directory e o si è
+ tentato un accesso che prevede la scrittura o si è usato
+ \const{O\_TMPFILE} con accesso che prevede la scrittura ma il kernel non
+ supporta la funzionalità.
+ \item[\errcode{EFBIG}] il file è troppo grande per essere aperto, in genere
+ dovuto al fatto che si è compilata una applicazione a 32 bit senza
+ abilitare il supporto per le dimesioni a 64 bit; questo è il valore
+ restituito fino al kernel 2.6.23, coi successivi viene restituito
+ \errcode{EOVERFLOW} come richiesto da POSIX.1.
\item[\errcode{ELOOP}] si sono incontrati troppi collegamenti simbolici nel
risolvere \param{pathname} o si è indicato \const{O\_NOFOLLOW} e
- \param{pathname} è un collegamento simbolico.
+ \param{pathname} è un collegamento simbolico (e non si è usato
+ \const{O\_PATH}).
\item[\errcode{ENODEV}] \param{pathname} si riferisce a un file di
dispositivo che non esiste.
\item[\errcode{ENOENT}] \param{pathname} non esiste e non si è richiesto
- \const{O\_CREAT}, o non esiste un suo componente.
+ \const{O\_CREAT}, o non esiste un suo componente, o si riferisce ad una
+ directory inesistente, si è usato \const{O\_TMPFILE} con accesso che
+ prevede la scrittura ma il kernel non supporta la funzionalità.
\item[\errcode{ENOTDIR}] si è specificato \const{O\_DIRECTORY} e
\param{pathname} non è una directory.
\item[\errcode{ENXIO}] si sono impostati \const{O\_NONBLOCK} o
\item[\errcode{EWOULDBLOCK}] la funzione si sarebbe bloccata ma si è
richiesto \const{O\_NONBLOCK}.
\end{errlist}
- ed inoltre \errval{EACCES}, \errval{EFAULT}, \errval{EMFILE},
+ ed inoltre \errval{EACCES}, \errval{EDQUOT}, \errval{EFAULT}, \errval{EMFILE},
\errval{ENAMETOOLONG}, \errval{ENFILE}, \errval{ENOMEM}, \errval{ENOSPC},
\errval{EROFS}, nel loro significato generico.}
\end{funcproto}
da \param{flags}. Essa può essere invocata in due modi diversi, specificando
opzionalmente un terzo argomento \param{mode}. Qualora il file non esista e
venga creato, questo argomento consente di indicare quali permessi dovranno
-essergli assegnati. I valori possibili sono gli stessi già visti in
+essergli assegnati.\footnote{questo è possibile solo se si è usato in
+ \param{flags} uno fra \const{O\_CREATE} e \const{O\_TMPFILE}, in tutti gli
+ altri casi sarà ignorato.} I valori possibili sono gli stessi già visti in
sez.~\ref{sec:file_perm_overview} e possono essere specificati come OR binario
delle costanti descritte in tab.~\ref{tab:file_bit_perm}. Questi permessi sono
comunque filtrati dal valore della \textit{umask} (vedi
\textbf{Flag} & \textbf{Significato} \\
\hline
\hline
- \constd{O\_CREAT} & Se il file non esiste verrà creato, con le regole
- di titolarità del file viste in
- sez.~\ref{sec:file_ownership_management}. Se si
- imposta questo flag l'argomento \param{mode} deve
- essere sempre specificato.\\
- \constd{O\_DIRECTORY}&Se \param{pathname} non è una directory la
- chiamata fallisce. Questo flag, introdotto con il
- kernel 2.1.126, è specifico di Linux e
- serve ad evitare dei possibili
- \itindex{Denial~of~Service~(DoS)}
- \textit{DoS}\footnotemark quando \func{opendir}
- viene chiamata su una \textit{fifo} o su un dispositivo
- associato ad una unità a nastri. Non viene
- usato al di fuori dell'implementazione di
- \func{opendir}, ed è utilizzabile soltanto se si è
- definita la macro \macro{\_GNU\_SOURCE}.\\
- \constd{O\_EXCL} & Deve essere usato in congiunzione con
- \const{O\_CREAT} ed in tal caso impone che il file
- indicato da \param{pathname} non sia già esistente
- (altrimenti causa il fallimento della chiamata con
- un errore di \errcode{EEXIST}).\\
- \constd{O\_LARGEFILE}&Viene usato sui sistemi a 32 bit per richiedere
- l'apertura di file molto grandi, la cui
- dimensione non è rappresentabile con la versione a
- 32 bit del tipo \type{off\_t}, utilizzando
- l'interfaccia alternativa abilitata con la
- macro \macro{\_LARGEFILE64\_SOURCE}. Come
- illustrato in sez.~\ref{sec:intro_gcc_glibc_std} è
- sempre preferibile usare la conversione automatica
- delle funzioni che si attiva assegnando a $64$ la
- macro \macro{\_FILE\_OFFSET\_BITS}, e non usare mai
- questo flag.\\
- \constd{O\_NOCTTY} & Se \param{pathname} si riferisce ad un dispositivo
- di terminale, questo non diventerà il terminale di
- controllo, anche se il processo non ne ha ancora
- uno (si veda sez.~\ref{sec:sess_ctrl_term}).\\
+ \constd{O\_CREAT} & Se il file non esiste verrà creato, con le regole
+ di titolarità del file viste in
+ sez.~\ref{sec:file_ownership_management}. Se si
+ imposta questo flag l'argomento \param{mode} deve
+ essere sempre specificato.\\
+ \constd{O\_DIRECTORY}& Se \param{pathname} non è una directory la
+ chiamata fallisce. Questo flag, introdotto con il
+ kernel 2.1.126, è specifico di Linux e
+ serve ad evitare dei possibili
+ \itindex{Denial~of~Service~(DoS)}
+ \textit{DoS}\footnotemark quando \func{opendir}
+ viene chiamata su una \textit{fifo} o su un
+ dispositivo associato ad una unità a nastri. Non
+ viene usato al di fuori dell'implementazione di
+ \func{opendir}, ed è utilizzabile soltanto se si è
+ definita la macro \macro{\_GNU\_SOURCE}.\\
+ \constd{O\_EXCL} & Deve essere usato in congiunzione con
+ \const{O\_CREAT} ed in tal caso impone che il file
+ indicato da \param{pathname} non sia già esistente
+ (altrimenti causa il fallimento della chiamata con
+ un errore di \errcode{EEXIST}).\\
+ \constd{O\_LARGEFILE}& Viene usato sui sistemi a 32 bit per richiedere
+ l'apertura di file molto grandi, la cui
+ dimensione non è rappresentabile con la versione a
+ 32 bit del tipo \type{off\_t}, utilizzando
+ l'interfaccia alternativa abilitata con la
+ macro \macro{\_LARGEFILE64\_SOURCE}. Come
+ illustrato in sez.~\ref{sec:intro_gcc_glibc_std} è
+ sempre preferibile usare la conversione automatica
+ delle funzioni che si attiva assegnando a $64$ la
+ macro \macro{\_FILE\_OFFSET\_BITS}, e non usare mai
+ questo flag.\\
+ \constd{O\_NOCTTY} & Se \param{pathname} si riferisce ad un dispositivo
+ di terminale, questo non diventerà il terminale di
+ controllo, anche se il processo non ne ha ancora
+ uno (si veda sez.~\ref{sec:sess_ctrl_term}).\\
\constd{O\_NOFOLLOW}& Se \param{pathname} è un collegamento simbolico
la chiamata fallisce. Questa è un'estensione BSD
aggiunta in Linux a partire dal kernel
2.1.126, ed utilizzabile soltanto se si è definita
la macro \macro{\_GNU\_SOURCE}.\\
- \constd{O\_TRUNC} & Se usato su un file di dati aperto in scrittura,
- ne tronca la lunghezza a zero; con un terminale o
- una \textit{fifo} viene ignorato, negli altri casi il
- comportamento non è specificato.\\
+ \const{O\_PATH} & Ottiene un file descriptor io cui uso è limitato
+ all'indicare una posizione sul filesystem o
+ eseguire operazioni che operano solo a livello del
+ file descriptor (e non di accesso al contenuto del
+ file). Introdotto con il kernel 2.6.39, è specifico
+ di Linux.\\
+ \const{O\_TMPFILE} & Consente di creare un file temporaneo anonimo, non
+ visibile con un pathname sul filesystem, ma
+ leggibile e scrivibile all'iterno del processo.
+ Introdotto con il kernel 3.11, è specifico di
+ Linux.\\
+ \constd{O\_TRUNC} & Se usato su un file di dati aperto in scrittura,
+ ne tronca la lunghezza a zero; con un terminale o
+ una \textit{fifo} viene ignorato, negli altri casi
+ il comportamento non è specificato.\\
\hline
\end{tabular}
\caption{Le costanti che identificano le \textit{modalità di apertura} di
\label{tab:open_time_flag}
\end{table}
-
-% TODO: aggiungere O_TMPFILE per la creazione di file temporanei senza che
-% questi appaiano sul filesystem, introdotto con il 3.11, vedi:
-% https://lwn.net/Articles/556512/, http://kernelnewbies.org/Linux_3.11
-% https://lwn.net/Articles/558598/ http://lwn.net/Articles/619146/
-
\footnotetext{acronimo di \itindex{Denial~of~Service~(DoS)} \textit{Denial of
Service}, si chiamano così attacchi miranti ad impedire un servizio
causando una qualche forma di carico eccessivo per il sistema, che resta
esistono con Linux.} Uno di questi, \const{O\_EXCL}, ha senso solo se usato
in combinazione a \const{O\_CREAT} quando si vuole creare un nuovo file per
assicurarsi che questo non esista di già, e lo si usa spesso per creare i
-cosiddetti ``\textsl{file di lock}'' (vedi sez.~\ref{sec:ipc_file_lock}). Si
-tenga presente che questa opzione è 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 un file di
-lock potrebbe 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 file di lock,
- (vedi sez.~\ref{sec:ipc_file_lock}).}
+cosiddetti ``\textsl{file di lock}'' (vedi sez.~\ref{sec:ipc_file_lock}).
+
+Si tenga presente che questa opzione è 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 un
+file di lock potrebbe dar luogo a una \textit{race condition}, in tal caso
+infatto 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 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
-specificare l'argomento di \param{mode}, che altrimenti è ignorato. Si tenga
-presente che indipendentemente dai permessi che si possono assegnare, che in
-seguito potrebbero non consentire lettura o scrittura, quando il file viene
-aperto l'accesso viene garantito secondo quanto richiesto con i flag di
+indefinito, escluso il caso in cui viene usato con uno dei due nuovi flag
+\const{O\_PATH} o \const{O\_TMPFILE} su cui torneremo a breve. Nella
+creazione di un file con \const{O\_CREAT} occorre sempre specificare
+l'argomento di \param{mode}, che altrimenti è ignorato. Si tenga presente che
+indipendentemente dai permessi che si possono assegnare, che in seguito
+potrebbero non consentire lettura o scrittura, quando il file viene aperto
+l'accesso viene garantito secondo quanto richiesto con i flag di
tab.~\ref{tab:open_access_mode_flag}. Quando viene creato un nuovo file
\const{O\_CREAT} con tutti e tre i tempi del file di
tab.~\ref{tab:file_file_times} vengono impostati al tempo corrente. Se invece
si tronca il file con \const{O\_TRUNC} verranno impostati soltanto il
\textit{modification time} e lo \textit{status change time}.
+Dei flag illustrati in tab.~\ref{tab:open_time_flag} due, specifici di Linux
+ed introdotti solo con i kernel più recenti, meritano un approfondimento. Il
+primo di questi è \constd{O\_PATH}, che viene usato per limitare l'uso del
+file descriptor restituito da \func{open} o all'identificazione di una
+posizione sul filesystem (ad uso delle \textit{at-functions} che tratteremo in
+sez.~\ref{sec:file_openat}) o a operazioni che riguardano solo il file
+descriptor; le sole funzioni con cui sarà possibile usare il file descriptor
+sono:
+
+\begin{itemize*}
+\item \func{close}
+\item \func{fchdir}, se il file descriptore fa riferimento a una directory
+ (dal kernel 3.5).
+\item \func{fstat} (dal kernel 3.6).
+\item \func{fstatfs} (dal kernel 3.12).
+\item le funzioni che duplicano il file descriptor (vedi
+ sez.~\ref{sec:file_dup})
+\item
+
+\end{itemize*}
+
+In realtà infatti usando \constd{O\_PATH} il file non viene effettivamente
+aperto, per cui ogni tentativo di usare il file descriptor così ottenuto con
+funzioni che operano effettivamente sul file (come ad esempio \func{read},
+\func{write}, \func{fchown}, \func{fchmod}, \func{ioctl}, ecc.) fallirano con
+un errore di \errval{EBADF} come se questo non fosse un file descriptor
+valido.
+
+
+
+% TODO: aggiungere O_TMPFILE per la creazione di file temporanei senza che
+% questi appaiano sul filesystem, introdotto con il 3.11, vedi:
+% https://lwn.net/Articles/556512/, http://kernelnewbies.org/Linux_3.11
+% https://lwn.net/Articles/558598/ http://lwn.net/Articles/619146/
+
+
\begin{table}[!htb]
\centering
\footnotesize
tutte le volte che il file è pronto per le
operazioni di lettura o scrittura. Questo flag si
può usare solo terminali, pseudo-terminali e socket
- e, a partire dal kernel 2.6, anche sulle \textit{fifo}. Per
- un bug dell'implementazione non è opportuno usarlo
- in fase di apertura del file, deve
- invece essere attivato successivamente con
+ e, a partire dal kernel 2.6, anche sulle
+ \textit{fifo}. Per un bug dell'implementazione non
+ è opportuno usarlo in fase di apertura del file,
+ deve invece essere attivato successivamente con
\func{fcntl}.\\
\constd{O\_CLOEXEC}& Attiva la modalità di \textit{close-on-exec} (vedi
sez.~\ref{sec:proc_exec}) sul file. Il flag è
montaggio. Introdotto con il kernel 2.6.8 ed
utilizzabile soltanto se si è definita la
macro \macro{\_GNU\_SOURCE}.\\
- \constd{O\_NONBLOCK}&Apre il file in \textsl{modalità non bloccante} per
- le operazioni di I/O (vedi
- sez.~\ref{sec:file_noblocking}). Questo significa
- il fallimento delle successive operazioni di
- lettura o scrittura qualora il file non sia pronto
- per la loro esecuzione immediata, invece del
- blocco delle stesse in attesa di una successiva
- possibilità di esecuzione come avviene
- normalmente. Questa modalità ha senso solo per le
- \textit{fifo}, vedi sez.~\ref{sec:ipc_named_pipe}), o quando
- si vuole aprire un file di dispositivo per eseguire
- una \func{ioctl} (vedi
- sez.~\ref{sec:file_fcntl_ioctl}).\\
+ \constd{O\_NONBLOCK}& Apre il file in \textsl{modalità non bloccante} per
+ le operazioni di I/O (vedi
+ sez.~\ref{sec:file_noblocking}). Questo significa
+ il fallimento delle successive operazioni di
+ lettura o scrittura qualora il file non sia pronto
+ per la loro esecuzione immediata, invece del
+ blocco delle stesse in attesa di una successiva
+ possibilità di esecuzione come avviene
+ normalmente. Questa modalità ha senso solo per le
+ \textit{fifo}, vedi sez.~\ref{sec:ipc_named_pipe}),
+ o quando si vuole aprire un file di dispositivo
+ per eseguire una \func{ioctl} (vedi
+ sez.~\ref{sec:file_fcntl_ioctl}).\\
\constd{O\_NDELAY} & In Linux è un sinonimo di \const{O\_NONBLOCK}, ma
origina da SVr4, dove però causava il ritorno da
una \func{read} con un valore nullo e non con un
\end{table}
+\texttt{ATTENZIONE PARTE DA RIVEDERE}
+
+
Un'ultima differenza fra le \textit{at-functions} e le funzioni tradizionali
di cui sono estensione è, come accennato in sez.~\ref{sec:file_temp_file},
quella relativa a \func{utimensat} che non è propriamente una corrispondente
esatta di \func{utimes} e \func{lutimes}, dato che questa funzione ha una
maggiore precisione nella indicazione dei tempi dei file, per i quali come per
\func{futimes}, si devono usare strutture \struct{timespec} che consentono una
-precisione fino al nanosecondo.
+precisione fino al nanosecondo; la funzione è stata introdotta con il kernel
+2.6.22,\footnote{in precedenza, a partire dal kernel 2.6.16, era stata
+ introdotta una \textit{system call} \funcm{futimesat} seguendo una bozza
+ della revisione dello standard poi modificata; questa funzione, sostituita
+ da \func{utimensat}, è stata dichiarata obsoleta, non è supportata da
+ nessuno standard e non deve essere più utilizzata: pertanto non ne
+ parleremo.} ed il suo prototipo è:
+
+\begin{funcproto}{
+\fhead{sys/time.h}
+\fdecl{int utimensat(int dirfd, const char *pathname, const struct
+ timespec times[2], int flags)}
+\fdesc{Cambia i tempi di un file.}
+}
+
+{La funzione ritorna $0$ in caso di successo e $-1$ per un errore, nel qual
+ caso \var{errno} assumerà uno dei valori:
+ \begin{errlist}
+ \item[\errcode{EACCES}] si è richiesta l'impostazione del tempo corrente ma
+ non si ha il permesso di scrittura sul file, o non si è proprietari del
+ file o non si hanno i privilegi di amministratore; oppure il file è
+ immutabile (vedi sez.~\ref{sec:file_perm_overview}).
+ \item[\errcode{EBADF}] \param{dirfd} non è \const{AT\_FDCWD} o un file
+ descriptor valido.
+ \item[\errcode{EFAULT}] \param{times} non è un puntatore valido oppure
+ \param{dirfd} è \const{AT\_FDCWD} ma \param{pathname} è \var{NULL} o non è
+ un puntatore valido.
+ \item[\errcode{EINVAL}] si sono usati dei valori non corretti per i tempi di
+ \param{times}, oppure è si usato un valore non valido per \param{flags},
+ oppure \param{pathname} è \var{NULL}, \param{dirfd} non è
+ \const{AT\_FDCWD} e \param{flags} contiene \const{AT\_SYMLINK\_NOFOLLOW}.
+ \item[\errcode{EPERM}] si è richiesto un cambiamento nei tempi non al tempo
+ corrente, ma non si è proprietari del file o non si hanno i privilegi di
+ amministratore; oppure il file è immutabile o \textit{append-only} (vedi
+ sez.~\ref{sec:file_perm_overview}).
+ \item[\errcode{ESRCH}] non c'è il permesso di attraversamento per una delle
+ componenti di \param{pathname}.
+ \end{errlist}
+ ed inoltre per entrambe \errval{EROFS} e per \func{utimensat}
+ \errval{ELOOP}, \errval{ENAMETOOLONG}, \errval{ENOENT}, \errval{ENOTDIR} nel
+ loro significato generico.}
+\end{funcproto}
+
+La funzione imposta i tempi dei file utilizzando i valori passati nel vettore
+di strutture \struct{timespec} esattamente come \func{futimes} (si veda quanto
+illustrato in sez.~\ref{sec:file_file_times}).
+
+La funzione supporta invece, rispetto ad \func{utimes} che abbiamo visto in
+sez.~\ref{sec:file_file_times}, una sintassi più complessa che consente una
+indicazione sicura del file su cui operare specificando la directory su cui si
+trova tramite il file descriptor \param{dirfd} ed il suo nome come
+\textit{pathname relativo} in \param{pathname}.\footnote{su Linux solo
+ \func{utimensat} è una \textit{system call} e \func{futimens} è una funzione
+ di libreria, infatti se \param{pathname} è \var{NULL} \param{dirfd} viene
+ considerato un file descriptor ordinario e il cambiamento del tempo
+ applicato al file sottostante, qualunque esso sia, per cui
+ \code{futimens(fd, times}) è del tutto equivalente a \code{utimensat(fd,
+ NULL, times, 0)} ma nella \acr{glibc} questo comportamento è disabilitato
+ seguendo lo standard POSIX, e la funzione ritorna un errore di
+ \errval{EINVAL} se invocata in questo modo.}
+
+Torneremo su questa sintassi e sulla sua motivazione in
+sez.~\ref{sec:file_openat}, quando tratteremo tutte le altre funzioni (le
+cosiddette \textit{at-functions}) che la utilizzano; essa prevede comunque
+anche la presenza dell'argomento \param{flags} con cui attivare flag di
+controllo che modificano il comportamento della funzione, nel caso specifico
+l'unico valore consentito è \const{AT\_SYMLINK\_NOFOLLOW} che indica alla
+funzione di non dereferenziare i collegamenti simbolici, cosa che le permette
+di riprodurre le funzionalità di \func{lutimes}.
+
+
+\texttt{ATTENZIONE PARTE DA RIVEDERE}
-% NOTA: manca prototipo di utimensat, per ora si lascia una menzione
\itindend{at-functions}
% LocalWords: FIONREAD epoll FIOQSIZE side effects SAFE BYCALLER QUERY EACCES
% LocalWords: EBUSY OpenBSD syncfs futimes timespec only init ESRCH kill NTPL
% LocalWords: ENXIO NONBLOCK WRONLY EPERM NOATIME ETXTBSY EWOULDBLOCK PGRP SZ
-% LocalWords: EFAULT capabilities GETPIPE SETPIPE RESOURCE
+% LocalWords: EFAULT capabilities GETPIPE SETPIPE RESOURCE dell'I all' NFSv
%%% Local Variables:
%%% mode: latex
%%% TeX-master: "gapil"
%%% End:
+% LocalWords: l'I nell' du vm Documentation Urlich Drepper futimesat times
+% LocalWords: futimens fs Tread all'I ll