Imprimer des permissions de fichiers comme ‘ls -l’ en utilisant stat (2) en C

J’essaie d’écrire un petit programme en C qui émule la commande unix ls -l . Pour ce faire, j’utilise l’appel système stat(2) et j’ai rencontré un petit hoquet qui écrit les permissions. J’ai une variable mode_t qui contient les permissions de fichier de st_mode , et il ne serait pas difficile d’parsingr cette valeur dans la représentation de chaîne s, mais je me demandais simplement s’il existait un meilleur moyen de le faire.

exemple de google

 #include  #include  #include  #include  int main(int argc, char **argv) { if(argc != 2) return 1; struct stat fileStat; if(stat(argv[1],&fileStat) < 0) return 1; printf("Information for %s\n",argv[1]); printf("---------------------------\n"); printf("File Size: \t\t%d bytes\n",fileStat.st_size); printf("Number of Links: \t%d\n",fileStat.st_nlink); printf("File inode: \t\t%d\n",fileStat.st_ino); printf("File Permissions: \t"); printf( (S_ISDIR(fileStat.st_mode)) ? "d" : "-"); printf( (fileStat.st_mode & S_IRUSR) ? "r" : "-"); printf( (fileStat.st_mode & S_IWUSR) ? "w" : "-"); printf( (fileStat.st_mode & S_IXUSR) ? "x" : "-"); printf( (fileStat.st_mode & S_IRGRP) ? "r" : "-"); printf( (fileStat.st_mode & S_IWGRP) ? "w" : "-"); printf( (fileStat.st_mode & S_IXGRP) ? "x" : "-"); printf( (fileStat.st_mode & S_IROTH) ? "r" : "-"); printf( (fileStat.st_mode & S_IWOTH) ? "w" : "-"); printf( (fileStat.st_mode & S_IXOTH) ? "x" : "-"); printf("\n\n"); printf("The file %sa symbolic link\n", (S_ISLNK(fileStat.st_mode)) ? "is" : "is not"); return 0; } 

résultat:

  Information pour 2.c
 ---------------------------
 Taille du fichier: 1223 octets
 Nombre de liens: 1
 Fichier inode: 39977236
 Autorisations de fichiers: -rw-r - r--

 Le fichier n'est pas un lien symbolique 

Les bases sont assez simples; les bits difficiles sont les bits SUID et SGID et le bit collant, qui modifient les bits “x”. Envisagez de scinder les permissions en trois chiffres octaux pour l’utilisateur, le groupe, le propriétaire et pour les indexer dans un tableau de chaînes de 3 caractères telles que rwx et --- . Ajustez ensuite les x bits appropriés en fonction des autres bits de mode. Le type de fichier devra être traité séparément, mais vous pouvez utiliser un décalage de 12 bits à droite (éventuellement avec masquage) et une table de 16 entrées pour traiter les 16 valeurs possibles (qui ne sont pas toutes valables sur un système donné). . Vous pouvez également utiliser des types connus, comme indiqué dans le code ci-dessous.

 +----+---+---+---+---+ |type|SSS|USR|GRP|OTH| +----+---+---+---+---+ 

Les 4 types de bits, les trois S-bits (setuid, setgid, sticky) et les bits d’utilisateur, de groupe et autres.

C’est le code que j’utilise pour convertir mode_t en chaîne. Il a été écrit pour un programme bien sans thread, il utilise donc des données statiques; il serait sortingvial de le modifier pour prendre la chaîne de sortie en tant que paramètre d’entrée:

 /* Convert a mode field into "ls -l" type perms field. */ static char *lsperms(int mode) { static const char *rwx[] = {"---", "--x", "-w-", "-wx", "r--", "rx", "rw-", "rwx"}; static char bits[11]; bits[0] = filetypeletter(mode); strcpy(&bits[1], rwx[(mode >> 6)& 7]); strcpy(&bits[4], rwx[(mode >> 3)& 7]); strcpy(&bits[7], rwx[(mode & 7)]); if (mode & S_ISUID) bits[3] = (mode & S_IXUSR) ? 's' : 'S'; if (mode & S_ISGID) bits[6] = (mode & S_IXGRP) ? 's' : 'l'; if (mode & S_ISVTX) bits[9] = (mode & S_IXOTH) ? 't' : 'T'; bits[10] = '\0'; return(bits); } static int filetypeletter(int mode) { char c; if (S_ISREG(mode)) c = '-'; else if (S_ISDIR(mode)) c = 'd'; else if (S_ISBLK(mode)) c = 'b'; else if (S_ISCHR(mode)) c = 'c'; #ifdef S_ISFIFO else if (S_ISFIFO(mode)) c = 'p'; #endif /* S_ISFIFO */ #ifdef S_ISLNK else if (S_ISLNK(mode)) c = 'l'; #endif /* S_ISLNK */ #ifdef S_ISSOCK else if (S_ISSOCK(mode)) c = 's'; #endif /* S_ISSOCK */ #ifdef S_ISDOOR /* Solaris 2.6, etc. */ else if (S_ISDOOR(mode)) c = 'D'; #endif /* S_ISDOOR */ else { /* Unknown type -- possibly a regular file? */ c = '?'; } return(c); } 

Je n’aime pas la syntaxe if/ else if .

Je préfère utiliser l’instruction switch . Après avoir un peu lutté, j’ai trouvé comment nous pouvons le faire en utilisant différentes macros, par exemple:

 S_ISCHR (mode) 

Est équivalent à:

 ((mode & S_IFMT) == S_IFCHR) 

Cela nous permet de construire une instruction switch comme ceci:

 char f_type(mode_t mode) { char c; switch (mode & S_IFMT) { case S_IFBLK: c = 'b'; break; case S_IFCHR: c = 'c'; break; case S_IFDIR: c = 'd'; break; case S_IFIFO: c = 'p'; break; case S_IFLNK: c = 'l'; break; case S_IFREG: c = '-'; break; case S_IFSOCK: c = 's'; break; default: c = '?'; break; } return (c); } 

Ce qui, à mon avis, est un peu plus élégant que l’approche if/else if .