lundi 6 novembre 2017

Chapitre 9: taille et informations d'un fichier



Avant de lire un fichier et de stocker son contenu dans le buffer, il serait intéressant de connaitre sa taille avant de le lire et d’agir en conséquence (par exemple : afficher un message d’erreur).
Dans la documentation des call system, nous trouvons l’appel newfstat code 6c (les autres fonctions comme stat et fstat ne sont pas implémentées) qui retourne toute une série d’information sur un fichier passé en paramètre. En fait c’est un pointeur qui est retourné dans le registre r0 et ce pointeur donne l’adresse d’une structure qui contient soit les informations soit des adresses vers d’autres données.
Il est possible d’accéder à chaque donnée de la structure en ajoutant son déplacement (offset) au pointeur de la structure  comme ldr r1,[r0,#8]. Mais il est plus parlant d’y accéder par ldr r1,[r0,#Taille] et il nous faut donc décrire la structure en assembleur. L’assembleur as n’est pas très bien conçu (avis personnel !) pour décrire les structures mais il offre quand même un mécanisme pour le faire. Il permet d’associer des noms de zones à un déplacement en indiquant la longueur en octets de chacune d’elles. L’instruction .struct effectue cette association sans réserver de zones en mémoire. Pour l’utilisation il suffira d’ajouter au pointeur de début de structure, le nom adéquat.
Voyons sur l’exemple des infos d’un fichier. La documentation des call system indique que la structure s'appelle stat et donne sa description en langage c

struct stat {
        unsigned int   st_dev;
        unsigned int   st_ino;
        unsigned int   st_mode;
        unsigned int   st_nlink;
        unsigned int   st_uid;
        unsigned int   st_gid;
        unsigned int   st_rdev;
        long           st_size;
        unsigned long  st_atime;
        unsigned long  st_mtime;
        unsigned long  st_ctime;
        unsigned int   st_blksize;
        unsigned int   st_blocks;
        unsigned int   st_flags;
        unsigned int   st_gen;
};

Et bien, nous allons reprendre cette description et la traduire pour l’assembleur en préfixant les zones par Stat et en considérant que chacune occupe 4 octets :


/* structure de type   stat  : infos fichier  */
    .struct  0
Stat_dev_t:                  /* ID of device containing file */
    .struct Stat_dev_t + 4
Stat_ino_t:                   /* inode */
    .struct Stat_ino_t + 4
Stat_mode_t:             /* File type and mode */
    .struct Stat_mode_t + 4          
Stat_nlink_t:                /* Number of hard links */
    .struct Stat_nlink_t + 4            
Stat_uid_t:                    /* User ID of owner */
    .struct Stat_uid_t + 4
Stat_gid_t:                      /* Group ID of owner */
    .struct Stat_gid_t + 4                
Stat_rdev_t:                  /* Device ID (if special file) */
    .struct Stat_rdev_t + 4
Stat_size_t:                   /* Total size, in bytes */
    .struct Stat_size_t + 4              
Stat_blksize_t:             /* Block size for filesystem I/O */
    .struct Stat_blksize_t + 4        
Stat_blkcnt_t:              /* Number of 512B blocks allocated */
    .struct Stat_blkcnt_t + 4         
Stat_Fin:            

Puis nous écrivons le programme qui va ouvrir le fichier, puis appeler la fonction NEWSTAT et nous allons afficher la mémoire correspondant au pointeur de la structure. Puis nous allons afficher la zone Stat_size_t qui devrait contenir la taille.
Voici le résultat sur le fichier fic1.
Mais il y a un petit problème : la taille affichée ne correspond pas à celle donnée par ls –l. Il y a un décalage entre les infos de la structure et le résultat. Donc je pars à la recherche sur Internet des différentes descriptions de Stats.h en C et je trouve que certaines données sont des short (2octets) et non pas des integer (4 octets) et d’autres comme la taille sont des longs (8 octets) et je complète aussi avec les zones concernant les dates du fichier . Donc je rectifie la structure comme suit :
/* structure de type   stat  : infos fichier  */
    .struct  0
Stat_dev_t:                  /* ID of device containing file */
    .struct Stat_dev_t + 4
Stat_ino_t:                   /* inode */
    .struct Stat_ino_t + 2
Stat_mode_t:             /* File type and mode */
    .struct Stat_mode_t + 2          
Stat_nlink_t:                /* Number of hard links */
    .struct Stat_nlink_t + 2            
Stat_uid_t:                    /* User ID of owner */
    .struct Stat_uid_t + 2
Stat_gid_t:                      /* Group ID of owner */
    .struct Stat_gid_t + 2                
Stat_rdev_t:                  /* Device ID (if special file) */
    .struct Stat_rdev_t + 2
Stat_size_deb:           /* la taille est sur 8 octets si gros fichiers */
                 .struct Stat_size_deb + 4
Stat_size_t:                   /* Total size, in bytes */
    .struct Stat_size_t + 4              
Stat_blksize_t:             /* Block size for filesystem I/O */
    .struct Stat_blksize_t + 4        
Stat_blkcnt_t:              /* Number of 512B blocks allocated */
    .struct Stat_blkcnt_t + 4         
Stat_atime:                   /*   date et heure fichier */
    .struct Stat_atime + 8    
Stat_mtime:                 /*   date et heure modif fichier */
    .struct Stat_atime + 8
Stat_ctime:                   /*   date et heure creation fichier */
    .struct Stat_atime + 8              
Stat_Fin:            
Cette fois ci le programme est correct et je trouve bien la longueur du fichier en hexa dans le registre r1. En conclusion, il nous faudra par la suite, vérifier par des tests la validité des structures.
Remarque : j’ai décrit la structure utilisée en reprenant les noms anglais, mais il est possible de franciser ces noms.
Exercice :  Afficher dans la console d’autres informations du fichier.
                  Et sans doute plus difficile, la date de création du fichier étant codée sur 8 octets, écrire une routine qui l’affiche sous la forme JJ/MM/AAAA  HHh MMm SSs.

Aucun commentaire:

Enregistrer un commentaire