Printing file permissions like 'ls -l' using stat(2) in C

后端 未结 3 1705
梦谈多话
梦谈多话 2021-02-01 20:53

I am trying to write a small C program that emulates the unix command ls -l. To do so, I am using the stat(2) syscall and have ran into a small hi

3条回答
  •  走了就别回头了
    2021-02-01 21:36

    The basics are simple enough; the tricky bits are the SUID and SGID bits and the sticky bit, which modify the 'x' bits. Consider splitting the permissions into 3 octal digits for user, group, owner, and using those to index into an array of 3-character strings such as rwx and ---. Then adjust the appropriate x bits based on the other mode bits. The file type will have to be dealt with separately, but you could use a 12-bit shift right (possibly with masking) and a 16 entry table to deal with the 16 possible values (not all of which are valid on any given system). Or you can deal with known types as shown in the code below.

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

    The 4 types bits, the three S-bits (setuid, setgid, sticky) and the user, group and other bits.

    This is code I use for converting mode_t into a string. It was written for a nicely threadless program, so it uses static data; it would be trivial to modify it to take the output string as an input parameter:

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

提交回复
热议问题