【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;
}
相关推荐
kp000001 小时前
GitHub信息收集
web安全·网络安全·信息收集
LuDvei7 小时前
CH9121T电路及配置详解
服务器·嵌入式硬件·物联网·网络协议·tcp/ip·网络安全·信号处理
山川绿水11 小时前
Ubuntu22.04更新Openssh至9.9p2无法正常连接,报错解决
服务器·web安全·网络安全
武汉唯众智创16 小时前
网络安全实训室建设方案全攻略
网络·安全·web安全·网络安全·网络安全实训室·网络安全实验室
宝山哥哥19 小时前
网络信息安全学习笔记1----------网络信息安全概述
网络·笔记·学习·安全·网络安全
在安全厂商修设备1 天前
SQL注入与防御-第六章-3:利用操作系统--巩固访问
sql·web安全·网络安全
情分丶1 天前
中国蚁剑使用方法
网络安全
王天天(Bennet)1 天前
【防火墙基础之传统墙到 UTM 到 NGFW 再到 AI 的变化】
人工智能·网络安全·防火墙·ngfw·防火墙发展与认知
2501_916008892 天前
iOS App抓包工具排查后台唤醒引发请求异常
websocket·网络协议·tcp/ip·http·网络安全·https·udp
Bruce_Liuxiaowei2 天前
安全分析:Zabbix 路径探测请求解析
安全·网络安全·zabbix