欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  科技

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

程序员文章站 2022-07-09 22:04:34
0 个人信息 张樱姿 201821121038 计算1812 1 实验目的 通过编程进一步了解文件系统。 2 实验内容 在服务器上用Vim编写一个程序:实现Linux系统命令ls -lai的功能 给出运行结果截图,对于每一列是如何获取的,结合源代码做解释 3 实验报告 3.1 ls -lai简介 l ......

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%s\033[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%s\033[0m ",name);
 74             else       //其他用户,文件名显示为绿色
 75                 printf("\33[1;32m%s\033[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\n",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("\n");
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("\n");
191     closedir(dir);
192 }

  3.4 分析结果

    3.4.1 ls -lai运行结果:

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

 

 

     3.4.2 ./myls -lai运行结果:

操作系统第四次实验报告——文件系统之使用LinuxAPI实现ls -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