笔记:Linux环境C语言复习(9)// 元数据、stat命令实现

元数据

文件元数据记录了文件所有的状态信息

获取元数据

  1. stat(1)命令获取文件元数据
    stat + 文件名
Desktop linraffe$:stat giraffe
  File: giraffe
  Size: 0         	Blocks: 0          IO Block: 4096   regular empty file
Device: 801h/2049d	Inode: 396525      Links: 1
Access: (0644/-rw-r--r--)  Uid: ( 1000/linraffe)   Gid: ( 1000/linraffe)
Access: 2020-03-20 11:59:46.058797586 +0800
Modify: 2020-03-20 11:59:46.058797586 +0800
Change: 2020-03-20 11:59:46.058797586 +0800
 Birth: -

// 这里的Links指硬链接数

  1. stat(2)系统调用获取文件元数据
stat - 获取文件状态信息(元数据)

所需头文件
       #include <sys/types.h>
       #include <sys/stat.h>
       #include <unistd.h>
函数原型
		int stat(const char *pathname, struct stat *statbuf);

参数
pathname - 需要查询元数据的文件路径

statbuf - 函数将文件元数据拷贝到statbuf指向的线性地址

返回值
获取成功,返回0
获取失败,返回-1,errno被设置

存储元数据结构体
           struct stat {
               dev_t     st_dev;         /* ID of device containing file */
               ino_t     st_ino;         /* Inode number */
               mode_t    st_mode;        /* File type and mode */
               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;     /* Block size for filesystem I/O */
               blkcnt_t  st_blocks;      /* Number of 512B blocks allocated */

               /* Since Linux 2.6, the kernel supports nanosecond
                  precision for the following timestamp fields.
                  For the details before Linux 2.6, see NOTES. */

               struct timespec st_atim;  /* Time of last access */
               struct timespec st_mtim;  /* Time of last modification */
               struct timespec st_ctim;  /* Time of last status change */
           };

stat(2)系统调用举例:

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

int main(int argc,char *argv[]){
        struct stat statbuf = {};
        if(stat(argv[1],&statbuf)){
                perror("stat");
                return -1;
        }
        else{
                printf("dev:%ld\n",statbuf.st_dev);
                printf("ino:%ld\n",statbuf.st_ino);
                printf("mod:%d\n",statbuf.st_mode);
                printf("lnk:%ld\n",statbuf.st_nlink);
                printf("uid:%d\n",statbuf.st_uid);
                printf("gid:%d\n",statbuf.st_gid);
        }
        return 0;

}

执行:

Desktop linraffe$:a.out giraffe
dev:2049
ino:396525
mod:33188
lnk:1
uid:1000
gid:1000

可见系统调用stat(2)和命令stat(1)的输出结果一致

元数据相关

1)inode - 系统对文件的编码;每个文件必须有一个inode与之对应,但是每个inode不一定只对应一个文件

2)硬链接文件 - 有相同inode的文件互为硬链接文件;本质就是同一个文件,只是文件名不同,当修改一个硬链接文件,与其有硬链接关系同其他文件也会被修改
创建硬链接方法:
ln 原文件名 要创建的硬链接文件名

3)软链接文件 - 软链接文件的内容是另一个文件的路径,当访问一个软链接文件时,系统会自动将访问者引导向另一个文件
与硬链接文件不同,软链接文件与它指向的文件的inode不同;如果软链接文件所指向的文件被删除,那么软链接文件存储的文件路径就会失效,访问会报错
创建软链接接方法:
ln -s 原文件名 要创建的软链接文件名

inode详细介绍,参见inode详解

stat命令实现

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

void GetFileType(mode_t mode){
        printf("File Type :");
        switch(mode & S_IFMT){
                case S_IFBLK:  printf("block device\n");            break;
                case S_IFCHR:  printf("character device\n");        break;
                case S_IFDIR:  printf("directory\n");               break;
                case S_IFIFO:  printf("FIFO/pipe\n");               break;
                case S_IFLNK:  printf("symlink\n");                 break;
                case S_IFREG:  printf("regular file\n");            break;
                case S_IFSOCK: printf("socket\n");                  break;
                default:       printf("unknown?\n");                break;
        }
        return;
}
void GetFileAccess(mode_t mode){
        printf("Access: (%o/",mode);
        if((mode & S_IRUSR) != 0)
                printf("r");
        else
                printf("-");
        if((mode & S_IWUSR) != 0)
                printf("w");
        else
                printf("-");
        if((mode & S_IXUSR) != 0)
                printf("x");
        else
                printf("-");
        if((mode & S_IRGRP) != 0)
                printf("r");
        else
                printf("-");
        if((mode & S_IWGRP) != 0)
                printf("w");
        else
                printf("-");
        if((mode & S_IXGRP) != 0)
                printf("x");
        else
                printf("-");
        if((mode & S_IROTH) != 0)
                printf("r");
        else
                printf("-");
        if((mode & S_IWOTH) != 0)
                printf("w");
        else
                printf("-");
        if((mode & S_IXOTH) != 0)
                printf("x) \t");
        else
                printf("-) \t");
        return;
}

void GetUid(uid_t uid){
        struct passwd *pwd = getpwuid(uid);
        printf("Uid: (%d/%s) \t",uid,pwd -> pw_name);
        return;
}

void GetGid(gid_t gid){
        struct group * grp = getgrgid(gid);
        printf("Gid: (%d/%s) \n",gid,grp -> gr_name);
        return;
}

void GetTime(struct stat * stat_p){
        printf("Access: %s",ctime(&(stat_p -> st_atim.tv_sec)));
        printf("Modify: %s",ctime(&(stat_p -> st_mtim.tv_sec)));
        printf("Change: %s",ctime(&(stat_p -> st_ctim.tv_sec)));
}

int main(int argc, char *argv[]){
        struct stat statbuf = {};
        if(stat(argv[1],&statbuf)){
                perror("stat");
                return -1;
        }
        else{
                printf("File: %s\n",argv[1]);
                printf("Size: %ld \tBlocks: %ld \tIO Block: %ld\t\t",statbuf.st_size,
                                statbuf.st_blocks,statbuf.st_blksize);
                GetFileType(statbuf.st_mode);
                printf("Device: %ld/%ld \tInode: %ld \tLinks: %ld \n",statbuf.st_rdev,
                                statbuf.st_dev,statbuf.st_ino,statbuf.st_nlink);
                GetFileAccess(statbuf.st_mode);
                GetUid(statbuf.st_uid);
                GetGid(statbuf.st_gid);
                GetTime(&statbuf);
        }
        return 0;
}

编译运行结果:

Desktop linraffe$:gcc MyStat.c -o MyStat
Desktop linraffe$:MyStat giraffe
File: giraffe
Size: 0 	Blocks: 0 	 IO Block: 4096		 File Type :regular file
Device: 0/2049 	Inode: 396525 	Links: 1 
Access: (100644/rw-r--r--) 	Uid: (1000/linraffe) 	Gid: (1000/linraffe) 
Access: Fri Mar 20 13:09:59 2020
Modify: Fri Mar 20 11:59:46 2020
Change: Fri Mar 20 11:59:46 2020


Desktop linraffe$:stat giraffe
  File: giraffe
  Size: 0         	Blocks: 0          IO Block: 4096   regular empty file
Device: 801h/2049d	Inode: 396525      Links: 1
Access: (0644/-rw-r--r--)  Uid: ( 1000/linraffe)   Gid: ( 1000/linraffe)
Access: 2020-03-20 13:09:59.703822557 +0800
Modify: 2020-03-20 11:59:46.058797586 +0800
Change: 2020-03-20 11:59:46.058797586 +0800
 Birth: -

实现中的要点

1)获取用typedef定义的数据类型的实际内置数据类型的技巧
当不清楚一个自定义数据类型所代表的实际数据内置类型时,可以通过gcc -E 获得与编译后的源文件,查找头文件中对自定义数据类型的定义:
打开.i文件后,在vim的普通模式下,输入‘/’+要找的自定义数据类型

2)获取文件类型,并以字符串输出
在stat的说明文档中给出获取文件类型的方式:通过stat结构体中的st_mode成员变量按位与S_IFMT可以的到文件类型

   The file type
   POSIX  refers  to  the stat.st_mode bits corresponding to the mask S_IFMT (see below) as the file type, the 12 bits corresponding to the mask 07777 as the file mode bits and the least significant 9 bits (0777) as the file permission bits.
       The following mask values are defined for the file type:
           S_IFMT     0170000   bit mask for the file type bit field
           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
Thus, to test for a regular file (for example), one could write:
           stat(pathname, &sb);
           if ((sb.st_mode & S_IFMT) == S_IFREG) {
               /* Handle regular file */
           }

3)通过uid获取对应用户名

getpwuid - get password file entry

所需头文件	#include <sys/types.h>
       		#include <pwd.h>
函数原型
       struct passwd *getpwuid(uid_t uid);

参数
uid - 用户的uid

返回值:
获取成功,返回0,并将passwd指针指向用户信息
passwd - 存储用户信息的结构体,成员如下:
           struct passwd {
               char   *pw_name;       /* username */
               char   *pw_passwd;     /* user password */
               uid_t   pw_uid;        /* user ID */
               gid_t   pw_gid;        /* group ID */
               char   *pw_gecos;      /* user information */
               char   *pw_dir;        /* home directory */
               char   *pw_shell;      /* shell program */
           };
获取失败,返回错误码,并将passwd指向NULL

补充:
/etc/passwd 记录了系统中所有用户的信息,这些信息就是从passwd结构体中获取的

4)通过gid获取对应组名

getgrgid - get group file entry

所需头文件	#include <sys/types.h>
       		#include <grp.h>

函数原型
       struct group *getgrgid(gid_t gid);

参数
gid - 要获取信息的组id

返回值
获取成功,返回0,并将group指针指向组信息
group - 存储组信息的结构体,成员如下:
           struct group {
               char   *gr_name;        /* group name */
               char   *gr_passwd;      /* group password */
               gid_t   gr_gid;         /* group ID */
               char  **gr_mem;         /* NULL-terminated array of pointers
                                          to names of group members */
           };
获取失败,返回错误码,group指针置空(指向NULL)

补充:
/etc/group 记录了系统中所有组的信息,这些信息就是从group结构体中获取的

5)以rwx的形式显示文件权限
从stat结构体的st_mode成员变量中可以获取八进制形式的文件权限,将权限转化为字符需要逐个判断每个分组中的读、写、可执行权限

       The following mask values are defined for the file mode component of the st_mode field:
           S_ISUID     04000   set-user-ID bit
           S_ISGID     02000   set-group-ID bit (see below)
           S_ISVTX     01000   sticky bit (see below)

           S_IRWXU     00700   owner has read, write, and execute permission
           S_IRUSR     00400   owner has read permission
           S_IWUSR     00200   owner has write permission
           S_IXUSR     00100   owner has execute permission

           S_IRWXG     00070   group has read, write, and execute permission
           S_IRGRP     00040   group has read permission
           S_IWGRP     00020   group has write permission
           S_IXGRP     00010   group has execute permission

           S_IRWXO     00007   others  (not  in group) have read, write, and
                               execute permission
           S_IROTH     00004   others have read permission

           S_IWOTH     00002   others have write permission
           S_IXOTH     00001   others have execute permission

6)将长整型表示的时间转换为字符串时间
ctime函数将长整型的时间转化为字符串形式的时间

ctime - transform date and time to brokendown time or ASCII

所需头文件 <time.h>

函数原型
       char *ctime(const time_t *timep);

timep - 以长整型记录的时间值变量的地址

返回值
成功,返回一个表示时间的字符串
失败,返回空指针,errno被设置
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值