From: Simone Piccardi Date: Sat, 21 Jul 2001 20:12:25 +0000 (+0000) Subject: Aggiunto materiale sui processi e i file X-Git-Url: https://gapil.gnulinux.it/gitweb/?a=commitdiff_plain;h=b61786a321acb8edfc249dd27b596d2323859db6;p=gapil.git Aggiunto materiale sui processi e i file --- diff --git a/filedir.tex b/filedir.tex index 16d8100..29feca0 100644 --- a/filedir.tex +++ b/filedir.tex @@ -34,26 +34,37 @@ accesso molto pi Ad ogni file unix associa sempre l'utente che ne è proprietario (il cosiddetto \textit{owner}) e il gruppo di appartenenza, secondo il meccanismo degli -identificatoti di utenti e gruppi (uid e gig) già accennato in -\secref{sec:intro_multiuser}, 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. +identificatori di utenti e gruppi (\textsl{uid} e \textsl{gid}), e accessibili +da programm tramite i campi \var{st\_uid} e \var{st\_gid} della struttura +\var{stat} (si veda \secref{sec:filedir_stat}). Ad ogni file viene inoltre +associato un insieme di permessi che sono divisi in tre classi, e cioè +attribuiti rispettivamente all'utente proprietario del file, a un 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 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} nell'output di \cmd{ls}) applicabili -rispettivamente al proprietario, al gruppo, a tutti (una descrizione più -dettagliata dei vari permessi associati ai file è riportata in -\secref{sec:filedir_suid_sgid}). I restanti tre bit sono usati per indicare -alcune caratteristiche più complesse (\textit{suid}, \textit{sgid}, e -\textit{sticky}) su cui pure torneremo in seguito (vedi +\textsl{w}, \textit{r} \textsl{x} nei comandi di sistema) applicabili +rispettivamente al proprietario, al gruppo, a tutti. I restanti tre bit +(\textsl{suid}, \textsl{sgid}, e \textsl{sticky}) sono usati per indicare +alcune caratteristiche più complesse su cui torneremo in seguito (vedi \secref{sec:filedir_suid_sgid} e \secref{sec:filedir_sticky}). -Tutte queste informazioni sono tenute per ciascun file nell'inode, in -opportuni bit del campo \var{st\_mode} della struttura letta da \func{stat} -(vedi \figref{fig:filedir_stat_struct}) che possono essere controllati con i -valori riportati in \ntab. +Anche i permessi sono tenuti per ciascun file (di qualunque tipo, quindi anche +per le fifo, i socket e i file di dispositivo) nell'inode, in opportuni bit +del campo \var{st\_mode} della struttura letta da \func{stat} (vedi +\figref{fig:filedir_stat_struct}). + + +In genere ci si riferisce a questi permessi usando le lettere \textsl{u} (per +\textit{user}), \textsl{g} (per \textit{group}) e \textsl{o} (per +\textit{other}), inoltre se si vuole indicare tutti questi gruppi insieme si +usa la lettera \textsl{a} (per \textit{all}). Si tenga ben presente questa +distinzione, dato che in certi casi, mutuando la termimologia in uso nel VMS, +si parla dei permessi base come di permessi di owner, group ed all, le cui +iniziali possono da luogo a confuzione. Le costanti che permettono di accedere +al valore numerico di questi bit sono riportate in \ntab. \begin{table}[htb] \centering @@ -65,7 +76,7 @@ valori riportati in \ntab. \hline \macro{S\_IRUSR} & \textit{user-read}, l'utente può leggere \\ \macro{S\_IWUSR} & \textit{user-write}, l'utente può scrivere \\ - \macro{S\_IXUSR} & \textit{user-execute}, l'utente può eseguire \\ + \macro{S\_IXUSR} & \textit{user-execute}, l'utente può eseguire \\ \hline \macro{S\_IRGRP} & \textit{group-read}, il gruppo può leggere \\ \macro{S\_IWGRP} & \textit{group-write}, il gruppo può scrivere \\ @@ -74,12 +85,64 @@ valori riportati in \ntab. \macro{S\_IROTH} & \textit{other-read}, tutti possono leggere \\ \macro{S\_IWOTH} & \textit{other-write}, tutti possono scrivere \\ \macro{S\_IXOTH} & \textit{other-execute}, tutti possono eseguire\\ + \hline \end{tabular} \caption{I bit dei permessi di accesso ai file, come definiti in \texttt{}} \label{tab:file_bit_perm} \end{table} +Questi permessi vengono usati in maniera diversa dalle varie funzioni, e a +seconda che si riferiscano a file, link simbolici o directory, qui ci +limiteremo ad un riassunto delle regole generali, entrando nei +dettagli più avanti. + +La prima regola è che per poter accedere ad un file attraverso il suo pathname +occorre il permesso di esecuzione in ciascuna delle directory che compongono +il pathname, e lo stesso vale per aprire un file nella directory corrente (per +la quale appunto serve il diritto di esecuzione). + +Per una directory infatti il permesso di esecuzione ha il significato +specifico che essa può essere attraversata nella risoluzione del pathname, ed +è distinto dal permesso di lettura che invece implica che si può leggere il +contenuto della directory. Questo significa che se si ha il permesso di +esecuzione senza permesso di lettura si potrà lo stesso aprire un file in una +directory (se si hanno i permessi opportuni per il medesimo) ma non si potrà +vederlo con \cmd{ls} (per crearlo occorrerà anche il permesso di scrittura per +la directory). + +Il permesso di lettura per un file consente di aprirlo con le opzioni di sola +lettura (\macro{O\_RDONLY}) o di lettura-scrittura (\macro{O\_RDWR}) e +leggerne il contenuto. Il permesso di scrittura consente di aprire un file in +sola scrittura (\macro{O\_WRONLY}) o lettura-scrittura (\macro{O\_RDWR}) e +modificarne il contenuto, lo stesso permesso è necessario per poter troncare +il file con l'opzione \macro{O\_TRUNC}. + +Non si può creare un file fintanto che non si disponga del permesso di +esecuzione e di quello di scrittura per la directory di destinazione; gli +stessi permessi occorrono per cancellare un file da una directory (si ricordi +che questo non implica necessariamente la rimozione fisica del file), non è +necessario nessun tipo di permesso per il file stesso (infatti esso non viene +toccato, viene solo modificato il contenute della directory). + +Per poter eseguire un file (che sia un programma compilato od uno script di +shell), occorre il permesso di esecuzione per il medesimo, inoltre solo i file +regolari possono essere eseguiti. + + +Per stabilire se un processo possiede un certo permesso ogni volta che si +apre, crea o cancella un file il kernel esegue una serie di controlli +guardando utente e gruppo a cui il file appartiene (i valori di \var{st\_uid} +e \var{st\_gid}) che confronta con l'\textit{effective user id}, +\textit{effective group id} e gli eventuali \textit{supplementary group id} +del processo (per una spiegazione dettagliata degli ID dei processi si veda +\secref{sec:prochand_perms}; normalmente, a parte quanto spiegato in +\secref{sec:filedir_suid_sgid}, essi corrispondo all'uid e al gid dell'utente +che ha lanciato il processo). + + + + % Quando un processo cerca l'accesso al file esso controlla i propri uid e gid % confrontandoli con quelli del file e se l'operazione richiesta è compatibile @@ -131,903 +194,908 @@ valori riportati in \ntab. +\section{La manipolazione delle caratteristiche dei files} +\label{sec:filedir_infos} -\section{La manipolazione di file e directory} - -Le prime funzioni che considereremo sono quelle relative alla gestione di file -e directory, secondo le caratteristiche standard che essi presentano in un -filesystem unix, la cui struttura abbiamo esaminato in precedenza (vedi -\secref{sec:fileintr_filesystem}). +Come spiegato in \secref{sec:fileintr_filesystem} tutte le informazioni +generali relative alle caratteristiche di ciascun file sono mantenute +nell'inode. Vedremo in questa sezione come sia possibile accedervi usando la +funzione \texttt{stat} ed esamineremo alcune funzioni utilizzabili per +manipolare una parte di questa informazione. Tutto quello che invece riguarda +il meccanismo di controllo di accesso ad i file e le relative funzioni di +manipolazione sarà invece esaminanto in \secref{sec:filedir_access_control}. -\subsection{Le funzioni \texttt{link} e \texttt{unlink}} -\label{sec:fileintr_link} -Una delle caratteristiche usate quando si opera con i file è quella di poter -creare dei nomi fittizi (alias o collegamenti) per potersi riferire allo -stesso file accedendovi da directory diverse. Questo è possibile anche in -ambiente unix, dove tali collegamenti sono usualmente chiamati \textit{link}, -ma data la struttura del sistema ci sono due metodi sostanzialmente diversi -per fare questa operazione. +\subsection{Le funzioni \texttt{stat}, \texttt{fstat} e \texttt{lstat}} +\label{sec:filedir_stat} -Come spiegato in \secref{sec:fileintr_architecture} l'accesso al contenuto di -un file su disco avviene attraverso il suo inode, e il nome che si trova in -una directory è solo una etichetta associata ad un puntatore a detto 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 -questi nomi viene ad assumere una particolare preferenza rispetto agli altri. +La lettura delle informazioni relative ai file è fatta attraverso la famiglia +delle funzioni \func{stat}, che è la funzione che il comando \cmd{ls} usa +per poter stampare tutti i dati dei files. I prototipi di queste funzioni sono +i seguenti: +\begin{functions} + \headdecl{sys/types.h} + \headdecl{sys/stat.h} + \headdecl{unistd.h} -Per aggiungere un nome ad un inode si utilizza la funzione \texttt{link}; si -suole chiamare questo tipo di associazione un collegamento diretto (o -\textit{hard link}). Il prototipo della funzione e le sue caratteristiche -principali, come risultano dalla man page, sono le seguenti: -\begin{prototype}{unistd.h} -{int link(const char * oldpath, const char * newpath)} - Crea un nuovo collegamento diretto al file indicato da \texttt{oldpath} - dandogli nome \texttt{newpath}. + \funcdecl{int stat(const char *file\_name, struct stat *buf)} Legge le + informazione del file specificato da \var{file\_name} e le inserisce in + \var{buf}. - La funzione restituisce zero in caso di successo e -1 in caso di errore. La - variabile \texttt{errno} viene settata opportunamente, i principali codici - di errore sono: - \begin{errlist} - \item \texttt{EXDEV} \texttt{oldpath} e \texttt{newpath} non sono sullo - stesso filesystem. - \item \texttt{EPERM} il filesystem che contiene \texttt{oldpath} e - \texttt{newpath} non supporta i link diretti o è una directory. - \item \texttt{EEXIST} un file (o una directory) con quel nome esiste di - già. - \item \texttt{EMLINK} ci sono troppi link al file \texttt{oldpath} (il - numero massimo è specificato dalla variabile \texttt{LINK\_MAX}, vedi - \secref{sec:xxx_limits}). - \end{errlist} + \funcdecl{int lstat(const char *file\_name, struct stat *buf)} Identica a + \func{stat} eccetto che se il \var{file\_name} è un link simbolico vengono + lette le informazioni relativa ad esso e non al file a cui fa riferimento. -\end{prototype} - -La creazione di un nuovo collegamento diretto non copia il contenuto del file, -ma si limita ad aumentare di uno il numero di referenze al file aggiungendo il -nuovo nome ai precedenti. Si noti che uno stesso file può essere così -richiamato in diverse directory. - -Per quanto dicevamo in \secref{sec:fileintr_filesystem} la creazione del -collegamento diretto è possibile solo se entrambi i pathname sono nello stesso -filesystem; inoltre il filesystem deve supportare i collegamenti diretti (non è -il caso ad esempio del filesystem \texttt{vfat} di windows). - -La funzione opera sui file ordinari, come sugli altri oggetti del filesystem, -in alcuni filesystem solo l'amministratore è in grado di creare un -collegamento diretto ad un'altra directory, questo lo si fa perché in questo -caso è possibile creare dei circoli nel filesystem (vedi -\secref{sec:fileintr_symlink}) che molti programmi non sono in grado di -gestire e la cui rimozione diventa estremamente complicata (in genere occorre -far girare il programma \texttt{fsck} per riparare il filesystem); data la sua -pericolosità in generale nei filesystem usati in Linux questa caratteristica è -stata disabilitata, e la funzione restituisce l'errore \texttt{EPERM}. - -La rimozione di un file (o più precisamente della voce che lo referenzia) si -effettua con la funzione \texttt{unlink}; il suo prototipo è il seguente: - -\begin{prototype}{unistd.h}{int unlink(const char * pathname)} - Cancella il nome specificato dal pathname nella relativa directory e - decrementa il numero di riferimenti nel relativo inode. Nel caso di link - simbolico cancella il link simbolico; nel caso di socket, fifo o file di - dispositivo rimuove il nome, ma come per i file i processi che hanno aperto - uno di questi oggetti possono continuare ad utilizzarlo. + \funcdecl{int fstat(int filedes, struct stat *buf)} Identica a \func{stat} + eccetto che si usa con un file aperto, specificato tramite il suo file + descriptor \var{filedes}. - La funzione restituisce zero in caso di successo e -1 per un errore, nel - qual caso il file non viene toccato. La variabile \texttt{errno} viene - settata secondo i seguenti codici di errore: + Le funzioni restituiscono zero in caso di successo e -1 per un errore, in + caso di errore \texttt{errno} viene settato ai valori: \begin{errlist} - \item \texttt{EISDIR} \var{pathname} si riferisce ad una directory - (valore specifico ritornato da linux che non consente l'uso di - \texttt{unlink} con le directory, e non conforme allo standard POSIX, che - prescrive invece l'uso di \texttt{EPERM} in caso l'operazione non sia - consnetita o il processo non abbia privilegi sufficienti). - \item \texttt{EROFS} \var{pathname} è su un filesystem montato in sola - lettura. - \item \texttt{EISDIR} \var{pathname} fa riferimento a una directory. + \item \texttt{EACCESS} non c'è il permesso di accedere al file. + \item \texttt{ENOTDIR} una componente del pathname non è una directory. + \item \texttt{EMLOOP} ci sono troppi link simbolici nel pathname. + \item \texttt{EFAULT} i puntatori usati sono fuori dallo spazio di indirizzi + del processo. + \item \texttt{ENOMEM} il kernel non ha a disposizione memoria sufficiente a + completare l'operazione. + \item \texttt{ENAMETOOLONG} il filename è troppo lungo. \end{errlist} -\end{prototype} - -Per cancellare una voce in una directory è necessario avere il permesso di -scrittura su di essa (dato che si va a rimuovere una voce dal suo contenuto) e -il diritto di esecuzione sulla directory che la contiene (torneremo in -dettaglio sui permessi e gli attributi fra poco), se inoltre lo -\textit{sticky} bit è settato occorrerà anche essere proprietari del file o -proprietari della directory (o root, per cui nessuna delle restrizioni è -applicata). +\end{functions} -Una delle caratteristiche di queste funzioni è che la creazione/rimozione -della nome dalla directory e l'incremento/decremento del numero di riferimenti -nell'inode deve essere una operazione atomica (cioè non interrompibile da -altri) processi, per questo entrambe queste funzioni sono realizzate tramite -una singola system call. +La struttura \texttt{stat} è definita nell'header \texttt{sys/stat.h} e in +generale dipende dall'implementazione, la versione usata da Linux è mostrata +in \nfig, così come riportata dalla man page (in realtà la definizione +effettivamente usata nel kernel dipende dall'architettura e ha altri campi +riservati per estensioni come tempi più precisi, o per il padding dei campi). -Si ricordi infine che il file non viene eliminato dal disco fintanto che tutti -i riferimenti ad esso sono stati cancellati, solo quando il \textit{link - count} mantenuto nell'inode diventa zero lo spazio occupato viene rimosso. A -questo però si aggiunge una altra condizione, e cioè che non ci siano processi -che abbiano detto file aperto. Come accennato questa proprietà viene spesso -usata per essere sicuri di non lasciare file temporanei su disco in caso di -crash dei programmi; la tecnica è quella di aprire il file e chiamare -\texttt{unlink} subito dopo. +\begin{figure}[!htb] + \footnotesize + \centering + \begin{minipage}[c]{15cm} + \begin{lstlisting}[labelstep=0,frame=,indent=1cm]{} +struct stat { + dev_t st_dev; /* device */ + ino_t st_ino; /* inode */ + mode_t st_mode; /* protection */ + nlink_t st_nlink; /* number of hard links */ + uid_t st_uid; /* user ID of owner */ + gid_t st_gid; /* group ID of owner */ + dev_t st_rdev; /* device type (if inode device) */ + off_t st_size; /* total size, in bytes */ + unsigned long st_blksize; /* blocksize for filesystem I/O */ + unsigned long st_blocks; /* number of blocks allocated */ + time_t st_atime; /* time of last access */ + time_t st_mtime; /* time of last modification */ + time_t st_ctime; /* time of last change */ +}; + \end{lstlisting} + \end{minipage} + \normalsize + \caption{La struttura \texttt{stat} per la lettura delle informazioni dei + file} + \label{fig:filedir_stat_struct} +\end{figure} -\subsection{Le funzioni \texttt{remove} e \texttt{rename}} -\label{sec:fileintr_remove} +Si noti come i vari membri della struttura siano specificati come tipi nativi +del sistema (di quelli definiti in \tabref{tab:xxx_sys_types}, e dichiarati in +\texttt{sys/types.h}). -Al contrario di quanto avviene con altri unix in Linux non è possibile usare -\texttt{unlink} sulle directory, per cancellare una directory si può usare la -funzione \texttt{rmdir} (vedi \secref{sec:filedir_dir_creat_rem}), oppure la -funzione \texttt{remove}. Questa è la funzione prevista dallo standard ANSI C -per cancellare un file o una directory (e funziona anche per i sistemi che non -supportano i link diretti), che per i file è identica alla \texttt{unlink} e -per le directory è identica alla \texttt{rmdir}: -\begin{prototype}{stdio.h}{int remove(const char *pathname)} - Cancella un nome dal filesystem. Usa \texttt{unlink} per i file e - \texttt{rmdir} per le directory. - - La funzione restituisce zero in caso di successo e -1 per un errore, nel - qual caso il file non viene toccato. Per i codici di errori vedi quanto - riportato nella descrizione di \texttt{unlink} e \texttt{rmdir}. -\end{prototype} +\subsection{I tipi di file} +\label{sec:filedir_file_types} -Per cambiare nome ad un file si usa invece la funzione \texttt{rename}, il -vantaggio nell'uso di questa funzione al posto della chiamata successiva di -\texttt{unlink} e \texttt{link} è che l'operazione è eseguita atomicamente, in -questo modo non c'è la possibilità che un processo che cerchi di accedere al -nuovo nome dopo che il vecchio è stato cambiato lo trovi mancante. +Come riportato in \tabref{tab:fileintr_file_types} in Linux oltre ai file e +alle directory esistono vari altri oggetti che possono stare su un filesystem; +il tipo di file è ritornato dalla \texttt{stat} nel campo \texttt{st\_mode}. -\begin{prototype}{stdio.h} -{int rename(const char *oldpath, const char *newpath)} - Rinomina un file, spostandolo fra directory diverse quando richiesto. +Dato che il valore numerico può variare a seconda delle implementazioni lo +standard POSIX definisce un insieme di macro per verificare il tipo di files, +queste venfono usate anche da Linux che supporta pure le estensioni per link +simbolici e socket definite da BDS, l'elenco è riportato in \ntab: +\begin{table}[htb] + \centering + \footnotesize + \begin{tabular}[c]{|l|l|} + \hline + Macro & Tipo del file \\ + \hline + \hline + \macro{S\_ISREG(m)} & file normale \\ + \macro{S\_ISDIR(m)} & directory \\ + \macro{S\_ISCHR(m)} & device a caraetteri \\ + \macro{S\_ISBLK(m)} & device a blocchi\\ + \macro{S\_ISFIFO(m)} & fifo \\ + \macro{S\_ISLNK(m)} & link simbolico \\ + \macro{S\_ISSOCK(m)} & socket \\ + \hline + \end{tabular} + \caption{Macro per i tipi di file (definite in \texttt{sys/stat.h})} + \label{tab:filedir_file_type_macro} +\end{table} - La funzione restituisce zero in caso di successo e -1 per un errore, nel - qual caso il file non viene toccato. La variabile \texttt{errno} viene - settata secondo i seguenti codici di errore: - \begin{errlist} - \item \texttt{EISDIR} \texttt{newpath} è una directory già esistente mentre - \texttt{oldpath} non è una directory. - \item \texttt{EXDEV} \texttt{oldpath} e \texttt{newpath} non sono sullo - stesso filesystem. - \item \texttt{ENOTEMPTY} \texttt{newpath} è una directory già esistente e - non vuota. - \item \texttt{EBUSY} o \texttt{oldpath} o \texttt{newpath} sono in uso da - parte di qualche processo (come directory di lavoro o come root) o del - sistema (come mount point). - \item \texttt{EINVAL} \texttt{newpath} contiene un prefisso di - \texttt{oldpath} o più in generale si è cercato di creare una directory - come sottodirectory di se stessa. - \item \texttt{EMLINK} \texttt{oldpath} ha già il massimo numero di link - consentiti o è una directory e la directory che contiene \texttt{newpath} - ha già il massimo numero di link. - \item \texttt{ENOTDIR} Uno dei componenti dei pathname non è una directory - o\texttt{oldpath} è una directory e \texttt{newpath} esiste e non è una - directory. - \item \texttt{EFAULT} o \texttt{oldpath} o \texttt{newpath} è fuori dello - spazio di indirizzi del processo. - \item \texttt{EACCESS} Non c'è il permesso di scrittura per la directory in - cui si vuole creare il nuovo link o una delle directory del pathname non - consente la ricerca (permesso di esecuzione). - \item \texttt{EPERM} le directory contenenti \texttt{oldpath} o - \texttt{newpath} hanno lo sticky bit attivo e i permessi del processo non - consentono rispettivamente la cancellazione e la creazione del file, o il - filesystem non supporta i link. - \item \texttt{ENAMETOOLONG} uno dei pathname è troppo lungo. - \item \texttt{ENOENT} Uno dei componenti del pathname non esiste o è un link - simbolico spezzato. - \item \texttt{ENOMEM} il kernel non ha a disposizione memoria sufficiente a - completare l'operazione. - \item \texttt{EROFS} I file sono su un filesystem montato in sola lettura. - \item \texttt{ELOOP} Ci sono troppi link simbolici nella risoluzione del - pathname. - \item \texttt{ENOSPC} Il device di destinazione non ha più spazio per la - nuova voce. - \end{errlist} -\end{prototype} +Oltre a queste macro è possibile usare direttamente il valore di +\var{st\_mode} per ricavare il significato dei vari bit in esso memorizzati, +per questo sempre in \texttt{sys/stat.h} sono definiti i flag riportati in +\ntab: +\begin{table}[htb] + \centering + \footnotesize + \begin{tabular}[c]{|l|c|l|} + \hline + Flag & Valore & Significato \\ + \hline + \hline + \macro{S\_IFMT} & 0170000 & bitmask for the file type bitfields \\ + \macro{S\_IFSOCK} & 0140000 & socket \\ + \macro{S\_IFLNK} & 0120000 & symbolic link \\ + \macro{S\_IFREG} & 0100000 & regular file \\ + \macro{S\_IFBLK} & 0060000 & block device \\ + \macro{S\_IFDIR} & 0040000 & directory \\ + \macro{S\_IFCHR} & 0020000 & character device \\ + \macro{S\_IFIFO} & 0010000 & fifo \\ + \macro{S\_ISUID} & 0004000 & set UID bit \\ + \macro{S\_ISGID} & 0002000 & set GID bit (see below) \\ + \macro{S\_ISVTX} & 0001000 & sticky bit (see below) \\ + \macro{S\_IRWXU} & 00700 & mask for file owner permissions \\ + \macro{S\_IRUSR} & 00400 & owner has read permission \\ + \macro{S\_IWUSR} & 00200 & owner has write permission \\ + \macro{S\_IXUSR} & 00100 & owner has execute permission \\ + \macro{S\_IRWXG} & 00070 & mask for group permissions \\ + \macro{S\_IRGRP} & 00040 & group has read permission \\ + \macro{S\_IWGRP} & 00020 & group has write permission \\ + \macro{S\_IXGRP} & 00010 & group has execute permission \\ + \macro{S\_IRWXO} & 00007 & mask for permissions for others (not in + group) \\ + \macro{S\_IROTH} & 00004 & others have read permission \\ + \macro{S\_IWOTH} & 00002 & others have write permisson \\ + \macro{S\_IXOTH} & 00001 & others have execute permission \\ + \hline + \end{tabular} + \caption{Flag per il campo \var{st\_mode} (definite in + \texttt{sys/stat.h})} + \label{tab:filedir_file_mode_flags} +\end{table} -\subsection{I link simbolici} -\label{sec:fileintr_symlink} +Il primo valore definisce la maschera dei bit usati nei quali viene +memorizzato il tipo di files, mentre gli altri possono essere usati per +effettuare delle selezioni sul tipo di file voluto, combinando opportunamente +i vari flag; ad esempio se si volesse controllare se un file è una directory o +un file ordinario si potrebbe definire la condizione: +\begin{lstlisting}[labelstep=0,frame=,indent=1cm]{} +#define IS_FILE_DIR(x) (((x) & S_IFMT) & (S_IFDIR | S_IFREG)) +\end{lstlisting} +in cui prima si estraggono da \var{st\_mode} i bit relativi al tipo di file e +poi si effettua il confronto con la combinazione di tipi scelta. -Siccome la funzione \texttt{link} crea riferimenti agli inodes, essa può -funzionare soltanto per file che risiedono sullo stesso filesystem, dato che -in questo caso è garantita l'unicità dell'inode, e solo per un filesystem di -tipo unix. Inoltre in Linux non è consentito eseguire un link diretto ad una -directory. +\subsection{La dimensione dei file} +\label{sec:filedir_file_size} -Per ovviare a queste limitazioni i sistemi unix supportano un'altra forma di -link (i cosiddetti \textit{soft link} o \textit{symbolic link}), che sono, -come avviene in altri sistemi operativi, dei file che contengono il -semplicemente il riferimento ad un altro file (o directory). In questo modo è -possibile effettuare link anche attraverso filesystem diversi e a directory, e -pure a file che non esistono ancora. +Il membro \var{st\_size} contiene la dimensione del file in bytes (se il file +è un file normale, nel caso di un link simbolico al dimensione è quella del +pathname che contiene). -Il sistema funziona in quanto i link simbolici sono contrassegnati come tali -al kernel (analogamente a quanto avviene per le directory) per cui la chiamata -ad una \texttt{open} o una \texttt{stat} su un link simbolico comporta la -lettura del contenuto del medesimo e l'applicazione della funzione al file -specificato da quest'ultimo. Invece altre funzioni come quelle per cancellare -o rinominare i file operano direttamente sul link simbolico (per l'elenco vedi -\ntab). Inoltre esistono funzioni apposite, come la \texttt{readlink} e la -\texttt{lstat} per accedere alle informazioni del link invece che a quelle del -file a cui esso fa riferimento. +Il campo \var{st\_blocks} definisce la lunghezza del file in blocchi di 512 +bytes. Il campo \var{st\_blksize} infine definisce la dimensione preferita per +i trasferimenti sui file (che è la dimensione usata anche dalle librerie del C +per l'interfaccia degli stream); scrivere sul file a blocchi di dati di +dimensione inferiore sarebbe inefficiente. -Le funzioni per operare sui link simbolici sono le seguenti, esse sono tutte -dichiarate nell'header file \texttt{unistd.h}. +Si tenga conto che lunghezza del file riportata in \var{st\_size} non è detto +che corrisponda all'occupazione dello spazio su disco per via della possibile +esistenza dei cosiddetti \textsl{buchi} (detti normalmente \textit{holes}) che +si formano tutte le volte che si va a scrivere su un file dopo aver eseguito +una \func{seek} (vedi \secref{sec:fileunix_lseek}) oltre la sua conclusione +corrente. -\begin{prototype}{unistd.h} -{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 - \secref{sec:filedir_access_control}) ai quali si aggiungono i seguenti: - \begin{errlist} - \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{errlist} -\end{prototype} +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}. -Dato che la funzione \texttt{open} segue i link simbolici, è necessaria usare -un'altra funzione quando si vuole leggere il contenuto di un link simbolico, -questa funzione è la: +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. -\begin{prototype}{unistd.h} -{int readlink(const char * path, char * buff, size\_t size)} - Legge il contenuto del link simbolico indicato da \texttt{path} nel buffer - \texttt{buff} di dimensione \texttt{size}. Non chiude la stringa con un - carattere nullo e la tronca a \texttt{size} nel caso il buffer sia troppo - piccolo per contenerla. +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: +\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 + un valore massimo specificato da \var{lenght}. - La funzione restituisce il numero di caratteri letti dentro \texttt{buff} o - -1 per un errore, in caso di errore. La variabile \texttt{errno} viene - settata secondo i codici di errore: + \funcdecl{int ftruncate(int fd, off\_t length))} Identica a \func{truncate} + 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 \texttt{errno} viene settato ai valori: \begin{errlist} - \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}. + \item \texttt{EACCESS} non c'è il permesso di accedere al file. + \item \texttt{ENOTDIR} una componente del pathname non è una directory. + \item \texttt{EMLOOP} ci sono troppi link simbolici nel pathname. + \item \texttt{EFAULT} i puntatori usati sono fuori dallo spazio di indirizzi + del processo. + \item \texttt{ENOMEM} il kernel non ha a disposizione memoria sufficiente a + completare l'operazione. + \item \texttt{ENOENT} il file non esiste. + \item \texttt{ENAMETOOLONG} il filename è troppo lungo. \end{errlist} -\end{prototype} +\end{functions} + +Se il file è più lungo della lunghezza specificata i dati in eccesso saranno +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). + + +\subsection{I tempi dei file} +\label{sec:filedir_file_times} + +Il sistema mantiene per ciascun file tre tempi. Questi sono registrati +nell'inode insieme agli altri attibuti del file e possono essere letti tramite +la funzione \func{stat}, che li restituisce attraverso tre campi della +struttura in \figref{fig:filedir_stat_struct}. Il significato di detti tempi e +dei relativi campi è riportato nello schema in \ntab: -In \ntab\ si è riportato un elenco dei comportamenti delle varie funzioni che -operano sui file rispetto ai link simbolici; specificando quali seguono il -link simbolico e quali possono operare direttamente sul suo contenuto. \begin{table}[htb] \centering - \footnotesize - \begin{tabular}[c]{|l|c|c|} + \begin{tabular}[c]{|c|l|l|c|} + \hline + Membro & Significato & Funzione&opzione \\ + \hline + \hline + \var{st\_atime}& ultimo accesso ai dati del file &\func{read}& \cmd{-u}\\ + \var{st\_mtime}& ultima modifica ai dati del file &\func{write}& default\\ + \var{st\_ctime}& ultima modifica ai dati dell'inode&\func{chmod}, + \func{utime} & \cmd{-c} \\ \hline - Funzione & Segue il link & Non segue il link \\ - \hline - \hline - \func{access} & $\bullet$ & \\ - \func{chdir} & $\bullet$ & \\ - \func{chmod} & $\bullet$ & \\ - \func{chown} & & $\bullet$ \\ - \func{creat} & $\bullet$ & \\ - \func{exec} & $\bullet$ & \\ - \func{lchown} & $\bullet$ & $\bullet$ \\ - \func{link} & & \\ - \func{lstat} & & $\bullet$ \\ - \func{mkdir} & $\bullet$ & \\ - \func{mkfifo} & $\bullet$ & \\ - \func{mknod} & $\bullet$ & \\ - \func{open} & $\bullet$ & \\ - \func{opendir} & $\bullet$ & \\ - \func{pathconf} & $\bullet$ & \\ - \func{readlink} & & $\bullet$ \\ - \func{remove} & & $\bullet$ \\ - \func{rename} & & $\bullet$ \\ - \func{stat} & $\bullet$ & \\ - \func{truncate} & $\bullet$ & \\ - \func{unlink} & & $\bullet$ \\ - \hline \end{tabular} - \caption{Uso dei link simbolici da parte di alcune funzioni.} - \label{tab:filedir_symb_effect} + \caption{I tre tempi associati a ciascun file} + \label{tab:filedir_file_times} \end{table} -si noti che non si è specificato il comportamento delle funzioni che operano -con i file descriptor, in quanto la gestione del link simbolico viene in -genere effttuata dalla funzione che restituisce il file descriptor -(normalmente la \func{open}). -\begin{figure}[htb] +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 +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 +le informazioni contenute nell'inode senza toccare il file, diventa necessario +l'utilizzo di un altro tempo. + +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). + +Il tempo di ultima modifica invece viene usato da \cmd{make} per decidere +quali file necessitano di essere ricompilati o (talvolta insieme anche al +tempo di cambiamento di stato) per decidere quali file devono essere +archiviati per il backup. Il comando \cmd{ls} (quando usato con le opzioni +\cmd{-l} o \cmd{-t}) mostra i tempi dei file secondo lo schema riportato +nell'ultima colonna di \curtab. + +L'effetto delle varie funzioni di manipolazione dei file sui tempi è +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. + +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. + +\begin{table}[htb] \centering - \includegraphics[width=5cm]{img/link_loop.eps} - \caption{Esempio di loop nel filesystem creato con un link simbolico.} - \label{fig:filedir_link_loop} -\end{figure} + \footnotesize + \begin{tabular}[c]{|l|c|c|c|c|c|c|l|} + \hline + \multicolumn{1}{|c|}{Funzione} + &\multicolumn{3}{p{2cm}}{File o directory di riferimento} + &\multicolumn{3}{p{2cm}}{Directory genitrice del riferimento} + &\multicolumn{1}{|c|}{Note} \\ + \cline{2-7} + & \textsl{(a)} & \textsl{(m)}& \textsl{(c)} + & \textsl{(a)} & \textsl{(m)}& \textsl{(c)}& \\ + \hline + \hline + \func{chmod}, \func{fchmod} + & & &$\bullet$& & & & \\ + \func{chown}, \func{fchown} + & & &$\bullet$& & & & \\ + \func{creat} + &$\bullet$&$\bullet$&$\bullet$& &$\bullet$&$\bullet$& con + \macro{O\_CREATE} \\ \func{creat} + & &$\bullet$&$\bullet$& &$\bullet$&$\bullet$& + con \macro{O\_TRUNC} \\ \func{exec} + &$\bullet$& & & & & & \\ + \func{lchown} + & & &$\bullet$& & & & \\ + \func{link} + & & &$\bullet$& &$\bullet$&$\bullet$& \\ + \func{mkdir} + &$\bullet$&$\bullet$&$\bullet$& &$\bullet$&$\bullet$& \\ + \func{mkfifo} + &$\bullet$&$\bullet$&$\bullet$& &$\bullet$&$\bullet$& \\ + \func{open} + &$\bullet$&$\bullet$&$\bullet$& &$\bullet$&$\bullet$& con + \macro{O\_CREATE} \\ \func{open} + & &$\bullet$&$\bullet$& & & & con + \macro{O\_TRUNC} \\ \func{pipe} + &$\bullet$&$\bullet$&$\bullet$& & & & \\ + \func{read} + &$\bullet$& & & & & & \\ + \func{remove} + & & &$\bullet$& &$\bullet$&$\bullet$& using + \func{unlink}\\ \func{remove} + & & & & &$\bullet$&$\bullet$& using + \func{rmdir}\\ \func{rename} + & & &$\bullet$& &$\bullet$&$\bullet$& per entrambi + gli argomenti\\ \func{rmdir} + & & & & &$\bullet$&$\bullet$& \\ + \func{truncate}, \func{ftruncate} + & &$\bullet$&$\bullet$& & & & \\ + \func{unlink} + & & &$\bullet$& &$\bullet$&$\bullet$& \\ + \func{utime} + &$\bullet$&$\bullet$&$\bullet$& & & & \\ + \func{write} + & &$\bullet$&$\bullet$& & & & \\ + \hline + \end{tabular} + \caption{Effetti delle varie funzioni su tempi di ultimo accesso + \textsl{(a)}, ultima modifica \textsl{(m)} e ultimo cambiamento + \textsl{(c)}} + \label{tab:filedir_times_effects} +\end{table} -Un caso comune che si può avere con i link simbolici è la creazione dei -cosiddetti \textit{loop}. La situazione è illustrata in \curfig, che riporta -la struttura della directory \file{/boot}. Come si vede si è creato al suo -interno un link simbolico che punta di nuovo a \file{/boot}\footnote{Questo - tipo di loop è stato effettuato per poter permettere a \cmd{grub} (un - bootloader estremamente avanzato in grado di accedere direttamente - attraverso vari filesystem al file da lanciare come sistema operativo) di - vedere i file in questa directory, che è montata su una partizione separata - (e che grub vedrebbe come radice), con lo stesso path con cui verrebbero - visti dal sistema operativo.}. +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 +esiste. -Questo può causare problemi per tutti quei programmi che effettuassero uno -scan di una directory senza tener conto dei link simbolici, in quel caso -infatti il loop nella directory -Un secondo punto da tenere presente è che un link simbolico può essere fatto -anche ad un file che non esiste; ad esempio possiamo creare un file temporaneo -nella nostra directory con un link del tipo: -\begin{verbatim} -$ln -s /tmp/tmp_file temporaneo -\end{verbatim}%$ -ma anche se \file{/tmp/tmp\_file} non esiste. Aprendo in scrittura -\file{temporaneo} questo verrà scritto; ma se cercassimo di accederlo in sola -lettura (ad esempio con \cmd{cat}) otterremmo: -\begin{verbatim} -$ cat prova -cat: prova: No such file or directory -\end{verbatim}%$ -con un errore che sembra sbagliato, dato \cmd{ls} ci mostrerebbe l'esistenza -di \file{temporaneo}. +\subsection{La funzione \texttt{utime}} +\label{sec:filedir_utime} +I tempi di ultimo accesso e modifica possono essere cambiati usando la +funzione \func{utime}, il cui prototipo è: -\subsection{Le funzioni \texttt{mkdir} e \texttt{rmdir}} -\label{sec:filedir_dir_creat_rem} +\begin{prototype}{utime.h} +{int utime(const char * filename, struct utimbuf *times)} -Per creare una nuova directory si può usare la seguente funzione, omonima -dell'analogo comando di shell \texttt{mkdir}; per accedere ai tipi usati -programma deve includere il file \texttt{sys/types.h}. +Cambia i tempi di ultimo accesso e modifica dell'inode specificato da +\var{filename} secondo i campi \var{actime} e \var{modtime} di \var{times}. Se +questa è \macro{NULL} allora viene usato il tempo corrente. -\begin{prototype}{sys/stat.h} -{int mkdir (const char * dirname, mode\_t mode)} - Questa funzione crea una nuova directory vuota con il nome indicato da - \texttt{dirname}, assegnandole i permessi indicati da \texttt{mode}. Il nome - può essere indicato con il pathname assoluto o relativo. - - La funzione restituisce zero in caso di successo e -1 per un errore, in caso - di errore \texttt{errno} viene settata secondo i codici di errore standard - di accesso ai files (trattati in dettaglio in - \secref{sec:filedir_access_control}) ai quali si aggiungono i seguenti: - \begin{errlist} - \item \texttt{EACCESS} - Non c'è il permesso di scrittura per la directory in cui si vuole inserire - la nuova directory. - \item \texttt{EEXIST} Un file (o una directory) con quel nome esiste di già. - \item \texttt{EMLINK} La directory in cui si vuole creare la nuova directory - contiene troppi file. Sotto Linux questo normalmente non avviene perché il - filesystem standard consente la creazione di un numero di file maggiore di - quelli che possono essere contenuti nell'hard-disk, ma potendo avere a che - fare anche con filesystem di altri sistemi questo errore può presentarsi. - \item \texttt{ENOSPC} Non c'è abbastanza spazio sul file system per creare - la nuova directory. - \item \texttt{EROFS} La directory su cui si vuole inserire la nuova - directory è su un filesystem montato readonly. - \end{errlist} +La funzione restituisce zero in caso di successo e -1 in caso di errore, nel +qual caso \var{errno} è settata opportunamente. +\begin{errlist} +\item \texttt{EACCESS} non si ha il permesso di scrittura sul file. +\item \texttt{ENOENT} \var{filename} non esiste. +\end{errlist} \end{prototype} +La struttura \var{utimebuf} usata da \func{utime} è definita come: +\begin{lstlisting}[labelstep=0,frame=,indent=1cm]{} +struct utimbuf { + time_t actime; /* access time */ + time_t modtime; /* modification time */ +}; +\end{lstlisting} -\subsection{Accesso alle directory} -\label{sec:filedir_dir_read} +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 +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). -Benché le directory siano oggetti del filesystem come tutti gli altri non ha -ovviamente senso aprirle come fossero dei file di dati. Può però essere utile -poterne leggere il contenuto ad esempio per fare la lista dei file che esse -contengono o ricerche sui medesimi. +Si tenga presente che non è comunque possibile specificare il tempo di +cambiamento di stato del file, che viene comunque cambiato dal kernel tutte le +volte che si modifica l'inode (quindi anche alla chiamata di \func{utime}). +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. -Per accedere al contenuto delle directory si usano i cosiddetti -\textit{directory streams} (chiamati così per l'analogia con i file stream); -la funzione \texttt{opendir} apre uno di questi stream e la funzione -\texttt{readdir} legge il contenuto della directory, i cui elementi sono le -\textit{directory entries} (da distinguersi da quelle della cache di cui -parlavamo in \secref{sec:fileintr_vfs}) in una opportuna struttura -\texttt{struct dirent}. -\subsection{La directory di lavoro} -\label{sec:filedir_work_dir} -A ciascun processo è associato ad una directory nel filesystem che è chiamata -directory corrente o directory di lavoro (\textit{current working directory}) -che è quella a cui si fa riferimento quando un filename è espresso in forma -relativa (relativa appunto a questa directory). -Quando un utente effettua il login questa directory viene settata alla -cosiddetta \textit{home directory} del suo account, il comando \texttt{cd} -della shell consente di cambiarla a piacere, spostandosi da una directory ad -un'altra. Siccome la directory corrente resta la stessa quando viene creato -un processo figlio, la directory corrente della shell diventa anche la -directory corrente di qualunque comando da essa lanciato. -Le funzioni qui descritte servono esaminare e cambiare la directory di lavoro -corrente. +\section{La manipolazione di file e directory} -\begin{prototype}{unistd.h}{char * getcwd (char * buffer, size\_t size)} - Restituisce il filename completo della directory di lavoro corrente nella - stringa puntata da \texttt{buffer}, che deve essere precedentemente - allocata, per una dimensione massima di \texttt{size}. Si può anche - specificare un puntatore nullo come \textit{buffer}, nel qual caso la - stringa sarà allocata automaticamente per una dimensione pari a - \texttt{size} qualora questa sia diversa da zero, o della lunghezza esatta - del pathname altrimenti. In questo caso si deve ricordare di disallocare la - stringa una volta cessato il suo utilizzo. - - La funzione restituisce il puntatore \texttt{buffer} se riesce, - \texttt{NULL} se fallisce, in quest'ultimo caso la variabile - \texttt{errno} è settata con i seguenti codici di errore: - \begin{errlist} - \item \texttt{EINVAL} L'argomento \texttt{size} è zero e \texttt{buffer} non - è nullo. - \item \texttt{ERANGE} L'argomento \texttt{size} è più piccolo della - lunghezza del pathname. - \item \texttt{EACCESS} Manca il permesso di lettura o di ricerca su uno dei - componenti del pathname (cioè su una delle directory superiori alla - corrente). - \end{errlist} -\end{prototype} +Come già accennato in \secref{sec:fileintr_filesystem} in un sistema unix-like +i file hanno delle caratteristiche specifiche dipendenti dall'architettura del +sistema, esamineremo qui allora le funzioni usate per la creazione di link +simbolici e diretti e per la gestione delle directory, approfondendo quanto +già accennato in precedenza. -Di questa funzione esiste una versione \texttt{char * getwd(char * buffer)} -fatta per compatibilità all'indietro con BSD, che non consente di specificare -la dimensione del buffer; esso deve essere allocato in precedenza ed avere una -dimensione superiore a \texttt{PATH\_MAX} (di solito 256 bytes, vedi -\secref{sec:xxx_limits}; il problema è che in Linux non esiste una dimensione -superiore per un pathname, per cui non è detto che il buffer sia sufficiente a -contenere il nome del file, e questa è la ragione principale per cui questa -funzione è deprecata. -Una seconda funzione simile è \texttt{char * get\_current\_dir\_name(void)} -che è sostanzialmente equivalente ad una \texttt{getcwd(NULL, 0)}, con la sola -differenza che essa ritorna il valore della variabile di ambiente -\texttt{PWD}, che essendo costruita dalla shell può contenere anche dei -riferimenti simbolici. +\subsection{Le funzioni \texttt{link} e \texttt{unlink}} +\label{sec:fileintr_link} -Come già detto in unix anche le directory sono file, è possibile pertanto -riferirsi ad esse tramite il file descriptor dell'interfaccia a basso livello, -e non solo tramite il filename; per questo motivo ci sono due diverse funzioni -per cambiare directory di lavoro. +Una delle caratteristiche comuni a vari sistemi operativi è quella di poter +creare dei nomi fittizi (alias o collegamenti) per potersi riferire allo +stesso file accedendovi da directory diverse. Questo è possibile anche in +ambiente unix, dove tali collegamenti sono usualmente chiamati \textit{link}, +ma data la struttura del sistema ci sono due metodi sostanzialmente diversi +per fare questa operazione. -\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}. -\end{prototype} - -\begin{prototype}{unistd.h}{int fchdir (int filedes)} - Analoga alla precedente, ma usa un file descriptor invece del pathname. +Come spiegato in \secref{sec:fileintr_architecture} l'accesso al contenuto di +un file su disco avviene attraverso il suo inode, e il nome che si trova in +una directory è solo una etichetta associata ad un puntatore a detto 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 +questi nomi viene ad assumere una particolare preferenza rispetto agli altri. - Entrambe le funzioni restituiscono zero in caso di successo e -1 per un - errore, in caso di errore \texttt{errno} viene settata secondo i codici di - errore standard di accesso ai files (trattati in dettaglio in - \secref{sec:filedir_access_control}) ai quali si aggiunge il codice - \texttt{ENOTDIR} nel caso il \texttt{filename} indichi un file che non sia - una directory. +Per aggiungere un nome ad un inode si utilizza la funzione \texttt{link}; si +suole chiamare questo tipo di associazione un collegamento diretto (o +\textit{hard link}). Il prototipo della funzione e le sue caratteristiche +principali, come risultano dalla man page, sono le seguenti: +\begin{prototype}{unistd.h} +{int link(const char * oldpath, const char * newpath)} + Crea un nuovo collegamento diretto al file indicato da \texttt{oldpath} + dandogli nome \texttt{newpath}. + + La funzione restituisce zero in caso di successo e -1 in caso di errore. La + variabile \texttt{errno} viene settata opportunamente, i principali codici + di errore sono: + \begin{errlist} + \item \texttt{EXDEV} \texttt{oldpath} e \texttt{newpath} non sono sullo + stesso filesystem. + \item \texttt{EPERM} il filesystem che contiene \texttt{oldpath} e + \texttt{newpath} non supporta i link diretti o è una directory. + \item \texttt{EEXIST} un file (o una directory) con quel nome esiste di + già. + \item \texttt{EMLINK} ci sono troppi link al file \texttt{oldpath} (il + numero massimo è specificato dalla variabile \texttt{LINK\_MAX}, vedi + \secref{sec:xxx_limits}). + \end{errlist} + \end{prototype} +La creazione di un nuovo collegamento diretto non copia il contenuto del file, +ma si limita ad aumentare di uno il numero di referenze al file (come si può +controllare con il campo \var{st\_nlink} di \var{stat}) aggiungendo il nuovo +nome ai precedenti. Si noti che uno stesso file può essere così richiamato in +diverse directory. + +Per quanto dicevamo in \secref{sec:fileintr_filesystem} la creazione del +collegamento diretto è possibile solo se entrambi i pathname sono nello stesso +filesystem; inoltre il filesystem deve supportare i collegamenti diretti (non è +il caso ad esempio del filesystem \texttt{vfat} di windows). +La funzione opera sui file ordinari, come sugli altri oggetti del filesystem, +in alcuni filesystem solo l'amministratore è in grado di creare un +collegamento diretto ad un'altra directory, questo lo si fa perché in questo +caso è possibile creare dei circoli nel filesystem (vedi +\secref{sec:fileintr_symlink}) che molti programmi non sono in grado di +gestire e la cui rimozione diventa estremamente complicata (in genere occorre +far girare il programma \texttt{fsck} per riparare il filesystem); data la sua +pericolosità in generale nei filesystem usati in Linux questa caratteristica è +stata disabilitata, e la funzione restituisce l'errore \texttt{EPERM}. -\section{La manipolazione delle caratteristiche dei files} -\label{sec:filedir_infos} - -Come spiegato in \secref{sec:fileintr_filesystem} tutte le informazioni -generali relative alle caratteristiche di ciascun file sono mantenute -nell'inode. Vedremo in questa sezione come sia possibile accedervi usando la -funzione \texttt{stat} ed esamineremo alcune funzioni utilizzabili per -manipolare una parte di questa informazione. Tutto quello che invece riguarda -il meccanismo di controllo di accesso ad i file e le relative funzioni di -manipolazione sarà invece esaminanto in \secref{sec:filedir_access_control}. - - -\subsection{Le funzioni \texttt{stat}, \texttt{fstat} e \texttt{lstat}} -\label{sec:filedir_stat} - -La lettura delle informazioni relative ai file è fatta attraverso la famiglia -delle funzioni \func{stat}, che è la funzione che il comando \cmd{ls} usa -per poter stampare tutti i dati dei files. I prototipi di queste funzioni sono -i seguenti: -\begin{functions} - \headdecl{sys/types.h} - \headdecl{sys/stat.h} - \headdecl{unistd.h} +La rimozione di un file (o più precisamente della voce che lo referenzia) si +effettua con la funzione \texttt{unlink}; il suo prototipo è il seguente: - \funcdecl{int stat(const char *file\_name, struct stat *buf)} Legge le - informazione del file specificato da \var{file\_name} e le inserisce in - \var{buf}. - - \funcdecl{int lstat(const char *file\_name, struct stat *buf)} Identica a - \func{stat} eccetto che se il \var{file\_name} è un link simbolico vengono - lette le informazioni relativa ad esso e non al file a cui fa riferimento. - - \funcdecl{int fstat(int filedes, struct stat *buf)} Identica a \func{stat} - eccetto che si usa con un file aperto, specificato tramite il suo file - descriptor \var{filedes}. +\begin{prototype}{unistd.h}{int unlink(const char * pathname)} + Cancella il nome specificato dal pathname nella relativa directory e + decrementa il numero di riferimenti nel relativo inode. Nel caso di link + simbolico cancella il link simbolico; nel caso di socket, fifo o file di + dispositivo rimuove il nome, ma come per i file i processi che hanno aperto + uno di questi oggetti possono continuare ad utilizzarlo. - Le funzioni restituiscono zero in caso di successo e -1 per un errore, in - caso di errore \texttt{errno} viene settato ai valori: + La funzione restituisce zero in caso di successo e -1 per un errore, nel + qual caso il file non viene toccato. La variabile \texttt{errno} viene + settata secondo i seguenti codici di errore: \begin{errlist} - \item \texttt{EACCESS} non c'è il permesso di accedere al file. - \item \texttt{ENOTDIR} una componente del pathname non è una directory. - \item \texttt{EMLOOP} ci sono troppi link simbolici nel pathname. - \item \texttt{EFAULT} i puntatori usati sono fuori dallo spazio di indirizzi - del processo. - \item \texttt{ENOMEM} il kernel non ha a disposizione memoria sufficiente a - completare l'operazione. - \item \texttt{ENAMETOOLONG} il filename è troppo lungo. + \item \texttt{EISDIR} \var{pathname} si riferisce ad una directory + (valore specifico ritornato da linux che non consente l'uso di + \texttt{unlink} con le directory, e non conforme allo standard POSIX, che + prescrive invece l'uso di \texttt{EPERM} in caso l'operazione non sia + consnetita o il processo non abbia privilegi sufficienti). + \item \texttt{EROFS} \var{pathname} è su un filesystem montato in sola + lettura. + \item \texttt{EISDIR} \var{pathname} fa riferimento a una directory. \end{errlist} -\end{functions} +\end{prototype} -La struttura \texttt{stat} è definita nell'header \texttt{sys/stat.h} e in -generale dipende dall'implementazione, la versione usata da Linux è mostrata -in \nfig, così come riportata dalla man page (in realtà la definizione -effettivamente usata nel kernel dipende dall'architettura e ha altri campi -riservati per estensioni come tempi più precisi, o per il padding dei campi). +Per cancellare una voce in una directory è necessario avere il permesso di +scrittura su di essa (dato che si va a rimuovere una voce dal suo contenuto) e +il diritto di esecuzione sulla directory che la contiene (torneremo in +dettaglio sui permessi e gli attributi fra poco), se inoltre lo +\textit{sticky} bit è settato occorrerà anche essere proprietari del file o +proprietari della directory (o root, per cui nessuna delle restrizioni è +applicata). -\begin{figure}[!htb] - \footnotesize - \centering - \begin{minipage}[c]{15cm} - \begin{lstlisting}[labelstep=0,frame=,indent=1cm]{} -struct stat { - dev_t st_dev; /* device */ - ino_t st_ino; /* inode */ - mode_t st_mode; /* protection */ - nlink_t st_nlink; /* number of hard links */ - uid_t st_uid; /* user ID of owner */ - gid_t st_gid; /* group ID of owner */ - dev_t st_rdev; /* device type (if inode device) */ - off_t st_size; /* total size, in bytes */ - unsigned long st_blksize; /* blocksize for filesystem I/O */ - unsigned long st_blocks; /* number of blocks allocated */ - time_t st_atime; /* time of last access */ - time_t st_mtime; /* time of last modification */ - time_t st_ctime; /* time of last change */ -}; - \end{lstlisting} - \end{minipage} - \normalsize - \caption{La struttura \texttt{stat} per la lettura delle informazioni dei - file} - \label{fig:filedir_stat_struct} -\end{figure} +Una delle caratteristiche di queste funzioni è che la creazione/rimozione +della nome dalla directory e l'incremento/decremento del numero di riferimenti +nell'inode deve essere una operazione atomica (cioè non interrompibile da +altri) processi, per questo entrambe queste funzioni sono realizzate tramite +una singola system call. -Si noti come i vari membri della struttura siano specificati come tipi nativi -del sistema (di quelli definiti in \tabref{tab:xxx_sys_types}, e dichiarati in -\texttt{sys/types.h}). +Si ricordi infine che il file non viene eliminato dal disco fintanto che tutti +i riferimenti ad esso sono stati cancellati, solo quando il \textit{link + count} mantenuto nell'inode diventa zero lo spazio occupato viene rimosso. A +questo però si aggiunge una altra condizione, e cioè che non ci siano processi +che abbiano detto file aperto. Come accennato questa proprietà viene spesso +usata per essere sicuri di non lasciare file temporanei su disco in caso di +crash dei programmi; la tecnica è quella di aprire il file e chiamare +\texttt{unlink} subito dopo. +\subsection{Le funzioni \texttt{remove} e \texttt{rename}} +\label{sec:fileintr_remove} -\subsection{I tipi di file} -\label{sec:filedir_file_types} +Al contrario di quanto avviene con altri unix in Linux non è possibile usare +\texttt{unlink} sulle directory, per cancellare una directory si può usare la +funzione \texttt{rmdir} (vedi \secref{sec:filedir_dir_creat_rem}), oppure la +funzione \texttt{remove}. Questa è la funzione prevista dallo standard ANSI C +per cancellare un file o una directory (e funziona anche per i sistemi che non +supportano i link diretti), che per i file è identica alla \texttt{unlink} e +per le directory è identica alla \texttt{rmdir}: -Come riportato in \tabref{tab:fileintr_file_types} in Linux oltre ai file e -alle directory esistono vari altri oggetti che possono stare su un filesystem; -il tipo di file è ritornato dalla \texttt{stat} nel campo \texttt{st\_mode}. +\begin{prototype}{stdio.h}{int remove(const char *pathname)} + Cancella un nome dal filesystem. Usa \texttt{unlink} per i file e + \texttt{rmdir} per le directory. + + La funzione restituisce zero in caso di successo e -1 per un errore, nel + qual caso il file non viene toccato. Per i codici di errori vedi quanto + riportato nella descrizione di \texttt{unlink} e \texttt{rmdir}. +\end{prototype} -Dato che il valore numerico può variare a seconda delle implementazioni lo -standard POSIX definisce un insieme di macro per verificare il tipo di files, -queste venfono usate anche da Linux che supporta pure le estensioni per link -simbolici e socket definite da BDS, l'elenco è riportato in \ntab: -\begin{table}[htb] - \centering - \footnotesize - \begin{tabular}[c]{|l|l|} - \hline - Macro & Tipo del file \\ - \hline - \hline - \macro{S\_ISREG(m)} & file normale \\ - \macro{S\_ISDIR(m)} & directory \\ - \macro{S\_ISCHR(m)} & device a caraetteri \\ - \macro{S\_ISBLK(m)} & device a blocchi\\ - \macro{S\_ISFIFO(m)} & fifo \\ - \macro{S\_ISLNK(m)} & link simbolico \\ - \macro{S\_ISSOCK(m)} & socket \\ - \hline - \end{tabular} - \caption{Macro per i tipi di file (definite in \texttt{sys/stat.h})} - \label{tab:filedir_file_type_macro} -\end{table} +Per cambiare nome ad un file si usa invece la funzione \texttt{rename}, il +vantaggio nell'uso di questa funzione al posto della chiamata successiva di +\texttt{unlink} e \texttt{link} è che l'operazione è eseguita atomicamente, in +questo modo non c'è la possibilità che un processo che cerchi di accedere al +nuovo nome dopo che il vecchio è stato cambiato lo trovi mancante. -Oltre a queste macro è possibile usare direttamente il valore di -\var{st\_mode} per ricavare il significato dei vari bit in esso memorizzati, -per questo sempre in \texttt{sys/stat.h} sono definiti i flag riportati in -\ntab: -\begin{table}[htb] - \centering - \footnotesize - \begin{tabular}[c]{|l|c|l|} - \hline - Flag & Valore & Significato \\ - \hline - \hline - \macro{S\_IFMT} & 0170000 & bitmask for the file type bitfields \\ - \macro{S\_IFSOCK} & 0140000 & socket \\ - \macro{S\_IFLNK} & 0120000 & symbolic link \\ - \macro{S\_IFREG} & 0100000 & regular file \\ - \macro{S\_IFBLK} & 0060000 & block device \\ - \macro{S\_IFDIR} & 0040000 & directory \\ - \macro{S\_IFCHR} & 0020000 & character device \\ - \macro{S\_IFIFO} & 0010000 & fifo \\ - \macro{S\_ISUID} & 0004000 & set UID bit \\ - \macro{S\_ISGID} & 0002000 & set GID bit (see below) \\ - \macro{S\_ISVTX} & 0001000 & sticky bit (see below) \\ - \macro{S\_IRWXU} & 00700 & mask for file owner permissions \\ - \macro{S\_IRUSR} & 00400 & owner has read permission \\ - \macro{S\_IWUSR} & 00200 & owner has write permission \\ - \macro{S\_IXUSR} & 00100 & owner has execute permission \\ - \macro{S\_IRWXG} & 00070 & mask for group permissions \\ - \macro{S\_IRGRP} & 00040 & group has read permission \\ - \macro{S\_IWGRP} & 00020 & group has write permission \\ - \macro{S\_IXGRP} & 00010 & group has execute permission \\ - \macro{S\_IRWXO} & 00007 & mask for permissions for others (not in - group) \\ - \macro{S\_IROTH} & 00004 & others have read permission \\ - \macro{S\_IWOTH} & 00002 & others have write permisson \\ - \macro{S\_IXOTH} & 00001 & others have execute permission \\ - \hline - \end{tabular} - \caption{Flag per il campo \var{st\_mode} (definite in - \texttt{sys/stat.h})} - \label{tab:filedir_file_mode_flags} -\end{table} - -Il primo valore definisce la maschera dei bit usati nei quali viene -memorizzato il tipo di files, mentre gli altri possono essere usati per -effettuare delle selezioni sul tipo di file voluto, combinando opportunamente -i vari flag; ad esempio se si volesse controllare se un file è una directory o -un file ordinario si potrebbe definire la condizione: -\begin{lstlisting}[labelstep=0,frame=,indent=1cm]{} -#define IS_FILE_DIR(x) (((x) & S_IFMT) & (S_IFDIR | S_IFREG)) -\end{lstlisting} -in cui prima si estraggono da \var{st\_mode} i bit relativi al tipo di file e -poi si effettua il confronto con la combinazione di tipi scelta. +\begin{prototype}{stdio.h} +{int rename(const char *oldpath, const char *newpath)} + Rinomina un file, spostandolo fra directory diverse quando richiesto. -\subsection{La dimensione dei file} -\label{sec:filedir_file_size} + La funzione restituisce zero in caso di successo e -1 per un errore, nel + qual caso il file non viene toccato. La variabile \texttt{errno} viene + settata secondo i seguenti codici di errore: + \begin{errlist} + \item \texttt{EISDIR} \texttt{newpath} è una directory già esistente mentre + \texttt{oldpath} non è una directory. + \item \texttt{EXDEV} \texttt{oldpath} e \texttt{newpath} non sono sullo + stesso filesystem. + \item \texttt{ENOTEMPTY} \texttt{newpath} è una directory già esistente e + non vuota. + \item \texttt{EBUSY} o \texttt{oldpath} o \texttt{newpath} sono in uso da + parte di qualche processo (come directory di lavoro o come root) o del + sistema (come mount point). + \item \texttt{EINVAL} \texttt{newpath} contiene un prefisso di + \texttt{oldpath} o più in generale si è cercato di creare una directory + come sottodirectory di se stessa. + \item \texttt{EMLINK} \texttt{oldpath} ha già il massimo numero di link + consentiti o è una directory e la directory che contiene \texttt{newpath} + ha già il massimo numero di link. + \item \texttt{ENOTDIR} Uno dei componenti dei pathname non è una directory + o\texttt{oldpath} è una directory e \texttt{newpath} esiste e non è una + directory. + \item \texttt{EFAULT} o \texttt{oldpath} o \texttt{newpath} è fuori dello + spazio di indirizzi del processo. + \item \texttt{EACCESS} Non c'è il permesso di scrittura per la directory in + cui si vuole creare il nuovo link o una delle directory del pathname non + consente la ricerca (permesso di esecuzione). + \item \texttt{EPERM} le directory contenenti \texttt{oldpath} o + \texttt{newpath} hanno lo sticky bit attivo e i permessi del processo non + consentono rispettivamente la cancellazione e la creazione del file, o il + filesystem non supporta i link. + \item \texttt{ENAMETOOLONG} uno dei pathname è troppo lungo. + \item \texttt{ENOENT} Uno dei componenti del pathname non esiste o è un link + simbolico spezzato. + \item \texttt{ENOMEM} il kernel non ha a disposizione memoria sufficiente a + completare l'operazione. + \item \texttt{EROFS} I file sono su un filesystem montato in sola lettura. + \item \texttt{ELOOP} Ci sono troppi link simbolici nella risoluzione del + pathname. + \item \texttt{ENOSPC} Il device di destinazione non ha più spazio per la + nuova voce. + \end{errlist} +\end{prototype} -Il membro \var{st\_size} contiene la dimensione del file in bytes (se il file -è un file normale, nel caso di un link simbolico al dimensione è quella del -pathname che contiene). +\subsection{I link simbolici} +\label{sec:fileintr_symlink} -Il campo \var{st\_blocks} definisce la lunghezza del file in blocchi di 512 -bytes. Il campo \var{st\_blksize} infine definisce la dimensione preferita per -i trasferimenti sui file (che è la dimensione usata anche dalle librerie del C -per l'interfaccia degli stream); scrivere sul file a blocchi di dati di -dimensione inferiore sarebbe inefficiente. +Siccome la funzione \texttt{link} crea riferimenti agli inodes, essa può +funzionare soltanto per file che risiedono sullo stesso filesystem, dato che +in questo caso è garantita l'unicità dell'inode, e solo per un filesystem di +tipo unix. Inoltre in Linux non è consentito eseguire un link diretto ad una +directory. -Si tenga conto che lunghezza del file riportata in \var{st\_size} non è detto -che corrisponda all'occupazione dello spazio su disco per via della possibile -esistenza dei cosiddetti \textsl{buchi} (detti normalmente \textit{holes}) che -si formano tutte le volte che si va a scrivere su un file dopo aver eseguito -una \func{seek} (vedi \secref{sec:fileunix_lseek}) oltre la sua conclusione -corrente. +Per ovviare a queste limitazioni i sistemi unix supportano un'altra forma di +link (i cosiddetti \textit{soft link} o \textit{symbolic link}), che sono, +come avviene in altri sistemi operativi, dei file che contengono il +semplicemente il riferimento ad un altro file (o directory). In questo modo è +possibile effettuare link anche attraverso filesystem diversi e a directory, e +pure a file che non esistono ancora. -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}. +Il sistema funziona in quanto i link simbolici sono contrassegnati come tali +al kernel (analogamente a quanto avviene per le directory) per cui la chiamata +ad una \texttt{open} o una \texttt{stat} su un link simbolico comporta la +lettura del contenuto del medesimo e l'applicazione della funzione al file +specificato da quest'ultimo. Invece altre funzioni come quelle per cancellare +o rinominare i file operano direttamente sul link simbolico (per l'elenco vedi +\ntab). Inoltre esistono funzioni apposite, come la \texttt{readlink} e la +\texttt{lstat} per accedere alle informazioni del link invece che a quelle del +file a cui esso fa riferimento. -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. +Le funzioni per operare sui link simbolici sono le seguenti, esse sono tutte +dichiarate nell'header file \texttt{unistd.h}. -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: -\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 - un valore massimo specificato da \var{lenght}. - - \funcdecl{int ftruncate(int fd, off\_t length))} Identica a \func{truncate} - eccetto che si usa con un file aperto, specificato tramite il suo file - descriptor \var{fd}, +\begin{prototype}{unistd.h} +{int symlink(const char * oldname, const char * newname)} + Crea un nuovo link simbolico al file indicato da \texttt{oldname} dandogli + nome \texttt{newname}. - Le funzioni restituiscono zero in caso di successo e -1 per un errore, in - caso di errore \texttt{errno} viene settato ai valori: + 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 + \secref{sec:filedir_access_control}) ai quali si aggiungono i seguenti: \begin{errlist} - \item \texttt{EACCESS} non c'è il permesso di accedere al file. - \item \texttt{ENOTDIR} una componente del pathname non è una directory. - \item \texttt{EMLOOP} ci sono troppi link simbolici nel pathname. - \item \texttt{EFAULT} i puntatori usati sono fuori dallo spazio di indirizzi - del processo. - \item \texttt{ENOMEM} il kernel non ha a disposizione memoria sufficiente a - completare l'operazione. - \item \texttt{ENOENT} il file non esiste. - \item \texttt{ENAMETOOLONG} il filename è troppo lungo. + \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{errlist} -\end{functions} - -Se il file è più lungo della lunghezza specificata i dati in eccesso saranno -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). - +\end{prototype} -\subsection{I tempi dei file} -\label{sec:filedir_file_times} +Dato che la funzione \texttt{open} segue i link simbolici, è necessaria usare +un'altra funzione quando si vuole leggere il contenuto di un link simbolico, +questa funzione è la: -Il sistema mantiene per ciascun file tre tempi. Questi sono registrati -nell'inode insieme agli altri attibuti del file e possono essere letti tramite -la funzione \func{stat}, che li restituisce attraverso tre campi della -struttura in \figref{fig:filedir_stat_struct}. Il significato di detti tempi e -dei relativi campi è riportato nello schema in \ntab: +\begin{prototype}{unistd.h} +{int readlink(const char * path, char * buff, size\_t size)} + Legge il contenuto del link simbolico indicato da \texttt{path} nel buffer + \texttt{buff} di dimensione \texttt{size}. Non chiude la stringa con un + carattere nullo e la tronca a \texttt{size} nel caso il buffer sia troppo + piccolo per contenerla. + + La funzione restituisce il numero di caratteri letti dentro \texttt{buff} o + -1 per un errore, in caso di errore. La variabile \texttt{errno} viene + settata secondo i codici di errore: + \begin{errlist} + \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{errlist} +\end{prototype} +In \ntab\ si è riportato un elenco dei comportamenti delle varie funzioni che +operano sui file rispetto ai link simbolici; specificando quali seguono il +link simbolico e quali possono operare direttamente sul suo contenuto. \begin{table}[htb] \centering - \begin{tabular}[c]{|c|l|l|c|} - \hline - Membro & Significato & Funzione&opzione \\ - \hline - \hline - \var{st\_atime}& ultimo accesso ai dati del file &\func{read}& \cmd{-u}\\ - \var{st\_mtime}& ultima modifica ai dati del file &\func{write}& default\\ - \var{st\_ctime}& ultima modifica ai dati dell'inode&\func{chmod}, - \func{utime} & \cmd{-c} \\ + \footnotesize + \begin{tabular}[c]{|l|c|c|} \hline + Funzione & Segue il link & Non segue il link \\ + \hline + \hline + \func{access} & $\bullet$ & \\ + \func{chdir} & $\bullet$ & \\ + \func{chmod} & $\bullet$ & \\ + \func{chown} & & $\bullet$ \\ + \func{creat} & $\bullet$ & \\ + \func{exec} & $\bullet$ & \\ + \func{lchown} & $\bullet$ & $\bullet$ \\ + \func{link} & & \\ + \func{lstat} & & $\bullet$ \\ + \func{mkdir} & $\bullet$ & \\ + \func{mkfifo} & $\bullet$ & \\ + \func{mknod} & $\bullet$ & \\ + \func{open} & $\bullet$ & \\ + \func{opendir} & $\bullet$ & \\ + \func{pathconf} & $\bullet$ & \\ + \func{readlink} & & $\bullet$ \\ + \func{remove} & & $\bullet$ \\ + \func{rename} & & $\bullet$ \\ + \func{stat} & $\bullet$ & \\ + \func{truncate} & $\bullet$ & \\ + \func{unlink} & & $\bullet$ \\ + \hline \end{tabular} - \caption{I tre tempi associati a ciascun file} - \label{tab:filedir_file_times} + \caption{Uso dei link simbolici da parte di alcune funzioni.} + \label{tab:filedir_symb_effect} \end{table} +si noti che non si è specificato il comportamento delle funzioni che operano +con i file descriptor, in quanto la gestione del link simbolico viene in +genere effttuata dalla funzione che restituisce il file descriptor +(normalmente la \func{open}). + +\begin{figure}[htb] + \centering + \includegraphics[width=5cm]{img/link_loop.eps} + \caption{Esempio di loop nel filesystem creato con un link simbolico.} + \label{fig:filedir_link_loop} +\end{figure} + +Un caso comune che si può avere con i link simbolici è la creazione dei +cosiddetti \textit{loop}. La situazione è illustrata in \curfig, che riporta +la struttura della directory \file{/boot}. Come si vede si è creato al suo +interno un link simbolico che punta di nuovo a \file{/boot}\footnote{Questo + tipo di loop è stato effettuato per poter permettere a \cmd{grub} (un + bootloader estremamente avanzato in grado di accedere direttamente + attraverso vari filesystem al file da lanciare come sistema operativo) di + vedere i file in questa directory, che è montata su una partizione separata + (e che grub vedrebbe come radice), con lo stesso path con cui verrebbero + visti dal sistema operativo.}. + +Questo può causare problemi per tutti quei programmi che effettuassero uno +scan di una directory senza tener conto dei link simbolici, in quel caso +infatti il loop nella directory + +Un secondo punto da tenere presente è che un link simbolico può essere fatto +anche ad un file che non esiste; ad esempio possiamo creare un file temporaneo +nella nostra directory con un link del tipo: +\begin{verbatim} +$ln -s /tmp/tmp_file temporaneo +\end{verbatim}%$ +ma anche se \file{/tmp/tmp\_file} non esiste. Aprendo in scrittura +\file{temporaneo} questo verrà scritto; ma se cercassimo di accederlo in sola +lettura (ad esempio con \cmd{cat}) otterremmo: +\begin{verbatim} +$ cat prova +cat: prova: No such file or directory +\end{verbatim}%$ +con un errore che sembra sbagliato, dato \cmd{ls} ci mostrerebbe l'esistenza +di \file{temporaneo}. -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 -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 -le informazioni contenute nell'inode senza toccare il file, diventa necessario -l'utilizzo di un altro tempo. -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). +\subsection{Le funzioni \texttt{mkdir} e \texttt{rmdir}} +\label{sec:filedir_dir_creat_rem} -Il tempo di ultima modifica invece viene usato da \cmd{make} per decidere -quali file necessitano di essere ricompilati o (talvolta insieme anche al -tempo di cambiamento di stato) per decidere quali file devono essere -archiviati per il backup. Il comando \cmd{ls} (quando usato con le opzioni -\cmd{-l} o \cmd{-t}) mostra i tempi dei file secondo lo schema riportato -nell'ultima colonna di \curtab. +Per creare una nuova directory si può usare la seguente funzione, omonima +dell'analogo comando di shell \texttt{mkdir}; per accedere ai tipi usati +programma deve includere il file \texttt{sys/types.h}. -L'effetto delle varie funzioni di manipolazione dei file sui tempi è -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. +\begin{prototype}{sys/stat.h} +{int mkdir (const char * dirname, mode\_t mode)} + Questa funzione crea una nuova directory vuota con il nome indicato da + \texttt{dirname}, assegnandole i permessi indicati da \texttt{mode}. Il nome + può essere indicato con il pathname assoluto o relativo. + + La funzione restituisce zero in caso di successo e -1 per un errore, in caso + di errore \texttt{errno} viene settata secondo i codici di errore standard + di accesso ai files (trattati in dettaglio in + \secref{sec:filedir_access_control}) ai quali si aggiungono i seguenti: + \begin{errlist} + \item \texttt{EACCESS} + Non c'è il permesso di scrittura per la directory in cui si vuole inserire + la nuova directory. + \item \texttt{EEXIST} Un file (o una directory) con quel nome esiste di già. + \item \texttt{EMLINK} La directory in cui si vuole creare la nuova directory + contiene troppi file. Sotto Linux questo normalmente non avviene perché il + filesystem standard consente la creazione di un numero di file maggiore di + quelli che possono essere contenuti nell'hard-disk, ma potendo avere a che + fare anche con filesystem di altri sistemi questo errore può presentarsi. + \item \texttt{ENOSPC} Non c'è abbastanza spazio sul file system per creare + la nuova directory. + \item \texttt{EROFS} La directory su cui si vuole inserire la nuova + directory è su un filesystem montato readonly. + \end{errlist} +\end{prototype} + -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. +\subsection{Accesso alle directory} +\label{sec:filedir_dir_read} -\begin{table}[htb] - \centering - \footnotesize - \begin{tabular}[c]{|l|c|c|c|c|c|c|l|} - \hline - \multicolumn{1}{|c|}{Funzione} - &\multicolumn{3}{p{2cm}}{File o directory di riferimento} - &\multicolumn{3}{p{2cm}}{Directory genitrice del riferimento} - &\multicolumn{1}{|c|}{Note} \\ - \cline{2-7} - & \textsl{(a)} & \textsl{(m)}& \textsl{(c)} - & \textsl{(a)} & \textsl{(m)}& \textsl{(c)}& \\ - \hline - \hline - \func{chmod}, \func{fchmod} - & & &$\bullet$& & & & \\ - \func{chown}, \func{fchown} - & & &$\bullet$& & & & \\ - \func{creat} - &$\bullet$&$\bullet$&$\bullet$& &$\bullet$&$\bullet$& con - \macro{O\_CREATE} \\ \func{creat} - & &$\bullet$&$\bullet$& &$\bullet$&$\bullet$& - con \macro{O\_TRUNC} \\ \func{exec} - &$\bullet$& & & & & & \\ - \func{lchown} - & & &$\bullet$& & & & \\ - \func{link} - & & &$\bullet$& &$\bullet$&$\bullet$& \\ - \func{mkdir} - &$\bullet$&$\bullet$&$\bullet$& &$\bullet$&$\bullet$& \\ - \func{mkfifo} - &$\bullet$&$\bullet$&$\bullet$& &$\bullet$&$\bullet$& \\ - \func{open} - &$\bullet$&$\bullet$&$\bullet$& &$\bullet$&$\bullet$& con - \macro{O\_CREATE} \\ \func{open} - & &$\bullet$&$\bullet$& & & & con - \macro{O\_TRUNC} \\ \func{pipe} - &$\bullet$&$\bullet$&$\bullet$& & & & \\ - \func{read} - &$\bullet$& & & & & & \\ - \func{remove} - & & &$\bullet$& &$\bullet$&$\bullet$& using - \func{unlink}\\ \func{remove} - & & & & &$\bullet$&$\bullet$& using - \func{rmdir}\\ \func{rename} - & & &$\bullet$& &$\bullet$&$\bullet$& per entrambi - gli argomenti\\ \func{rmdir} - & & & & &$\bullet$&$\bullet$& \\ - \func{truncate}, \func{ftruncate} - & &$\bullet$&$\bullet$& & & & \\ - \func{unlink} - & & &$\bullet$& &$\bullet$&$\bullet$& \\ - \func{utime} - &$\bullet$&$\bullet$&$\bullet$& & & & \\ - \func{write} - & &$\bullet$&$\bullet$& & & & \\ - \hline - \end{tabular} - \caption{Effetti delle varie funzioni su tempi di ultimo accesso - \textsl{(a)}, ultima modifica \textsl{(m)} e ultimo cambiamento - \textsl{(c)}} - \label{tab:filedir_times_effects} -\end{table} +Benché le directory siano oggetti del filesystem come tutti gli altri non ha +ovviamente senso aprirle come fossero dei file di dati. Può però essere utile +poterne leggere il contenuto ad esempio per fare la lista dei file che esse +contengono o ricerche sui medesimi. -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 -esiste. +Per accedere al contenuto delle directory si usano i cosiddetti +\textit{directory streams} (chiamati così per l'analogia con i file stream); +la funzione \texttt{opendir} apre uno di questi stream e la funzione +\texttt{readdir} legge il contenuto della directory, i cui elementi sono le +\textit{directory entries} (da distinguersi da quelle della cache di cui +parlavamo in \secref{sec:fileintr_vfs}) in una opportuna struttura +\texttt{struct dirent}. -\subsection{La funzione \texttt{utime}} -\label{sec:filedir_utime} +\subsection{La directory di lavoro} +\label{sec:filedir_work_dir} -I tempi di ultimo accesso e modifica possono essere cambiati usando la -funzione \func{utime}, il cui prototipo è: +A ciascun processo è associato ad una directory nel filesystem che è chiamata +directory corrente o directory di lavoro (\textit{current working directory}) +che è quella a cui si fa riferimento quando un filename è espresso in forma +relativa (relativa appunto a questa directory). -\begin{prototype}{utime.h} -{int utime(const char * filename, struct utimbuf *times)} +Quando un utente effettua il login questa directory viene settata alla +cosiddetta \textit{home directory} del suo account, il comando \texttt{cd} +della shell consente di cambiarla a piacere, spostandosi da una directory ad +un'altra. Siccome la directory corrente resta la stessa quando viene creato +un processo figlio, la directory corrente della shell diventa anche la +directory corrente di qualunque comando da essa lanciato. -Cambia i tempi di ultimo accesso e modifica dell'inode specificato da -\var{filename} secondo i campi \var{actime} e \var{modtime} di \var{times}. Se -questa è \macro{NULL} allora viene usato il tempo corrente. +Le funzioni qui descritte servono esaminare e cambiare la directory di lavoro +corrente. -La funzione restituisce zero in caso di successo e -1 in caso di errore, nel -qual caso \var{errno} è settata opportunamente. -\begin{errlist} -\item \texttt{EACCESS} non si ha il permesso di scrittura sul file. -\item \texttt{ENOENT} \var{filename} non esiste. -\end{errlist} +\begin{prototype}{unistd.h}{char * getcwd (char * buffer, size\_t size)} + Restituisce il filename completo della directory di lavoro corrente nella + stringa puntata da \texttt{buffer}, che deve essere precedentemente + allocata, per una dimensione massima di \texttt{size}. Si può anche + specificare un puntatore nullo come \textit{buffer}, nel qual caso la + stringa sarà allocata automaticamente per una dimensione pari a + \texttt{size} qualora questa sia diversa da zero, o della lunghezza esatta + del pathname altrimenti. In questo caso si deve ricordare di disallocare la + stringa una volta cessato il suo utilizzo. + + La funzione restituisce il puntatore \texttt{buffer} se riesce, + \texttt{NULL} se fallisce, in quest'ultimo caso la variabile + \texttt{errno} è settata con i seguenti codici di errore: + \begin{errlist} + \item \texttt{EINVAL} L'argomento \texttt{size} è zero e \texttt{buffer} non + è nullo. + \item \texttt{ERANGE} L'argomento \texttt{size} è più piccolo della + lunghezza del pathname. + \item \texttt{EACCESS} Manca il permesso di lettura o di ricerca su uno dei + componenti del pathname (cioè su una delle directory superiori alla + corrente). + \end{errlist} \end{prototype} - -La struttura \var{utimebuf} usata da \func{utime} è definita come: -\begin{lstlisting}[labelstep=0,frame=,indent=1cm]{} -struct utimbuf { - time_t actime; /* access time */ - time_t modtime; /* modification time */ -}; -\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 -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). +Di questa funzione esiste una versione \texttt{char * getwd(char * buffer)} +fatta per compatibilità all'indietro con BSD, che non consente di specificare +la dimensione del buffer; esso deve essere allocato in precedenza ed avere una +dimensione superiore a \texttt{PATH\_MAX} (di solito 256 bytes, vedi +\secref{sec:xxx_limits}; il problema è che in Linux non esiste una dimensione +superiore per un pathname, per cui non è detto che il buffer sia sufficiente a +contenere il nome del file, e questa è la ragione principale per cui questa +funzione è deprecata. -Si tenga presente che non è comunque possibile specificare il tempo di -cambiamento di stato del file, che viene comunque cambiato dal kernel tutte le -volte che si modifica l'inode (quindi anche alla chiamata di \func{utime}). -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. +Una seconda funzione simile è \texttt{char * get\_current\_dir\_name(void)} +che è sostanzialmente equivalente ad una \texttt{getcwd(NULL, 0)}, con la sola +differenza che essa ritorna il valore della variabile di ambiente +\texttt{PWD}, che essendo costruita dalla shell può contenere anche dei +riferimenti simbolici. + +Come già detto in unix anche le directory sono file, è possibile pertanto +riferirsi ad esse tramite il file descriptor dell'interfaccia a basso livello, +e non solo tramite il filename; per questo motivo ci sono due diverse funzioni +per cambiare directory di lavoro. + +\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}. +\end{prototype} + +\begin{prototype}{unistd.h}{int fchdir (int filedes)} + Analoga alla precedente, ma usa un file descriptor invece del pathname. + + Entrambe le funzioni restituiscono zero in caso di successo e -1 per un + errore, in caso di errore \texttt{errno} viene settata secondo i codici di + errore standard di accesso ai files (trattati in dettaglio in + \secref{sec:filedir_access_control}) ai quali si aggiunge il codice + \texttt{ENOTDIR} nel caso il \texttt{filename} indichi un file che non sia + una directory. +\end{prototype} diff --git a/fileintro.tex b/fileintro.tex index 2bcfe81..966625f 100644 --- a/fileintro.tex +++ b/fileintro.tex @@ -1,4 +1,3 @@ - \chapter{I files: l'architettura} \label{cha:files_intro} diff --git a/gapil.tex b/gapil.tex index 18f10c4..91f93a0 100644 --- a/gapil.tex +++ b/gapil.tex @@ -1,4 +1,4 @@ -%% +%% %% GaPiL : Guida alla Programmazione in Linux %% %% S. Piccardi Feb. 2001 diff --git a/prochand.tex b/prochand.tex index e43caa9..c8f6ad4 100644 --- a/prochand.tex +++ b/prochand.tex @@ -132,6 +132,8 @@ viene eseguito dal padre o dal figlio. \label{sec:prochand_exec} + + \section{Il controllo di accesso} \label{sec:prochand_perms}