Finalmente ho scritto qualcosa sui socket, ho aggiornato pure la parte
[gapil.git] / files.tex
1 \chapter{I files}
2 \label{cha:files}
3
4 Uno dei concetti fondamentali del design di unix è il cosiddetto
5 \textit{everything is a file}, cioè il fatto che l'accesso alle periferiche
6 viene gestito attraverso un'interfaccia astratta che tratta nello stesso modo
7 sia i normali file di dati che le periferiche. Si può accedere cioè a queste
8 ultime (con l'eccezione delle interfacce di rete) attraverso i cosiddetti file
9 di dispositivo (i \textit{device files}) che permettono ai programmi di
10 interfacciarsi alle varie periferiche come la seriale, la parallela, la
11 console, e gli stessi dischi.
12
13 \section{Concetti generali sui files}
14 \label{sec:file_gen}
15
16 Per poter accedere ai singoli file su disco è necessario l'uso di un
17 \textit{filesystem}, cioè di un'interfaccia del kernel che permetta di
18 strutturare l'informazione tenuta sullo spazio grezzo disponibile sui dischi
19 in files e directory. Sarà quest'ultimo a gestire l'accesso ai dati
20 memorizzati all'interno del disco stesso, e l'uso delle normali directory e
21 files.
22
23 %In generale un filesystem piazzerà opportunamente sul disco dei blocchi di
24 %informazioni riservate che tengono conto degli inodes allocati, di quelli
25 %liberi, e delle posizioni fisiche su disco dei dati contenuti nei files, per
26
27 Per poter accedere ai file contenuti in un disco occorrerà poi attivare il
28 filesystem \textit{montando} il disco (o la partizione del disco). 
29
30 In unix, a differenza di quanto avviene in altri sistemi operativi, tutti i
31 file vengono tenuti all'interno di un unico albero la cui radice (la directory
32 di \textit{root}) viene montata all'avvio. Pertanto un file viene identificato
33 dall'utente usando il suo \textit{pathname}, cioè il percorso completo che si
34 deve fare a partire dalla radice, per accedere al file.
35
36 Dopo la fase di inizializzazione il kernel riceve dal boot loader
37 l'indicazione di quale dispositivo contiene il filesystem da usare come punto
38 di partenza e questo viene montato come radice dell'albero (cioè nella
39 directory \texttt{/}); tutti gli ulteriori dischi devono poi essere inseriti
40 nell'albero utilizzando opportune subdirectory (in genere sotto
41 \texttt{/mnt}) .
42
43 Alcuni filesystem speciali (come \texttt{/proc} che contiene un'interfaccia ad
44 alcune strutture interne del kernel) sono generati automaticamente dal kernel
45 stesso, ma anche essi devono essere montati all'interno dell'albero.
46
47 All'interno dello stesso albero si potranno poi inserire anche gli altri
48 oggetti visti attraverso l'interfaccia che manipola i files come le FIFO, i
49 link, i socket e gli stessi i file di dispositivo (questi ultimi, per
50 convenzione, sono inseriti nella directory \texttt{/dev}).
51
52 \subsection{Il \textit{virtual filesystem} di linux}
53 \label{sec:file_vfs}
54
55 Esamineremo adesso come viene implementato l'accesso ai files in linux. Questa
56 sezione riporta informazioni sui dettagli di come il kernel gestisce i files,
57 ed è basata sul documento di Richard Goochs distribuito coi sorgenti del
58 kernel (\texttt{linux/Documentation/vfs.txt}).
59
60 L'argomento è abbastanza ``esoterico'' e questa sezione può essere saltata ad
61 una prima lettura; è bene però tenere presente che vengono introdotti qui
62 alcuni termini che potranno comparire in seguito, come \textit{inode},
63 \textit{dentry}, \textit{dcache}.
64
65 In linux il concetto di \textit{everything is a file} è stato implementato
66 attraverso il \textit{virtual filesystem} (da qui in avanti VFS) che è
67 l'interfaccia astratta che il kernel rende disponibile ai programmi in user
68 space attraverso la quale vengono manipolati i files, esso provvede anche
69 un'astrazione delle operazioni di manipolazione sui files che permette la
70 coesistenza di diversi filesystem all'interno dello stesso kernel.
71
72 La funzione più importante implementata dal VFS è la system call \texttt{open}
73 che permette di aprire un file. Dato un pathname viene eseguita una ricerca
74 dentro la \textit{directory entry cache} (la \textit{dcache}) una tabella di
75 hash che contiene tutte le \textit{directory entry} (in breve \textit{dentry})
76 che permette di associare in maniera rapida ed efficiente il pathname a una
77 specifica dentry.
78
79 Una singola dentry contiene in genere il puntatore ad un \textit{inode};
80 quest'ultimo è la struttura base che sta sul disco e che identifica un singolo
81 oggetto del VFS che può essere un file, una directory, una FIFO, un file di
82 dispositivo, o una qualsiasi altra cosa che possa essere rappresentata dal
83 VFS (sui tipi di files possibili torneremo in seguito).
84
85 Le dentries ``vivono'' in memoria e non vengono mai salvate su disco, vengono
86 usate per motivi di velocità, gli inodes invece vivono su disco e vengono
87 copiati in memoria quando serve, ed ogni cambiamento viene copiato
88 all'indietro sul disco, gli inodes che stanno in memoria sono inodes del VFS
89 ed è ad essi che puntano le singole dentry.
90
91 La dcache costituisce perciò una sorta di vista completa di tutto l'albero dei
92 files, ovviamente per non riempire tutta la memoria questa vista è parziale
93 (la dcache cioè contiene solo le dentry per i file per i quali è stato
94 richiesto l'accesso), quando si vuole risolvere un nuovo pathname il VFS deve
95 creare una nuova dentry e caricare l'inode corrispondente in memoria. 
96
97 Questo procedimento viene eseguito dalla metodo \texttt{lookup()} dell'inode
98 della directory che contiene il file; esso viene installato dallo specifico
99 filesystem su cui l'inode va a vivere.
100
101 Una volta che il VFS ha a disposizione la dentry (ed il relativo inode)
102 diventa possibile accedere a operazioni sul file come la \texttt{open} per
103 aprire il file o la \texttt{stat} per leggere i dati dell'inode e passarli in
104 user space.
105
106 L'apertura di un file richiede comunque un'altra operazione, l'allocazione di
107 una struttura di tipo \texttt{file} in cui viene inserito un puntatore alla
108 dentry e una struttura \verb|f_ops| che contiene i puntatori ai metodi che
109 implementano le operazioni disponibili sul file. In questo modo i processi in
110 user space possono accedere alle operazioni attraverso detti metodi, che
111 saranno diversi a seconda del tipo di file (o dispositivo) aperto. Un elenco
112 delle operazioni disponibili è riportato in \ntab.
113
114 % La struttura file viene poi inserita nella tavola dei file
115 % , non
116 % tutte le operazioni possibili sono definite per tutti i dispositivi; un elenco
117 % delle operazioni definite in linux è riportato in \ntab.
118
119 \begin{table}[htb]
120   \centering
121   \begin{tabular}[c]{c p{7cm}}
122     \textbf{funzione} & \textbf{operazione} \\
123     \hline
124     \textit{open}    & apre il file \\
125     \textit{read}    & legge dal file \\
126     \textit{write}   & scrive sul file \\ 
127     \textit{llseek}  & sposta la posizione corrente sul file \\
128     \textit{ioctl}   & accede alle operazioni di controllo 
129                        (tramite la \texttt{ioctl})\\
130     \textit{readdir} & per leggere il contenuto di una directory \\
131     \textit{poll}    & \\
132     \textit{mmap}    & chiamata dalla system call \texttt{mmap}. 
133                        mappa il file in memoria\\
134     \textit{release} & chiamata quando l'ultima referenza a un file 
135                        aperto è chiusa\\
136     \textit{fsync}   & chiamata dalla system call \texttt{fsync} \\
137     \textit{fasync}  & chiamate da \texttt{fcntl} quando è abilitato 
138                        il modo asincrono per l'I/O su file. \\
139     \hline
140   \end{tabular}
141   \caption{Operazioni sui file definite nel VFS.}
142   \label{tab:file_operations}
143 \end{table}
144
145 In questo modo per ciascun file diventano utilizzabili una serie di operazioni
146 (non è dette che tutte siano disponibili), che costituiscono l'interfaccia
147 astratta del VFS, e qualora se ne voglia eseguire una il kernel andrà ad
148 utilizzare la opportuna routine dichiarata in \verb|f_ops| appropriata al tipo
149 di file in questione. 
150
151 Così sarà possibile scrivere sulla porta seriale come su un file di dati
152 normale; ovviamente certe operazioni (nel caso la \textit{seek}) non saranno
153 disponibili, però con questo sistema l'utilizzo di diversi filesystem è
154 immediato e (relativamente) trasparente per l'utente ed il programmatore.
155
156 \subsection{Proprietari e permessi}
157 \label{sec:file_perms}
158
159 In unix è implementata da qualunque filesystem standard una forma elementare
160 (ma adatta alla maggior parte delle esigenze) di controllo di accesso ai
161 files. Torneremo sull'argomento in dettaglio più avanti, qui ci limitiamo ad
162 una introduzione dei concetti essenziali.
163
164 Si tenga conto poi che quanto diremo è vero solo per filesystem di tipo unix,
165 e non è detto che sia applicabile (ed infatti non è vero per il filesystem di
166 windows) a un filesystem qualunque. Esistono inoltre estensioni che permettono
167 di implementare le ACL (\textit{Access Control List}) che sono un meccanismo
168 di controllo di accesso molto più sofisticato.
169
170 Ad ogni file unix associa sempre l'utente che ne è proprietario (il cosiddetto
171 \textit{owner}) e il gruppo di appartenenza, secondo il meccanismo degli uid e
172 gid spiegato in \ref{sec:intro_usergroup}, e un insieme di permessi che sono
173 divisi in tre classi, e cioè attribuiti rispettivamente al proprietario, a
174 qualunque utente faccia parte del gruppo cui appartiene il file, e a tutti gli
175 altri utenti.
176
177 I permessi sono espressi da un insieme di 12 bit, di questi i nove meno
178 significativi sono usati a gruppi di tre per indicare i permessi base di
179 lettura, scrittura ed esecuzione (indicati rispettivamente con le lettere
180 \textit{w}, \textit{r} \textit{x}) applicabili rispettivamente al
181 proprietario, al gruppo, a tutti. I restanti tre bit sono usati per indicare
182 alcune caratteristiche più complesse (\textit{suid}, \textit{sgid}, e
183 \textit{sticky}) su cui torneremo in seguito.
184
185 Tutte queste informazioni sono tenute per ciascun file nell'inode. Quando un
186 processo cerca l'accesso al file esso controlla i propri uid e gid
187 confrontandoli con quelli del file e se l'operazione richiesta è compatibile
188 con i permessi associati al file essa viene eseguita, altrimenti viene
189 bloccata ed è restituito un errore di \texttt{EPERM}. Questo procedimento non
190 viene eseguito per l'amministratore di sistema (il cui uid è zero) il quale ha
191 pertanto accesso senza restrizione a qualunque file del sistema.
192
193 In realtà il procedimento è più complesso di quanto descritto in maniera
194 elementare qui, in quanto ad un processo sono associati diversi
195 identificatori, torneremo su questo in maggiori dettagli in seguito in
196 \ref{sec:proc_perms}.
197
198 \subsection{I tipi di files}
199 \label{sec:file_types}
200
201 Come detto in precedenza esistono vari tipi di oggetti implementati del VFS
202 per i quali è disponibile l'interfaccia astratta da esso provveduta. Un elenco
203 dei vari tipi di file è il seguente:
204  
205 \begin{table}[htb]
206   \begin{center}
207     \begin{tabular}[c]{l l p{7cm}}
208     \multicolumn{2}{c}{\textbf{Nome}} & \textbf{Descrizione} \\
209     \hline
210       \textit{regular file} & \textsl{file normale} &
211       un file che contiene dei dati (l'accezione normale di file) \\
212       \textit{directory} & \textsl{cartella o direttorio} &
213       un file che contiene una lista di nomi associati a degli inodes \\
214       \textit{symbolic link} & \textsl{collegamento simbolico} &
215       un file che contiene un riferimento ad un altro file/directory \\
216       \textit{char device} & \textsl{dispositivo a caratteri} &
217       un file che identifica una periferica ad accesso sequenziale \\
218       \textit{block device} & \textsl{dispositivo a blocchi} &
219       un file che identifica una periferica ad accesso diretto \\
220       \textit{fifo} & \textsl{tubo} &
221       un file speciale che identifica una linea di comunicazione software
222       (unidirezionale) \\
223       \textit{socket} & \textsl{presa} &
224       un file speciale che identifica una linea di comunicazione software
225       (bidirezionale) \\
226     \hline
227     \end{tabular}
228     \caption{Tipologia dei file definiti nel VFS}
229     \label{tab:file_types}
230   \end{center}
231 \end{table}
232
233 Tutto ciò non ha ovviamente nulla a che fare con la classificazione sui tipi
234 di file (in questo caso file di dati) in base al loro contenuto, o tipo di
235 accesso.  Una delle differenze principali con altri sistemi operativi (come il
236 VMS o windows) è che per unix tutti i file di dati sono identici e contengono
237 un flusso continuo di bytes; non esiste cioè differenza per come vengono visti
238 dal sistema file di diverso contenuto o formato (come nel caso di quella fra
239 file di testo e binari che c'è in windows) né c'è una strutturazione a record
240 per il cosiddetto ``accesso diretto'' come nel caso del VMS.
241
242 Una seconda differenza è nel formato dei file ascii; in unix la fine riga è
243 codificata in maniera diversa da windows o macintosh, in particolare il fine
244 riga è il carattere \texttt{LF} al posto del \texttt{CR} del mac e del
245 \texttt{CR LF} di windows. Questo può causare alcuni problemi qualora si
246 facciano assunzioni sul terminatore della riga.
247
248
249 \section{Una panoramica sull'I/O sui file}
250 \label{sec:file_io_base}
251
252 Per poter accedere al contenuto dei file occorre anzitutto aprirlo. Questo
253 crea un canale di comunicazione che permette di eseguire una serie di
254 operazioni. Una volta terminate le operazioni, il file dovrà essere chiuso, e
255 questo chiuderà il canale di comunicazione impedendo ogni ulteriore operazione.
256
257
258 \subsection{Le due interfacce ai file}
259 \label{sec:file_base_api}
260
261 In unix le modalità di accesso ai file e le relative interfacce di
262 programmazione sono due, basate su due diversi meccanismi di connessione. 
263
264 La prima è quella dei cosiddetti \textit{file descriptor} (descrittore di
265 file), che è specifica di unix e che provvede un accesso diretto a basso
266 livello non bufferizzato, con un'interfaccia primitiva ed essenziale; i file
267 descriptors sono rappresentati da numeri interi (cioè semplici variabili di
268 tipo \texttt{int}). L'interfaccia è definita nell'header \texttt{unistd.h}.
269
270 La seconda è quella degli \textit{stream}, che provvede un'interfaccia più
271 evoluta e un accesso bufferizzato. Questa è anche l'interfaccia standard usata
272 dal linguaggio C e perciò si trova anche su tutti i sistemi non unix. Gli
273 stream sono oggetti complessi e sono rappresentati da puntatori ad un
274 opportuna struttura definita dalle librerie del C, si accede ad essi sempre in
275 maniera indiretta utilizzando il tipo \texttt{FILE *}. L'interfaccia è
276 definita nell'header \texttt{stdio.h}.
277
278 Entrambe le interfacce possono essere usate per l'accesso ai file come agli
279 altri oggetti del VFS (pipes, socket, device), ma per poter accedere alle
280 operazioni di controllo sul particolare tipo di oggetto del VFS scelto occorre
281 usare l'interfaccia a basso livello dei file descriptor. Allo stesso modo
282 devono essere usati i file descriptor se si vuole ricorrere a modalità
283 speciali di I/O come il polling o il non-bloccante (vedi
284 \ref{sec:file_bohhhhh}).
285
286 Gli stream forniscono un'interfaccia di alto livello costruita sopra quella
287 dei file descriptor, che tratta tutti i file nello stesso modo, con
288 l'eccezione di poter scegliere tre diversi stili di bufferizzazione.  Il
289 maggior vantaggio degli stream è che l'interfaccia per le operazioni di
290 input/output è enormemente più ricca di quella dei file descriptor, che
291 provvedono solo funzioni elementari per la lettura/scrittura diretta di
292 blocchi di bytes.  In particolare dispongono di tutte le funzioni di
293 formattazione per l'input e l'output adatte per manipolare anche i dati in
294 forma di linee o singoli caratteri.
295
296 In ogni caso, dato che gli stream sono implementati sopra l'interfaccia a
297 basso livello dei file descriptor, è sempre possibile estrarre il file
298 descriptor da uno stream ed eseguirvi operazioni di basso livello, o associare
299 in un secondo tempo uno stream ad un file descriptor.
300
301 In generale, se non necessitano specificatamente le funzionalità di basso
302 livello, è opportuno usare sempre gli stream per la loro maggiore portabilità
303 essendo questi ultimi definito nello standard ISO C; l'interfaccia con i file
304 descriptor invece segue solo lo standard POSIX.1 dei sistemi unix ed è
305 pertanto di portabilità più limitata.
306
307 \subsection{Caratteristiche specifiche dei file in unix}
308 \label{sec:files_spec_unix}
309
310 Essendo un sistema multitasking e multiutente esistono alcune caratteristiche
311 specifiche di unix che devono essere tenute in conto nell'accesso ai file. È
312 infatti normale che più processi o programmi possano accedere
313 contemporaneamente allo stesso file e devono poter eseguire le loro operazioni
314 indipendentemente da quello che fanno gli altri processi.
315
316 Per questo motivo le strutture usate per all'accesso ai file sono relative al
317 processo che effettua l'accesso.  All'apertura di ogni file infatti viene
318 creata all'interno del processo una apposita struttura in cui sono memorizzati
319 tutti gli attributi del medesimo, che viene utilizzata per tutte le
320 operazioni. Questa è una struttura che resta locale al processo stesso; in
321 questo modo processi diversi possono usare le proprie strutture locali per
322 accedere ai file (che può essere sempre lo stesso) in maniera assolutamente
323 indipendente.
324
325 Questo ha delle conseguenze di cui è bene tenere conto; ad esempio in tutti i
326 sistemi POSIX uno degli attributi di un file aperto è la posizione corrente nel
327 file, cioè il punto nel file in cui verrebbe letto o scritto alla operazione
328 successiva. Essa è rappresentata da un numero intero che indica il numero di
329 bytes dall'inizio del file, che viene (a meno che non si apra il file in
330 append) inizializzato a zero all'apertura del medesimo. 
331
332
333 Questo è uno dei dati che viene mantenuto nella suddetta struttura, per cui
334 ogni processo avrà la sua posizione corrente nel file, che non sarà
335 influenzata da quello che altri processi possono fare. Anzi, aprire un file
336 significa appunto creare ed inizializzare una tale struttura, per cui se si
337 apre due volte lo stesso file all'interno dello stesso processo, si otterrano
338 due file descriptor o due stream che avranno ancora un posizione corrente nel
339 file assolutamente indipendente.
340
341 Si tenga conto inoltre che un'altro dei dati contenuti nella struttura di
342 accesso è un riferimento all'inode del file, pertanto anche se il file viene
343 cancellato da un altro processo, sarà sempre possibile mantenere l'accesso,
344 e lo spazio su disco non verrà rilasciato fintanto che il file non sarà chiuso
345 e l'ultimo riferimento cancellato. È pertanto possibile (e pratica comune)
346 aprire un file provvisorio per cancellarlo immediatamente dopo; in questo modo
347 all'uscita del programma il file scomparirà definitivamente dal disco, ma il
348 file ed il suo contenuto saranno disponibili per tutto il tempo in cui il
349 processo è attivo.
350
351
352 \subsection{L'accesso ai files: nomi e directory}
353 \label{sec:file_names}
354
355 L'organizzazione dei nomi dei file deriva direttamente dall'organizzazione dei
356 medesimi nella gerarchia di directory descritta in \ref{sec:file_base}; una
357 directory comunque, come già specificato in \ref{sec:file_vfs}, è solo un
358 particolare tipo di file che il sistema riconosce come tale, che contiene le
359 informazioni che associano un inode ad un nome. Per questo, anche se è usuale
360 parlare di ``file in una directory'' in realtà una directory contiene solo dei
361 riferimenti ai file, non i file stessi.
362
363 I nomi contenuti nelle directory sono chiamati componenti (\textit{file name
364   components}), un file può essere indicato rispetto alla directory corrente
365 semplicemente specificando il nome da essa contenuto. Una directory contiene
366 semplicemente un elenco di questi componenti, che possono corrispondere a un
367 qualunque oggetto del filesystem, compresa un'altra directory.
368
369 Un nome di file è composto da una serie di componenti separati da una
370 \texttt{/} (in linux più \texttt{/} consecutive sono considerate equivalenti
371 ad una sola). Il nome completo di un file viene usualmente chiamato
372 \textit{pathname}, anche se questo può generare confusione, dato che con
373 \textit{path} si indica anche un insieme di directory su cui effettuare una
374 ricerca (ad esempio quello in cui si cercano i comandi).
375
376 Il processo con cui si associa ad un pathname uno specifico file (cioè si
377 identifica l'inode a cui fare riferimento) è chiamato risoluzione del nome
378 (\textit{file name resolution} o \textit{pathname resolution}).
379 La risoluzione viene fatta esaminando il pathname da destra a sinistra e
380 localizzando ogni componente nella directory indicata dal componente
381 precedente: ovviamente perché il procedimento funzioni occorre che i
382 componenti indicati come directory esistano e siano effettivamente directory,
383 inoltre i permessi devono consentire l'accesso.
384
385
386 Se il pathname comincia per \texttt{/} la ricerca parte dalla directory radice
387 del processo che (a meno di un \textit{chroot} su cui torneremo in seguito) è
388 la stessa per tutti i processi ed equivale alla radice dell'albero
389 (\ref{sec:file_gen}): in questo caso si parla di un pathname
390 \textsl{assoluto}. Altrimenti la ricerca parte dalla directory di lavoro
391 corrente (\textit{current working directory}, su cui pure torneremo più avanti)
392 ed il pathname è detto \textsl{relativo}.
393
394 I componenti \texttt{.} e \texttt{..} hanno un significato speciale e vengono
395 inseriti in ogni directory, il primo fa riferimento alla directory corrente e
396 il secondo alla directory \textsl{genitore} (\textit{parent directory}) cioè
397 la directory che contiene il riferimento alla directory corrente; nel caso
398 questa sia la directory radice allora il riferimento è a se stessa.
399
400 Infine si ricordi che in unix non esistono i tipi di file e che non c'è nessun
401 supporto per le estensioni come parte del filesystem. Ciò non ostante molti
402 programmi adottano delle convenzioni per i nomi dei file, ad esempio il codice
403 C normalmente si mette in file con l'estensione .c, ma questa è solo una
404 convenzione.
405
406
407 \section{I file stream}
408 \label{sec:file_stream}
409
410 Esamineremo in questa sezione l'interfaccia per i file stream, le modalità per
411 crearli, e le funzioni disponibili per leggere, scrivere e compiere le varie
412 operazioni connesse all'uso dei file. L'interfaccia è accessibile includendo
413 l'header file \texttt{stdio.h}.
414
415 Per ragioni storiche la struttura di dati che rappresenta un stream è stata
416 chiamata \texttt{FILE}, dato che le funzioni di libreria usano sempre come
417 parametri oggetti di tipo \texttt{FILE *} alle volte si usa il termine
418 puntatore a file come sinonimo di stream. 
419
420
421
422
423
424 %La struttura fondamentale che contiene i dati essenziali relativi ai file è il
425 %cosiddetto \textit{inode}; questo conterrà informazioni come il
426 %tipo di file (file di dispositivo, directory, file di dati, per un elenco
427 %completo vedi \ntab), i permessi (vedi \ref{sec:file_perms}), le date (vedi
428 %\ref{sec:file_times}).
429