2012-04-25 26 views
14

Tôi đang cố viết một chương trình C nhỏ mô phỏng lệnh unix ls -l. Để làm như vậy, tôi đang sử dụng tòa nhà chọc trời stat(2) và đã gặp phải một trục trặc nhỏ bằng văn bản cho phép. Tôi có một biến số mode_t giữ quyền truy cập tệp từ st_mode và sẽ không khó để phân tích giá trị đó thành biểu diễn chuỗi, nhưng tôi đã tự hỏi liệu có cách nào tốt hơn để thực hiện điều đó không.In tệp quyền như 'ls -l' bằng cách sử dụng chỉ số (2) trong C

Trả lời

40

ví dụ từ google

#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; 
} 

kết quả:

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
+1

Cảm ơn câu trả lời. Điều này đã giúp một tấn. – cheezone

+2

Lưu ý rằng vì mã sử dụng 'stat()' thay vì 'lstat()', lần duy nhất nó sẽ báo cáo 'liên kết tượng trưng' là khi liên kết tượng trưng bị hỏng. Nếu không, nó sẽ báo cáo về tệp ở cuối liên kết tượng trưng. –

14

Những điều cơ bản là đủ đơn giản; các bit khéo léo là các bit SUID và SGID và bit dính, điều chỉnh các bit 'x'. Cân nhắc chia quyền thành 3 số bát phân cho người dùng, nhóm, chủ sở hữu và sử dụng các số đó để lập chỉ mục thành một mảng gồm các chuỗi gồm 3 ký tự như rwx---. Sau đó điều chỉnh các bit x thích hợp dựa trên các bit chế độ khác. Loại tệp sẽ phải được xử lý riêng, nhưng bạn có thể sử dụng quyền dịch 12 bit (có thể với mặt nạ) và bảng nhập 16 để xử lý 16 giá trị có thể (không phải tất cả đều hợp lệ trên bất kỳ hệ thống nào) . Hoặc bạn có thể xử lý các loại đã biết như được hiển thị trong mã bên dưới.

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

Bốn loại bit, ba bit S (setuid, setgid, sticky) và người dùng, nhóm và các bit khác.

Đây là mã tôi sử dụng để chuyển đổi mode_t thành chuỗi. Nó được viết cho một chương trình không có chủ đề độc đáo, vì vậy nó sử dụng dữ liệu tĩnh; nó sẽ là tầm thường để sửa đổi nó để lấy chuỗi đầu ra làm tham số đầu vào:

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

Đánh giá cao độ sâu được cung cấp bởi câu trả lời của bạn! Học điều mới mỗi ngày! – cheezone

+0

clang '' -Weverything'' khá đúng phàn nàn :) –

+0

@ ArranCudbard-Bell: Tôi đã dọn dẹp một tập hợp các lệnh với một cái gì đó tương tự như 'clang -Weverything' và đôi lúc nó có thể hơi đau. Tôi đã không thực sự cố gắng 'clang -Weverything' trực tiếp; nó có thể ít hơn so với các tùy chọn tôi đang sử dụng (khoảng 18 '-W *' cờ; '-Wconversion' là nguyên nhân lớn nhất gây rắc rối cho mã của tôi). –

0

Tôi không thích cú pháp if/ else if.

Tôi thích sử dụng câu lệnh switch. Sau khi vật lộn một chút tôi thấy cách chúng ta có thể làm điều đó sử dụng các macro khác nhau, ví dụ:

S_ISCHR (mode) 

Tương đương với:

((mode & S_IFMT) == S_IFCHR) 

Điều này cho phép chúng ta xây dựng một câu lệnh switch như thế này:

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

Theo ý kiến ​​của tôi, nó thanh lịch hơn một chút so với phương pháp if/else if.

+0

Bạn đã bỏ mã lắp ráp để xác định mã nào hiệu quả hơn? (ví dụ: 'gcc -S -masm = intel -O2 -o filemode.asm filemode.c') –

Các vấn đề liên quan