enumerator: Implement globbing enumerator on Windows
We don't have glob() available there. This replacement should work similarly for simple cases like `include conf.d/*.conf`. Fixes #3684.
This commit is contained in:
@@ -27,6 +27,8 @@
|
|||||||
|
|
||||||
#ifdef HAVE_GLOB_H
|
#ifdef HAVE_GLOB_H
|
||||||
#include <glob.h>
|
#include <glob.h>
|
||||||
|
#elif defined(WIN32)
|
||||||
|
#include <fileapi.h>
|
||||||
#endif /* HAVE_GLOB_H */
|
#endif /* HAVE_GLOB_H */
|
||||||
|
|
||||||
#include <utils/debug.h>
|
#include <utils/debug.h>
|
||||||
@@ -201,8 +203,6 @@ typedef struct {
|
|||||||
glob_t glob;
|
glob_t glob;
|
||||||
/** iteration count */
|
/** iteration count */
|
||||||
u_int pos;
|
u_int pos;
|
||||||
/** absolute path of current file */
|
|
||||||
char full[PATH_MAX];
|
|
||||||
} glob_enum_t;
|
} glob_enum_t;
|
||||||
|
|
||||||
METHOD(enumerator_t, destroy_glob_enum, void,
|
METHOD(enumerator_t, destroy_glob_enum, void,
|
||||||
@@ -273,6 +273,143 @@ enumerator_t* enumerator_create_glob(const char *pattern)
|
|||||||
return &this->public;
|
return &this->public;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#elif defined(WIN32) /* HAVE_GLOB_H */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enumerator implementation for glob enumerator on Windows
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
/** implements enumerator_t */
|
||||||
|
enumerator_t public;
|
||||||
|
/** search handle */
|
||||||
|
HANDLE handle;
|
||||||
|
/** current file path */
|
||||||
|
char path[PATH_MAX];
|
||||||
|
/** base path */
|
||||||
|
char *base;
|
||||||
|
} glob_enum_t;
|
||||||
|
|
||||||
|
METHOD(enumerator_t, destroy_glob_enum, void,
|
||||||
|
glob_enum_t *this)
|
||||||
|
{
|
||||||
|
if (this->handle != INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
FindClose(this->handle);
|
||||||
|
}
|
||||||
|
free(this->base);
|
||||||
|
free(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the combined path from the given file data
|
||||||
|
*/
|
||||||
|
static bool combine_glob_path(glob_enum_t *this, WIN32_FIND_DATA *data)
|
||||||
|
{
|
||||||
|
if (snprintf(this->path, sizeof(this->path), "%s%s%s", this->base,
|
||||||
|
DIRECTORY_SEPARATOR, data->cFileName) >= sizeof(this->path))
|
||||||
|
{
|
||||||
|
DBG1(DBG_LIB, "path for '%s' too long, ignored", data->cFileName);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the path and stat data for the current file
|
||||||
|
*/
|
||||||
|
static bool enumerate_glob_enum_data(glob_enum_t *this, va_list args)
|
||||||
|
{
|
||||||
|
struct stat *st;
|
||||||
|
char **file;
|
||||||
|
|
||||||
|
VA_ARGS_VGET(args, file, st);
|
||||||
|
|
||||||
|
if (file)
|
||||||
|
{
|
||||||
|
*file = this->path;
|
||||||
|
}
|
||||||
|
if (st && stat(this->path, st))
|
||||||
|
{
|
||||||
|
DBG1(DBG_LIB, "stat() on '%s' failed: %s", this->path,
|
||||||
|
strerror(errno));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
METHOD(enumerator_t, enumerate_glob_enum, bool,
|
||||||
|
glob_enum_t *this, va_list args)
|
||||||
|
{
|
||||||
|
WIN32_FIND_DATA data;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (!FindNextFile(this->handle, &data))
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (!combine_glob_path(this, &data));
|
||||||
|
|
||||||
|
return enumerate_glob_enum_data(this, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
METHOD(enumerator_t, enumerate_glob_enum_first, bool,
|
||||||
|
glob_enum_t *this, va_list args)
|
||||||
|
{
|
||||||
|
if (enumerate_glob_enum_data(this, args))
|
||||||
|
{
|
||||||
|
this->public.venumerate = _enumerate_glob_enum;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Described in header
|
||||||
|
*/
|
||||||
|
enumerator_t *enumerator_create_glob(const char *pattern)
|
||||||
|
{
|
||||||
|
glob_enum_t *this;
|
||||||
|
WIN32_FIND_DATA data;
|
||||||
|
|
||||||
|
if (!pattern)
|
||||||
|
{
|
||||||
|
return enumerator_create_empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
INIT(this,
|
||||||
|
.public = {
|
||||||
|
.enumerate = enumerator_enumerate_default,
|
||||||
|
.venumerate = _enumerate_glob_enum_first,
|
||||||
|
.destroy = _destroy_glob_enum,
|
||||||
|
},
|
||||||
|
.base = path_dirname(pattern),
|
||||||
|
);
|
||||||
|
|
||||||
|
this->handle = FindFirstFile(pattern, &data);
|
||||||
|
if (this->handle == INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
if (GetLastError() == ERROR_FILE_NOT_FOUND ||
|
||||||
|
GetLastError() == ERROR_PATH_NOT_FOUND)
|
||||||
|
{
|
||||||
|
DBG1(DBG_LIB, "no files found matching '%s'", pattern);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DBG1(DBG_LIB, "FindFirstFile failed for pattern '%s' (%d)", pattern,
|
||||||
|
GetLastError());
|
||||||
|
}
|
||||||
|
destroy_glob_enum(this);
|
||||||
|
return enumerator_create_empty();
|
||||||
|
}
|
||||||
|
else if (!combine_glob_path(this, &data))
|
||||||
|
{ /* check the next file if we can't combine the path for the first one */
|
||||||
|
this->public.venumerate = _enumerate_glob_enum;
|
||||||
|
}
|
||||||
|
return &this->public;
|
||||||
|
}
|
||||||
|
|
||||||
#else /* HAVE_GLOB_H */
|
#else /* HAVE_GLOB_H */
|
||||||
|
|
||||||
enumerator_t* enumerator_create_glob(const char *pattern)
|
enumerator_t* enumerator_create_glob(const char *pattern)
|
||||||
|
|||||||
Reference in New Issue
Block a user