操作系统第4次实验报告:文件系统

  • 姓名:毛琳淇
  • 学号201821121007
  • 班级计算1811

1. 编写程序

在服务器上用Vim编写一个程序:实现Linux系统命令ls -lai的功能,给出源代码。

ls -l 以长格式显示目录下的内容列表。输出的信息从左到右依次包括文件名,文件类型、权限模式、硬连接数、所有者、组、文件大小和文件的最后修改时间等

ls -a 显示所有档案及目录(ls内定将档案名或目录名称为“.”的视为影藏,不会列出)

ls -i 显示文件索引节点号(inode number,一个索引节点代表一个文件

 

 

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<dirent.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<fcntl.h>
#include<time.h>
#include<pwd.h>
#include<grp.h>
void error_printf(const char* );
void list_dir(const char* );
void list_message(const char* , const struct stat*);

void file_type(const struct stat* );
void file_power(const struct stat* );
void file_id(const struct stat* );
void file_mtime(const struct stat* );
void link_printf(const char* );
void error_printf(const char* funname)
{
    perror(funname);
    exit(EXIT_FAILURE);
    /*
    * EXIT_SUCCESS和EXIT_FAILURE是两个常量。
    * EXIT_SUCCESS=0,EXIT_FAILURE=1。
    * 0表示程序寿终正寝,1表示死于非命。
    */
}

void list_dir(const char* pathname)
{
    DIR* ret_opendir = opendir(pathname); // 打开目录"pathname"
    if(ret_opendir == NULL)
        error_printf("opendir");
    int ret_chdir = chdir(pathname); // 改变工作目录至"pathname",便于stat函数的使用
    if(ret_chdir == -1)
        error_printf("chdir");
    struct dirent* ret_readdir = NULL; // 定义readdir函数返回的结构体变量
    while(ret_readdir = readdir(ret_opendir)) // 判断是否读取到目录尾
    {
        char* filename = ret_readdir->d_name; // 获取文件名
        struct stat file_message = {}; // 定义stat函数返回的结构体变量
        int ret_stat = lstat(filename, &file_message); // 获取文件信息
        if(ret_stat == -1) // stat读取文件错误则输出提示信息
            printf("%s error!", filename);
        else if(strcmp(filename,".") && strcmp(filename,"..")) // 不输出当前目录与上一级目录
            list_message(filename, &file_message);
    }
}
void list_message(const char* filename, const struct stat* file_message)
{  
    file_type(file_message); // 判断打印文件类型
 printf("%d ",(int)file_message->st_ino);//添加索引号
    file_power(file_message); // 判断并打印文件权限
    printf("%d ", file_message->st_nlink); // 打印硬链接数
    file_id(file_message); // 转换并打印用户id与组id
    printf("%5ld ", file_message->st_size); // 打印文件大小
    file_mtime(file_message); // 打印文件最后修改时间
    printf("%s ", filename); // 打印文件名
    if(S_ISLNK(file_message->st_mode)) // 如果是软链接文件,打印其指向的位置
        link_printf(filename);
    puts("");
}
void file_type(const struct stat* file_message)
{
    mode_t mode = file_message->st_mode;
    if     (S_ISREG(mode))  printf("-"); // 普通文件
    else if(S_ISDIR(mode))  printf("d"); // 目录文件
    else if(S_ISCHR(mode))  printf("c"); // 字符设备文件
    else if(S_ISBLK(mode))  printf("b"); // 块设备文件
    else if(S_ISFIFO(mode)) printf("p"); // 管道文件
    else if(S_ISLNK(mode))  printf("l"); // 链接文件
    else                    printf("s"); // socket文件
}
void file_power(const struct stat* file_message)
{
    mode_t mode = file_message->st_mode;

    printf("%c", mode&S_IRUSR?'r':'-');
    printf("%c", mode&S_IWUSR?'w':'-');
    printf("%c", mode&S_IXUSR?'x':'-');

    printf("%c", mode&S_IRGRP?'r':'-');
    printf("%c", mode&S_IWGRP?'w':'-');
    printf("%c", mode&S_IXGRP?'x':'-');
    printf("%c", mode&S_IROTH?'r':'-');
    printf("%c", mode&S_IWOTH?'w':'-');
    printf("%c ", mode&S_IXOTH?'x':'-');
}
void file_id(const struct stat* file_message)
{
    struct passwd* pwd;
    pwd = getpwuid(file_message->st_uid);
    printf("%s ",pwd->pw_name);
    struct group* grp;
    grp = getgrgid(file_message->st_gid);
    printf("%s ",grp->gr_name);
  
}
void file_mtime(const struct stat* file_message)
{
    struct tm* t = localtime(&file_message->st_mtime);
    printf("%2d月 %2d %02d:%02d ", t->tm_mon+1, t->tm_mday, t->tm_hour, t->tm_min);
}
void link_printf(const char* filename)
{
    char buf[1024] = "123";
    if(0 == readlink(filename, buf, sizeof(buf)))
        error_printf("readlink");
    printf("-> %s ",buf);
}
 int main()
 { char path[1024] = {};
strcpy(path,"./");
 struct stat file_message = {};
int ret_stat = lstat(path, &file_message);
if(ret_stat == -1)
error_printf("stat");
if(S_ISDIR(file_message.st_mode)) // 判断是否为目录
 list_dir(path);
else
list_message(path, &file_message);
 return 0;
 }

2. 分析运行结果

给出运行结果截图,对于每一列是如何获取的,结合源代码做解释

suqiankun@jmu-cs-ubuntu:~$ ls -lai

total 160

920635 drwx------   6 suqiankun ubuntu  4096 Apr 27 09:52

.131195 drwxr-xr-x 129 root      root    4096 Apr 25 21:52 ..

920658 -rw-------   1 suqiankun ubuntu 10359 Apr 27 10:38 .bash_history

920636 -rw-r--r--   1 suqiankun ubuntu   220 Apr  5  2018 .bash_logout

920638 -rw-r--r--   1 suqiankun ubuntu  3771 Apr  5  2018 .bashrc

920656 drwx------   2 suqiankun ubuntu  4096 Mar 11 16:01 .cache

执行代码:

 

 

第一个字段为文件索引号,通过st_mode查找。

printf("%d\t",file_message->st_ino);

第二个字段为文件权限,首字符为文件类型,后面九个字符三个为一组,分别代表本人权限,组员权限,他人权限。通过文件索引号查找

void file_type(const struct stat* file_message)

void file_power(const struct stat* file_message)

通过这两个函数实现

第三个字段为硬连接个数,通过st_nlink查询。

printf("%d ", file_message->st_nlink);

第四个字段为文件在etc/passwd文件中对应的用户信息。通过getpwuid(stat.st_uid)查询。

pwd = getpwuid(file_message->st_uid);

  printf("%s ",pwd->pw_name);

第五个数据为文件对应的组信息,通过getgrgid(stat.st_gid)可以查询到。

grp = getgrgid(file_message->st_gid);
 printf("%s ",grp->gr_name);

第六个为文件大小st_size

printf("%5ld ", file_message->st_size);

第七个为文件上一次被修改的时间,通过st_mtime可以反映该信息。

void file_mtime(const struct stat* file_message)

通过此函数实现

第八个为文件名。

printf("%s ", filename);

 

posted @ 2020-04-30 20:35  my7in7i  阅读(229)  评论(0编辑  收藏  举报