使用C中的stat(2)打印文件权限,例如’ls -l’

我正在尝试编写一个模拟unix命令ls -l的小型C程序。 为此,我使用stat(2)系统调用并遇到了写入权限的小打嗝。 我有一个mode_t变量,它保存来自st_mode的文件权限,并且将该值解析为s字符串表示并不困难,但我只是想知道是否有更好的方法来做到这一点。

来自谷歌的例子

 #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; } 

结果:

  2.c的信息
 ---------------------------
文件大小:1223个字节
链接数量:1
文件inode:39977236
文件权限:-rw-r  -  r--

该文件不是符号链接 

基础很简单; 棘手的位是SUID和SGID位以及粘滞位,它们修改’x’位。 考虑将权限分为用户,组,所有者的3个八进制数字,并使用这些数字索引为3个字符的字符串数组,如rwx--- 。 然后根据其他模式位调整适当的x位。 文件类型必须单独处理,但您可以使用12位右移(可能带有屏蔽)和16条表来处理16个可能的值(并非所有值都在任何给定系统上都有效) 。 或者您可以处理已知类型,如下面的代码所示。

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

4种类型的比特,三个S比特(setuid,setgid,sticky)以及用户,组和其他比特。

这是我用来将mode_t转换为字符串的代码。 它是为一个很好的无线程程序编写的,因此它使用静态数据; 修改它以将输出字符串作为输入参数将是微不足道的:

 /* 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); } 

我不喜欢if/ else if语法。

我更喜欢使用switch语句。 经过一段时间的努力,我找到了使用不同宏的方法,例如:

 S_ISCHR (mode) 

相当于:

 ((mode & S_IFMT) == S_IFCHR) 

这允许我们构建一个这样的switch语句:

 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); } 

在我看来,它比if/else if方法更优雅。