zoukankan      html  css  js  c++  java
  • Linux网络编程综合运用之MiniFtp实现(九)

    上次中实现了FTP命令的映射来避免很多if....else的判断,这次主要是开始实现目录列表的传输,先看一下目前实现的:

    数据连接创建好之后则开始进行目录列表的传输了,而要传输目录列表,首先要将目录列表这些数据获取出来,所以这次主要是完成目录列表数据的获取。

    还是对照着vsftpd的目录列表的显示来做参考:

    将其列表输出拷贝出来:

    其它跟"ls -l"的输出形式类似:

    下面定义一个函数来将当前目录列出来:

    int list_common(void)
    {
        //打开当前目录
        DIR *dir = opendir(".");
        if (dir == NULL)
        {
            return 0;
        }
    
        return 1;
    }

    接下来读取目录进行遍历,可以通过如下函数:

    【说明】:关于文件目录操作的知识,在之前的系统编程中已经学过了。

    int list_common(void)
    {
        //打开当前目录
        DIR *dir = opendir(".");
        if (dir == NULL)
        {
            return 0;
        }
    
        //读取目录并进行遍历
        struct dirent *dt;
        while ((dt = readdir(dir)) != NULL)
        {
        }
    
        return 1;
    }

    接下来读取文件的状态,并按vsftpd的输出格式来输出:

    首先需要获取文件的状态,可以通过如下函数:

    上面有两个获取文件状态的函数:stat、lstat,那这里要使用哪一个呢?这里要使用lstat,先看一下他们两者的区别:

    所以代码如下:

    int list_common(void)
    {
        //打开当前目录
        DIR *dir = opendir(".");
        if (dir == NULL)
        {
            return 0;
        }
    
        //读取目录并进行遍历
        struct dirent *dt;
        struct stat sbuf;
        while ((dt = readdir(dir)) != NULL)
        {    //获取文件的状态
            if (lstat(dt->d_name, &sbuf) < 0)
            {
                continue;
            }
        }
    
        return 1;
    }

    接下来从文件状态中来读取权限位,首先读取的是文件类型:

    而它的获取,可以通过它来:

    具体代码如下:

    int list_common(void)
    {
        //打开当前目录
        DIR *dir = opendir(".");
        if (dir == NULL)
        {
            return 0;
        }
    
        //读取目录并进行遍历
        struct dirent *dt;
        struct stat sbuf;
        while ((dt = readdir(dir)) != NULL)
        {    //获取文件的状态
            if (lstat(dt->d_name, &sbuf) < 0)
            {
                continue;
            }
    
            char perms[] = "----------";
            perms[0] = '?';
            //获取文件类型
            mode_t mode = sbuf.st_mode;
            switch (mode & S_IFMT)
            {
            case S_IFREG://普通文件
                perms[0] = '-';
                break;
            case S_IFDIR://目录文件
                perms[0] = 'd';
                break;
            case S_IFLNK://链接文件
                perms[0] = 'l';
                break;
            case S_IFIFO://管道文件
                perms[0] = 'p';
                break;
            case S_IFSOCK://套接字文件
                perms[0] = 's';
                break;
            case S_IFCHR://字符设备文件
                perms[0] = 'c';
                break;
            case S_IFBLK://块设备文件
                perms[0] = 'b';
                break;
            }
        }
    
        return 1;
    }

    接下来要获取的是9位的权限:

    也可以通过这些来获取到:

    具体代码如下:

    int list_common(void)
    {
        //打开当前目录
        DIR *dir = opendir(".");
        if (dir == NULL)
        {
            return 0;
        }
    
        //读取目录并进行遍历
        struct dirent *dt;
        struct stat sbuf;
        while ((dt = readdir(dir)) != NULL)
        {    //获取文件的状态
            if (lstat(dt->d_name, &sbuf) < 0)
            {
                continue;
            }
    
            char perms[] = "----------";
            perms[0] = '?';
            //获取文件类型
            mode_t mode = sbuf.st_mode;
            switch (mode & S_IFMT)
            {
            case S_IFREG://普通文件
                perms[0] = '-';
                break;
            case S_IFDIR://目录文件
                perms[0] = 'd';
                break;
            case S_IFLNK://链接文件
                perms[0] = 'l';
                break;
            case S_IFIFO://管道文件
                perms[0] = 'p';
                break;
            case S_IFSOCK://套接字文件
                perms[0] = 's';
                break;
            case S_IFCHR://字符设备文件
                perms[0] = 'c';
                break;
            case S_IFBLK://块设备文件
                perms[0] = 'b';
                break;
            }
    
            //获取文件9个权限位
            if (mode & S_IRUSR)
            {
                perms[1] = 'r';
            }
            if (mode & S_IWUSR)
            {
                perms[2] = 'w';
            }
            if (mode & S_IXUSR)
            {
                perms[3] = 'x';
            }
            if (mode & S_IRGRP)
            {
                perms[4] = 'r';
            }
            if (mode & S_IWGRP)
            {
                perms[5] = 'w';
            }
            if (mode & S_IXGRP)
            {
                perms[6] = 'x';
            }
            if (mode & S_IROTH)
            {
                perms[7] = 'r';
            }
            if (mode & S_IWOTH)
            {
                perms[8] = 'w';
            }
            if (mode & S_IXOTH)
            {
                perms[9] = 'x';
            }
        }
    
        return 1;
    }

    接下来就是一些特珠的权限位,下面来看下:

    文件a的权限如上,下面给它更改一下权限:

    同样的组权限也有类似的小s,大s,而其它组的权限有小t,大T权限,所以下面来处理这些特珠权限:

    int list_common(void)
    {
        //打开当前目录
        DIR *dir = opendir(".");
        if (dir == NULL)
        {
            return 0;
        }
    
        //读取目录并进行遍历
        struct dirent *dt;
        struct stat sbuf;
        while ((dt = readdir(dir)) != NULL)
        {    //获取文件的状态
            if (lstat(dt->d_name, &sbuf) < 0)
            {
                continue;
            }
    
            char perms[] = "----------";
            perms[0] = '?';
            //获取文件类型
            mode_t mode = sbuf.st_mode;
            switch (mode & S_IFMT)
            {
            case S_IFREG://普通文件
                perms[0] = '-';
                break;
            case S_IFDIR://目录文件
                perms[0] = 'd';
                break;
            case S_IFLNK://链接文件
                perms[0] = 'l';
                break;
            case S_IFIFO://管道文件
                perms[0] = 'p';
                break;
            case S_IFSOCK://套接字文件
                perms[0] = 's';
                break;
            case S_IFCHR://字符设备文件
                perms[0] = 'c';
                break;
            case S_IFBLK://块设备文件
                perms[0] = 'b';
                break;
            }
    
            //获取文件9个权限位
            if (mode & S_IRUSR)
            {
                perms[1] = 'r';
            }
            if (mode & S_IWUSR)
            {
                perms[2] = 'w';
            }
            if (mode & S_IXUSR)
            {
                perms[3] = 'x';
            }
            if (mode & S_IRGRP)
            {
                perms[4] = 'r';
            }
            if (mode & S_IWGRP)
            {
                perms[5] = 'w';
            }
            if (mode & S_IXGRP)
            {
                perms[6] = 'x';
            }
            if (mode & S_IROTH)
            {
                perms[7] = 'r';
            }
            if (mode & S_IWOTH)
            {
                perms[8] = 'w';
            }
            if (mode & S_IXOTH)
            {
                perms[9] = 'x';
            }
            //获取特珠权限位
            if (mode & S_ISUID)
            {
                perms[3] = (perms[3] == 'x') ? 's' : 'S';
            }
            if (mode & S_ISGID)
            {
                perms[6] = (perms[6] == 'x') ? 's' : 'S';
            }
            if (mode & S_ISVTX)
            {
                perms[9] = (perms[9] == 'x') ? 't' : 'T';
            }
        }
    
        return 1;
    }

    并且要将之前获取的权限信息与连接接,以及后面的那些信息连接起来格式化,所以下面将获取的信息格式化:

    int list_common(void)
    {
        //打开当前目录
        DIR *dir = opendir(".");
        if (dir == NULL)
        {
            return 0;
        }
    
        //读取目录并进行遍历
        struct dirent *dt;
        struct stat sbuf;
        while ((dt = readdir(dir)) != NULL)
        {    //获取文件的状态
            if (lstat(dt->d_name, &sbuf) < 0)
            {
                continue;
            }
    
            char perms[] = "----------";
            perms[0] = '?';
            //获取文件类型
            mode_t mode = sbuf.st_mode;
            switch (mode & S_IFMT)
            {
            case S_IFREG://普通文件
                perms[0] = '-';
                break;
            case S_IFDIR://目录文件
                perms[0] = 'd';
                break;
            case S_IFLNK://链接文件
                perms[0] = 'l';
                break;
            case S_IFIFO://管道文件
                perms[0] = 'p';
                break;
            case S_IFSOCK://套接字文件
                perms[0] = 's';
                break;
            case S_IFCHR://字符设备文件
                perms[0] = 'c';
                break;
            case S_IFBLK://块设备文件
                perms[0] = 'b';
                break;
            }
    
            //获取文件9个权限位
            if (mode & S_IRUSR)
            {
                perms[1] = 'r';
            }
            if (mode & S_IWUSR)
            {
                perms[2] = 'w';
            }
            if (mode & S_IXUSR)
            {
                perms[3] = 'x';
            }
            if (mode & S_IRGRP)
            {
                perms[4] = 'r';
            }
            if (mode & S_IWGRP)
            {
                perms[5] = 'w';
            }
            if (mode & S_IXGRP)
            {
                perms[6] = 'x';
            }
            if (mode & S_IROTH)
            {
                perms[7] = 'r';
            }
            if (mode & S_IWOTH)
            {
                perms[8] = 'w';
            }
            if (mode & S_IXOTH)
            {
                perms[9] = 'x';
            }
            //获取特珠权限位
            if (mode & S_ISUID)
            {
                perms[3] = (perms[3] == 'x') ? 's' : 'S';
            }
            if (mode & S_ISGID)
            {
                perms[6] = (perms[6] == 'x') ? 's' : 'S';
            }
            if (mode & S_ISVTX)
            {
                perms[9] = (perms[9] == 'x') ? 't' : 'T';
            }
            
            //格式化信息
            char buf[1024] = {0};
            int off = 0;
            off += sprintf(buf, "%s ", perms);//连接权限位
            off += sprintf(buf + off, " %3d %-8d %-8d ", sbuf.st_nlink, sbuf.st_uid, sbuf.st_gid);//连接连接数、uid、gid
            off += sprintf(buf + off, "%8lu ", (unsigned long)sbuf.st_size);//连接文件大小,以8位的长度展现
        }
    
        return 1;
    }

    这两个日期显示的规则是这样:

    下面来具体实现:

    首先需要获取系统的当前时间,可以利用这个函数:

    【说明】而格式化中的“%b”、“%e”、"%Y"是什么意思,可以查看该函数:strftime:

    接下来将日期进行格式化:

    最后一个信息则是文件名:

    写了这么多,下面来编译运行一下:

    一大堆头文件没有包含,所以需要包含一下:

    再次编译运行:

    编译通过了,下面来编写一下测试代码来验证当前目录输出代码是不OK:

    运行看下效果:

    再次编译运行:

    将编译的可执行文件拷贝到home目录,以便跟vsftptd的进行对比,然后再进入home目录来运行:

    修改代码如下:

    再次编译运行:

    上面来看已经跟vsftpd显示的效果基本一样了,但是有一个链接文件b是指向a的,这里没有显示出来,看下vsftpd是如何显示的:

    所以下面得对符号链接文件要进行修改,代码如下:

    其中判断一个文件是否是符号链接文件可以用宏S_ISLNK,实际它的内部是:

    再次编译运行:

    最后跟vsftpd的输出做一下对比:

    好了,这次的东西有点多,需好好消化,下次则继续完成FTP目录列表的显示~

    27_23

  • 相关阅读:
    Django与forms组件校验源码
    局部钩子和和全局钩子
    Form组件参数配置
    Form渲染错误信息
    Django与分页器
    Django与from组件
    uiautomatorview 提示:no android devies were detected by adb
    Flutter 应用入门:包管理
    Flutter 应用入门:路由管理
    Flutter 应用入门:计数器
  • 原文地址:https://www.cnblogs.com/webor2006/p/4612247.html
Copyright © 2011-2022 走看看