• Linux下文件属性


    ++++++++++++++++++++++++++++++++++++++++++

    本文系本站原创,欢迎转载! 转载请注明出处:

    http://blog.csdn.net/mr_raptor/article/details/6844692

    ++++++++++++++++++++++++++++++++++++++++++

       当我们用ls –l filename,这个shell命令时,会打印出,文件的详细信息,如下图:

    这些文件的详细信息是存放在一个结构体stat里面的,当文件系统运行起来后,它从磁盘里面将文件详细信息加载到内核空间内存里,用户空间可以通过系统调用函数stat(),fstat()来取得这个结构体的信息。

    Stat结构体:

    struct stat {

                  dev_t     st_dev;       /* 文件系统设备号 */

                  ino_t     st_ino;        /* i结点号 */

                  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;      /* 块大小 */

                  blkcnt_t  st_blocks;      /* 文件所占块个数 */

                  time_t    st_atime;      /* 上次访问时间 */

                  time_t    st_mtime;     /* 上次修改时间 */

                  time_t    st_ctime;       /* 上次文件状态修改时间 */

    };   

    首先,其类型被typedef过了,因此看不出其类型来,可以通过grep命令来查看(具体操作看第一节),我们对比着上图文件信息来看,基本上这一个结构体,将整个的文件的基本信息都包含了,通过读取这个结构体,就能实现一个简单的ls –l的shell命令了。

    Stat函数

    #include <sys/types.h>

    #include <sys/stat.h>

    #include <unistd.h>

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

    功能:查看文件或目录属性

    参数:path是文件的路径, buf就是stat结构体的指针。

    返回值:成功返回0,错误返回-1

    现在通过这个函数我们可以取得stat结构体了,那么通过读结构体就能得到ls –l 一样的效果了。

    我们来看一个例子:

    #include <stdio.h>

    #include <sys/stat.h>

    int main(int argc, char * argv[])

    {

            if(argc != 2) {

                    printf("Usage: <pathname>\n");

            }

            int i = 0;

            struct stat buf;

            if(stat(argv[1], &buf) < 0) {

                    perror("stat");

            }

            printf("%d %d %d %d %d %d %s\n", buf.st_mode,

                    buf.st_nlink, buf.st_uid, buf.st_gid,

                    buf.st_size, buf.st_atime, argv[1]);

            return 0;

    }

    运行结果:

    我们发现,除了硬链接数,文件大小,文件名一样,其它全部都不一样。

    看来还有很多东西要处理下,我们来分析下。

    首先是st_mode,它是一个int型的成员,而ls –l显示出来是字符串

    st_uid, st_gid这两个也是int型成员,而ls是用户名

    日期就更没有谱了,完全不一样。这些问题我们一一解决。

    先来看st_mode。

    S_ISUID              执行时设置-用户- I D

    S_ISGID              执行时设置-组- I D

    S_ISVTX             保存正文

    S_IRWXU            用户(所有者)读、写和执行

    S_IRUSR             用户(所有者)读

    S_IWUSR            用户(所有者)写

    S_IXUSR             用户(所有者)执行

    S_IRWXG            组读、写和执行

    S_IRGRP              组读

    S_IWGRP             组写

    S_IXGRP             组执行

    S_IRWXO            其他读、写和执行

    S_IROTH             其他读

    S_IWOTH            其他写

    S_IXOTH             其他执行

    这些权限在前面的open时,就有学过,它们都是用的一套宏定义。

    我们用grep得到其值,再转化成二进制分别为:

     

    由此图我们可以轻易的看出,其实每一个权限位对应一个bit,当该比特为1证明拥有此权限,为0,没有权限,这也能说明,当时为什么我们用chomod 修改用户权限时,加上777表示拥有全部权限。

    因此我们要想实现ls –l显示文件权限功能,只要将其mode值和对应标志相与即可判断出是否具有权限。

    if( buf.st_mode & S_IRUSR )

           putchar(‘r’);

    else

           putchar(‘-‘);

    我们要注意下,如果用ls –l 目录名,那么权限位第一位上显示是d,如果是文件其显示的是-,这也说明,我们还要去判断一个文件的类型。其原理和上面文件权限非常相似。

     

    因此我们也可以用类似的方法得到其类型:

           if( buf.st_mode & S_IFREG )

                  putchar(‘-’);

    if( buf.st_mode & S_IFDIR )

                  putchar(‘d‘);

    但是系统给我们已经提供了几个宏,如下:

     

    因此可以通过这几个宏来代替我们的与运算:

           if(S_ISREG(buf.st_mode)

                  putchar(‘-‘);

           if(S_ISDIR(buf.st_mode)

                  putchar(‘d‘);

    通过上面对st_mode成员的分析我们可以得出这样的结论,st_mode用了16个bit来表示一个文件的类型和权限,这样又节省了内存资源,运用位运算还能加快其运算速度。总结一下如下图:

     

    现在我们来看怎样取得用户名。

    我们通过st_uid和st_gid可以取得主人用户ID和组ID,我们应该还记得在刚开始学习linux基本操作和shell编程的时候,有说到,/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

    它们都用 : 分开来的,其中,第一个是用户名,第三个是其对应的用户ID,我们可以通过读取passwd文件内容来取出对应的用户名。通过读取/etc/group文件来取得组名。

    如果你不想去这样写这个函数,我们的系统调用接口也提供了这样一个通过ID取其用户名和组名的函数:

    getpwuid();

    getgrgid();

    这两个函数的具体的用法自己去man 吧,要不就自己通过读passwd的方法来取。嘿嘿!

    最后一个,显示时间。

    这个要了解一个Linux里面的时间机制,系统里面的时间是用一个很大的数来表示的,它是指的从1970年1月1日(UTC)开始到当前时间所经过的秒数,因此它是个很大的数,既然它是个秒数,那我们就能把它转化成当前的时间,这个我们直接使用库函数就行了。因为时间的显示格式有很多种,因此要对转化后的日期时间也要转化下。

    localtime()将秒数时间转化成一个本地时区的时间结构体,再通过strftime()将时间以格式打印出日期来。这儿也自己去man 一下。

    进阶篇

    我们通过上面所讲的可以写出一个最简单的ls –l 的命令了,但是还有很多细节没有考虑到,看下面:

    上面的test.txt文件,当它的用户权限拥有执行权限时,设置它的s位,那么显示的是小写s,当用户权限没有执行权限时,它的s位是大写的S,因此这儿也要将我们的ls –l再进一步的修改。同样t位也用同样的方式显示。

    当我们将修改用户主人时,可以指定一个uid,比如下面,设置文件的主人是uid为9999的主人,但是以9999为用户id的用户并不存在,系统ls 会像下面这样显示,直接显示出它的uid并不会显示其用户名。

     

    当显示一个文件的详细信息时,如果这是一个普通文件,没有什么问题,但是如果当前文件是一个链接文件的话,系统的ls会像下面那样显示:

     

    它打印的是(链接文件)的详细信息,后面跟出了链接文件指向的文件(Linux里面的链接文件和我们windows里的快捷方式很相似)这儿就要多考虑一点了,如果当前文件是一个链接文件,还要打印出,这个链接文件所指向的文件。这儿用到readlink系统调用,这个自己去man 一下,very easy。

           当显示多个文件的时候,我们注意一下系统ls –l 它总是排列的很整齐,可见,它在打印信息的时候,取的当前列里最长的字符的长度打印的,同时还有它的文件名是按照降序排列的。

    ++++++++++++++++++++++++++++++++++++++++++

    本文系本站原创,欢迎转载! 转载请注明出处:

    http://blog.csdn.net/mr_raptor/article/details/6844692

    ++++++++++++++++++++++++++++++++++++++++++

  • 相关阅读:
    mybatis中大于等于小于等于的写法
    RandomAccess接口
    ArrayList源码解析
    使用Docker搭建MySQL主从复制(一主一从)
    狂神Docker视频学习笔记(基础篇)
    【JQ】jQuery实现将div中滚动条滚动到指定位置的方法
    JAVA线程池的基本使用
    史上最全的Java技术体系思维导图,没有之一!
    springboot整合kafka
    spring cloud alibaba 分布式事务解决方案之seata-1.3.0
  • 原文地址:https://www.cnblogs.com/javawebsoa/p/2458052.html
Copyright © 2020-2023  润新知