/* leggifloppy.c
* Stefano Salvi - 25/9/02
* Programma che:
* - legge il boot sector di un disco (floppy o hard disk) con file system FAT
* e ne stampa le caratteristiche.
* - legge la boot directory.
* - ogni volta che trova un'entry di tipo 'directory', dopo aver stampato l'entry
* stmapa la sotto directory descritta
* la stampa delle sottodirectory deve essere ricorsiva (se una sottodirectory contiene
* altre sottodirectory, stampa anche quelle).
* Ogni volta che entra in una sottodirectory, indenta la lista di 2 spazi.
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/types.h>
#include <linux/msdos_fs.h>
// Descrittore del disco
struct disco {
int fd; // File Descriptor per il dispositivo
int rootDir; // posizione in byte della root Directory
int rootDirSize; // Dimensione in 'entries' della root directory
int clusterBytes; // Dimensione di un cluster in byte
int firstDataByte; // Primo byte dell'area dati
int FATPos; // Posizione della FAT (in byte)
};
// Struttura con i campi di bit che descrive la 'data' in formato MS-DOS
struct date {
unsigned int giorno:5;
unsigned int mese:4;
unsigned int anno:7;
};
// Struttura con i campi di bit che descrive l' 'ora' in formato MS-DOS
struct time {
unsigned int sec:5;
unsigned int min:6;
unsigned int ora:5; //perchè si tengono solo i pari
};
int openDevice (char *device, struct disco *d); // apre il device, legge boot rec
void readRootDir (struct disco *d); // Legge l'albero delle directory
int printDirEntry (struct disco *d, int pos, int indent); // Stampa un'entry di dir.
void readSubDir (struct disco *d, int cluster, int indent); // Legge una subdirectroy
int clusterByte (struct disco *d, int cluster); // Trasforma in byte un num. cluster
int nextCluster (struct disco *d, int cluster); // Legge nella FAT il prossimo cluster
int main(int argc, char **argv)
{
struct disco d; // Descrittore del dispositivo
char *device = "/dev/fd0"; // Nome del file (dispositivo) da aprire
if (argc > 1) // Se c'e' almeno un parametro
{
device = argv [1]; // Prende il primo parametro e lo usa come 'dispositivo'
}
if(openDevice(device, &d)) // Apre il dispositivo
{
return 1;
}
readRootDir (&d);
}
/* printDirEntry
* Stampa un'entry di directory.
* Riceve il descrittore del dispositivo (d) e la posizione in byte dell'entry.
* Ritorna la posizione della prossima direntry, oppure 0 se incontra l'ultima
* direntry (nome che comincia con byte 0x00).
* Operazioni:
* - Si posiziona sul record
* - Legge una 'dir entry'
* - Se la 'dir entry' ha nome che comincia per 0x00, ritorna 0
* - Se l'entry non e' 'hidden' o cancellata, la stampa
* - Ritorna la posizione della prossima dir entry.
* Non stampa le entry cancellate (che cominciano per 0xe5) o con gli attributi
* 'hidden,system,readonly,label' (sono nomi estesi, quindi non stampabili)
* Se trova una sottodirectory, che non sia '.' o '..', la stampa dopo il nome della
* sottodirectory, indentata di due spazi.
*/
int printDirEntry (struct disco *d, int pos, int indent)
{
struct msdos_dir_entry dirEntry;// Buffer per il record di directory
struct date *p; // Record per visualizzare le date
struct time *t; // Record per visualizzare le ore
int i;
// Posizionamento sulla dir entry
if (lseek(d->fd, pos, SEEK_SET) < 0)
{
printf ("Errore nel posizionamento al byte %d\n",pos);
return 0;
}
// Lettura dir entry
if (read(d->fd,&dirEntry,sizeof(dirEntry)) != sizeof(dirEntry))
{
printf ("Errore nella lettura della DirEntry al byte %d\n",pos);
return 0;
}
if (dirEntry.name[0] == 0) // Entry terminatrice della Directory
{
return 0; // Termina il 'chiamante'
}
/* Se il file non e' 'hidden,system,readonly,label' (nomi estesi) o comincia
*con 0xe5 (file cancellati)
*/
if (dirEntry.attr != (ATTR_HIDDEN | ATTR_RO | ATTR_SYS | ATTR_VOLUME) &&
(dirEntry.name[0] & 0xff) != 0xe5)
{
// Indenta l'entry
for (i = 0; i < indent; i++)
{
printf (" ");
}
/* Analizza bit per bit gli 'attr' e per ognuno stampa una lettera */
if(dirEntry.attr & ATTR_RO)
{
printf("R");
}
else
{
printf("-");
}
if(dirEntry.attr&ATTR_HIDDEN)
{
printf("H");
}
else
{
printf("-");
}
if(dirEntry.attr&ATTR_SYS)
{
printf("S");
}
else
{
printf("-");
}
if(dirEntry.attr&ATTR_VOLUME)
{
printf("L");
}
else
{
printf("-");
}
if(dirEntry.attr&ATTR_DIR)
{
printf("D");
}
else
{
printf("-");
}
if(dirEntry.attr&ATTR_ARCH)
{
printf("A ");
}
else
{
printf("- ");
}
/*informazioni sul file*/
for(i=0;i<8;i++) // Otto cratteri del nome
{
printf("%c",dirEntry.name[i]);
}
printf (".");
for(i=0;i<3;i++) // Tre caratteri dell'estensione
{
printf("%c",dirEntry.ext[i]);
}
p=(struct date *)&(dirEntry.date); // Sovrappone 'date' a data
printf(" %2d/%02d/%04d ",p->giorno,p->mese,p->anno+1980);
t=(struct time *)&(dirEntry.time); // Sovrappone 'time' a ora
printf(" %2d:%02d:%02d",t->ora,t->min,t->sec);
printf(" %8d\n",(__u32)dirEntry.size);
// Se e' una sottodirectory, e non e' ne' '.' ne '..'
if((dirEntry.attr&ATTR_DIR) && // E' una 'dir'
!(dirEntry.name[0] == '.' && dirEntry.name[1] == ' ') && // Non e' '. '
// Non e' nemmeno '.. '
!(dirEntry.name[0] == '.' && dirEntry.name[1] == '.' && dirEntry.name[2] == ' '))
{
// Stampa la sottodirectory, aumentando l'indent
readSubDir (d, dirEntry.start, indent + 2);
}
}
return pos + sizeof (dirEntry);
}
/* readSubDir
* Legge un'intera sottodirectory, posizionata a partire dal cluster 'cluster', sul
* dispositivo 'd' e la stampa indentata di 'indent' spazi.
* Se la directory e' registrata su piu' cluster, letto il primo cluster trova nella
* FAT il prossimo per continuare.
*/
void readSubDir (struct disco *d, int cluster, int indent)
{
int pos; // Posizione in byte dell'entry corrente
int end; // Fine del cluster, in byte
do {
pos = clusterByte (d, cluster); // Calcola inizio in byte
end = clusterByte (d, cluster + 1); // Calcola fine in byte
do {
if ((pos = printDirEntry (d, pos, indent)) == 0) // Stampa una dir entry
{
return; // Se e' l'untima, termina
}
} while (pos < end); // Finche' non ha finito il cluster
cluster = nextCluster (d, cluster); // Cerca il nuovo cluster
} while (cluster); // Finche' non e' arrivato all'ultimo
}
/* nextCluster
* Ritorna il prossimo cluster letto dalla FAT nell'entry relativa al cluster 'cluster'
* pasato per paramentro, nel dispositivo descritto da 'd'
* Se il cluster e' l'ultimo del file (il prossimo cluster e' 0xfff) ritorna 0.
*
* FAT a 12 bit:
* 2 cluster ogni 3 byte.
* Indico con 'P' il cluster pari e con D il cluster dispari:
* I tre byte sono codificati cosi':
* PP DP DD
*/
int nextCluster (struct disco *d, int cluster)
{
unsigned char dCluster [3]; // Buffer per la coppia di elementi
int pos = d -> FATPos + (cluster / 2) * 3; // Posizione in byte della coppia di elementi
int nuovoCluster; // Cluster letto nell'elemento
// Si posiziona sulla coppia di elementi
if (lseek(d->fd, pos, SEEK_SET) < 0)
{
printf ("Errore nel posizionamento al byte %d\n",pos);
return 0;
}
// Legge la coppia
if (read(d->fd,dCluster,sizeof(dCluster)) != sizeof(dCluster))
{
printf ("Errore nella lettura dell' elemento di FAT al byte %d\n",pos);
return 0;
}
// Ricompone il numero di cluster in base alla formula esposta all'inizio
if (cluster % 2) // Cluster pari
{
nuovoCluster = dCluster [2];
nuovoCluster = ((dCluster [1] >> 4) & 0xf) | ((nuovoCluster << 4) & 0xff0);
} else { // Cluster dispari
nuovoCluster = dCluster [1];
nuovoCluster = ((nuovoCluster << 8) & 0xf00) | (dCluster [0] & 0xff);
}
// Se il nuovo cluster e' 0xfff, ritorna 0, se no ritorna il nuovo cluster
return (nuovoCluster == 0xfff) ? 0 : nuovoCluster;
}
/* clusterByte
* Converte in byte dall'inizio del disco un numero di cluster.
* Utilizza le informazioni del descrittore per il calcolo
* Le prime due entry nella FAT sono riservate, quindi il primo cluster e' il 2
*/
int clusterByte (struct disco *d, int cluster)
{
if (cluster < 2) // Se il cluster e' illegale
{
return 0; // ritorno 0 (errore)
}
cluster -= 2; // tolgo i cluster riservati
cluster *= d -> clusterBytes; // moltiplico per la dimensione del cluster
return cluster + d -> firstDataByte; // aggiungo l'inizio dell'area dati
}
/* readRootDir
* Stampa la root directory del disco.
* Riceve come parametro il descrittore del disco.
* Stampa 'd -> rootDirSize' elementi.
* Se 'printDirEntry' indica che la directory e' teminata, finisce prima.
*/
void readRootDir (struct disco *d)
{
int pos = d -> rootDir; // Posizione della directory
int i; // Contatore entries
for (i = 0; i < d -> rootDirSize; i++) // quante ce ne sono al massimo
{
if ((pos = printDirEntry (d, pos, 0)) == 0) // Stampa una dir entry (indent 0)
{
break; // Se e' l'untima, termina
}
}
}
/* openDevice
* Apre il file 'device', ne legge il boot record, compilando il descrittore
* puntato da 'd'.
* Ritorna 0 se tutto questo funziona.
* Ritorna 1 se c'e' un errore.
*/
int openDevice (char *device, struct disco *d)
{
struct fat_boot_sector boot; // Record nel quale leggere il primo settore
if((d->fd=open(device,O_RDONLY))==-1) // Apre il dispositivo
{
printf("Errore di apertura! Forse mancano i diritti sul dispositivo\n");
return 1;
}
read(d->fd,&boot,sizeof(boot)); // Legge il boot sector
// Compila il descrittore del dispositivo
d->rootDir= (boot.reserved + boot.fats * boot.fat_length) *
*(__u16 *)boot.sector_size; // posizione in byte della root Directory
d->rootDirSize=*(__u16 *)boot.dir_entries; // Dimensione in 'entries' della root directory
// Dimensione di un cluster in byte
d->clusterBytes = boot.cluster_size * *(__u16 *)boot.sector_size;
// Primo byte dell'area dati
d->firstDataByte = d->rootDir + (d->rootDirSize * sizeof (struct msdos_dir_entry));
// posizione in byte della FAT
d -> FATPos = boot.reserved * *(__u16 *)boot.sector_size;
// Stampa le caratteristiche interessanti
printf("\nNum\t\t Description\t\t\t Variabile\n");
printf("%s\t Volume Name\t\t\t (system_id[8])\n",boot.system_id);
printf("%d\t\t bytes per logical sector\t (sector_size[2])\n",
*(__u16 *)boot.sector_size); //dimensione settore
printf("%d\t\t sectors/cluster\t\t (cluster_size)\n",boot.cluster_size); //settori per cluster
printf("%d\t\t reserved sectors\t\t (reserved)\n",boot.reserved);
printf("%d\t\t number of FATs\t\t\t (fats)\n",boot.fats);
printf("%d\t\t root directory entries\t\t (dir_entries)\n",*(__u16 *)boot.dir_entries);
printf("%d\t\t number of sectors\t\t (sectors[2])\n",*(__u16*)boot.sectors);
printf("%d\t\t media code\t\t\t (media)\n",boot.media);
printf("%d\t\t sectors/FAT\t\t\t (fat_length)\n",boot.fat_length);
printf("%d\t\t Start in bytes of ROOT dir\n",d->rootDir);
printf("%d\t\t sectors per track\t\t (secs_track)\n",(__u16)boot.secs_track);
printf("%d\t\t number of heads\t\t (heads)\n",boot.heads);
printf("%d\t\t hidden sectors\t\t\t (hidden)\n",boot.hidden);
printf("%d\t\t number of sectors\t\t (total_sect)\n\n",boot.total_sect);
return 0;
}
|