我正在尝试编写一个模拟unix命令的小型C程序 ls -l
。为此,我正在使用系统调用stat(2)
,并且遇到了写入权限的小问题。我有一个mode_t
变量,它拥有st_mode
的文件许可权,并且将该值解析为s字符串表示形式并不困难,但我只是想知道是否有更好的方法可以做到这一点。从谷歌打印文件权限像'ls -l'使用stat(2)中的C
回答
例如
#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;
}
结果:
Information for 2.c --------------------------- File Size: 1223 bytes Number of Links: 1 File inode: 39977236 File Permissions: -rw-r--r-- The file is not a symbolic link
基础知识足够简单;棘手的位是SUID和SGID位以及修改'x'位的粘性位。考虑将权限分为用户,组,所有者的三个八进制数字,并使用它们索引到一个由3个字符组成的数组,例如rwx
和---
。然后根据其他模式位调整相应的x
位。文件类型必须单独处理,但您可以使用12位右移(可能带有掩码)和16个条目表来处理16个可能值(并非所有值在任何给定系统上都是有效的) 。或者你可以处理已知的类型,如下面的代码所示。
+----+---+---+---+---+
|type|SSS|USR|GRP|OTH|
+----+---+---+---+---+
的4个类型的位,的三个S位(的setuid,setgid的,粘性的)和用户,组等的位。
这是我用于将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);
}
欣赏您的答案提供的深度!每天学些新东西! – cheezone 2012-04-25 20:46:05
铿锵''-Weverything''完全正确地抱怨:) – 2015-01-26 15:01:28
@ ArranCudbard-Bell:我一直在用'clang -Weverything'类似的东西来清理一个命令语料库,有时可能会有点痛苦。我实际上没有直接尝试'clang -Weverything';它可能比我使用的选项更麻烦(大约18'-W *'标志;'-Wconversion'是我的代码出现问题的最大原因)。 – 2015-01-26 15:04:53
我不喜欢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
方法更优雅。
你倾销了汇编代码以确定哪一个更高效? (例如'gcc -S -masm = intel -O2 -o filemode.asm filemode.c') – 2017-06-16 05:23:07
- 1. 如何使用ls -l查看文件w/o的权限?
- 2. 如何在Linux中获取文件权限和绝对路径,完全像ls -l一样?
- 3. 使用C++和stat获取所有者的访问权限
- 4. 以ls -l
- 5. C#打印文档打印图像
- 6. 使用GD :: Graph打印到.gif文件。权限被拒绝而写入文件
- 7. 如何在C++中打开文件时设置文件权限?
- 8. 如何使用打印机的Web C#我打印JPG文件
- 9. Diffrence(GIT LS-文件-s | WC -1)和$(GIT LS-文件-s>出&& WC -l <出)
- 10. - >结果= $(ls -l)(或) - >结果=`ls -l`
- 11. Python长列表目录(ls -l),ls *
- 12. 使用c#windows服务打印文件
- 13. 从检查ls -l输出中删除文件的能力
- 14. 如何使用Windows用户权限为PDF打印创建打印机?
- 15. 使用ofstream打开文件时设置文件权限
- 16. 关于C#中的文件权限
- 17. Linux文件权限
- 18. C#文件/目录权限
- 19. C#权限保存文件
- 20. C和文件权限
- 21. C stat()忽略文件
- 22. 如何将文件权限打印为字符串?
- 23. Web文件夹的Symfony 2权限
- 24. 使用多图在C++中读取并打印超过2列的csv文件
- 25. 如果在PHP中不使用exec(“ls -l”),如果有1000个文件,我们是否需要调用stat()来获取文件大小1000倍?
- 26. Linux文件权限
- 27. 捕获要打印到图像文件中的打印作业
- 28. 我想`LS -l`在ESHELL
- 29. 打开共享权限的文件
- 30. C#应用程序中的文件和文件夹权限
感谢您的回答。这帮了一大笔钱。 – cheezone 2012-04-25 20:45:46
请注意,因为代码使用'stat()'而不是'lstat()',所以只会在符号链接断开时报告'符号链接'。否则,它将在符号链接的末尾报告该文件。 – 2015-01-26 13:37:13