• linux系统编程之文件与io(三)


    上次我们利用文件的read和write来实现了简易的cp命令,其中将源文件拷贝到目标文件时,我们给目标文件的权限是写死的,而非根据源文件的权限生成的,如下:

    今天就来解决这个问题,来学习获取文件权限相关的函数,言归正传,正入正题。

    stat:功能:读取文件元数据
     
    关于stat结构体的结构如下:
    struct stat {
        dev_t     st_dev;     /* ID of device containing file文件保存在磁盘上的设备号,包含主设备号和次设备号,它是16位的整数,高八位为主设备号,低八位为次设备号 */
        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) 如果文件是设备文件,所对应的设备ID*/
        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 最后状态改变的时间,比如说改变了文件权限,并未改变文件的内容*/
    };

    下面就以程序例子来对其进行说明:

    #include <unistd.h>
    #include <sys/stat.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    
    #include <stdlib.h>
    #include <stdio.h>
    #include <errno.h>
    #include <string.h>
    
    
    #define ERR_EXIT(m) 
        do 
        { 
            perror(m); 
            exit(EXIT_FAILURE); 
        } while(0)
    
    #define MAJOR(a) (int)((unsigned short)a >> 8)//获取高八位数据,也就是主设备号
    #define MINOR(a) (int)((unsigned short)a & 0xFF)//获取低八位数据,也就是次设备号
    
    int main(int argc, char *argv[])
    {
        if (argc != 2)
        {
            fprintf(stderr, "Usage %s file
    ", argv[0]);
            exit(EXIT_FAILURE);
        }
        struct stat sbuf;
        printf("Filename:%s
    ", argv[1]);//打印文件名
        if (stat(argv[1], &sbuf) == -1)
            ERR_EXIT("stat error");
    
        printf("File number:major %d,minor %d inode %d
    ", MAJOR(sbuf.st_dev)/**文件主设备号**/, MINOR(sbuf.st_dev)/**文件次设备号**/, sbuf.st_ino/**inode数**/);
      return 0; }

    编译:

    这时再编译运行:

    实际上上面的数据都可由系统命令来进行查看,如下:

    总结:主设备号用来区分不同的设备,它决定了用什么样的驱动程序来访问设备;次设备号用来区分同设备中的不同分区。

    下面我们继续来查看文件信息,先来打印下文件类型,关于这个数据,它是存放到stat结构体中的mode_t字段中: 

    先来查看下man帮助:

    下面具体代码如下:

    #include <unistd.h>
    #include <sys/stat.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    
    #include <stdlib.h>
    #include <stdio.h>
    #include <errno.h>
    #include <string.h>
    
    
    #define ERR_EXIT(m) 
        do 
        { 
            perror(m); 
            exit(EXIT_FAILURE); 
        } while(0)
    
    #define MAJOR(a) (int)((unsigned short)a >> 8)
    #define MINOR(a) (int)((unsigned short)a & 0xFF)
    
    int filetype(struct stat *buf);//获取文件类型函数定义
    
    int main(int argc, char *argv[])
    {
        if (argc != 2)
        {
            fprintf(stderr, "Usage %s file
    ", argv[0]);
            exit(EXIT_FAILURE);
        }
        struct stat sbuf;
        printf("Filename:%s
    ", argv[1]);
        if (lstat(argv[1], &sbuf) == -1)
            ERR_EXIT("stat error");
    
        printf("File number:major %d,minor %d inode %d
    ", MAJOR(sbuf.st_dev), MINOR(sbuf.st_dev), (int)sbuf.st_ino);
    
        if (filetype(&sbuf))
        {
        //如果文件类型是设备文件,还可以获取设备更详细的信息:主设备号、次设备号 printf("Device number:major %d,minor %d ", MAJOR(sbuf.st_rdev), MINOR(sbuf.st_rdev)); }
    return 0; } int filetype(struct stat *buf)//如果是设备文件,则返回1,否则返回0 { int flag = 0; printf("Filetype:"); mode_t mode; mode = buf->st_mode; switch (mode & S_IFMT) { case S_IFSOCK: printf("socket "); break; case S_IFLNK: printf("symbolic link "); break; case S_IFREG: printf("regular file "); break; case S_IFBLK: printf("block device "); flag = 1; break; case S_IFDIR: printf("directory "); break; case S_IFCHR: printf("character device "); flag = 1; break; case S_IFIFO: printf("FIFO "); break; default: printf("unknown file type "); break; } return flag; }

    编译运行:

    下面来打印文件的权限信息:

    下面看具体代码:

    #include <unistd.h>
    #include <sys/stat.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    
    #include <stdlib.h>
    #include <stdio.h>
    #include <errno.h>
    #include <string.h>
    
    
    #define ERR_EXIT(m) 
        do 
        { 
            perror(m); 
            exit(EXIT_FAILURE); 
        } while(0)
    
    #define MAJOR(a) (int)((unsigned short)a >> 8)
    #define MINOR(a) (int)((unsigned short)a & 0xFF)
    
    int filetype(struct stat *buf);
    void fileperm(struct stat *buf, char *perm);//查看文件权限,以rwx进行格式化
    
    int main(int argc, char *argv[])
    {
        if (argc != 2)
        {
            fprintf(stderr, "Usage %s file
    ", argv[0]);
            exit(EXIT_FAILURE);
        }
    
        struct stat sbuf;
        printf("Filename:%s
    ", argv[1]);
        if (stat(argv[1], &sbuf) == -1)
            ERR_EXIT("stat error");
    
        printf("File number:major %d,minor %d inode %d
    ", MAJOR(sbuf.st_dev), MINOR(sbuf.st_dev), (int)sbuf.st_ino);
        if (filetype(&sbuf))
        {
            printf("Device number:major %d,minor %d
    ", MAJOR(sbuf.st_rdev), MINOR(sbuf.st_rdev));
        }
        
      //打印文件的权限信息
    char perm[11] = {0}; fileperm(&sbuf, perm); printf("File permission bits=%o %s ", sbuf.st_mode & 07777, perm); return 0; } int filetype(struct stat *buf) { int flag = 0; printf("Filetype:"); mode_t mode; mode = buf->st_mode; switch (mode & S_IFMT) { case S_IFSOCK: printf("socket "); break; case S_IFLNK: printf("symbolic link "); break; case S_IFREG: printf("regular file "); break; case S_IFBLK: printf("block device "); flag = 1; break; case S_IFDIR: printf("directory "); break; case S_IFCHR: printf("character device "); flag = 1; break; case S_IFIFO: printf("FIFO "); break; default: printf("unknown file type "); break; } return flag; } void fileperm(struct stat *buf, char *perm) { strcpy(perm, "----------"); perm[0] = '?'; mode_t mode; mode = buf->st_mode; switch (mode & S_IFMT)//确定第一位文件类型 { case S_IFSOCK: perm[0] = 's'; break; case S_IFLNK: perm[0] = 'l'; break; case S_IFREG: perm[0] = '-'; break; case S_IFBLK: perm[0] = 'b'; break; case S_IFDIR: perm[0] = 'd'; break; case S_IFCHR: perm[0] = 'c'; break; case S_IFIFO: perm[0] = 'p'; break; } if (mode & S_IRUSR)//与用户读权限进行与操作之后,如果为真,则代表有这个权限 perm[1] = 'r'; if (mode & S_IWUSR) perm[2] = 'w'; if (mode & S_IXUSR) perm[3] = 'x'; if (mode & S_IRGRP) perm[4] = 'r'; if (mode & S_IWGRP) perm[5] = 'w'; if (mode & S_IXGRP) perm[6] = 'x'; if (mode & S_IROTH) perm[7] = 'r'; if (mode & S_IWOTH) perm[8] = 'w'; if (mode & S_IXOTH) perm[9] = 'x'; perm[10] = ''; }

    编译运行:

    利用上面所学的东西,我们就可以实现自己的ls -l的功能了,在实现这个功能之时,还有几个知识点需介绍一下:

    先看一下ls -l会显示什么信息:

    文件权限,这个上面已经实现过了,所以不成问题

    连接数,对应的是stat->nlink_t,所以不成问题

    用户名,我们知道stat->uid_t,可以根据用户ID获得用户名,通过如下函数:

     

    ④组名,我们知道stat->gid_t,可以根据组ID获得组名,通过如下函数:

    文件大小,可以通过stat->st_size来获得

    文件修改时间,可以通过stat->st_mtime来获得

    文件名,这个肯定可以获取。

    但是,对于符号链接文件,还需要做一个特珠的处理,如下:
    那对于符号链接文件,怎么才能获取它所指向的链接文件呢?可以通过如下函数获取:
    所以说,我们完全有能力实现跟ls -l系统命令一样的功能:
    注意:
    对于符号链接文件,我们查看其文件信息时,应该是lstat函数,而不是stat
    对于目前我们实现查看的程序,是用的stat函数,那查看我们新创建的a链接文件的信息是什么呢?
     
    这时,我们将state改为lstate,再次查看下:
    编译运行:
    查看一下lsate函数的说明:
     
    好了,今天文件信息的查看学到这,下次下见。
  • 相关阅读:
    学习《Building Applications with FME Objects》 之十 使用集合
    oracle左右连接的另外表示方法
    拥抱SQLAlchemy 之二 拉拉手,我请你去看电影~
    Oracle中的Union、Union All、Intersect、Minus
    System.Data.SQLite测试
    SmartSVN + google code
    学习《Building Applications with FME Objects》 之九 高级要素处理
    Django静态文件配置备忘录
    测试oracle with as
    测量坐标系中单个多边形面积解析法计算的程序源代码
  • 原文地址:https://www.cnblogs.com/webor2006/p/3496281.html
Copyright © 2020-2023  润新知