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\n", argv[0]);
        exit(EXIT_FAILURE);
    }
    struct stat sbuf;
    printf("Filename:%s\n", argv[1]);//打印文件名
    if (stat(argv[1], &sbuf) == -1)
        ERR_EXIT("stat error");

    printf("File number:major %d,minor %d inode %d\n", 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\n", argv[0]);
        exit(EXIT_FAILURE);
    }
    struct stat sbuf;
    printf("Filename:%s\n", argv[1]);
    if (lstat(argv[1], &sbuf) == -1)
        ERR_EXIT("stat error");

    printf("File number:major %d,minor %d inode %d\n", MAJOR(sbuf.st_dev), MINOR(sbuf.st_dev), (int)sbuf.st_ino);

    if (filetype(&sbuf))
    {
    //如果文件类型是设备文件,还可以获取设备更详细的信息:主设备号、次设备号 printf("Device number:major %d,minor %d\n", 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\n"); break; case S_IFLNK: printf("symbolic link\n"); break; case S_IFREG: printf("regular file\n"); break; case S_IFBLK: printf("block device\n"); flag = 1; break; case S_IFDIR: printf("directory\n"); break; case S_IFCHR: printf("character device\n"); flag = 1; break; case S_IFIFO: printf("FIFO\n"); break; default: printf("unknown file type\n"); 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\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    struct stat sbuf;
    printf("Filename:%s\n", argv[1]);
    if (stat(argv[1], &sbuf) == -1)
        ERR_EXIT("stat error");

    printf("File number:major %d,minor %d inode %d\n", MAJOR(sbuf.st_dev), MINOR(sbuf.st_dev), (int)sbuf.st_ino);
    if (filetype(&sbuf))
    {
        printf("Device number:major %d,minor %d\n", MAJOR(sbuf.st_rdev), MINOR(sbuf.st_rdev));
    }
    
  //打印文件的权限信息
char perm[11] = {0}; fileperm(&sbuf, perm); printf("File permission bits=%o %s\n", 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\n"); break; case S_IFLNK: printf("symbolic link\n"); break; case S_IFREG: printf("regular file\n"); break; case S_IFBLK: printf("block device\n"); flag = 1; break; case S_IFDIR: printf("directory\n"); break; case S_IFCHR: printf("character device\n"); flag = 1; break; case S_IFIFO: printf("FIFO\n"); break; default: printf("unknown file type\n"); 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] = '\0'; }

编译运行:

 

利用上面所学的东西,我们就可以实现自己的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函数的说明:
 
好了,今天文件信息的查看学到这,下次下见。

posted on 2013-12-29 13:27  cexo  阅读(623)  评论(0编辑  收藏  举报

导航