-\chapter{I files}
+\chapter{I files: introduzione}
\label{cha:files}
-
+
Uno dei concetti fondamentali del design di unix è il cosiddetto
-\textit{everything is a file}, cioè il fatto che l'accesso alle periferiche
-viene gestito attraverso un'interfaccia astratta che tratta nello stesso modo
-sia i normali file di dati che le periferiche. Si può accedere cioè a queste
-ultime (con l'eccezione delle interfacce di rete) attraverso i cosiddetti file
-di dispositivo (i \textit{device files}) che permettono ai programmi di
-interfacciarsi alle varie periferiche come la seriale, la parallela, la
-console, e gli stessi dischi.
-
-\section{Concetti generali sui files}
+\textit{everything is a file}, cioè il fatto che l'accesso ai vari dispositivi
+di I/O del computer viene effettuato attraverso un'interfaccia astratta che
+tratta le periferiche allo stesso modo degli usuali file di dati.
+
+Si può accedere cioè a qualunque periferica del computer, dalla seriale, alla
+parallela, alla console, e agli stessi dischi, (unica eccezione le interfacce
+di rete, che che non rientrano bene nell'astrazione) attraverso i cosiddetti
+file di dispositivo (i \textit{device files}). Questi sono dei file speciali
+agendo sui quali i programmi possono leggere, scrivere e compiere operazioni
+sulle perferiche, usando le stesse funzioni che si usano per i normali file di
+dati.
+
+\section{Concetti generali riguardanti i files}
\label{sec:file_gen}
-Per poter accedere ai singoli file su disco è necessario l'uso di un
-\textit{filesystem}, cioè di un'interfaccia del kernel che permetta di
-strutturare l'informazione tenuta sullo spazio grezzo disponibile sui dischi
-in files e directory. Sarà quest'ultimo a gestire l'accesso ai dati
-memorizzati all'interno del disco stesso, e l'uso delle normali directory e
-files.
+Visto il ruolo fondamentale che i files vengono ad assumere in un sistema
+unix, è anzitutto opportuno fornire un'introduzione dettagliata su come essi
+vengono trattati dal sistema. In particolare occorre tenere presente dov'è che
+si situa il limite fondamentale fra kernel space e user space che tracciavamo
+al Cap.~\ref{cha:intro_unix}.
+
+Partiamo allora da come viene strutturata nel sistema la disposizione dei
+file: per potervi accedere il kernel usa una apposita interfaccia che permetta
+di strutturare l'informazione tenuta sullo spazio grezzo disponibile sui
+dischi, cioè quello che si chiama un \textit{filesystem}.
+
+Sarà attraverso quest'ultimo che il kernel andrà a gestire l'accesso ai dati
+memorizzati all'interno del disco stesso, strutturando l'informazione in files
+e directory. Per poter accedere ai file contenuti in un disco occorrerà
+perciò attivare il filesystem, questo viene fatto \textsl{montando} il disco
+(o la partizione del disco).
%In generale un filesystem piazzerà opportunamente sul disco dei blocchi di
%informazioni riservate che tengono conto degli inodes allocati, di quelli
%liberi, e delle posizioni fisiche su disco dei dati contenuti nei files, per
-Per poter accedere ai file contenuti in un disco occorrerà poi attivare il
-filesystem \textit{montando} il disco (o la partizione del disco).
-
-In unix, a differenza di quanto avviene in altri sistemi operativi, tutti i
+In Unix, a differenza di quanto avviene in altri sistemi operativi, tutti i
file vengono tenuti all'interno di un unico albero la cui radice (la directory
di \textit{root}) viene montata all'avvio. Pertanto un file viene identificato
-dall'utente usando il suo \textit{pathname}, cioè il percorso completo che si
-deve fare a partire dalla radice, per accedere al file.
+dall'utente usando quello che viene chiamato \textit{pathname}, cioè il
+percorso completo che si deve fare a partire dalla radice, per accedere al
+file.
Dopo la fase di inizializzazione il kernel riceve dal boot loader
l'indicazione di quale dispositivo contiene il filesystem da usare come punto
di partenza e questo viene montato come radice dell'albero (cioè nella
directory \texttt{/}); tutti gli ulteriori dischi devono poi essere inseriti
-nell'albero utilizzando opportune subdirectory (in genere sotto
-\texttt{/mnt}) .
+nell'albero utilizzando opportune subdirectory.
Alcuni filesystem speciali (come \texttt{/proc} che contiene un'interfaccia ad
alcune strutture interne del kernel) sono generati automaticamente dal kernel
La funzione più importante implementata dal VFS è la system call \texttt{open}
che permette di aprire un file. Dato un pathname viene eseguita una ricerca
-dentro la \textit{directory entry cache} (la \textit{dcache}) una tabella di
-hash che contiene tutte le \textit{directory entry} (in breve \textit{dentry})
-che permette di associare in maniera rapida ed efficiente il pathname a una
-specifica dentry.
+dentro la \textit{directory entry cache} (in breve \textit{dcache}) che è
+una tabella di hash che contiene tutte le \textit{directory entry} (in breve
+\textit{dentry}) che permette di associare in maniera rapida ed efficiente il
+pathname a una specifica dentry.
Una singola dentry contiene in genere il puntatore ad un \textit{inode};
quest'ultimo è la struttura base che sta sul disco e che identifica un singolo
-oggetto del VFS che può essere un file, una directory, una FIFO, un file di
-dispositivo, o una qualsiasi altra cosa che possa essere rappresentata dal
-VFS (sui tipi di files possibili torneremo in seguito).
+oggetto del VFS sia esso un file ordinario, una directory, una FIFO, un file
+di dispositivo, o una qualsiasi altra cosa che possa essere rappresentata dal
+VFS (sui tipi di ``files'' possibili torneremo in seguito).
Le dentries ``vivono'' in memoria e non vengono mai salvate su disco, vengono
-usate per motivi di velocità, gli inodes invece vivono su disco e vengono
+usate per motivi di velocità, gli inodes invece stanno su disco e vengono
copiati in memoria quando serve, ed ogni cambiamento viene copiato
all'indietro sul disco, gli inodes che stanno in memoria sono inodes del VFS
ed è ad essi che puntano le singole dentry.
saranno diversi a seconda del tipo di file (o dispositivo) aperto. Un elenco
delle operazioni disponibili è riportato in \ntab.
-% La struttura file viene poi inserita nella tavola dei file
-% , non
-% tutte le operazioni possibili sono definite per tutti i dispositivi; un elenco
-% delle operazioni definite in linux è riportato in \ntab.
-
\begin{table}[htb]
\centering
\begin{tabular}[c]{c p{7cm}}
di file in questione.
Così sarà possibile scrivere sulla porta seriale come su un file di dati
-normale; ovviamente certe operazioni (nel caso la \textit{seek}) non saranno
-disponibili, però con questo sistema l'utilizzo di diversi filesystem è
-immediato e (relativamente) trasparente per l'utente ed il programmatore.
+normale; ovviamente certe operazioni (nel caso della seriale ad esempio la
+\textit{seek}) non saranno disponibili, però con questo sistema l'utilizzo di
+diversi filesystem (come quelli usati da Windows o MacOs) è immediato e
+(relativamente) trasparente per l'utente ed il programmatore.
\subsection{Proprietari e permessi}
\label{sec:file_perms}
-In unix è implementata da qualunque filesystem standard una forma elementare
+In Unix è implementata da qualunque filesystem standard una forma elementare
(ma adatta alla maggior parte delle esigenze) di controllo di accesso ai
files. Torneremo sull'argomento in dettaglio più avanti, qui ci limitiamo ad
una introduzione dei concetti essenziali.
-Si tenga conto poi che quanto diremo è vero solo per filesystem di tipo unix,
+Si tenga conto poi che quanto diremo è vero solo per filesystem di tipo Unix,
e non è detto che sia applicabile (ed infatti non è vero per il filesystem di
-windows) a un filesystem qualunque. Esistono inoltre estensioni che permettono
+Windows) a un filesystem qualunque. Esistono inoltre estensioni che permettono
di implementare le ACL (\textit{Access Control List}) che sono un meccanismo
di controllo di accesso molto più sofisticato.
-Ad ogni file unix associa sempre l'utente che ne è proprietario (il cosiddetto
+Ad ogni file Unix associa sempre l'utente che ne è proprietario (il cosiddetto
\textit{owner}) e il gruppo di appartenenza, secondo il meccanismo degli uid e
gid spiegato in \ref{sec:intro_usergroup}, e un insieme di permessi che sono
divisi in tre classi, e cioè attribuiti rispettivamente al proprietario, a
qualunque utente faccia parte del gruppo cui appartiene il file, e a tutti gli
altri utenti.
-I permessi sono espressi da un insieme di 12 bit, di questi i nove meno
+I permessi sono espressi da un insieme di 12 bit: di questi i nove meno
significativi sono usati a gruppi di tre per indicare i permessi base di
lettura, scrittura ed esecuzione (indicati rispettivamente con le lettere
\textit{w}, \textit{r} \textit{x}) applicabili rispettivamente al
\textit{fifo} & \textsl{tubo} &
un file speciale che identifica una linea di comunicazione software
(unidirezionale) \\
- \textit{socket} & \textsl{presa} &
+ \textit{socket} & \textsl{manicotto} &
un file speciale che identifica una linea di comunicazione software
(bidirezionale) \\
\hline
Tutto ciò non ha ovviamente nulla a che fare con la classificazione sui tipi
di file (in questo caso file di dati) in base al loro contenuto, o tipo di
accesso. Una delle differenze principali con altri sistemi operativi (come il
-VMS o windows) è che per unix tutti i file di dati sono identici e contengono
+VMS o Windows) è che per Unix tutti i file di dati sono identici e contengono
un flusso continuo di bytes; non esiste cioè differenza per come vengono visti
dal sistema file di diverso contenuto o formato (come nel caso di quella fra
file di testo e binari che c'è in windows) né c'è una strutturazione a record
per il cosiddetto ``accesso diretto'' come nel caso del VMS.
-Una seconda differenza è nel formato dei file ascii; in unix la fine riga è
-codificata in maniera diversa da windows o macintosh, in particolare il fine
-riga è il carattere \texttt{LF} al posto del \texttt{CR} del mac e del
-\texttt{CR LF} di windows. Questo può causare alcuni problemi qualora si
-facciano assunzioni sul terminatore della riga.
+Una seconda differenza è nel formato dei file ascii; in Unix la fine riga è
+codificata in maniera diversa da Windows o MacIntosh, in particolare il fine
+riga è il carattere \texttt{LF} (o \verb|\n|) al posto del \texttt{CR}
+(\verb|\r|) del mac e del \texttt{CR LF} di windows. Questo può causare alcuni
+problemi qualora si facciano assunzioni sul terminatore della riga.
-\section{Una panoramica sull'I/O sui file}
+\section{Una panoramica sull'uso dei file}
\label{sec:file_io_base}
Per poter accedere al contenuto dei file occorre anzitutto aprirlo. Questo
crea un canale di comunicazione che permette di eseguire una serie di
operazioni. Una volta terminate le operazioni, il file dovrà essere chiuso, e
-questo chiuderà il canale di comunicazione impedendo ogni ulteriore operazione.
+questo chiuderà il canale di comunicazione impedendo ogni ulteriore
+operazione.
\subsection{Le due interfacce ai file}
programmazione sono due, basate su due diversi meccanismi di connessione.
La prima è quella dei cosiddetti \textit{file descriptor} (descrittore di
-file), che è specifica di unix e che provvede un accesso diretto a basso
+file), che è specifica di Unix e che provvede un accesso diretto a basso
livello non bufferizzato, con un'interfaccia primitiva ed essenziale; i file
descriptors sono rappresentati da numeri interi (cioè semplici variabili di
tipo \texttt{int}). L'interfaccia è definita nell'header \texttt{unistd.h}.
La seconda è quella degli \textit{stream}, che provvede un'interfaccia più
evoluta e un accesso bufferizzato. Questa è anche l'interfaccia standard usata
-dal linguaggio C e perciò si trova anche su tutti i sistemi non unix. Gli
+dal linguaggio C e perciò si trova anche su tutti i sistemi non Unix. Gli
stream sono oggetti complessi e sono rappresentati da puntatori ad un
opportuna struttura definita dalle librerie del C, si accede ad essi sempre in
maniera indiretta utilizzando il tipo \texttt{FILE *}. L'interfaccia è
maggior vantaggio degli stream è che l'interfaccia per le operazioni di
input/output è enormemente più ricca di quella dei file descriptor, che
provvedono solo funzioni elementari per la lettura/scrittura diretta di
-blocchi di bytes. In particolare dispongono di tutte le funzioni di
-formattazione per l'input e l'output adatte per manipolare anche i dati in
+blocchi di bytes. In particolare gli stream dispongono di tutte le funzioni
+di formattazione per l'input e l'output adatte per manipolare anche i dati in
forma di linee o singoli caratteri.
In ogni caso, dato che gli stream sono implementati sopra l'interfaccia a
\label{sec:files_spec_unix}
Essendo un sistema multitasking e multiutente esistono alcune caratteristiche
-specifiche di unix che devono essere tenute in conto nell'accesso ai file. È
+specifiche di Unix che devono essere tenute in conto nell'accesso ai file. È
infatti normale che più processi o programmi possano accedere
contemporaneamente allo stesso file e devono poter eseguire le loro operazioni
indipendentemente da quello che fanno gli altri processi.
influenzata da quello che altri processi possono fare. Anzi, aprire un file
significa appunto creare ed inizializzare una tale struttura, per cui se si
apre due volte lo stesso file all'interno dello stesso processo, si otterrano
-due file descriptor o due stream che avranno ancora un posizione corrente nel
+due file descriptor o due stream che avranno ancora una posizione corrente nel
file assolutamente indipendente.
Si tenga conto inoltre che un'altro dei dati contenuti nella struttura di
accesso è un riferimento all'inode del file, pertanto anche se il file viene
-cancellato da un altro processo, sarà sempre possibile mantenere l'accesso,
-e lo spazio su disco non verrà rilasciato fintanto che il file non sarà chiuso
-e l'ultimo riferimento cancellato. È pertanto possibile (e pratica comune)
-aprire un file provvisorio per cancellarlo immediatamente dopo; in questo modo
-all'uscita del programma il file scomparirà definitivamente dal disco, ma il
-file ed il suo contenuto saranno disponibili per tutto il tempo in cui il
-processo è attivo.
+cancellato da un altro processo, sarà sempre possibile mantenere l'accesso ai
+dati, e lo spazio su disco non verrà rilasciato fintanto che il file non sarà
+chiuso e l'ultimo riferimento cancellato. È pertanto possibile (e pratica
+comune) aprire un file provvisorio per cancellarlo immediatamente dopo; in
+questo modo all'uscita del programma il file scomparirà definitivamente dal
+disco, ma il file ed il suo contenuto saranno disponibili per tutto il tempo
+in cui il processo è attivo.
\subsection{L'accesso ai files: nomi e directory}
semplicemente un elenco di questi componenti, che possono corrispondere a un
qualunque oggetto del filesystem, compresa un'altra directory.
-Un nome di file è composto da una serie di componenti separati da una
+Un nome di file è composto da una serie di \textsl{componenti} separati da una
\texttt{/} (in linux più \texttt{/} consecutive sono considerate equivalenti
ad una sola). Il nome completo di un file viene usualmente chiamato
-\textit{pathname}, anche se questo può generare confusione, dato che con
-\textit{path} si indica anche un insieme di directory su cui effettuare una
-ricerca (ad esempio quello in cui si cercano i comandi).
+\textit{filename} o \textit{pathname}, anche se quest'ultimo può generare
+confusione, dato che con \textit{path} si indica anche un insieme di directory
+su cui effettuare una ricerca (ad esempio quello in cui si cercano i comandi).
Il processo con cui si associa ad un pathname uno specifico file (cioè si
identifica l'inode a cui fare riferimento) è chiamato risoluzione del nome
la directory che contiene il riferimento alla directory corrente; nel caso
questa sia la directory radice allora il riferimento è a se stessa.
-Infine si ricordi che in unix non esistono i tipi di file e che non c'è nessun
+Infine si ricordi che in Unix non esistono i tipi di file e che non c'è nessun
supporto per le estensioni come parte del filesystem. Ciò non ostante molti
programmi adottano delle convenzioni per i nomi dei file, ad esempio il codice
-C normalmente si mette in file con l'estensione .c, ma questa è solo una
-convenzione.
+C normalmente si mette in file con l'estensione .c, ma questa è, appunto, solo
+una convenzione.
\section{L'interfaccia al filesystem}
\begin{itemize}
\item \texttt{int link(const char * oldname, const char * newname)}
- Crea un nuovo link al file indicato da \texttt{oldname} dandogli nome
- \texttt{newname}.
+ Crea un nuovo link diretto al file indicato da \texttt{oldname} dandogli
+ nome \texttt{newname}.
La funzione restituisce zero in caso di successo e -1 per un errore, in caso
di errore. La variabile \texttt{errno} viene settata secondo i codici di
\ref{sec:file_err_acc}) ai quali si aggiungono i seguenti:
\begin{itemize}
+ \item \texttt{EXDEV} \texttt{oldname} e \texttt{newname} non sono sullo
+ stesso filesystem.
+ \item \texttt{EPERM} il filesystem che contiene \texttt{oldname} e
+ \texttt{newname} non supporta i link diretti.
\item \texttt{EACCESS}
Non c'è il permesso di scrittura per la directory in cui si vuole creare
il nuovo link.
numero massimo è specificato dalla variabile \texttt{LINK\_MAX}, vedi
\ref{sec:sys_limits}.
\item \texttt{ENOSPC} La directory in cui si vuole creare il link è piena e
- non può essere .
+ non può essere ampliata.
\item \texttt{EROFS} La directory su cui si vuole inserire il nuovo link è
su un filesystem montato readonly.
\end{itemize}
\end{itemize}
+\begin{itemize}
+\item \texttt{int symlink(const char * oldname, const char * newname)}
+
+ Crea un nuovo link simbolico al file indicato da \texttt{oldname} dandogli
+ nome \texttt{newname}.
+
+ La funzione restituisce zero in caso di successo e -1 per un errore, in caso
+ di errore. La variabile \texttt{errno} viene settata secondo i codici di
+ errore standard di accesso ai files (trattati in dettaglio in
+ \ref{sec:file_err_acc}) ai quali si aggiungono i seguenti:
+
+ \begin{itemize}
+ \item \texttt{EEXIST} Un file (o una directory) con quel nome esiste di
+ già.
+ \item \texttt{EROFS} La directory su cui si vuole inserire il nuovo link è
+ su un filesystem montato readonly.
+ \item \texttt{ENOSPC} La directory o il filesystem in cui si vuole creare il
+ link è piena e non c'è ulteriore spazio disponibile.
+ \item \texttt{ELOOP} Ci sono troppi link simbolici nella risoluzione di
+ \texttt{oldname} o di \texttt{newname}.
+ \end{itemize}
+\end{itemize}
+
+
+
+
\section{L'input/output di basso livello}
\label{sec:file_lowlev_io}
%