X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=fileunix.tex;h=bc94a0e2f6d650fd91e539f008df2717964cf47b;hp=86652f3d57c6b1d09978ac9f680804135420cf01;hb=dfec603c0424b6ec1e0f8d630dd4303acf2e35a7;hpb=dd2dbdf77bcec1ae91fe5f65a998c1344cf3f1a6 diff --git a/fileunix.tex b/fileunix.tex index 86652f3..bc94a0e 100644 --- a/fileunix.tex +++ b/fileunix.tex @@ -2,121 +2,522 @@ \label{cha:file_unix_interface} Esamineremo in questo capitolo la prima delle due interfacce di programmazione -per i file, quella dei file descriptor, nativa di unix. Questa è l'interfaccia -di basso livello, che non prevede funzioni evolute come la bufferizzazione o -funzioni di lettura o scrittura formattata, ma è su questa che è costruita -anche l'interfaccia standard dei file definita dallo standard ANSI C. +per i file, quella dei \textit{file descriptor}, nativa di unix. Questa è +l'interfaccia di basso livello, che non prevede funzioni evolute come la +bufferizzazione o funzioni di lettura o scrittura formattata, ma è su questa +che è costruita anche l'interfaccia standard dei file definita dallo standard +ANSI C. \section{L'architettura di base} \label{sec:file_base_arch} -Iniziamo la trattazione con una panoramica sull'architettura base della -intefaccia dei file descriptor. Esamineremo in questa sezione la struttura -base dell'interfaccia con i file di unix, e le modalità con cui i processi -ed il kernel interagiscono per operare sui file. +In questa sezione faremo una breve introduzione sulla architettura su cui è +basata dell'interfaccia dei \textit{file descriptor}, che, sia pure con +differenze nella realizzazione pratica, resta sostanzialmente la stessa in +ogni implementazione di unix. -\subsection{L'architettura dei \textit{file descriptors}} +\subsection{L'architettura dei \textit{file descriptor}} \label{sec:file_fd} Per poter accedere al contenuto di un file occorre creare un canale di comunicazione con il kernel che renda possibile operare su di esso (si ricordi -quanto visto in \secref{sec:file_vfs_work}), questo si fa aprendo il file con +quanto visto in \secref{sec:file_vfs_work}). Questo si fa aprendo il file con la funzione \func{open} che provvederà a localizzare l'inode del file e inizializzare le funzioni che il VFS mette a disposizione (riportate in \tabref{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. -Per capire come funziona questo canale di comunicazione occorre spiegare -brevemente qual'è architettura con cui il kernel gestisce l'interazione fra -processi e file. Il kernel mantiene sempre un elenco dei processi attivi -nella cosiddetta \textit{process table} ed un elenco dei file aperti nella -\textit{file table}. La relazione fra queste tabelle è mostrata in \nfig. - - +All'interno di ogni processo i file aperti sono identificati da un intero non +negativo, chiamato appunto \textit{file descriptor}, quando un file viene +aperto la funzione restituisce il file descriptor, e tutte le successive +operazioni devono passare il \textit{file descriptors} come argomento. + +Per capire come funziona il meccanismo occorre spiegare a grandi linee come è +che il kernel gestisce l'interazione fra processi e file. Il kernel mantiene +sempre un elenco dei processi attivi nella cosiddetta \textit{process table} +ed un elenco dei file aperti nella \textit{file table}. + +La \textit{process table} è una tabella che contiene una voce per ciascun +processo attivo nel sistema. In Linux ciascuna voce è costituita da una +struttura di tipo \var{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 \var{files\_struct}, in cui sono +contenute le informazioni relative ai file che il processo ha aperto, ed in +particolare: +\begin{itemize*} +\item i flag relativi ai file descriptor. +\item il numero di file aperti. +\item una tabella che contiene un puntatore alla relativa voce nella + \textit{file table} per ogni file aperto. +\end{itemize*} +il \textit{file descriptor} in sostanza è l'intero positivo che indicizza +quest'ultima tabella. + +La \textit{file table} è una tabella che contiene una voce per ciascun file +che è stato aperto nel sistema. In Linux è costituita da strutture di tipo +\var{file}; in ciascuna di esse sono tenute varie informazioni relative al +file, fra cui: +\begin{itemize*} +\item lo stato del file (nel campo \var{f\_flags}). +\item il valore della posizione corrente (l'\textit{offset}) nel file (nel + campo \var{f\_pos}). +\item un puntatore all'inode\footnote{nel kernel 2.4.x si è in realtà passati + ad un puntatore ad una struttura \var{dentry} che punta a sua volta + all'inode passando per la nuova struttura del VFS} del file. +%\item un puntatore alla tabella delle funzioni \footnote{la struttura +% \var{f\_op} descritta in \secref{sec:file_vfs_work}} che si possono usare +% sul file. +\end{itemize*} + +In \figref{fig:file_proc_file} si è riportato uno schema in cui è illustrata +questa architettura, in cui si sono evidenziate le interrelazioni fra le varie +strutture di dati sulla quale essa è basata. \begin{figure}[htb] \centering - \includegraphics[width=7cm]{img/procfile.eps} - \caption{Schema delle operazioni del VFS} - \label{fig:file_VFS_scheme} + \includegraphics[width=14cm]{img/procfile.eps} + \caption{Schema della architettura dell'accesso ai file attraverso + l'interfaccia dei \textit{file descroptor}} + \label{fig:file_proc_file} \end{figure} +Ritorneremo su questo schema più volte, dato che esso è fondamentale per +capire i dettagli del funzionamento delle dell'interfaccia dei \textit{file + descriptor}. + + +\subsection{I file standard} +\label{sec:file_std_descr} + +Come accennato i \textit{file descriptor} non sono altro che un indice nella +tabella dei file aperti di ciascun processo; per questo motivo essi vengono +assegnati in successione tutte le volte che si apre un nuovo file (se non se +ne è chiuso nessuno in precedenza). + +In tutti i sistemi unix-like esiste una convenzione generale per cui ogni +processo viene lanciato con almeno tre file aperti. Questi, per quanto +dicevamo prima, avranno come \textit{file descriptor} i valori 0, 1 e 2. +Benché questa sia soltanto una convenzione, essa è seguita dalla gran parte +delle applicazioni, e non aderirvi potrebbe portare a gravi problemi di +interoperabilità. + +Il primo file è sempre associato a quello che viene chiamato \textit{standard + input}, è cioè il file da cui il processo si aspetta di ricevere i dati in +ingresso (nel caso della shell, è associato alla lettura della tastiera); il +secondo file è il cosiddetto \textit{standard output}, cioè il file su cui ci +si aspetta debbano essere inviati i dati in uscita (sempre nel caso della +shell, è il terminale su cui si sta scrivendo), il terzo è lo \textit{standard + error}, su cui viene inviato l'output relativo agli errori. +Lo standard POSIX.1 provvede tre costanti simboliche, definite nell'header +\file{unistd.h}, al posto di questi valori numerici: +\begin{table}[htb] + \centering + \footnotesize + \begin{tabular}[c]{|l|l|} + \hline + \textbf{Costante} & \textbf{Significato} \\ + \hline + \hline + \macro{STDIN\_FILENO} & \textit{file descriptor} dello \textit{standard + input} \\ + \macro{STDOUT\_FILENO} & \textit{file descriptor} dello \textit{standard + output} \\ + \macro{STDERR\_FILENO} & \textit{file descriptor} dello \textit{standard + error}\\ + \hline + \end{tabular} + \caption{Costanti definite in \file{unistd.h} per i file standard aperti + alla creazione di ogni processo.} + \label{tab:file_std_files} +\end{table} + +In \curfig\ si è utilizzata questa situazione come esempio, facendo +riferimento ad un programma in cui lo \textit{standard input} è associato ad +un file mentre lo \textit{standard output} e lo \textit{standard error} sono +entrambi associati ad un altro file (e quindi utilizzano lo stesso 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 +dimensioni del vettore di puntatori con cui era realizzata la tabella dei file +descriptor dentro \var{file\_struct}; questo limite intrinseco non sussiste +più, dato che si è passati da un vettore ad una linked list, ma restano i +limiti imposti dall'amministratore (vedi \secref{sec:sys_limits}). -Ciascuna voce della \textit{process table}, che in Linux è costituita da una -struttura \var{task\_struct}, contiene le informazioni relative ad ogni -processo attivo nel sistema; fra queste c'è anche il puntatore ad una -ulteriore struttura \var{files\_struct} in cui sono contenute le informazioni -relative a ogni file che il processo ha aperto, ed in particolare: -\begin{itemize} -\item i flag relativi ai file descriptor. -\item un puntatore alla struttura \var{file} nella \textit{file table} per - ogni file aperto. -\end{itemize} -Ciascuna voce della \textit{file table}, che in Linux è costituita da una -struttura \var{file}, contiene le informazioni relative ad ogni file aperto -nel sistema, fra queste ci sono: +\section{Le funzioni base} +\label{sec:file_base_func} + +L'interfaccia standard unix per l'input/output sui file è basata su cinque +funzioni fondamentali \func{open}, \func{read}, \func{write}, \func{lseek} e +\func{close}, usate rispettivamente per aprire, leggere, scrivere, spostarsi e +chiudere un file. + +La gran parte delle operazioni sui file si effettua attraverso queste cinque +funzioni, esse vengono chiamate anche funzioni di I/O non bufferizzato dato +che effettuano le operazioni di lettura e scrittura usando direttamente le +system call del kernel. + + +\subsection{La funzione \func{open}} +\label{sec:file_open} + +La funzione \func{open} è la funzione fondamentale per accedere ai file, ed è +quella che crea l'associazione fra un pathname ed un file descriptor; il suo +prototipo è: +\begin{functions} + \headdecl{sys/types.h} + \headdecl{sys/stat.h} + \headdecl{fcntl.h} + \funcdecl{int open(const char *pathname, int flags)} + \funcdecl{int open(const char *pathname, int flags, mode\_t mode)} + Apre il file indicato da \var{pathname} nella modalità indicata da + \var{flags}, e, nel caso il file sia creato, con gli eventuali permessi + specificati da \var{mode}. + + La funzione ritorna il file descriptor in caso di successo e -1 in caso di + errore. In questo caso la variabile \var{errno} viene settata ad uno dei + valori: + \begin{errlist} + \item \macro{EEXIST} \var{pathname} esiste e si è specificato + \macro{O\_CREAT} e \macro{O\_EXCL}. + \item \macro{EISDIR} \var{pathname} indica una directory e si è tentato + l'accesso in scrittura. + \item \macro{ENOTDIR} si è specificato \macro{O\_DIRECTORY} e \var{pathname} + non è una directory. + \item \macro{ENXIO} si sono settati \macro{O\_NOBLOCK} o \macro{O\_WRONLY} + ed il file è una fifo che non viene letta da nessun processo o + \var{pathname} è un file di dispositivo ma il dispositivo è assente. + \item \macro{ENODEV} \var{pathname} si riferisce a un file di dispositivo + che non esiste. + \item \macro{ETXTBSY} si è cercato di accedere in scrittura all'immagine di + un programma in esecuzione. + \item \macro{ELOOP} si sono incotrati troppi link simbolici nel risolvere + pathname o si è indicato \macro{O\_NOFOLLOW} e \var{pathname} è un link + simbolico. + \end{errlist} + ed inoltre \macro{EACCES}, \macro{ENAMETOOLONG}, \macro{ENOENT}, + \macro{EROFS}, \macro{EFAULT}, \macro{ENOSPC}, \macro{ENOMEM}, + \macro{EMFILE} e \macro{ENFILE}. +\end{functions} + +La funzione apre il file, usando il primo file descriptor libero, e crea +l'opportuna voce (cioè la struttura \var{file}) nella file table. Viene usato +sempre il file descriptor con il valore più basso, questa caratteristica +permette di prevedere qual'è il valore che si otterrà e viene talvolta usata +da alcune applicazioni per sostituire i file corrispondenti ai file standard +di \secref{sec:file_std_descr}: se ad esempio si chiude lo standard input e si +apre subito dopo un nuovo file questo diventerà il nuovo standard input (avrà +cioè il file descriptor 0). + + +\begin{table}[!htb] + \centering + \footnotesize + \begin{tabular}[c]{|l|p{12cm}|} + \hline + \textbf{Flag} & \textbf{Descrizione} \\ + \hline + \hline % modailtà di accesso al file + \macro{O\_RDONLY} & apre il file in sola lettura. \\ + \macro{O\_WRONLY} & apre il file in sola scrittura. \\ + \macro{O\_RDWR} & apre il file lettura/scrittura. \\ + \hline % modalita di apertura del file + \hline + \macro{O\_CREAT} & se il file non esiste verrà creato, con le regole di + titolarità del file viste in \secref{sec:file_ownership}. Il parametro + \var{mode} deve essere specificato. \\ + \macro{O\_EXCL} & usato in congiunzione con \macro{O\_CREAT} fa sì che + l'esistenza del file diventi un errore\footnote{la man page di \func{open} + segnala che questa opzione è difettosa su NFS, e che i programmi che la + usano per stabilire un file di lock possono incorrere in una race + condition. Si consiglia come alternativa di usare un file con un nome + univoco e la funzione \func{link} per verificarne l'esistenza.} che fa + fallire \func{open} con \macro{EEXIST}. \\ + \macro{O\_NONBLOCK} & apre il file in modalità non bloccante. Questo + valore specifica anche una modalità di operazione (vedi sotto), e + comporta che \func{open} ritorni immediatamente (torneremo su + questo in \secref{sec:file_noblocking}). \\ + \macro{O\_NOCTTY} & se \var{pathname} si riferisce ad un device di + terminale, questo non diventerà il terminale di controllo, anche se il + processo non ne ha ancora uno (si veda \secref{sec:sess_xxx}). \\ + \macro{O\_SHLOCK} & opzione di BSD, acquisisce uno shared lock (vedi + \secref{sec:file_locking}) sul file. Non è disponibile in Linux. \\ + \macro{O\_EXLOCK} & opzione di BSD, acquisisce uno lock esclusivo (vedi + \secref{sec:file_locking}) sul file. Non è disponibile in Linux. \\ + \macro{O\_TRUNC} & se il file esiste ed è un file di dati e la modalità di + apertura consente la scrittura, allora la sua lunghezza verrà troncata a + zero. Se il file è un terminale o una fifo il flag verrà ignorato, negli + altri casi il comportamento non è specificato. \\ + \macro{O\_NOFOLLOW} & se \var{pathname} è un link simbolico la chiamata + fallisce. Questa è una estensione BSD aggiunta in Linux dal kernel 2.1.126. + Nelle versioni precedenti i link simbolici sono sempre seguiti, e questa + opzione è ignorata. \\ + \macro{O\_DIRECTORY} & se \var{pathname} non è una directory la chiamata + fallisce. Questo flag è specifico di Linux ed è stato introdotto con il + kernel 2.1.126 per evitare dei DoS\footnote{Denial of Service, si chiamano + così attacchi miranti ad impedire un servizio causando una qualche forma + di carico eccessivo per il sistema, che resta bloccato nelle risposte + all'attacco} quando \func{opendir} viene chiamata su una fifo o su un + device di unità a nastri, non deve essere utilizzato al di fuori + dell'implementazione di \func{opendir}. \\ + \macro{O\_LARGEFILE} & nel caso di sistemi a 32 bit che supportano file di + grandi dimensioni consente di aprire file le cui dimensioni non possono + essere rappresentate da numeri a 31 bit. \\ + \hline + \hline % modalità di operazione col file + \macro{O\_APPEND} & il file viene aperto in append mode. Prima di ciascuna + scrittura la posizione corrente viene sempre settata alla fine del + file. Può causare corruzione del file con NFS se più di un processo scrive + allo stesso tempo\footnote{il problema è che NFS non supporta la scrittura + in append, ed il kernel deve simularla, ma questo comporta la possibilità + di una race condition}.\\ + \macro{O\_NONBLOCK} & il file viene aperto in modalità non bloccante per + le operazioni di I/O: questo significa il fallimento di una \func{read} in + assenza di dati da leggere e quello di una \func{write} in caso di + impossibilità di scrivere immediatamente. L'opzione è effettiva solo per + le fifo e per alcuni file di dispositivo. \\ + \macro{O\_NDELAY} & in Linux\footnote{l'opzione origina da SVr4, dove però + causava il ritorno da una \func{read} con un valore nullo e non con un + errore, questo introduce una ambiguità, dato che come vedremo in + \secref{sec:file_read} il ritorno di zero da parte di \func{read} ha il + significato di una end-of-file} è sinonimo di \macro{O\_NONBLOCK}.\\ + \macro{O\_ASYNC} & apre il file per l'input/output in modalità + asincrona. Non è supportato in Linux. \\ + \macro{O\_SYNC} & apre il file per l'input/output sincrono, ogni + \func{write} bloccherà fino al completamento della scrittura di tutti dati + sul sull'hardware sottostante.\\ + \macro{O\_FSYNC} & sinonimo di \macro{O\_SYNC}. \\ + \macro{O\_NOATIME} & blocca l'aggiornamento dei tempi dei di accesso dei + file (vedi \secref{sec:file_file_times}). In Linux questa opzione non è + disponibile per il singolo file ma come opzione per il filesystem in fase + di montaggio.\\ + \hline + \end{tabular} + \caption{Costanti definite in \file{fcntl.h} per indicare i vari bit + usabili per il specificare parametro \var{flags} di \func{open}.} + \label{tab:file_open_flags} +\end{table} + +Il nuovo file descriptor non è condiviso con nessun altro processo, (torneremo +sulla condivisione dei file, in genere accessibile dopo una \func{fork}, in +\secref{sec:file_sharing}). Il nuovo file descriptor è settato di default per +restare aperto attraverso una \func{exec} (come accennato in +\secref{sec:proc_exec}) ed l'offset è settato all'inizio del file. + +Il parametro \var{mode} specifica i permessi con cui il file viene +eventualmente creato; i valori possibili sono gli stessi già visti in +\secref{sec:file_perm_overview} e possono essere specificati come OR binario +delle costanti descritte in \tabref{tab:file_bit_perm}. Questi permessi +filtrati dal valore di \file{umask} (vedi \secref{sec:file_umask}) per il +processo. + +La funzione prevede diverse opzioni, che vengono specificate usando vari bit +del parametro \var{flags}. Alcuni di questi bit vanno anche a costituire il +flag di stato del file (o \textit{file status flag}), che è mantenuto nel +campo \var{f\_flags} della struttura \var{file} (al solito si veda lo schema +di \curfig). Essi sono divisi in tre categorie principali: \begin{itemize} -\item lo stato del file (lettura, scrittura, append, etc.). -\item il valore della posizione corrente (l'\textit{offset}). -\item un puntatore all'inode\footnote{nel kernel 2.4.x si è in realtà passati - ad un puntatore ad una struttura \var{dentry} che punta a sua volta - all'inode passando per la nuova struttura del VFS} del file (da cui si - accede all'inode). -\item un puntatore alla tabella delle operazioni definite sul file (si ricordi - quanto detto a proposito di \tabref{tab:file_file_operations} nella - spiegazione del VFS di Linux). +\item \textsl{i bit delle modalità di accesso}: specificano con quale modalità + si accederà al file: i valori possibili sono lettura, scrittura o + lettura/scrittura. Uno di questi bit deve essere sempre specificato quando + si apre un file. Vengono settati alla chiamata da \func{open}, e possono + essere riletti con una \func{fcntl} (fanno parte del \textit{file status + flag}), ma non modificati. +\item \textsl{i bit delle modalità di apertura}: permettono di specificare + alcune delle caratteristiche del comportamento di \func{open} quando viene + eseguita. Hanno effetto solo al momento della chiamata della funzione e non + sono memorizzati nè possono essere riletti. +\item \textsl{i bit delle modalità di operazione}: permettono di specificare + alcune caratteristiche del comportamento delle future operazioni sul file + (come la \func{read} o la \func{write}). Anch'essi fanno parte del + \textit{file status flag}. Il loro valore è settato alla chiamata di + \func{open}, ma possono essere riletti e modificati (insieme alle + caratteristiche operative che controllano) con una \func{fcntl}. \end{itemize} +In \tabref{tab:file_open_flags} si sono riportate, ordinate e divise fra loro +secondo le tre modalità appena elencate, le costanti mnemoniche associate a +ciascuno di questi bit, dette costanti possono essere combinate fra di loro +con un OR aritmetico per costruire il valore (in forma di maschera binaria) +del parametro \var{flags} da passare alla \func{open} per specificarne il +comportamento. +Nelle prime versioni di unix i flag specificabili per \func{open} erano solo +quelli relativi alle modalità di accesso del file. Per questo motivo per +creare un nuovo file c'era una system call apposita, \func{creat}, il cui +prototipo è: +\begin{prototype}{fcntl.h} + {int creat(const char *pathname, mode\_t mode)} + Crea un nuovo file vuoto, con i permessi specificati da \var{mode}. É del + tutto equivalente a \func{open(filedes, O\_CREAT|O\_WRONLY|O\_TRUNC, mode)}. +\end{prototype} +adesso questa funzione resta solo per compatibilità con i vecchi programmi. -All'interno di ogni processo i file aperti sono identificati da un intero non -negativo, chiamato appunto \textit{file descriptors}; +\subsection{La funzione \func{close}} +\label{sec:file_close} +La funzione \func{close} permette di chiudere un file, in questo modo il file +descriptor ritorna disponibile; il suo prototipo è: +\begin{prototype}{unistd.h}{int close(int fd)} + Chiude il descrittore \var{fd}. + + La funzione ritorna 0 in caso di successo e -1 n caso di errore. In questo + caso \var{errno} è settata ai valori: + \begin{errlist} + \item \macro{EBADF} \var{fd} non è un descrittore valido. + \item \macro{EINTR} la funzione è stata interrotta da un segnale. + \end{errlist} + ed \macro{EIO}. +\end{prototype} + +La chiusura di un file rilascia ogni blocco (il \textit{file locking} è +trattato in \secref{sec:file_locking}) che il processo poteva avere acquisito +su di esso; se \var{fd} è ultimo (di eventuali copie) riferimento ad un file +aperto, tutte le risorse nella file table vengono rilasciate. Infine se il +file descriptor era l'ultimo riferimento ad un file su disco quest'ultimo +viene cancellato. + +Si ricordi che quando un processo termina anche tutti i sui file descriptor +vengono chiusi, molti programmi sfruttano questa caratteristica e non usano +esplicitamente \func{close}. In genere comunque chiudere un file senza +controllarne lo stato di uscita è errore; infatti molti filesystem +implementano la tecnica del \textit{write-behind}, per cui una \func{write} +può avere successo anche se i dati non sono stati scritti, un eventuale errore +di I/O allora può sfuggire, ma verrà riportato alla chiusura del file: per +questo motivo non effettuare il controllo può portare ad una perdita di dati +inavvertita; in Linux questo comportamento è stato osservato con NFS e le +quote su disco. + +In ogni caso una \func{close} andata a buon fine non garantisce che i dati +siano stati effettivamente scritti su disco, perché il kernel può decidere di +ottimizzare l'accesso a disco ritardandone la scrittura. L'uso della funzione +\func{sync} effettua esplicitamente il \emph{flush} dei dati, ma anche in +questo caso resta l'incertezza dovuta al comportamento dell'hardware (che a +sua volta può introdurre ottimizzazioni dell'accesso al disco). +\subsection{La funzione \func{lseek}} +\label{sec:file_lseek} -\subsection{La condivisione dei files} -\label{sec:file_sharing} +Come già accennato in \secref{sec:file_fd} a ciascun file aperto è associata +una \textsl{posizione corrente nel file} (il cosiddetto \textit{file offset}, +mantenuto nel campo \var{f\_pos} di \var{file}) espressa da un numero intero +positivo come numero di bytes dall'inizio del file. Tutte le operazioni di +lettura e scrittura avvengono a partire da questa posizione che viene +automaticamente spostata in avanti del numero di byte letti o scritti. + +In genere (a meno di non avere richiesto la modalità \macro{O\_APPEND}) questa +posizione viene settata a zero all'apertura del file. È possibile settarla ad +un valore qualsiasi con la funzione \func{lseek}, il cui prototipo è: +\begin{functions} + \headdecl{sys/types.h} + \headdecl{unistd.h} + \funcdecl{off\_t lseek(int fd, off\_t offset, int whence)} + La funzione setta la posizione attuale nel file. + + La funzione ritorna valore della posizione corrente in caso di successo e -1 + in caso di errore nel qual caso \var{errno} viene settata ad uno dei valori: + \begin{errlist} + \item \macro{ESPIPE} \var{fd} è una pipe, un socket o una fifo. + \item \macro{EINVAL} \var{whence} non è un valore valido. + \end{errlist} + e \macro{EBADF}. +\end{functions} + +La nuova posizione è settata usando il valore specificato da \var{offset}, +sommato al riferimento dato da \var{whence}; quest'ultimo può assumere i +seguenti valori\footnote{per compatibilità con alcune vecchie notazioni + questi valori possono essere rimpiazzati rispettivamente con 0, 1 e 2 o con + \macro{L\_SET}, \macro{L\_INCR} e \macro{L\_XTND}}: +\begin{description} +\item \macro{SEEK\_SET} si fa riferimento all'inizio del file: il valore di + \var{offset} è la nuova posizione. +\item \macro{SEEK\_CUR} si fa riferimento alla posizione corrente del file: + \var{offset} che può essere negativo e positivo. +\item \macro{SEEK\_END} si fa riferimento alla fine del file: il valore di + \var{offset} può essere negativo e positivo. +\end{description} + +Come accennato in \secref{sec:file_file_size} con \func{lseek} è possibile +settare la posizione corrente anche al di la della fine del file, e alla +successiva scrittura il file sarà esteso. La chiamata non causa nessuna +attività di input/output, si limita a modificare la posizione corrente nel +kernel (cioè \var{f\_pos} in \var{file}, vedi \figref{fig:file_proc_file}). + +Dato che la funzione ritorna la nuova posizione, usando il valore zero per +\func{offset} si può riottenere la posizione corrente nel file chiamando la +funzione con \func{lseek(fd, 0, SEEK\_CUR}. + +Si tenga presente inoltre che usare \macro{SEEK\_END} non assicura affatto che +successiva scrittura avvenga alla fine del file, infatti se questo è stato +aperto anche da un altro processo che vi ha scritto, la fine del file può +essersi spostata, ma noi scriveremo alla posizione settata in precedenza. +Questa è una potenziale sorgente di \textit{race condition}, e quando si vuole +essere sicuri di scrivere alla fine del file questo deve essere posto in +modalità \macro{O\_APPEND}. + +Non tutti i file supportano la capacità di eseguire una \func{lseek}, in +questo caso la funzione ritorna l'errore \macro{EPIPE}. Questo, oltre che per +i tre casi citati nel prototipo, vale anche per tutti quei dispositivi che non +supportano questa funzione, come ad esempio per le \acr{tty}\footnote{altri + sistemi, usando \macro{SEEK\_SET} in questo caso ritornano il numero di + caratteri che vi sono stati scritti}. Lo standard POSIX però non specifica +niente al proposito. Infine alcuni device, ad esempio \file{/dev/null}, non +causano un errore ma restituiscono un valore indefinito. +\subsection{La funzione \func{read}} +\label{sec:file_read} -\section{Le funzioni base} -\label{sec:file_base_func} +Per leggere da un file precedentemente aperto, si può la funzione \func{read}, +il cui prototipo è: +\begin{prototype} + \headdecl{unistd.h} + \funcdecl{ssize\_t read(int fd, void * buf, size\_t count)} + + La funzione cerca di leggere \var{count} bytes dal file \var{fd} al buffer + \var{buf}. + + La funzione ritorna il numero di byte letti in caso di successo e -1 in + caso di errore, nel qual caso \var{errno} viene settata ad uno dei valori: + \begin{errlist} + \item \macro{EINTR} la funzione è stata interrotta da un segnale prima di + aver letto quasiasi dato. + \item \macro{EAGAIN} la funzione non aveva nessun dato da restituire e si + era aperto il file in modalità \macro{O\_NONBLOCK}. + \end{errlist} + ed inoltre \macro{EBADF}, \macro{EIO}, \macro{EISDIR}, \macro{EBADF}, + \macro{EINVAL} e \macro{EFAULT}. +\end{prototype} -L'interfaccia standard unix per l'input/output sui file è basata su cinque -funzioni fondamentali \func{open}, \func{read}, \func{write}, -\func{lseek} e \func{close}; +\subsection{La funzione \func{write}} +\label{sec:file_write} -\subsection{La funzione \func{open}} -\label{sec:file_open} -\subsection{La funzione \func{creat}} -\label{sec:file_creat} +\section{Funzioni avanzate} +\label{sec:file_adv_func} -\subsection{La funzione \func{close}} -\label{sec:file_close} -\subsection{La funzione \func{lseek}} -\label{sec:file_lseek} +\subsection{La condivisione dei files} +\label{sec:file_sharing} -\subsection{La funzione \func{read}} -\label{sec:file_read} +Si noti che i flag di stato del file, quelli settati dal parametro \var{flag} +di \func{open}, essendo tenuti nella vode sulla file table, vengono condivisi, +ai file sono però associati anche altri flag, (tenuti invece nella struttura +\var{file\_struct} interna alla process table) che sono unici per ciascun file +descriptor, e sono pertanto detti \textit{file descriptor flags} (l'unico +usato al momento è \macro{FD\_CLOEXEC}). -\subsection{La funzione \func{write}} -\label{sec:file_write} \subsection{Operazioni atomiche coi file} \label{sec:file_atomic} -\section{Funzioni avanzate} -\label{sec:file_adv_func} \subsection{La funzioni \func{dup} e \func{dup2}} \label{sec:file_dup} @@ -127,7 +528,3 @@ funzioni fondamentali \func{open}, \func{read}, \func{write}, \subsection{La funzione \func{ioctl}} \label{sec:file_ioctl} - - - -