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

  • 姓名:林顺达
  • 学号:201821121022
  • 班级:计算1811

1. 编写程序

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

 源代码:

#include<stdio.h>
#include<string.h>
#include<sys/types.h>
#include<dirent.h>
#include<sys/stat.h>
#include<grp.h>
#include<pwd.h>

void do_ls(char []);
void dostat(char *);
void show_file_info(char *, struct stat *);
void mode_to_letters(int mode, char str[]);
char *uid_to_name(uid_t uid);
char *gid_to_name(gid_t gid);

int main(int argc, char **argv)
{
    if (argc == 1)
    {
        do_ls(".");
    }
    else
    {
        while (--argc)
        {
            printf("%s:\n", *++argv);
            do_ls(*argv);
        }
    }
    return 0;
}

void do_ls(char dirname[])
{
    DIR *dir_ptr;
    struct dirent *direntp;

    if ((dir_ptr = opendir(dirname)) == NULL)
    {
        fprintf(stderr, "ls2: cannot open %s\n", dirname);
    }
    else
    {
        while((direntp = readdir(dir_ptr)) != NULL)
        {
            dostat(direntp->d_name);
        }
        closedir(dir_ptr);
    }
}

void dostat(char *filename)
{
    struct stat info;
    if (stat(filename, &info) == -1)
    {
        perror(filename);
    }
    else
    {
        show_file_info(filename, &info);
    }
}

void show_file_info(char *filename, struct stat *info_p)
{
    char *uid_to_name(), *ctime(), *gid_to_name();
    void mode_to_letters();
    char modestr[11];

    mode_to_letters(info_p->st_mode, modestr);
    printf("%d ",(int)info_p->st_ino);
    printf("%s",modestr);
    printf("%4d ",(int)info_p->st_nlink);
    printf("%-8s ", uid_to_name(info_p->st_uid));
    printf("%-8s ", gid_to_name(info_p->st_gid));
    printf("%8ld ", (long)info_p->st_size);
    printf("%.12s ", 4 + ctime(&info_p->st_mtime));
    printf("%s\n", filename);
}

void mode_to_letters(int mode, char str[])
{
    strcpy(str, "-----------");

    if (S_ISDIR(mode))    str[0] = 'd';
    if (S_ISCHR(mode))    str[0] = 'c';
    if (S_ISBLK(mode))    str[0] = 'b';

    if (mode & S_IRUSR)    str[1] = 'r';
    if (mode & S_IWUSR) str[2] = 'w';
    if (mode & S_IXUSR)    str[3] = 'x';

    if (mode & S_IRGRP)    str[4] = 'r';
    if (mode & S_IWGRP)    str[5] = 'w';
    if (mode & S_IXGRP) str[6] = 'x';

    if (mode & S_IROTH) str[7] = 'r';
    if (mode & S_IWOTH)    str[8] = 'w';
    if (mode & S_IXOTH)    str[9] = 'x';
}

char *uid_to_name(uid_t uid)
{
    struct passwd * getpwuid(), *pw_ptr;
    static char numstr[10];

    if ((pw_ptr = getpwuid(uid)) == NULL)
    {
        sprintf(numstr, "%d", uid);
        return numstr;
    }
    else
    {
        return pw_ptr->pw_name;
    }
}

char *gid_to_name(gid_t gid)
{
    struct group *getgrgid(), *grp_ptr;
    static char numstr[10];

    if ((grp_ptr = getgrgid(gid)) == NULL)
    {
        sprintf(numstr, "%d", gid);
        return numstr;
    }
    else
    {
        return grp_ptr->gr_name;
    }
}

分析:

ls -(参数)常用指令:

  -a或--all   下所有文件和目录。
  -A或--almost-all   显示所有文件和目录,但不显示现行目录和上层目录。
  -b或--escape   显示脱离字符。
  -B或--ignore-backups   忽略备份文件和目录。
  -c   以更改时间排序,显示文件和目录。
  -C   以又上至下,从左到右的直行方式显示文件和目录名称。
  -d或--directory   显示目录名称而非其内容。
  -D或--dired   用Emacs的模式产生文件和目录列表。
  -f   此参数的效果和同时指定"aU"参数相同,并关闭"lst"参数的效果。
  -F或--classify   在执行文件,目录,Socket,符号连接,管道名称后面,各自加上"*","/","=","@","|"号。
  -g   次参数将忽略不予处理。
  -G或--no-group   不显示群组名称。
  -h或--human-readable   用"K","M","G"来显示文件和目录的大小。
  -H或--si   此参数的效果和指定"-h"参数类似,但计算单位是1000Bytes而非1024Bytes。
  -i或--inode   显示文件和目录的inode编号。
  -I<范本样式>或--ignore=<范本样式>   不显示符合范本样式的文件或目录名称。
  -k或--kilobytes   此参数的效果和指定"block-size=1024"参数相同。
  -l   使用详细格式列表。
  -L或--dereference   如遇到性质为符号连接的文件或目录,直接列出该连接所指向的原始文件或目录。
  -m   用","号区隔每个文件和目录的名称。
  -n或--numeric-uid-gid   以用户识别码和群组识别码替代其名称。
  -N或--literal   直接列出文件和目录名称,包括控制字符。
  -o   此参数的效果和指定"-l" 参数类似,但不列出群组名称或识别码。
  -p或--file-type   此参数的效果和指定"-F"参数类似,但不会在执行文件名称后面加上"*"号。
  -q或--hide-control-chars   用"?"号取代控制字符,列出文件和目录名称。
  -Q或--quote-name   把文件和目录名称以""号标示起来。
  -r或--reverse   反向排序。
  -R或--recursive   递归处理,将指定目录下的所有文件及子目录一并处理。
  -s或--size   显示文件和目录的大小,以区块为单位。
  -S   用文件和目录的大小排序。
  -t   用文件和目录的更改时间排序。
  -T<跳格字符>或--tabsize=<跳格字数>   设置跳格字符所对应的空白字符数。
  -u   以最后存取时间排序,显示文件和目录。
  -U   列出文件和目录名称时不予排序。
  -v   文件和目录的名称列表以版本进行排序。
  -w<每列字符数>或--width=<每列字符数>   设置每列的最大字符数。
  -x   以从左到右,由上至下的横列方式显示文件和目录名称。
  -X   以文件和目录的最后一个扩展名排序。

此次实验为:ls -lai:

获取目录下文件名:

void do_ls(char dirname[])
{
    DIR* dir_ptr;
    struct dirent *direntp;

    if ((dir_ptr = opendir(dirname)) == NULL)
    {
        fprintf(stderr, "ls1: cannot open %s\n",dirname);
    }
    else
    {
        while((direntp = readdir(dir_ptr)) != NULL) 
        {
            if(    strcmp(direntp->d_name, ".") != 0 &&
                strcmp(direntp->d_name, "..") != 0)
            printf("%s\n", direntp->d_name);
        }
        close(dir_ptr);
    }
}

获取文件详细信息:

void show_stat_info(char *filename, struct stat *buf)
{
    printf("inode\t\t:%d\n",(int)info_p->st_ino);  //索引号
    printf("mode\t\t:%o\n", buf->st_mode);  //文件类型
    printf("linkers\t\t:%d\n",(int)buf->st_nlink);  //链接数
    printf("user\t\t:%d\n", buf->st_uid);  //用户id
    printf("group_id\t:%d\n", buf->st_gid);  //组id
    printf("size\t\t:%d\n", (int)buf->st_size);  //文件大小
    printf("modtime\t\t:%d\n", (int)buf->st_mtime);  //修改时间
    printf("group_name\t:%s\n", filename);  //文件名
}

通过上述结合处理显示即可得到与(ls -lai)一样的信息

2. 分析运行结果

 使用ls -lai运行结果:

 

 使用./ls.lai.out运行结果:

 

 分析:

  由于排版格式不同,导致在视觉上的效果不一致

  使用ls -lai得到的结果是根据inode排序的

3. 通过该实验产生新的疑问及解答

疑问:如何使输出结果的顺序与指令ls -lai顺序一致

解答:可在获取完文件各项信息后通过排序算法相对于inode进行排序最后再输出

posted @ 2020-04-30 15:32  丶Lin  阅读(272)  评论(0编辑  收藏  举报