From 1d513e11c8e4aaee86fb5016e67520c4d2f87bb8 Mon Sep 17 00:00:00 2001 From: Simone Piccardi Date: Thu, 27 Sep 2018 02:42:46 +0200 Subject: [PATCH] Revisione di open(2) e documentazione O_PATH (inizio). --- fileio.tex | 232 +++++++++++++++++++++++++++++++++-------------------- 1 file changed, 145 insertions(+), 87 deletions(-) diff --git a/fileio.tex b/fileio.tex index 3d16c07..2008e7a 100644 --- a/fileio.tex +++ b/fileio.tex @@ -162,8 +162,8 @@ aspetta di dover scrivere i dati in uscita. Il terzo è lo \textit{standard \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 @@ -248,17 +248,29 @@ corrispondente,\footnote{è \func{open} che alloca \kstruct{file}, la inserisce \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 @@ -272,7 +284,7 @@ corrispondente,\footnote{è \func{open} che alloca \kstruct{file}, la inserisce \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} @@ -281,7 +293,9 @@ La funzione apre il file indicato da \param{pathname} nella modalità indicata 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 @@ -396,51 +410,62 @@ sez.~\ref{sec:file_fcntl_ioctl}). \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 @@ -448,12 +473,6 @@ sez.~\ref{sec:file_fcntl_ioctl}). \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 @@ -467,28 +486,67 @@ Si è riportato in tab.~\ref{tab:open_time_flag} l'elenco dei flag delle 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 @@ -512,10 +570,10 @@ si tronca il file con \const{O\_TRUNC} verranno impostati soltanto il 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 è @@ -540,19 +598,19 @@ si tronca il file con \const{O\_TRUNC} verranno impostati soltanto il 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 -- 2.30.2