2019-10-23 16:25:06 -03:00
|
|
|
/*
|
|
|
|
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
|
|
|
*
|
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
*
|
|
|
|
* See the COPYRIGHT file distributed with this work for additional
|
|
|
|
* information regarding copyright ownership.
|
|
|
|
*/
|
|
|
|
|
2020-02-25 09:07:45 +01:00
|
|
|
#include <errno.h>
|
2019-10-23 16:25:06 -03:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include <isc/errno.h>
|
|
|
|
#include <isc/glob.h>
|
|
|
|
#include <isc/print.h>
|
|
|
|
#include <isc/result.h>
|
|
|
|
#include <isc/types.h>
|
|
|
|
#include <isc/util.h>
|
|
|
|
|
|
|
|
#if HAVE_GLOB_H
|
|
|
|
#include <glob.h>
|
2020-04-08 15:46:33 +02:00
|
|
|
#elif defined(_WIN32)
|
2019-10-23 16:25:06 -03:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <windows.h>
|
2020-02-25 09:07:45 +01:00
|
|
|
|
2019-10-23 16:25:06 -03:00
|
|
|
#include <isc/list.h>
|
2020-04-08 15:46:33 +02:00
|
|
|
#define GLOB_ERR 0x0004 /* Return on error. */
|
|
|
|
#define GLOB_NOSPACE (-1)
|
|
|
|
#define GLOB_NOMATCH (-3)
|
2019-10-23 16:25:06 -03:00
|
|
|
|
|
|
|
/* custom glob implementation for windows */
|
|
|
|
static int
|
|
|
|
glob(const char *pattern, int flags, void *unused, glob_t *pglob);
|
|
|
|
|
|
|
|
static void
|
|
|
|
globfree(glob_t *pglob);
|
|
|
|
|
|
|
|
#else
|
|
|
|
#error "Required header missing: glob.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
isc_result_t
|
|
|
|
isc_glob(const char *pattern, glob_t *pglob) {
|
|
|
|
REQUIRE(pattern != NULL);
|
|
|
|
REQUIRE(*pattern != '\0');
|
|
|
|
REQUIRE(pglob != NULL);
|
|
|
|
|
|
|
|
int rc = glob(pattern, GLOB_ERR, NULL, pglob);
|
|
|
|
|
|
|
|
switch (rc) {
|
2020-02-25 09:07:45 +01:00
|
|
|
case 0:
|
|
|
|
return (ISC_R_SUCCESS);
|
2019-10-23 16:25:06 -03:00
|
|
|
|
2020-02-25 09:07:45 +01:00
|
|
|
case GLOB_NOMATCH:
|
|
|
|
return (ISC_R_FILENOTFOUND);
|
2019-10-23 16:25:06 -03:00
|
|
|
|
2020-02-25 09:07:45 +01:00
|
|
|
case GLOB_NOSPACE:
|
|
|
|
return (ISC_R_NOMEMORY);
|
2019-10-23 16:25:06 -03:00
|
|
|
|
2020-02-25 09:07:45 +01:00
|
|
|
default:
|
|
|
|
return (errno != 0 ? isc_errno_toresult(errno) : ISC_R_IOERROR);
|
2019-10-23 16:25:06 -03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
isc_globfree(glob_t *pglob) {
|
|
|
|
REQUIRE(pglob != NULL);
|
|
|
|
globfree(pglob);
|
|
|
|
}
|
|
|
|
|
2020-04-08 15:46:33 +02:00
|
|
|
#if defined(_WIN32)
|
2019-10-23 16:25:06 -03:00
|
|
|
|
|
|
|
typedef struct file_path file_path_t;
|
|
|
|
|
|
|
|
struct file_path {
|
|
|
|
char *path;
|
|
|
|
ISC_LINK(file_path_t) link;
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef ISC_LIST(file_path_t) file_list_t;
|
|
|
|
|
|
|
|
/* map a winapi error to a convenient errno code */
|
|
|
|
static int
|
|
|
|
map_error(DWORD win_err_code) {
|
|
|
|
switch (win_err_code) {
|
|
|
|
case ERROR_FILE_NOT_FOUND:
|
|
|
|
case ERROR_PATH_NOT_FOUND:
|
|
|
|
return (GLOB_NOMATCH);
|
|
|
|
case ERROR_ACCESS_DENIED:
|
|
|
|
return (EACCES);
|
|
|
|
case ERROR_NOT_ENOUGH_MEMORY:
|
|
|
|
return (GLOB_NOSPACE);
|
|
|
|
default:
|
|
|
|
return (EIO);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* add file in directory dir, that matches glob expression
|
|
|
|
* provided in function glob(), to the linked list fl */
|
2020-04-08 15:46:33 +02:00
|
|
|
static void
|
2020-02-25 09:07:45 +01:00
|
|
|
append_file(isc_mem_t *mctx, file_list_t *fl, const char *dir, const char *file,
|
|
|
|
size_t full_path_len) {
|
2019-10-23 16:25:06 -03:00
|
|
|
file_path_t *fp = isc_mem_get(mctx, sizeof(file_path_t));
|
|
|
|
fp->path = isc_mem_get(mctx, full_path_len + 1);
|
|
|
|
_snprintf(fp->path, full_path_len + 1, "%s%s", dir, file);
|
|
|
|
|
|
|
|
ISC_LINK_INIT(fp, link);
|
|
|
|
ISC_LIST_PREPEND(*fl, fp, link);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* sort files alphabetically case insensitive on windows */
|
|
|
|
static int
|
|
|
|
path_cmp(const void *path1, const void *path2) {
|
|
|
|
return _stricmp((const char *)path1, (const char *)path2);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
glob(const char *pattern, int flags, void *unused, glob_t *pglob) {
|
|
|
|
char path[MAX_PATH];
|
2020-02-25 09:07:45 +01:00
|
|
|
WIN32_FIND_DATAA find_data;
|
2020-03-06 16:53:20 -03:00
|
|
|
int ec;
|
2019-10-23 16:25:06 -03:00
|
|
|
HANDLE hnd;
|
|
|
|
|
|
|
|
REQUIRE(pattern != NULL);
|
|
|
|
REQUIRE(pglob != NULL);
|
|
|
|
|
|
|
|
UNUSED(flags);
|
|
|
|
UNUSED(unused);
|
|
|
|
|
|
|
|
pglob->mctx = NULL;
|
|
|
|
pglob->gl_pathc = 0;
|
|
|
|
pglob->gl_pathv = NULL;
|
|
|
|
|
|
|
|
hnd = FindFirstFileA(pattern, &find_data);
|
|
|
|
if (hnd == INVALID_HANDLE_VALUE) {
|
|
|
|
return (map_error(GetLastError()));
|
|
|
|
}
|
|
|
|
|
|
|
|
path[MAX_PATH - 1] = 0;
|
|
|
|
strncpy(path, pattern, MAX_PATH);
|
|
|
|
if (path[MAX_PATH - 1] != 0) {
|
|
|
|
errno = ENAMETOOLONG;
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
// strip filename from path.
|
|
|
|
size_t dir_len = strlen(path);
|
2020-02-25 09:07:45 +01:00
|
|
|
while (dir_len > 0 && path[dir_len - 1] != '/' &&
|
|
|
|
path[dir_len - 1] != '\\') {
|
2019-10-23 16:25:06 -03:00
|
|
|
dir_len--;
|
|
|
|
}
|
|
|
|
|
|
|
|
path[dir_len] = '\0';
|
|
|
|
|
|
|
|
isc_mem_create(&pglob->mctx);
|
|
|
|
pglob->reserved = isc_mem_get(pglob->mctx, sizeof(file_list_t));
|
2020-03-06 16:53:20 -03:00
|
|
|
ISC_LIST_INIT(*(file_list_t *)pglob->reserved);
|
2019-10-23 16:25:06 -03:00
|
|
|
|
|
|
|
size_t entries = 0;
|
|
|
|
|
|
|
|
do {
|
|
|
|
size_t file_len = strlen(find_data.cFileName);
|
|
|
|
size_t full_path_len = dir_len + file_len;
|
|
|
|
|
|
|
|
if (full_path_len > MAX_PATH) {
|
|
|
|
errno = ENAMETOOLONG;
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
2020-02-25 09:07:45 +01:00
|
|
|
append_file(pglob->mctx, (file_list_t *)pglob->reserved, path,
|
|
|
|
find_data.cFileName, full_path_len);
|
2019-10-23 16:25:06 -03:00
|
|
|
|
|
|
|
entries++;
|
|
|
|
} while (FindNextFileA(hnd, &find_data));
|
|
|
|
|
|
|
|
FindClose(hnd);
|
|
|
|
|
2020-02-25 09:07:45 +01:00
|
|
|
pglob->gl_pathv = isc_mem_get(pglob->mctx,
|
|
|
|
(entries + 1) * sizeof(char *));
|
2019-10-23 16:25:06 -03:00
|
|
|
pglob->gl_pathv[entries] = NULL;
|
|
|
|
pglob->gl_pathc = entries;
|
|
|
|
|
|
|
|
file_list_t *fl = (file_list_t *)pglob->reserved;
|
|
|
|
|
|
|
|
size_t e = 0;
|
|
|
|
file_path_t *fp;
|
2020-02-25 09:07:45 +01:00
|
|
|
for (fp = ISC_LIST_HEAD(*fl); fp != NULL; fp = ISC_LIST_NEXT(fp, link))
|
|
|
|
{
|
2019-10-23 16:25:06 -03:00
|
|
|
pglob->gl_pathv[e++] = fp->path;
|
|
|
|
}
|
|
|
|
|
2020-02-25 09:07:45 +01:00
|
|
|
qsort(pglob->gl_pathv, pglob->gl_pathc, sizeof(char *), path_cmp);
|
2019-10-23 16:25:06 -03:00
|
|
|
|
|
|
|
return (0);
|
|
|
|
|
|
|
|
fail:
|
2020-03-06 16:53:20 -03:00
|
|
|
ec = errno;
|
2019-10-23 16:25:06 -03:00
|
|
|
|
|
|
|
FindClose(hnd);
|
|
|
|
|
|
|
|
if (pglob->mctx) {
|
|
|
|
globfree(pglob);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ec;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2020-02-25 09:07:45 +01:00
|
|
|
globfree(glob_t *pglob) {
|
2019-10-23 16:25:06 -03:00
|
|
|
REQUIRE(pglob != NULL);
|
|
|
|
REQUIRE(pglob->mctx != NULL);
|
|
|
|
|
|
|
|
/* first free memory used by char ** gl_pathv */
|
|
|
|
if (pglob->gl_pathv) {
|
2020-02-25 09:07:45 +01:00
|
|
|
isc_mem_put(pglob->mctx, pglob->gl_pathv,
|
2019-10-23 16:25:06 -03:00
|
|
|
(pglob->gl_pathc + 1) * sizeof(char *));
|
|
|
|
pglob->gl_pathv = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
file_list_t *fl = (file_list_t *)pglob->reserved;
|
|
|
|
file_path_t *p, *next;
|
|
|
|
|
|
|
|
/* next free each individual file path string + nodes in list */
|
|
|
|
for (p = ISC_LIST_HEAD(*fl); p != NULL; p = next) {
|
|
|
|
next = ISC_LIST_NEXT(p, link);
|
|
|
|
isc_mem_put(pglob->mctx, p->path, strlen(p->path) + 1);
|
|
|
|
isc_mem_put(pglob->mctx, p, sizeof(file_path_t));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* free linked list of files */
|
|
|
|
isc_mem_put(pglob->mctx, pglob->reserved, sizeof(file_list_t));
|
|
|
|
pglob->reserved = NULL;
|
|
|
|
pglob->gl_pathc = 0;
|
|
|
|
pglob->gl_pathv = NULL;
|
|
|
|
|
|
|
|
isc_mem_destroy(&pglob->mctx);
|
|
|
|
pglob->mctx = NULL;
|
|
|
|
}
|
|
|
|
|
2020-04-08 15:46:33 +02:00
|
|
|
#endif /* defined(_WIN32) */
|