天天看點

Linux之檔案類型和權限的擷取與操作

最近兩天學習了有關檔案屬性的擷取和操作,下面是在學習過程中的一個例程。

Linux中有關檔案屬性的資訊存儲在struct stat這個結構體中:

struct stat {
               dev_t     st_dev;     /* ID of device containing file */
               ino_t     st_ino;     /* inode number */
               mode_t    st_mode;    /* protection */
               nlink_t   st_nlink;   /* number of hard links */
               uid_t     st_uid;     /* user ID of owner */
               gid_t     st_gid;     /* group ID of owner */
               dev_t     st_rdev;    /* device ID (if special file) */
               off_t     st_size;    /* total size, in bytes */
               blksize_t st_blksize; /* blocksize for file system I/O */
               blkcnt_t  st_blocks;  /* number of 512B blocks allocated */
               time_t    st_atime;   /* time of last access */
               time_t    st_mtime;   /* time of last modification */
               time_t    st_ctime;   /* time of last status change */
           };
           

我們可以通過系統API stat()擷取檔案的該結構體。例程中,我主要解析了st_mode這一結構體元素,該元素存儲了有關檔案類型和權限的資訊。

類型和權限都是通過位标志進行存儲和識别的:

S_IFMT     0170000   bit mask for the file type bit fields
           S_IFSOCK   0140000   socket
           S_IFLNK    0120000   symbolic link
           S_IFREG    0100000   regular file
           S_IFBLK    0060000   block device
           S_IFDIR    0040000   directory
           S_IFCHR    0020000   character device
           S_IFIFO    0010000   FIFO
           S_ISUID    0004000   set UID bit
           S_ISGID    0002000   set-group-ID bit (see below)
           S_ISVTX    0001000   sticky bit (see below)
           S_IRWXU    00700     mask for file owner permissions
           S_IRUSR    00400     owner has read permission
           S_IWUSR    00200     owner has write permission
           S_IXUSR    00100     owner has execute permission
           S_IRWXG    00070     mask for group permissions
           S_IRGRP    00040     group has read permission

           S_IWGRP    00020     group has write permission
           S_IXGRP    00010     group has execute permission
           S_IRWXO    00007     mask for permissions for others (not in group)
           S_IROTH    00004     others have read permission
           S_IWOTH    00002     others have write permission
           S_IXOTH    00001     others have execute permission
           

可以看到,檔案類型和權限由不同的掩碼進行控制,特定的類型和權限都對應不同的位,可以通過比對位辨別識别某一檔案的類型或是權限。

另外,檔案類型除了用上述的方法進行識别外,linux中還提供了專門的帶參宏定義,通過這些宏定義可以更加友善的識别檔案類型:

S_ISREG(m)  is it a regular file?

           S_ISDIR(m)  directory?

           S_ISCHR(m)  character device?

           S_ISBLK(m)  block device?

           S_ISFIFO(m) FIFO (named pipe)?

           S_ISLNK(m)  symbolic link? (Not in POSIX.1-1996.)

           S_ISSOCK(m) socket? (Not in POSIX.1-1996.)
           

m就是st_mode元素。這種方法在例程中也有使用。

例程如下:

#include<stdio.h>
#include<string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

int main(int argc,char *argv[])
{
        int ret = -1;
        struct stat buf;
        memset(&buf,0,sizeof(struct stat));

        ret = stat(argv[1],&buf);//擷取結構體struct stat的資訊
        if(ret < 0)
        {
                perror("open");
                exit(-1);
        }
        printf("ino_t:%d\n",buf.st_ino);//列印inode
        
        if(1 == S_ISREG(buf.st_mode))//identify file types using macros,用帶參宏定義判斷檔案類型
        {
                printf("%s is a regular file\n",argv[1]);
        }
        printf("S_ISLNK(buf.st_mode) is:%d\n",S_ISLNK(buf.st_mode));
        if(1 == S_ISLNK(buf.st_mode))//can't pass the test,判斷符号連結檔案,但在測試的時候沒有判斷出來
        {
                printf("%s is a symbolic link\n",argv[1]);
        }

        printf("S_IFREG:%d,buf.st_mode:%d\n",S_IFREG,buf.st_mode);//列印st_mode資訊
        switch(S_IFMT & buf.st_mode)//用掩碼和位标志判斷檔案類型
        {
                case S_IFREG:printf("%s is a regular file\n",argv[1]);break;
                case S_IFDIR:printf("%s is a directory\n",argv[1]);break;
                case S_IFSOCK:printf("%s is a socket file\n",argv[1]);break;
                case S_IFLNK:printf("%s is a link file\n",argv[1]);break;
                case S_IFBLK:printf("%s is a block device file\n",argv[1]);break;
                case S_IFCHR:printf("%s is a character device file\n",argv[1]);break;
                case S_IFIFO:printf("%s is a FIFO/pipe file\n",argv[1]);break;
                default:printf("can't identify\n");
        }

         switch(S_IRWXU & buf.st_mode)//用位标志判斷檔案權限
        {
                case S_IRUSR|S_IWUSR|S_IXUSR:printf("owner of %s has rwx permission \n",argv[1]);break;
                case S_IWUSR:printf("owner of %s has w permission\n",argv[1]);break;
                case S_IXUSR:printf("owner of %s has x permission\n",argv[1]);break;
                case S_IRUSR:printf("owner of %s has r permission \n",argv[1]);break;
                case S_IWUSR|S_IXUSR:printf("owner of %s has wx permission \n",argv[1]);break;
                case S_IRUSR|S_IXUSR:printf("owner of %s has rx permission \n",argv[1]);break;
                case S_IRUSR|S_IWUSR:printf("owner of %s has rw permission \n",argv[1]);break;
                default:printf("owner of %s has no permission\n");
        }
        return 0;
}
           

權限識别隻是識别了檔案屬主對檔案的操作權限,其它的組權限和其他權限如法炮制。由于權限是w r x的組合,而檔案類型的位辨別是單獨的,是以兩者在判斷的時候略有不同。

測試時候的一個發現:有關符号連結檔案(軟連接配接檔案)本身都是rwx屬性,而且用chmod指令修改權限也是無效的。但其st_mode代表的則是所連結的檔案的權限。換句話說符号連接配接檔案本身都是可讀可寫可執行的,但其st_mode則和源檔案保持一緻。

測試發現的一個問題:符号連結檔案被當作了普通檔案,帶參宏定義和位标志都無法正确識别符号連接配接檔案。

繼續閱讀