【9】Strongswan collections —— enumerator

//以目录枚举为例子,说明enumerator,从源码剥离可运行

c 复制代码
#include <stdio.h>
#include <stdbool.h>
#include <dirent.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdint.h>
#include <stddef.h>
#include <sys/time.h>
#include <stdarg.h>

/**
 * This macro allows counting the number of arguments passed to a macro.
 * Combined with the VA_ARGS_DISPATCH() macro this can be used to implement
 * macro overloading based on the number of arguments.
 * 0 to 10 arguments are currently supported.
 */
#define VA_ARGS_NUM(...) _VA_ARGS_NUM(0,##__VA_ARGS__,10,9,8,7,6,5,4,3,2,1,0)
#define _VA_ARGS_NUM(_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,NUM,...) NUM

/**
 * This macro can be used to dispatch a macro call based on the number of given
 * arguments, for instance:
 *
 * @code
 * #define MY_MACRO(...) VA_ARGS_DISPATCH(MY_MACRO, __VA_ARGS__)(__VA_ARGS__)
 * #define MY_MACRO1(arg) one_arg(arg)
 * #define MY_MACRO2(arg1,arg2) two_args(arg1,arg2)
 * @endcode
 *
 * MY_MACRO() can now be called with either one or two arguments, which will
 * resolve to one_arg(arg) or two_args(arg1,arg2), respectively.
 */
#define VA_ARGS_DISPATCH(func, ...) _VA_ARGS_DISPATCH(func, VA_ARGS_NUM(__VA_ARGS__))
#define _VA_ARGS_DISPATCH(func, num) __VA_ARGS_DISPATCH(func, num)
#define __VA_ARGS_DISPATCH(func, num) func ## num

/**
 * Assign variadic arguments to the given variables.
 *
 * @note The order and types of the variables are significant and must match the
 * variadic arguments passed to the function that calls this macro exactly.
 *
 * @param last		the last argument before ... in the function that calls this
 * @param ...		variable names
 */
#define VA_ARGS_GET(last, ...) ({ \
    va_list _va_args_get_ap; \
    va_start(_va_args_get_ap, last); \
    _VA_ARGS_GET_ASGN(__VA_ARGS__) \
    va_end(_va_args_get_ap); \
})

/**
 * Assign variadic arguments from a va_list to the given variables.
 *
 * @note The order and types of the variables are significant and must match the
 * variadic arguments passed to the function that calls this macro exactly.
 *
 * @param list		the va_list variable in the function that calls this
 * @param ...		variable names
 */
#define VA_ARGS_VGET(list, ...) ({ \
    va_list _va_args_get_ap; \
    va_copy(_va_args_get_ap, list); \
    _VA_ARGS_GET_ASGN(__VA_ARGS__) \
    va_end(_va_args_get_ap); \
})

#define _VA_ARGS_GET_ASGN(...) VA_ARGS_DISPATCH(_VA_ARGS_GET_ASGN, __VA_ARGS__)(__VA_ARGS__)
#define _VA_ARGS_GET_ASGN1(v1) __VA_ARGS_GET_ASGN(v1)
#define _VA_ARGS_GET_ASGN2(v1,v2) __VA_ARGS_GET_ASGN(v1) __VA_ARGS_GET_ASGN(v2)
#define _VA_ARGS_GET_ASGN3(v1,v2,v3) __VA_ARGS_GET_ASGN(v1) __VA_ARGS_GET_ASGN(v2) \
    __VA_ARGS_GET_ASGN(v3)
#define _VA_ARGS_GET_ASGN4(v1,v2,v3,v4) __VA_ARGS_GET_ASGN(v1) __VA_ARGS_GET_ASGN(v2) \
    __VA_ARGS_GET_ASGN(v3) __VA_ARGS_GET_ASGN(v4)
#define _VA_ARGS_GET_ASGN5(v1,v2,v3,v4,v5) __VA_ARGS_GET_ASGN(v1) __VA_ARGS_GET_ASGN(v2) \
    __VA_ARGS_GET_ASGN(v3) __VA_ARGS_GET_ASGN(v4) __VA_ARGS_GET_ASGN(v5)
#define __VA_ARGS_GET_ASGN(v) v = va_arg(_va_args_get_ap, typeof(v));

#ifndef FALSE
# define FALSE false
#endif /* FALSE */
#ifndef TRUE
# define TRUE  true
#endif /* TRUE */

typedef struct enumerator_t enumerator_t;


struct enumerator_t {

    /**
     * 枚举集合。
     *
     * enumerate() 方法接受可变数量的指针参数(枚举到的值被写入这些参数)
     *
     *通常只需分配调用枚举器的 venumerate() 方法的通用 enumerator_enumerate_default() 函数就足够了。 ...
     *
     * @param ...	枚举项的变量列表,取决于实现
     * @return		TRUE if pointers returned
     */
    bool (*enumerate)(enumerator_t *this, ...);

    /**
     * 枚举集合。
     *
     * venumerate() 方法采用一个变量参数列表,其中包含将枚举值写入的指针。
     *
     * @param args	枚举项的变量列表,取决于实现
     * @return		TRUE if pointers returned
     */
    bool (*venumerate)(enumerator_t *this, va_list args);

    /**
     * Destroy an enumerator_t instance.
     */
    void (*destroy)(enumerator_t *this);
};

/**
 * Enumerator implementation for directory enumerator
 */
typedef struct {
    /** implements enumerator_t */
    enumerator_t public;
    /** directory handle */
    DIR *dir;
    /** absolute path of current file */
    char full[PATH_MAX];
    /** where directory part of full ends and relative file gets written */
    //完整路径中的目录部分结束以及相对文件将被写入的位置
    char *full_end;
} dir_enum_t;
/**
 * Helper function that compares two strings for equality
 */
static inline bool streq(const char *x, const char *y)
{
    return (x == y) || (x && y && strcmp(x, y) == 0);
}


bool enumerate_dir_enum(dir_enum_t *this, va_list args){
    //读取目录中的条目,依靠此函数特性实现枚举
    struct dirent *entry = readdir(this->dir);
    struct stat *st = NULL;
    size_t remaining;
    char **relative = NULL, **absolute = NULL;;
    int len;

    //对应enumerate输入的变参... &relative, &file, NULL 下面写入这些值相当于写入那些值
    VA_ARGS_VGET(args, relative, absolute, st);

    if (!entry)
    {
        return FALSE;
    }
    if (streq(entry->d_name, ".") || streq(entry->d_name, ".."))
    {
        return this->public.enumerate(&this->public, relative, absolute, st);
    }
    if (relative)
    {
        //条目名称
        *relative = entry->d_name;
    }
    if (absolute || st)
    {
        //full是路径,relative
        remaining = sizeof(this->full) - (this->full_end - this->full);
        len = snprintf(this->full_end, remaining, "%s", entry->d_name);
        if (len < 0 || len >= remaining)
        {
            return FALSE;
        }
        if (absolute)
        {
            *absolute = this->full;
        }
        if (st && stat(this->full, st))
        {
            /* try lstat() e.g. if a symlink is not valid anymore */
            if ((errno != ENOENT && errno != ENOTDIR) || lstat(this->full, st))
            {
                return FALSE;
            }
        }
    }
    return TRUE;
}


# define DIRECTORY_SEPARATOR "/"
static inline bool path_is_separator(char c)
{
    return c == DIRECTORY_SEPARATOR[0];
}

/**
 * Object allocation/initialization macro, using designated initializer.
 */
#define INIT(this, ...) ({ (this) = malloc(sizeof(*(this))); \
                           *(this) = (typeof(*(this))){ __VA_ARGS__ }; (this); })

bool enumerator_enumerate_default(enumerator_t *enumerator, ...)
{
    va_list args;
    bool result;

    if (!enumerator->venumerate)
    {
        return FALSE;
    }
    //va_start用于获取函数参数列表...中可变参数的首指针
    //输出参数args保存函数参数列表中可变参数的首指针(即,可变参数列表)
    //输入参数enumerator为函数参数列表中最后一个固定参数(...之前)
    va_start(args, enumerator);
    result = enumerator->venumerate(enumerator, args);
    va_end(args);
    return result;
}

void destroy_dir_enum(dir_enum_t *this){
    closedir(this->dir);
    free(this);
}

enumerator_t* enumerator_create_directory(const char *path)
{
    dir_enum_t *this;
    int len;

    //实例化
    INIT(this,
        .public = {
            .enumerate = enumerator_enumerate_default,
            .venumerate = enumerate_dir_enum,
            .destroy = destroy_dir_enum,
        },
    );

    if (*path == '\0')
    {
        path = "./";
    }
    len = snprintf(this->full, sizeof(this->full)-1, "%s", path);
    if (len < 0 || len >= sizeof(this->full)-1)
    {
        free(this);
        return NULL;
    }
    /* append a '/' if not already done */
    if (!path_is_separator(this->full[len-1]))
    {
        this->full[len++] = DIRECTORY_SEPARATOR[0];
        this->full[len] = '\0';
    }
    this->full_end = &this->full[len];

    //打开目录
    this->dir = opendir(path);
    if (!this->dir)
    {
        free(this);
        return NULL;
    }
    return &this->public;
}

int main()
{
    char *file;
    char *relative;
    char *st;
    char *path = "/root/open/strongswan-6.0.0";
    enumerator_t *enumerator;
    enumerator = enumerator_create_directory(path);
    if (enumerator){
        while (enumerator->enumerate(enumerator, &relative, &file, NULL))
        {
            printf("file: %s | relative: %s | size:%s\n", file, relative, NULL);
        }

        enumerator->destroy(enumerator);
    }

    return 0;
}
相关推荐
iOS技术狂热者1 小时前
多图超详细安装flutter&Android Studio开发环境,并配置插件
websocket·网络协议·tcp/ip·http·网络安全·https·udp
盛满暮色 风止何安4 小时前
VLAN的高级特性
运维·服务器·开发语言·网络·网络协议·网络安全·php
故事与他6456 小时前
电子文档安全管理系统V6.0接口backup存在任意文件下载漏洞
java·开发语言·前端·javascript·安全·网络安全
SecPulse14 小时前
流影---开源网络流量分析平台(四)(分析引擎部署)
运维·服务器·人工智能·网络安全·开源·流影
浩浩测试一下14 小时前
网络安全之超强Linux信息收集:渗透测试与应急响应的基石(命令超强集合工作手册)
linux·运维·服务器·安全·web安全·网络安全·系统安全
金丝猴也是猿18 小时前
手机硬件检测详解:从版本信息到相机功能的全面指南
websocket·网络协议·tcp/ip·http·网络安全·https·udp
iOS技术狂热者1 天前
wireshark开启对https密文抓包
websocket·网络协议·tcp/ip·http·网络安全·https·udp
燕雀安知鸿鹄之志哉.1 天前
ctfshow WEB web5
安全·web安全·网络安全·系统安全