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

che*_*one 15 c stat

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

ask*_*pen 46

谷歌的例子

#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;
}
Run Code Online (Sandbox Code Playgroud)

结果:

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

  • 谢谢你的回答。这有很大帮助。 (2认同)
  • 请注意,因为代码使用`stat()`而不是`lstat()`,所以报告'symlink'的唯一时间是符号链接断开的时候.否则,它将报告符号链接末尾的文件. (2认同)

Jon*_*ler 17

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

+----+---+---+---+---+
|type|SSS|USR|GRP|OTH|
+----+---+---+---+---+
Run Code Online (Sandbox Code Playgroud)

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);
}
Run Code Online (Sandbox Code Playgroud)