Linux文件元数据(文件的属性数据)

一、文件的属性

Linux系统下,使用ls -il 命令,会在终端输出类似下面这种结果

676607 drwxr-xr-x 2 admin admin 4096  7月30日 20:00 dir
676599 -rw-r--r-- 1 admin admin    0  7月30日 20:00 file
676602 -rw-r--r-- 1 admin admin    0  7月30日 20:00 test

其中,

  • 第一列 —— 代表文件的inode值,可以找到对应的inode,获取到文件的元数据,ls命令使用-i选项可以查看inode号

  • 第二列 —— 说明文件的类型和权限
    第一个字母代表文件类型:
    d : 目录(文件夹)
    - : 普通文件
    c :字符设备文件
    b :块设备文件
    p :管道文件
    s :socket文件
    l :软连接文件
    后面的9个字符代表权限,分别是
    r - 读
    w - 写
    x - 执行
    每三个一组,分别是属主权限、数组权限和其他用户权限,对应位置为-代表没有对应权限。

  • 第三列 —— 硬链接数量(如果是文件夹,就是文件夹下面的文件数量,新建一个空文件夹,查看时这个值是2,因为每个文件夹下面都有.和…两个路径,)

  • 第四列 —— 属主

  • 第五列 —— 数组

  • 第六列 —— 文件大小,如果是文件夹,那就是4096

  • 第七列 —— 文件的修改时间

  • 第八列 —— 文件名

这些都是文件的元数据,存储在inode信息里面。具体的说明参考下面这个链接
https://www.cnblogs.com/llife/p/11470668.html

1.2 查看文件的全部属性

# stat命令查看文件的全部属性
[root@localhost ~]# stat test.txt
  File: ‘test.txt’
  Size: 18              Blocks: 8          IO Block: 4096   regular file
Device: fd00h/64768d    Inode: 33574994    Links: 1
Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
Context: unconfined_u:object_r:admin_home_t:s0
Access: 2019-08-28 19:55:05.920240744 +0800
Modify: 2019-08-28 19:55:05.920240744 +0800
Change: 2019-08-28 19:55:05.920240744 +0800

其中,时间属性:
ctime:change time是最后一次改变文件或目录(属性)的时间,例如执行chmod,chown等命令。
atime:access time是最后一次访问文件或目录的时间。
mtime:modify time是最后一次修改文件或目录(内容)的时间。

二、软链接和硬链接

2.1 软链接

把文件链接到一个文件,类似于windows下面的快捷方式,使用这个文件实际上是使用指向的那个文件。
如果删除了指向的文件,那么这个链接就无效了。
删除软链接,不影响指向的文件。
软链接的创建:

# 创建软链接linkfile指向srcfile
ln -s srcfile linkfile

2.2 硬链接

硬链接是两个文件具有相同的inode值,也就是引用相同的inode,修改其中一个文件,另一个也会同步修改。
但是删除一个不会对另一个造成影响。删除之后另一个可以正常使用。
硬链接创建:

#创建src的硬链接dst
ln src dst

三、C使用系统调用获取文件的元数据

3.1 记录文件元数据的结构体类型

使用man 2 stat查看对应的手册
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 */

       #define st_atime st_atim.tv_sec      /* Backward compatibility */
       #define st_mtime st_mtim.tv_sec
       #define st_ctime st_ctim.tv_sec

}

3.2 获取文件元数据的函数

原型:
**int stat(const char pathname, struct stat statbuf);
其中:
pathname —— 要获取的文件名
statbuf —— 获取的元数据保存到的对象指针
返回值 —— 成功返回0,失败返回-1,并设置对应的错误码

四、根据uid和gid获取对应的用户和组数据

4.1 用户信息和组信息

  • 用户信息
    Linux下用户信息保存在/etc/passwd里面,
    使用cat /etc/passwd命令查看
    得到如下结果
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin

其中,每一项以:分隔
第一项 —— 表示用户名
第二项 —— x表示有密码
第三项 —— 表示用户id
第四项 —— 表示组id
第五项 —— 表示用户的附加信息,一般是说明性的信息
第六项 —— 表示用户的家目录
第七项 —— 表示用户的默认程序?

Linux下组信息保存在/etc/group里面
使用cat /etc/group命令查看
得到如下结果

root:x:0:
bin:x:1:
daemon:x:2:

其中:
第一项 —— 表示组名
第二项 —— x表示没有密码
第三项 —— 表示组id
第四项 —— 表示组里面的用户(和组名相同的一般默认省略)

4.2 C获取用户和组信息的函数

通过用户id获取用户信息
原型
struct passwd* getpwuid(uid_t uid) -
其中:
uid —— 用户id
返回值 —— struct 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 */
};
这个结构体的成员正好对应/etc/passwd文件的用户信息

通过组id获取组信息
原型
struct group* getgrgid(gid_t gid)
其中:
gid —— 组id
返回值 —— struct 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 */
};
这个结构体的成员正好对应/etc/group文件的组信息

五、获取文件元数据的实例

下面实例简化的实现了ls 指令,其中支持-i -l两个选项
lsm.h —— 头文件

#ifndef _LSM_H_
#define _LSM_H_

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

void on_i(const struct stat *statbuf);

void on_l(const struct stat *statbuf);

void on_h();

#endif // _LSM_H_

lsm.c ——源文件

#include "lsm.h"

void on_i(const struct stat *statbuf)
{
    printf("%u ", statbuf->st_ino);
}

void on_l(const struct stat *statbuf)
{
    // 输出文件类型
    switch (statbuf->st_mode & S_IFMT)
    {
        case S_IFREG:
            printf("-");
            break;
        case S_IFDIR:
            printf("d");
            break;
        case S_IFSOCK:
            printf("s");
            break;
        case S_IFLNK:
            printf("l");
            break;
        case S_IFBLK:
            printf("b");
            break;
        case S_IFCHR:
            printf("c");
            break;
        case S_IFIFO:
            printf("f");
            break;
        default:
            break;
    }
    // 输出文件权限
    char ur = ((statbuf->st_mode & S_IRWXU) & S_IRUSR) ? 'r' : '-';
    char uw = ((statbuf->st_mode & S_IRWXU) & S_IWUSR) ? 'w' : '-';
    char ux = ((statbuf->st_mode & S_IRWXU) & S_IXUSR) ? 'x' : '-';
    char gr = ((statbuf->st_mode & S_IRWXG) & S_IRGRP) ? 'r' : '-';
    char gw = ((statbuf->st_mode & S_IRWXG) & S_IWGRP) ? 'w' : '-';
    char gx = ((statbuf->st_mode & S_IRWXG) & S_IXGRP) ? 'x' : '-';
    char otr = ((statbuf->st_mode & S_IRWXO) & S_IROTH) ? 'r' : '-';
    char otw = ((statbuf->st_mode & S_IRWXO) & S_IWOTH) ? 'w' : '-';
    char otx = ((statbuf->st_mode & S_IRWXO) & S_IXOTH) ? 'x' : '-';
    printf("%c%c%c%c%c%c%c%c%c", ur, uw, ux, gr, gw, gx, otr, otw, otx);
    // 输出文件链接数
    printf(" %u", statbuf->st_nlink);
    // 输出用户名
    struct passwd *pw = getpwuid(statbuf->st_uid);
    printf(" %s", pw->pw_name);
    // 输出组名
    struct group *grp = getgrgid(statbuf->st_gid);
    printf(" %s", grp->gr_name);
    // 输出文件大小
    printf(" %ld", statbuf->st_size);
    // 输出文件修改时间
    char buf[1024];
    strcpy(buf,ctime(&statbuf->st_atime));
    size_t len = strlen(buf);
    for (size_t i = len -2; i<len;++i)
    {
        if (buf[i] == '\n')
        {
            buf[i] = '\0';
        }
    }
    printf(" %s ", buf);
}

void on_h()
{
    printf("help:\n");
    printf("the first arg must be file name which you want to watch\n");
    printf("-h or --help for help tips of using this command\n");
    printf("-i or --inod for printf the inode of the file\n");
    printf("-l or --list for list the info of the file\n");
}

main文件 —— 完成对命令行参数的处理

#include "lsm.h"
#include <stdbool.h>

int main(int argc, char *argv[])
{
    if (argc < 2)
    {
        printf("参数不足,请输入文件名\n");
        return -1;
    }
    struct stat statbuf;
// 命令行参数和命令选项的区分不是十分清楚,所以这里用了两个bool类型的变量来记录是否有对应的选项,后面根据这两个标志进行相应的选项的操作
    bool b_i = false;
    bool b_l = false;
    struct option longopt[] = {
        {"inode", 0, NULL, 'i'},
        {"list", 0, NULL, 'l'},
        {"help", 0, NULL, 'h'},
        {NULL, 0, NULL, 0}
    };
    const char *shortopt = "ilh"; 
    int opt = getopt_long(argc, argv, shortopt, longopt, NULL);
    while (opt != -1)
    {
        switch (opt)
        {
            case 'h':
                on_h();
                return 0;
                break;
            case 'i':
                b_i = true;
                break;
            case 'l':
                b_l = true;
                break;
            case '?':
                printf("未知参数\n");
                on_h();
                return 0;
                break;
            default:
                break;
        }
        opt = getopt_long(argc, argv, shortopt, longopt, NULL);
    }
    if (b_i || b_l)
    {
        int res = stat(argv[argc - 1], &statbuf);
        if (res == -1)
        {
            perror(argv[argc - 1]);
            return -1;
        }
        if (b_i)
        {
            on_i(&statbuf);
        }
        if (b_l)
        {
            on_l(&statbuf);
        }
    }
    printf("%s\n", argv[argc - 1]);
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值