-\section{La manipolazione di file e directory}
+\section{La gestione di file e directory}
Come già accennato in \secref{sec:file_filesystem} in un sistema unix-like la
gestione dei file ha delle caratteristiche specifiche che derivano
direttamente dall'architettura del sistema; in questa sezione esamineremo le
funzioni usate per manipolazione nel filesytem di file e directory, per la
creazione di link simbolici e diretti, per la gestione e la lettura delle
-directory; mettendo in evidenza le conseguenze della struttura standard della
-gestione dei file in un sistema unix-like, già accennate al capitolo
-precedente.
+directory; il tutto mettendo in evidenza le conseguenze della struttura
+standard della gestione dei file in un sistema unix-like, già accennate al
+capitolo precedente.
\subsection{Le funzioni \func{link} e \func{unlink}}
Una caratteristica comune a diversi sistemi operativi è quella di poter creare
dei nomi fittizi (come gli alias del MacOS o i collegamenti di Windows) che
-permettono di fare riferiremento allo stesso file, chiamandolo con nomi
-diversi o accedendovi da directory diverse.
+permettono di fare riferiremento allo stesso file chiamandolo con nomi diversi
+o accedendovi da directory diverse.
Questo è possibile anche in ambiente unix, dove tali collegamenti sono
-usualmente chiamati \textit{link}, ma data la struttura del sistema di
+usualmente chiamati \textit{link}; ma data la struttura del sistema di
gestione dei file (ed in particolare quanto trattato in
\secref{sec:file_architecture}) ci sono due metodi sostanzialmente diversi per
fare questa operazione.
una directory è solo una etichetta associata ad un puntatore a che fa
riferimento al suddetto inode.
-
Questo significa che la realizzazione di un link è immediata in quanto uno
stesso file può avere tanti nomi diversi allo stesso tempo, dati da
altrettante diverse associazioni allo stesso inode; si noti poi che nessuno di
Windows).
La funzione inoltre opera sia sui file ordinari che sugli altri oggetti del
-filesystem, con l'eccezione delle directory. In alcuni sistemi solo
+filesystem, con l'eccezione delle directory. In alcuni versioni di unix solo
l'amministratore è in grado di creare un collegamento diretto ad un'altra
directory, questo viene fatto perché con una tale operazione è possibile
creare dei circoli nel filesystem (vedi l'esempio mostrato in
\secref{sec:file_symlink}, dove riprenderemo il discorso) che molti programmi
non sono in grado di gestire e la cui rimozione diventerebbe estremamente
-complicata (in genere occorre far girare il programma \cmd{fsck} per riparare
-il filesystem).
+complicata (in genere per questo tipo di errori occorre far girare il
+programma \cmd{fsck} per riparare il filesystem).
Data la pericolosità di questa operazione e la disponibilità dei link
simbolici che possono fornire la stessa funzionalità senza questi problemi,
\end{errlist}
ed inoltre: \macro{EACCES}, \macro{EFAULT}, \macro{ENOENT}, \macro{ENOTDIR},
\macro{ENOMEM}, \macro{EROFS}, \macro{ELOOP}, \macro{EIO}.
-
\end{prototype}
Per cancellare una voce in una directory è necessario avere il permesso di
\label{sec:file_remove}
Al contrario di quanto avviene con altri unix in Linux non è possibile usare
-\func{unlink} sulle directory, per cancellare una directory si può usare la
+\func{unlink} sulle directory; per cancellare una directory si può usare la
funzione \func{rmdir} (vedi \secref{sec:file_dir_creat_rem}), oppure la
funzione \func{remove}. Questa è la funzione prevista dallo standard ANSI C
per cancellare un file o una directory (e funziona anche per i sistemi che non
riportato nelle descrizioni di \func{unlink} e \func{rmdir}.
\end{prototype}
-Per cambiare nome ad un file (o a una directory) si usa invece la funzione
-\func{rename}\footnote{la funzione è definita dallo standard ANSI C solo per i
- file, POSIX estende la funzione anche alle directory}, il cui prototipo è:
+Per cambiare nome ad un file o a una directory (che devono comunque essere
+nello stesso filesystem) si usa invece la funzione \func{rename}\footnote{la
+ funzione è definita dallo standard ANSI C solo per i file, POSIX estende la
+ funzione anche alle directory}, il cui prototipo è:
\begin{prototype}{stdio.h}
-{int rename(const char *oldpath, const char *newpath)}
- Rinomina un file, spostandolo fra directory diverse quando richiesto.
+ {int rename(const char *oldpath, const char *newpath)}
+
+ Rinomina \var{oldpath} in \var{newpth}, eseguendo se necessario lo
+ spostamento di un file fra directory diverse. Eventuali altri link diretti
+ allo stesso file non vengono influenzati.
La funzione restituisce zero in caso di successo e -1 per un errore, nel
qual caso il file non viene toccato. La variabile \var{errno} viene settata
\item \macro{ENOTEMPTY} \var{newpath} è una directory già esistente e non
vuota.
\item \macro{EBUSY} o \var{oldpath} o \var{newpath} sono in uso da parte di
- qualche processo (come directory di lavoro o come root) o del sistema
+ qualche processo (come directory di lavoro o come radice) o del sistema
(come mount point).
\item \macro{EINVAL} \var{newpath} contiene un prefisso di \var{oldpath} o
più in generale si è cercato di creare una directory come sottodirectory
\macro{ELOOP} e \macro{ENOSPC}.
\end{prototype}
-
-il vantaggio nell'uso
-di questa funzione al posto della chiamata successiva di \func{link} e
-\func{unlink} è che l'operazione è eseguita atomicamente, e non c'è un momento
-in cui il file su disco presenta ad un altro processo un diverso numero di
-collegamenti diretti. Inoltre in questo modo non c'è modo che il nuovo nome
-esista senza essere connesso all'inode; se si ha un crollo del sistema durante
-l'esecuzione può essere possibile che entrambi i nomi esistano, ma il nuovo
-nome quando esiste, è sempre connesso al file.
-
-
-L'effetto è diverso a seconda che si voglia spostare un file o una directory;
-se ci riferisce a un file allora \var{newpath} deve essere una di
-
+Il comportamento della funzione è diverso a seconda che si voglia rinominare
+un file o una directory; se ci riferisce a un file allora \var{newpath}, se
+esiste, non deve essere una directory (altrimenti si ha l'errore
+\macro{EISDIR}). Nel caso \var{newpath} indichi un file esistente questo viene
+cancellato e rimpiazzato (atomicamente).
+
+Se \var{oldpath} è una directory allora \var{newpath} se esiste deve essere
+una directory vuota, altrimenti si avranno gli errori \macro{ENOTDIR} (se non
+è una directory) o \macro{ENOTEMPTY} (se non è vuota). Chiaramente
+\var{newpath} non può contenere \var{oldpath}.
+
+Se \var{oldpath} si riferisce a un link simbolico questo sara rinominato; se
+\var{newpath} è un link simbolico verrà cancellato come qualunque altro file.
+Infine qualora \var{oldpath} e \var{newpath} siano due nomi dello stesso file
+lo standard POSIX prevede che la funzione non dia errore, e non faccia nulla,
+lasciando entrambi i nomi; Linux segue questo standard, anche se come fatto
+notare dal manuale delle glibc, il comportamento più ragionevole sarebbe
+quello di cancellare \var{oldpath}.
+
+Il vantaggio nell'uso di questa funzione al posto della chiamata successiva di
+\func{link} e \func{unlink} è che l'operazione è eseguita atomicamente, non
+può esistere cioè nessun istante in cui un altro processo può trovare attivi
+entrambi i nomi dello stesso file, o, in caso di sostituzione di un file
+esistente, non trovare quest'ultimo prima che la sostituzione sia stata
+eseguita.
+
+In ogni caso se \var{newpath} esiste e l'operazione fallisce per un qualche
+motivo (come un crash del kernel), \func{rename} garantisce di lasciare
+presente una istanza di \var{newpath}, tuttavia nella sovrascrittura potrà
+esistere una finestra in cui sia \var{oldpath} che \var{newpath} fanno
+riferimento allo stesso file.
\subsection{I link simbolici}
\label{sec:file_symlink}
\end{errlist}
\end{prototype}
-Dato che la funzione \func{open} segue i link simbolici, è necessaria usare
-un'altra funzione quando si vuole leggere il contenuto di un link simbolico,
-questa funzione è la:
+Dato che, come indicato in \secref{tab:file_symb_effect}, la funzione
+\func{open} segue i link simbolici, è necessaria usare un'altra funzione
+quando si vuole leggere il contenuto di un link simbolico, questa funzione è
+la:
\begin{prototype}{unistd.h}
{int readlink(const char * path, char * buff, size\_t size)}
\begin{prototype}{unistd.h}{int chdir (const char * pathname)}
Come dice il nome (che significa \textit{change directory}) questa funzione
serve a cambiare la directory di lavoro a quella specificata dal pathname
- contenuto nella stringa \texttt{pathname}.
+ contenuto nella stringa \var{pathname}.
\end{prototype}
\begin{prototype}{unistd.h}{int fchdir (int filedes)}
In tal caso si avranno differenti risultati a seconda del modi in cui si
calcola la lunghezza del file, ad esempio il comando \cmd{du}, (che riporta il
numero di blocchi occupati) potrà dare una dimensione inferiore, mentre se si
-legge dal file (ad esempio usando \cmd{wc -c}), dato che in tal caso per le
-parti non scritte vengono restituiti degli zeri, si avrà lo stesso risultato
-di \cmd{ls}.
-
-Se è sempre possibile allargare un file scrivendoci sopra od usando la
-funzione \func{seek} per spostarsi oltre la sua fine. Esistono però anche casi
-in cui si può avere bisogno di effettuare un troncamento scartando i dati al
-di là della dimensione scelta come nuova fine del file.
-
-Un file può essere troncato a zero aprendolo con il flag \macro{O\_TRUNC}, ma
-questo è un caso particolare; per qualunque altra dimensione si possono usare
-le due funzioni:
+legge dal file (ad esempio usando il comando \cmd{wc -c}), dato che in tal
+caso per le parti non scritte vengono restituiti degli zeri, si avrà lo stesso
+risultato di \cmd{ls}.
+
+Se è sempre possibile allargare un file, scrivendoci sopra od usando la
+funzione \func{seek} per spostarsi oltre la sua fine, esistono anche casi in
+cui si può avere bisogno di effettuare un troncamento, scartando i dati
+presenti al di là della dimensione scelta come nuova fine del file.
+
+Un file può sempre essere troncato a zero aprendolo con il flag
+\macro{O\_TRUNC}, ma questo è un caso particolare; per qualunque altra
+dimensione si possono usare le due funzioni:
\begin{functions}
\headdecl{unistd.h} \funcdecl{int truncate(const char *file\_name, off\_t
length)} Fa si che la dimensione del file \var{file\_name} sia troncata ad
eccetto che si usa con un file aperto, specificato tramite il suo file
descriptor \var{fd}.
- Le funzioni restituiscono zero in caso di successo e -1 per un errore, in
- caso di errore \var{errno} viene settato opportunamente; per
- \func{ftruncate} si hanno i valori:
+ Le funzioni restituiscono zero in caso di successo e -1 per un errore, nel
+ qual caso \var{errno} viene settato opportunamente; per \func{ftruncate} si
+ hanno i valori:
\begin{errlist}
\item \macro{EBADF} \var{fd} non è un file descriptor.
- \item \texttt{EINVAL} \var{fd} è un riferimento ad un socket, non a un file
+ \item \macro{EINVAL} \var{fd} è un riferimento ad un socket, non a un file
o non è aperto in scrittura.
\end{errlist}
per \func{truncate} si hanno:
\begin{errlist}
- \item \texttt{EACCES} il file non ha permesso di scrittura o non si ha il
+ \item \macro{EACCES} il file non ha permesso di scrittura o non si ha il
permesso di esecuzione una delle directory del pathname.
- \item \texttt{ETXTBSY} Il file è un programma in esecuzione.
+ \item \macro{ETXTBSY} Il file è un programma in esecuzione.
\end{errlist}
ed anche \macro{ENOTDIR}, \macro{ENAMETOOLONG}, \macro{ENOENT},
\macro{EROFS}, \macro{EIO}, \macro{EFAULT}, \macro{ELOOP}.
perduti; il comportamento in caso di lunghezza inferiore non è specificato e
dipende dall'implementazione: il file può essere lasciato invariato o esteso
fino alla lunghezza scelta; in quest'ultimo caso lo spazio viene riempito con
-zeri (e in genere si ha la creazione di un hole nel file).
+zeri (e in genere si ha la creazione di un \textit{hole} nel file).
\subsection{I tempi dei file}
\label{sec:file_file_times}
Il sistema mantiene per ciascun file tre tempi. Questi sono registrati
-nell'inode insieme agli altri attributi del file e possono essere letti tramite
-la funzione \func{stat}, che li restituisce attraverso tre campi della
-struttura in \figref{fig:file_stat_struct}. Il significato di detti tempi e
-dei relativi campi è riportato nello schema in \ntab:
+nell'inode insieme agli altri attributi del file e possono essere letti
+tramite la funzione \func{stat}, che li restituisce attraverso tre campi della
+struttura \var{stat} di \figref{fig:file_stat_struct}. Il significato di detti
+tempi e dei relativi campi è riportato nello schema in \ntab:
\begin{table}[htb]
\centering
Il primo punto da tenere presente è la differenza fra il cosiddetto tempo di
modifica (il \textit{modification time} \var{st\_mtime}) e il tempo di
-cambiamento di stato (il \textit{chage time} \var{st\_ctime}). Il primo
+cambiamento di stato (il \textit{change time} \var{st\_ctime}). Il primo
infatti fa riferimento ad una modifica del contenuto di un file, mentre il
secondo ad una modifica dell'inode; siccome esistono molte operazioni (come la
funzione \func{link} e molte altre che vedremo in seguito) che modificano solo
Il sistema non tiene conto dell'ultimo accesso all'inode, pertanto funzioni
come \func{access} o \func{stat} non hanno alcuna influenza sui tre tempi. Il
-tempo di ultimo accesso viene di solito usato per cancellare i file che non
-servono più dopo un certo lasso di tempo (ad esempio \cmd{leafnode} cancella i
-vecchi articoli sulla base di questo tempo).
+tempo di ultimo accesso (ai dati) viene di solito usato per cancellare i file
+che non servono più dopo un certo lasso di tempo (ad esempio \cmd{leafnode}
+cancella i vecchi articoli sulla base di questo tempo).
Il tempo di ultima modifica invece viene usato da \cmd{make} per decidere
quali file necessitano di essere ricompilati o (talvolta insieme anche al
illustrato in \ntab. Si sono riportati gli effetti sia per il file a cui si fa
riferimento, sia per la directory che lo contiene; questi ultimi possono
essere capiti se si tiene conto di quanto già detto, e cioè che anche le
-directory sono files, che il sistema tratta in maniera del tutto analoga agli
-altri.
+directory sono file (che contengono una lista di nomi) che il sistema tratta
+in maniera del tutto analoga a tutti gli altri.
Per questo motivo tutte le volte che compiremo una operazione su un file che
-comporta una modifica della sua directory entry, andremo anche a scrivere
-sulla directory che lo contiene cambiandone il tempo di modifica. Un esempio
-di questo può essere la cancellazione di un file, mentre leggere o scrivere o
-cambiarne i permessi ha effetti solo sui tempi del file.
+comporta una modifica del nome contenuto nella directory, andremo anche a
+scrivere sulla directory che lo contiene cambiandone il tempo di modifica. Un
+esempio di questo può essere la cancellazione di un file, invece leggere o
+scrivere o cambiare i permessi di un file ha effetti solo sui tempi di
+quest'ultimo.
\begin{table}[htb]
\centering
\end{table}
Si noti infine come \var{st\_ctime} non abbia nulla a che fare con il tempo di
-creazione del file, usato da molti altri sistemi operativi, che in unix non
+creazione del file, usato in molti altri sistemi operativi, ma che in unix non
esiste.
\end{lstlisting}
L'effetto della funzione e i privilegi necessari per eseguirla dipendono da
-cosa è l'argomento \var{times}; se è \textit{NULL} la funzione setta il tempo
+cosa è l'argomento \var{times}; se è \macro{NULL} la funzione setta il tempo
corrente ed è sufficiente avere accesso in scrittura al file; se invece si è
specificato un valore la funzione avrà successo solo se si è proprietari del
file (o si hanno i privilegi di amministratore).
Questo serve anche come misura di sicurezza per evitare che si possa
modificare un file nascondendo completamente le proprie tracce. In realtà la
cosa resta possibile, se si è in grado di accedere al device, scrivendo
-direttamente sul disco senza passare attraverso il filesystem, ma ovviamente è
-molto più complicato da realizzare.
-
+direttamente sul disco senza passare attraverso il filesystem, ma ovviamente
+in questo modo la cosa è molto più complicata da realizzare.
all'amministratore) l'accesso è sempre garantito senza nessun ulteriore
controllo. Per questo motivo \textsl{root} ha piena libertà di accesso a
tutti i file.
-\item Se l'\textit{effective user id} del processo è uguale all'uid del
+\item Se l'\textit{effective user id} del processo è uguale all'\acr{uid} del
proprietario del file (nel qual caso si dice che il processo è proprietario
del file) allora:
\begin{itemize}
stesso problema di presenta per la creazione di nuove directory (procedimento
descritto in \secref{sec:file_dir_creat_rem}).
-Lo standard POSIX prescrive che l'uid del nuovo file corrisponda
+Lo standard POSIX prescrive che l'\acr{uid} del nuovo file corrisponda
all'\textit{effective user id} del processo che lo crea; per il \acr{gid}
invece prevede due diverse possibilità:
\begin{itemize}
semantica BSD. Linux invece segue quella che viene chiamata semantica SVR4; di
norma cioè il nuovo file viene creato, seguendo la prima opzione, con il
\acr{gid} del processo, se però la directory in cui viene creato il file ha il
-bit \acr{sgid} settato allora viene usata la seconda opzione..
+bit \acr{sgid} settato allora viene usata la seconda opzione.
Usare la semantica BSD ha il vantaggio che il \acr{gid} viene sempre
automaticamente propagato, restando coerente a quello della directory di
un file viene fatto usando \textit{effective user id} e \textit{effective
group id} del processo, ma ci sono casi in cui si può voler effettuare il
controllo usando il \textit{real user id} e il \textit{real group id} (cioè
-l'uid dell'utente che ha lanciato il programma, che, come accennato in
+l'\acr{uid} dell'utente che ha lanciato il programma, che, come accennato in
\secref{sec:file_suid_sgid} e spiegato in \secref{sec:proc_perms} non è
detto sia uguale all'\textit{effective user id}). Per far questo si può usare
la funzione \func{access}, il cui prototipo è:
file indicato da \var{pathname}.
La funzione ritorna 0 se l'accesso è consentito, -1 altrimenti; in
- quest'ultimo caso la variabile \texttt{errno} viene settata secondo i codici
+ quest'ultimo caso la variabile \var{errno} viene settata secondo i codici
di errore: \macro{EACCES}, \macro{EROFS}, \macro{EFAULT}, \macro{EINVAL},
\macro{ENAMETOOLONG}, \macro{ENOENT}, \macro{ENOTDIR}, \macro{ELOOP},
\macro{EIO}.
\end{prototype}
-
I valori possibili per il parametro \var{mode} sono esprimibili come
combinazione delle costanti numeriche riportate in \ntab\ (attraverso un OR
binario). I primi tre valori implicano anche la verifica dell'esistenza del
Un esempio tipico per l'uso di questa funzione è quello di un processo che sta
eseguendo un programma coi privilegi di un altro utente (attraverso l'uso del
-suid bit) che vuole controllare se l'utente originale ha i permessi per
+\acr{suid} bit) che vuole controllare se l'utente originale ha i permessi per
accedere ad un certo file.
-\subsection{Le funzioni \texttt{chmod} e \texttt{fchmod}}
+\subsection{Le funzioni \func{chmod} e \func{fchmod}}
\label{sec:file_chmod}
Per cambiare i permessi di un file il sistema mette ad disposizione due
funzioni, che operano rispettivamente su un filename e su un file descriptor,
-i cui prototipi sono:
+i loro prototipi sono:
\begin{functions}
\headdecl{sys/types.h}
il file descriptor \var{fd} per indicare il file.
Le funzioni restituiscono zero in caso di successo e -1 per un errore, in
- caso di errore \texttt{errno} può assumere i valori:
+ caso di errore \var{errno} può assumere i valori:
\begin{errlist}
\item \macro{EPERM} L'\textit{effective user id} non corrisponde a quello
del proprietario del file o non è zero.
\end{functions}
I valori possibili per \var{mode} sono indicati in \ntab. I valori possono
-esser combinati con l'OR binario delle relative macro, o specificati
-direttamente, come per l'analogo comando di shell, con il valore ottale. Ad
-esempio i permessi standard assegnati ai nuovi file (lettura e scrittura per
-il proprietario, sola lettura per il gruppo e gli altri) sono corrispondenti
-al valore ottale $0644$, un programma invece avrebbe anche il bit di
-esecuzione attivo, con un valore di $0755$, se si volesse attivare il bit suid
-il valore da fornire sarebbe $4755$.
+esser combinati con l'OR binario delle relative costanti simboliche, o
+specificati direttamente, come per l'analogo comando di shell, con il valore
+numerico (la shell lo vuole in ottale, dato che i bit dei permessi sono
+divisibili in gruppi di tre). Ad esempio i permessi standard assegnati ai
+nuovi file (lettura e scrittura per il proprietario, sola lettura per il
+gruppo e gli altri) sono corrispondenti al valore ottale $0644$, un programma
+invece avrebbe anche il bit di esecuzione attivo, con un valore di $0755$, se
+si volesse attivare il bit suid il valore da fornire sarebbe $4755$.
\begin{table}[!htb]
\centering
anche se si è proprietari del file non tutte le operazioni sono permesse, in
particolare:
\begin{itemize}
-\item siccome solo l'amministratore può settare lo \textit{sticky bit} se se
+\item siccome solo l'amministratore può settare lo \textit{sticky bit}; se
l'\textit{effective user id} del processo non è zero esso viene
automaticamente cancellato (senza notifica di errore) qualora sia stato
indicato in \var{mode}.