• 操作系统第四次实验报告——文件系统之使用LinuxAPI实现ls -lai命令


    0 个人信息

    • 张樱姿
    • 201821121038
    • 计算1812

    1 实验目的

    • 通过编程进一步了解文件系统。

    2 实验内容

    • 在服务器上用Vim编写一个程序:实现Linux系统命令ls -lai的功能
    • 给出运行结果截图,对于每一列是如何获取的,结合源代码做解释

    3 实验报告

      3.1 ls -lai简介

    ls -l   #以长格式显示目录下的内容列表。输出的信息从左到右依次包括文件名,文件类型、权限模式、硬连接数、所有者、组、文件大小和文件的最后修改时间等
    ls -a   #显示所有档案及目录(ls内定将档案名或目录名称为“.”的视为影藏,不会列出)
    ls -i   #显示文件索引节点号(inode number),一个索引节点代表一个文件

      3.2 实现过程

        3.2.1 获取文件信息的函数及文件信息结构体

         stat函数:

    #include<sys/stat.h>
    int stat(const char * path,struct stat * buf); /*将path参数(文件或目录)的文件信息写到buf中,buf为传出参数*/

         stat结构体:

    struct stat{
        dev_t st_dev;            //设备id号(无需用到)
        ino_t st_ino;            //索引节点号
        mode_t st_mode;          //权限与文件类型
        nlink_t st_nlink;        //硬链接数
        uid_t st_uid;            //用户id
        ggid_t st_gid;           //所在组id
        dev_t st_rdev;           //设备id,对于特殊文件才有(无需用到)
        off_t st_size;           //大小,较为常用
        blksize_t st_blocks;     //文件系统I/O的块大小(无需用到)
        blkcnt_t st_blksize;     //分配的512B(扇区)块数(无需用到)
        time_t st_atime;         //最后的访问时间(无需用到)
        time_t st_mtime;         //最后的修改时间,较为常用
        time_t st_ctime;         //最后的状态改变时间(无需用到)
    }                    

           因此,需对上述相应字段格式化处理。

        3.2.2 mode权限与类型判断

         判断文件类型的宏函数:

        S_ISREG(m)  is it a regular file?  //判断是否是普通文件
        S_ISDIR(m)  directory?             //判断是否是目录
        S_ISCHR(m)  character device?      //判断是否是字符设备
        S_ISBLK(m)  block device?          //判断是否是块设备
        S_ISFIFO(m) FIFO (named pipe)?     //判断是否是管道文件
        S_ISLNK(m)  symbolic link? (Not in POSIX.1-1996.)//判断使是否是符号链接(软连接)
        S_ISSOCK(m) socket? (Not in POSIX.1-1996.)       //判断是否是SOCKET文件

         文件权限宏变量:

            S_IRUSR     00400     //用户有读权限
            S_IWUSR     00200     //用户有写权限
            S_IXUSR     00100     //用户有执行权限
            S_IRGRP     00040     //组有读权限
            S_IWGRP     00020     //组有写权限
            S_IXGRP     00010     //组有执行权限
            S_IROTH     00004     //其他人有读权限
            S_IWOTH     00002     //其他人有写权限
            S_IXOTH     00001     //其他人有可执行权限       

        3.2.3 目录操作函数及目录信息结构体

         opendir函数及readdir函数:

    DIR * opendir(const char * name);    //打开一个目录
    struct dirent * readdir(DIR *);      //读目录,依次返回目录的子项

          dirent结构体:

    struct dirent{
        ino_t d_ino;    //子项的i节点
        off_t d_off;    //节点的偏移量
        unsigned short d_reclen;//长度
        unsigned char d_type;   //子项类型(常用)
        char d_name[256];       //子文件名(常用)
    };

        3.2.4 表示时间的方式

         ①秒差形式,1970年1月1日0时0分0秒的秒数差,得到的类型为time_t;

        ②结构形式,tm结构体:

    struct tm{
        int tm_sec;  //Second [0,60].包含闰秒
        int tm_min;  //Minutes [0,59].
        int tm_hour; //Hour [0,23].
        int tm_mday; //Day of month [1,31].
        int tm_mon;  //Month of year [0,11].(January = 0)
        int tm_year; //Year Since 1900.
        int tm_wday; //Day of week [0,6] (Sunday = 0).
        int tm_yday; //Day of year [0,365].包含闰年
        int tm_isdat;//Daylight Savings flag
    }

        计算机大多数情况使用time_t,因为效率高。但是显示时为tm结构形式。localtime()函数可以实现: time_t 到 tm 的转换。time_t的指针做参数,返回值tm的指针。

      3.3 源代码

      1 #include<stdio.h>
      2 #include<stdlib.h>
      3 #include<string.h>
      4 #include<time.h>
      5 #include<unistd.h>
      6 #include<sys/types.h>
      7 #include<dirent.h>
      8 #include<grp.h>
      9 #include<pwd.h>
     10 #include<errno.h>
     11 #include<sys/stat.h>
     12 #include<limits.h>
     13 #include<assert.h>
     14 
     15 int flag = 0;
     16 //用于分析参数
     17 void AnalPara(int argc,char *argv[],char *path)
     18 {
     19     int i = 0;
     20     for(i = 1;i < argc; ++i)
     21     {    //如果argv[i]中第一个字符是'-',则判断是l a i中的哪些
     22         if(strncmp(argv[i],"-",1)==0)
     23         {
     24             //参数为a时,把1赋值给flag,flag所在内存中第一个位置为1
     25             if(strstr(argv[i],"a") != NULL)
     26             {
     27                 flag |= 1 << 0; ////-a参数显示该隐藏文件
     28             }
     29             //参数为l时,第二个位置为1
     30             if(strstr(argv[i],"l") != NULL)
     31             {
     32                 flag |= 1 << 1;    //-l参数显示该文件的详细信息
     33             }
     34             //参数为i时,第三个位置为1
     35             if(strstr(argv[i],"i") != NULL)
     36             {
     37                 flag |= 1 << 2;    //-i参数显示该文件的inode number
     38             }
     39             //位运算可使用一个变量同时标记多个参数是否传递
     40         }
     41         //如果argv[i]中第一个字符不是'-',则判断所给路径是直接路径还是间接路径
     42         else
     43         {
     44             //直接路径,copy到path字符数组中
     45             if(strncmp(argv[i],"/",1) == 0)
     46             {
     47                 strcpy(path,argv[i]);
     48             }
     49             //间接路径,将当前路径与所给路径连接
     50             else
     51             {
     52                 strcat(path,"/");
     53                 strcat(path,argv[i]);
     54             }
     55         }
     56     }
     57 }
     58 //用于输出文件名
     59 void PrintfFileName(int mode,int uid,char *name)
     60 {
     61     //是目录文件
     62     if(S_ISDIR(mode))
     63     {
     64         //文件名显示为蓝色
     65         printf("33[1;34m%s33[0m ",name);
     66     }
     67     //是普通文件
     68     else if(S_ISREG(mode))
     69     {
     70         if(mode & S_IXUSR||mode & S_IXGRP||mode & S_IXOTH)
     71         {
     72             if(uid==0) //属主用户,文件名显示为红色
     73                 printf("33[41;37m%s33[0m ",name);
     74             else       //其他用户,文件名显示为绿色
     75                 printf("33[1;32m%s33[0m ",name);
     76         }
     77         else
     78         {
     79             printf("%s ",name);
     80         }
     81     }
     82     else
     83     {
     84         printf("%s ",name);
     85     }
     86 }
     87 //用于输出文件详细信息
     88 void PrintMoreInfo(int mode,struct stat st)
     89 {    //文件权限判断
     90     char str[10] = {"----------"};
     91 
     92     if(S_ISDIR(mode)) str[0] = 'd';
     93     if(S_ISCHR(mode)) str[0] = 'c';
     94     if(S_ISBLK(mode)) str[0] = 'b';
     95 
     96     if(mode & S_IRUSR) str[1] = 'r';
     97     if(mode & S_IWUSR) str[2] = 'w';
     98     if(mode & S_IXUSR) str[3] = 'x';
     99 
    100     if(mode & S_IRGRP) str[4] = 'r';
    101     if(mode & S_IWGRP) str[5] = 'w';
    102     if(mode & S_IXGRP) str[6] = 'x';
    103 
    104     if(mode & S_IROTH) str[7] = 'r';
    105     if(mode & S_IWOTH) str[8] = 'w';
    106     if(mode & S_IXOTH) str[9] = 'x';
    107 
    108     int i = 0;
    109     for(; i < 10; i++)
    110     {
    111         printf("%c",str[i]);
    112     }
    113     printf(". ");
    114     printf("%ld ",st.st_nlink);
    115     //输出属主
    116     struct passwd *pd = getpwuid(st.st_uid);
    117     assert(pd != NULL);
    118     printf("%4s ",pd->pw_name);
    119     //输出组用户
    120     struct group *gp = getgrgid(st.st_gid);
    121     assert(gp != NULL);
    122     printf("%4s ",gp->gr_name);
    123     //输出文件大小
    124     printf("%4ld ",st.st_size);
    125     //输出最近操作时间
    126     struct tm * lchangetime = localtime(&(st.st_mtime));
    127     printf("%d %d %d:%d ",(lchangetime->tm_mon+1),lchangetime->tm_mday,lchangetime->tm_hour,lchangetime->tm_min);
    128 }
    129 
    130 int main(int argc,char *argv[])
    131 {
    132     char path[128]={0};
    133     //获取当前路径
    134     getcwd(path,127);
    135     //参数分析函数
    136     AnalPara(argc,argv,path);
    137     //打开该目录并建立一个目录流
    138     DIR *dir = opendir(path);
    139     if(dir == NULL)
    140     {
    141         char *p = path + strlen(path);
    142         while(*p != '/')
    143             p--;
    144         p++;
    145         printf("ls:can not access %s:No such file or directory
    ",p);
    146         exit(0);
    147     }
    148     //需要使用dirent结构体中的文件名和文件的inode number
    149     struct dirent *dr = NULL;
    150     //调用readdir函数获取该目录中的目录项
    151     while((dr = readdir(dir)) != NULL)
    152     {    
    153         //当文件名第一个字符是.时,为隐藏文件,不输出
    154         if(((flag&1)==0) && (strncmp(dr->d_name,".",1) == 0))
    155         {
    156             continue;
    157         }
    158 
    159         struct stat st;
    160         char temp[128] = {0};
    161         strcpy(temp,path);
    162         strcat(temp,"/");
    163         strcat(temp,dr->d_name);
    164         stat(temp,&st);
    165         //-li
    166         if ((flag&2)==2)
    167         {
    168             //有参数i
    169             if((flag&4)==4)
    170             {
    171                 printf("%ld  ",st.st_ino);
    172             }
    173             //有参数l
    174             PrintMoreInfo(st.st_mode,st);
    175             PrintfFileName(st.st_mode,st.st_uid,dr->d_name);
    176             printf("
    ");
    177             continue;
    178         }
    179         //-ai
    180         if((flag&4)==4)
    181         {
    182             printf("%ld  ",dr->d_ino);
    183             PrintfFileName(st.st_mode,st.st_uid,dr->d_name);
    184             continue;
    185         }
    186         //-a
    187         PrintfFileName(st.st_mode,st.st_uid,dr->d_name);
    188     }
    189     if(argc == 1||(argc >1&&flag == 0))
    190         printf("
    ");
    191     closedir(dir);
    192 }

      3.4 分析结果

        3.4.1 ls -lai运行结果:

         3.4.2 ./myls -lai运行结果:

         3.4.3 分析输出格式:

        第一列为文件/目录的索引编号(inode number),如果是目录,则使用dirent结构体中的d_ino获取;如果是文件,则使用stat结构体中的st_ino获取。

        第二列为文件的权限,第一位的-表示不同的文件类型(普通文件,管道文件)。后面九位分别表示,该文件的属主,组用户和其他用户的读、写、执行三种不同的权限。

        第三列为文件的硬链接数,如果是一个目录,则第2字段表示该目录所含子目录的个数。使用stat结构体中的st_nlink获取。

        第四列为属主用户,使用stat结构体中的st_uid获取。

        第五列为组用户,使用stat结构体中的st_gid获取。

        第六列为文件所占用的大小,以字节为单位,如果是目录文件,则表示该目录的大小,而不是该目录下所有文件的大小。使用stat结构体中的st_size获取。

        第七列为最后修改时间,使用stat结构体中的st_mtime获取。

        第八列为文件名,使用dirent结构体中的d_name获取。

    4 References

     

  • 相关阅读:
    发送邮件
    php防止表单重复提交
    mysql 优化之注意
    mysqldump
    项目中下拉框链接问题
    css在IE和Firefox下的兼容性
    利用curl并发来提高页面访问速度
    修改linux下mysql目录权限
    ajax跨域
    wireshark抓包
  • 原文地址:https://www.cnblogs.com/MilkoSilver/p/12806078.html
Copyright © 2020-2023  润新知