diff options
Diffstat (limited to 'src/fluent-bit/plugins/in_tail/tail_scan_win32.c')
-rw-r--r-- | src/fluent-bit/plugins/in_tail/tail_scan_win32.c | 245 |
1 files changed, 245 insertions, 0 deletions
diff --git a/src/fluent-bit/plugins/in_tail/tail_scan_win32.c b/src/fluent-bit/plugins/in_tail/tail_scan_win32.c new file mode 100644 index 000000000..94733f065 --- /dev/null +++ b/src/fluent-bit/plugins/in_tail/tail_scan_win32.c @@ -0,0 +1,245 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2015-2022 The Fluent Bit Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * This file implements glob-like patch matching feature for Windows + * based on Win32 API. + */ + +#include <fluent-bit/flb_info.h> +#include <fluent-bit/flb_compat.h> +#include <fluent-bit/flb_input_plugin.h> +#include <fluent-bit/flb_utils.h> + +#include <shlwapi.h> + +#include "tail.h" +#include "tail_file.h" +#include "tail_signal.h" +#include "tail_config.h" + +#include "win32.h" + +static int tail_is_excluded(char *path, struct flb_tail_config *ctx) +{ + struct mk_list *head; + struct flb_slist_entry *pattern; + + if (!ctx->exclude_list) { + return FLB_FALSE; + } + + mk_list_foreach(head, ctx->exclude_list) { + pattern = mk_list_entry(head, struct flb_slist_entry, _head); + if (PathMatchSpecA(path, pattern->str)) { + return FLB_TRUE; + } + } + + return FLB_FALSE; +} + +/* + * This function is a thin wrapper over flb_tail_file_append(), + * adding normalization and sanity checks on top of it. + */ +static int tail_register_file(const char *target, struct flb_tail_config *ctx, + time_t ts) +{ + int64_t mtime; + struct stat st; + char path[MAX_PATH]; + + if (_fullpath(path, target, MAX_PATH) == NULL) { + flb_plg_error(ctx->ins, "cannot get absolute path of %s", target); + return -1; + } + + if (stat(path, &st) != 0 || !S_ISREG(st.st_mode)) { + return -1; + } + + if (ctx->ignore_older > 0) { + mtime = flb_tail_stat_mtime(&st); + if (mtime > 0) { + if ((ts - ctx->ignore_older) > mtime) { + flb_plg_debug(ctx->ins, "excluded=%s (ignore_older)", + target); + return -1; + } + } + } + + if (tail_is_excluded(path, ctx) == FLB_TRUE) { + flb_plg_trace(ctx->ins, "skip '%s' (excluded)", path); + return -1; + } + + return flb_tail_file_append(path, &st, FLB_TAIL_STATIC, ctx); +} + +/* + * Perform patern match on the given path string. This function + * supports patterns with "nested" wildcards like below. + * + * tail_scan_pattern("C:\fluent-bit\*\*.txt", ctx); + * + * On success, the number of files found is returned (zero indicates + * "no file found"). On error, -1 is returned. + */ +static int tail_scan_pattern(const char *path, struct flb_tail_config *ctx) +{ + char *star, *p0, *p1; + char pattern[MAX_PATH]; + char buf[MAX_PATH]; + int ret; + int n_added = 0; + time_t now; + int64_t mtime; + HANDLE h; + WIN32_FIND_DATA data; + + if (strlen(path) > MAX_PATH - 1) { + flb_plg_error(ctx->ins, "path too long '%s'"); + return -1; + } + + star = strchr(path, '*'); + if (star == NULL) { + return -1; + } + + /* + * C:\data\tmp\input_*.conf + * 0<-----| + */ + p0 = star; + while (path <= p0 && *p0 != '\\') { + p0--; + } + + /* + * C:\data\tmp\input_*.conf + * |---->1 + */ + p1 = star; + while (*p1 && *p1 != '\\') { + p1++; + } + + memcpy(pattern, path, (p1 - path)); + pattern[p1 - path] = '\0'; + + h = FindFirstFileA(pattern, &data); + if (h == INVALID_HANDLE_VALUE) { + return 0; /* none matched */ + } + + now = time(NULL); + do { + /* Ignore the current and parent dirs */ + if (!strcmp(".", data.cFileName) || !strcmp("..", data.cFileName)) { + continue; + } + + /* Avoid an infinite loop */ + if (strchr(data.cFileName, '*')) { + continue; + } + + /* Create a path (prefix + filename + suffix) */ + memcpy(buf, path, p0 - path + 1); + buf[p0 - path + 1] = '\0'; + + if (strlen(buf) + strlen(data.cFileName) + strlen(p1) > MAX_PATH - 1) { + flb_plg_warn(ctx->ins, "'%s%s%s' is too long", buf, data.cFileName, p1); + continue; + } + strcat(buf, data.cFileName); + strcat(buf, p1); + + if (strchr(p1, '*')) { + ret = tail_scan_pattern(buf, ctx); /* recursive */ + if (ret >= 0) { + n_added += ret; + } + continue; + } + + /* Try to register the target file */ + ret = tail_register_file(buf, ctx, now); + if (ret == 0) { + n_added++; + } + } while (FindNextFileA(h, &data) != 0); + + FindClose(h); + return n_added; +} + +static int tail_filepath(char *buf, int len, const char *basedir, const char *filename) +{ + char drive[_MAX_DRIVE]; + char dir[_MAX_DIR]; + char fname[_MAX_FNAME]; + char ext[_MAX_EXT]; + char tmp[MAX_PATH]; + int ret; + + ret = _splitpath_s(basedir, drive, _MAX_DRIVE, dir, _MAX_DIR, NULL, 0, NULL, 0); + if (ret) { + return -1; + } + + ret = _splitpath_s(filename, NULL, 0, NULL, 0, fname, _MAX_FNAME, ext, _MAX_EXT); + if (ret) { + return -1; + } + + ret = _makepath_s(tmp, MAX_PATH, drive, dir, fname, ext); + if (ret) { + return -1; + } + + if (_fullpath(buf, tmp, len) == NULL) { + return -1; + } + + return 0; +} + +static int tail_scan_path(const char *path, struct flb_tail_config *ctx) +{ + int ret; + int n_added = 0; + time_t now; + + if (strchr(path, '*')) { + return tail_scan_pattern(path, ctx); + } + + /* No wildcard involved. Let's just handle the file... */ + now = time(NULL); + ret = tail_register_file(path, ctx, now); + if (ret == 0) { + n_added++; + } + + return n_added; +} |