stat函数(stat、fstat、lstat)

#include <sys/types.h>

#include <sys/stat.h>

#include <unistd.h>     //需包含头文件

有如下三个函数的函数原型:

int stat(const char *path, struct stat *buf);

第一个形参:指出文件(文件路径); 第二个形参:出参数(函数对该参数操作,然后传出)。

int fstat(int fd, struct stat *buf);

fstat函数与stat函数的功能一样,只是第一个形参是文件描述符。

int lstat(const char *path, struct stat *buf);

lstat函数的形参跟stat函数的形参一样。其功能也跟stat函数功能一样,仅有一点不同:stat函数是穿透(追踪)函数,即对软链接文件进行操作时,操作的是链接到的那一个文件,不是软链接文件本身;而lstat函数是不穿透(不追踪)函数,对软链接文件进行操作时,操作的是软链接文件本身。

以上三个函数:成功返回0,失败返回-1,并且将详细错误信息赋值给errno全局变量。

其它Linux系统函数类似,带l表示不追踪,不带l表示追踪(穿透)。如:ls –l命令查看的文件属性,是不追踪(不穿透)的;rm删除文件时,是不追踪的;Vi和Vim是穿透的;对于穿透的命令,是无法判断文件是不是软链接文件,比如ls –l命令,其是不穿透的,因此可以判断是否是软链接文件;如果是用stat函数实现的ls –l命令,则是穿透的,对于查看原文件和链接文件的属性是一样的,无法区别两者,因此可以考虑用lstat函数来实现ls –l命令的功能。

注意:创建软链接最好用绝对路径  ln –s 原文件 软链接文件(采用绝对路径)

statlstatfstat函数中 struct stat类型的说明:

struct stat {

               dev_t     st_dev;     /* 文件的设备编号 */

               ino_t     st_ino;     /* 索引结点编号 */

               mode_t    st_mode;    /* 文件类型和权限*/

               nlink_t   st_nlink;   /*硬链接数 */

               uid_t     st_uid;     /*用户ID*/

               gid_t     st_gid;     /* ID*/

               dev_t     st_rdev;    /* 设备类型(若此文件为设备文件,则为设备编号*/

               off_t      st_size;    /* 文件大小*/

               blksize_t   st_blksize; /*文件系统的I/O缓冲区大小*/

               blkcnt_t   st_blocks;  /* 块数 */

               time_t    st_atime;   /* 访问时间 */

               time_t    st_mtime;   /* 修改时间 */

               time_t    st_ctime;   /* 更改时间 */

         };  //标红为重点内容

上述结构体中,对st_mode成员做一个详细的介绍:

mode_t    st_mode;    /* 文件类型和权限*/

st_mode变量(mode_t类型):该变量占 2byte共16位,为16位的整型值。用于储存文件类型和权限。 如下图所示:

每一位均为二进制数。r代表4,即100;w代表2,即010;x代表1,即001。由于总共16位二进制数,因此需要6位8进制数来进行表示,其中8进制数以0开头,共7位。

其他人权限(0~2位)。读权限:0000004,在所给函数头文件中进行了宏定义为:S_IROTH;写:0000002,S_IWOTH;执行:0000001,S_IXOTH。 掩码为:0000007,S_IRWXO  掩码的作用:st_mode & 掩码 就可以过滤st_mode中除其他人权限以外的信息,所得结果直接是其他人的权限信息,下面原理相同。

所属组权限(3~5位)。读权限:0000040, S_IRGRP;写:0000020,S_IWGRP;执行:0000010,S_IXGRP。 掩码为:0000070,S_IRWXG。

所属主权限(6~8位)。读权限:0000400, S_IRUSR;写:0000200,S_IWUSR;执行:0000100,S_IXUSR。 掩码为:0000700,S_IRWXU。

特殊权限位(9~11位)。SUID:0004000, S_ISUID;SGID:0002000,S_ISGID;SBIT:0001000,S_ISVTX。 //特殊权限位很少用

文件类型(12~15位,共7种类型文件)。套接字(socket)文件s:0140000,S_IFSOCK;链接文件(软链接)l:0120000,S_IFLNK;普通文件-:0100000,S_IFREG;块设备文件b:0060000,S_IFBLK;目录文件d:0040000,S_IFDIR;字符设备文件c:0020000,S_IFCHR;管道文件p:0010000,S_IFIFO。    掩码:0170000  作用一样,st_mode & 掩码 的结果与七种类型的宏相比较,就可以判断是哪一种文件。

强调一下特殊权限位SBIT(粘滞位)的功能:1.对目录设置粘滞位,则该目录内的文件只能被文件所有者、超级用户和目录所有者这三类用户删除,其他用户都没有删除的权限;2.对文件设置了粘滞位,那么在内存资源十分紧张的情况下,也不会把该文件放回到磁盘上。如磁盘的对换区SWAP,当内存紧张,优先级别低的进程会被暂时放回到对换区中,但是一旦设置了粘滞位,则不会放回磁盘,依然处于内存。

下面是说明stat函数的使用的代码:

//运用stat函数实现查看文件大小属性的功能

[root@localhost work]# vim statuse.c

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

int main( int argc,char *argv[ ] )   //命令行参数
{
    if( argc < 2 )
    printf("./statuse filename1 filename2 ...\n");

    struct stat zsx;
    int ret;
    int i=1;
    for( i=1;i<argc;i++ )
    {
        ret = stat( argv[i],&zsx);   //stat函数获取文件的属性,穿透的
        if( ret == -1 )
        {
            perror("stat filename");
            exit(1);
        }

        int size = (int)zsx.st_size;   //注意,必须强制转换,后者变量是off_t类型
        printf("%s      %d\n",argv[i],size);
    }

    return 0;
}

[root@localhost work]# gcc -pipe -ggdb3 -pedantic -Wall statuse.c -o statuse

[root@localhost work]# ls

english.txt  ls-l.c  stat.c  statuse  statuse.c

[root@localhost work]# ./statuse english.txt ls-l.c stat.c statuse statuse.c

english.txt      109055

ls-l.c       2204

stat.c       416

statuse     57468

statuse.c  535

 [root@localhost work]# ll english.txt

-rwxrwxrwx. 1 root root 109055 Mar 19 10:30 english.txt

//运用stat函数实现ls –l 命令的功能

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <time.h>
#include <pwd.h>
#include <grp.h>


int main(int argc, char* argv[])
{
    if(argc < 2)


int main(int argc, char* argv[])
{
    if(argc < 2)
    {
        printf("./a.out filename\n");
        exit(1);
    }

    struct stat st;
    int ret = stat(argv[1], &st);
    if(ret == -1)
    {
        perror("stat");
        exit(1);
    }

    // 存储文件类型和访问权限
    char perms[11] = {0};
    // 判断文件类型
    switch(st.st_mode & S_IFMT)
    {
        case S_IFLNK:
            perms[0] = 'l';
            break;
        case S_IFDIR:
            perms[0] = 'd';
            break;
        case S_IFREG:
            perms[0] = '-';
            break;
        case S_IFBLK:
            perms[0] = 'b';
            break;
        case S_IFCHR:
            perms[0] = 'c';
            break;
        case S_IFSOCK:
            perms[0] = 's';
            break;
        case S_IFIFO:
            perms[0] = 'p';
            break;
        default:
            perms[0] = '?';
            break;
    }
    // 判断文件的访问权限
    // 文件所有者
    perms[1] = (st.st_mode & S_IRUSR) ? 'r' : '-';
    perms[2] = (st.st_mode & S_IWUSR) ? 'w' : '-';
    perms[3] = (st.st_mode & S_IXUSR) ? 'x' : '-';
    // 文件所属组
    perms[4] = (st.st_mode & S_IRGRP) ? 'r' : '-';
    perms[5] = (st.st_mode & S_IWGRP) ? 'w' : '-';
    perms[6] = (st.st_mode & S_IXGRP) ? 'x' : '-';
    // 其他人
    perms[7] = (st.st_mode & S_IROTH) ? 'r' : '-';
    perms[8] = (st.st_mode & S_IWOTH) ? 'w' : '-';
    perms[9] = (st.st_mode & S_IXOTH) ? 'x' : '-';

    // 硬链接计数
    int linkNum = st.st_nlink;
    // 文件所有者
    char* fileUser = getpwuid(st.st_uid)->pw_name;
    // 文件所属组
    char* fileGrp = getgrgid(st.st_gid)->gr_name;
    // 文件大小
    int fileSize = (int)st.st_size;
    // 修改时间
    char* time = ctime(&st.st_mtime);
    char mtime[512] = {0};
    strncpy(mtime, time, strlen(time)-1);

    char buf[1024];
    sprintf(buf, "%s  %d  %s  %s  %d  %s  %s", perms, linkNum, fileUser, fileGrp, fileSize, mtime, argv[1]);

    printf("%s\n", buf);

    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_33883085/article/details/88695946