我正在尝试编写一个模拟 unix 命令的小型 C 程序
ls -l
。为此,我正在使用stat(2)
系统调用并且在编写权限时遇到了一个小问题。我有一个mode_t
变量来保存来自 的文件权限st_mode
,并且不难将该值解析为 s 字符串表示形式,但我只是想知道是否有比这更好的方法。
问问题
75921 次
3 回答
66
来自谷歌的例子
#include <unistd.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
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 %s a symbolic link\n", (S_ISLNK(fileStat.st_mode)) ? "is" : "is not");
return 0;
}
结果:
2.c 的信息 -------------------------- 文件大小:1223 字节 链接数:1 文件索引节点:39977236 文件权限:-rw-r--r-- 该文件不是符号链接
于 2012-04-25T20:20:16.587 回答
20
基础很简单;棘手的位是 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--", "r-x", "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);
}
于 2012-04-25T20:20:31.717 回答
1
我不喜欢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
方法更优雅一些。
于 2017-06-16T04:12:01.883 回答