20

UNIXコマンドをエミュレートする小さなCプログラムを作成しようとしてい ls -lます。そうするために、私はstat(2)syscallを使用していて、権限を書き込む小さな問題に遭遇しました。mode_tからのファイルパーミッションを保持する変数がありst_mode、その値を文字列表現に解析するのは難しくありませんが、それよりも優れた方法があるかどうか疑問に思っていました。

4

3 に答える 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
ファイル i ノード: 39977236
ファイルのパーミッション: -rw-r--r--

ファイルはシンボリックリンクではありません
于 2012-04-25T20:20:16.587 に答える
20

基本は単純です。トリッキーなビットは、「x」ビットを変更する SUID および SGID ビットとスティッキー ビットです。アクセス許可をユーザー、グループ、所有者の 3 つの 8 進数に分割し、それらを使用してrwxおよびなどの 3 文字の文字列の配列にインデックスを付けることを検討してください---x次に、他のモード ビットに基づいて適切なビットを調整します。ファイルの種類は個別に処理する必要がありますが、12 ビットの右シフト (おそらくマスキングを使用) と 16 のエントリ テーブルを使用して、16 の可能な値を処理できます (特定のシステムですべてが有効であるとは限りません)。 . または、以下のコードに示すように、既知の型を処理できます。

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

4 つのタイプのビット、3 つの 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 に答える