Skip to content

Commit 0daa930

Browse files
fujimotosedsiper
authored andcommitted
in_tail: add POSIX emulation layer for Windows
This commit does the large potion of work that we need to bring the new, refactored logic to Windows. - INODE: Windows' native stat(2) lacks the support for inode, and always return `0` for st_ino. Our implementation fixes it by emulating inodes using NTFS File IDs. - SYMLINK: A symbolic link on NTFS is a file with a certain reparse point. We added the support for it too, so that lstat(2) just works on Windows. To use the new implementation, just include "win32.h": #include "win32.h" ... then you can start using stat/lstat/fstat/open functions just as in POSIX systems. Signed-off-by: Fujimoto Seiji <[email protected]>
1 parent 1d19acd commit 0daa930

File tree

6 files changed

+370
-0
lines changed

6 files changed

+370
-0
lines changed

plugins/in_tail/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ if(FLB_PARSER)
2020
endif()
2121

2222
if(MSVC)
23+
set(src
24+
${src}
25+
win32/stat.c
26+
win32/io.c
27+
)
2328
FLB_PLUGIN(in_tail "${src}" "Shlwapi")
2429
else()
2530
FLB_PLUGIN(in_tail "${src}" "")

plugins/in_tail/win32.h

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2+
3+
/* Fluent Bit
4+
* ==========
5+
* Copyright (C) 2019-2020 The Fluent Bit Authors
6+
* Copyright (C) 2015-2018 Treasure Data Inc.
7+
*
8+
* Licensed under the Apache License, Version 2.0 (the "License");
9+
* you may not use this file except in compliance with the License.
10+
* You may obtain a copy of the License at
11+
*
12+
* http://www.apache.org/licenses/LICENSE-2.0
13+
*
14+
* Unless required by applicable law or agreed to in writing, software
15+
* distributed under the License is distributed on an "AS IS" BASIS,
16+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17+
* See the License for the specific language governing permissions and
18+
* limitations under the License.
19+
*/
20+
21+
/*
22+
* This is the interface file that replaces POSIX functions
23+
* with our own custom implementation.
24+
*/
25+
26+
#ifndef FLB_TAIL_WIN32_H
27+
#define FLB_TAIL_WIN32_H
28+
29+
#include "win32/interface.h"
30+
31+
#undef open
32+
#undef stat
33+
#undef lstat
34+
#undef fstat
35+
36+
#undef S_IFDIR
37+
#undef S_IFCHR
38+
#undef S_IFIFO
39+
#undef S_IFREG
40+
#undef S_IFLNK
41+
#undef S_IFMT
42+
#undef S_ISDIR
43+
#undef S_ISCHR
44+
#undef S_ISFIFO
45+
#undef S_ISREG
46+
#undef S_ISLNK
47+
48+
#define open win32_open
49+
#define stat win32_stat
50+
#define lstat win32_lstat
51+
#define fstat win32_fstat
52+
53+
#define S_IFDIR WIN32_S_IFDIR
54+
#define S_IFCHR WIN32_S_IFCHR
55+
#define S_IFIFO WIN32_S_IFIFO
56+
#define S_IFREG WIN32_S_IFREG
57+
#define S_IFLNK WIN32_S_IFLNK
58+
#define S_IFMT WIN32_S_IFMT
59+
60+
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
61+
#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
62+
#define S_ISIFO(m) (((m) & S_IFMT) == S_IFIFO)
63+
#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
64+
#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
65+
#endif

plugins/in_tail/win32/interface.h

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2+
3+
/* Fluent Bit
4+
* ==========
5+
* Copyright (C) 2019-2020 The Fluent Bit Authors
6+
* Copyright (C) 2015-2018 Treasure Data Inc.
7+
*
8+
* Licensed under the Apache License, Version 2.0 (the "License");
9+
* you may not use this file except in compliance with the License.
10+
* You may obtain a copy of the License at
11+
*
12+
* http://www.apache.org/licenses/LICENSE-2.0
13+
*
14+
* Unless required by applicable law or agreed to in writing, software
15+
* distributed under the License is distributed on an "AS IS" BASIS,
16+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17+
* See the License for the specific language governing permissions and
18+
* limitations under the License.
19+
*/
20+
21+
#ifndef FLB_TAIL_WIN32_INTERFACE_H
22+
#define FLB_TAIL_WIN32_INTERFACE_H
23+
24+
struct win32_stat {
25+
uint64_t st_ino;
26+
uint16_t st_mode;
27+
int64_t st_mtime;
28+
int16_t st_nlink;
29+
int64_t st_size;
30+
};
31+
32+
int win32_stat(const char *path, struct win32_stat *wst);
33+
int win32_lstat(const char *path, struct win32_stat *wst);
34+
int win32_fstat(int fd, struct win32_stat *wst);
35+
36+
int win32_open(const char *path, int flags);
37+
38+
#define WIN32_S_IFDIR 0x1000
39+
#define WIN32_S_IFCHR 0x2000
40+
#define WIN32_S_IFIFO 0x4000
41+
#define WIN32_S_IFREG 0x8000
42+
#define WIN32_S_IFLNK 0xc000
43+
#define WIN32_S_IFMT 0xf000
44+
45+
#endif

plugins/in_tail/win32/io.c

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2+
3+
/* Fluent Bit
4+
* ==========
5+
* Copyright (C) 2019-2020 The Fluent Bit Authors
6+
* Copyright (C) 2015-2018 Treasure Data Inc.
7+
*
8+
* Licensed under the Apache License, Version 2.0 (the "License");
9+
* you may not use this file except in compliance with the License.
10+
* You may obtain a copy of the License at
11+
*
12+
* http://www.apache.org/licenses/LICENSE-2.0
13+
*
14+
* Unless required by applicable law or agreed to in writing, software
15+
* distributed under the License is distributed on an "AS IS" BASIS,
16+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17+
* See the License for the specific language governing permissions and
18+
* limitations under the License.
19+
*/
20+
21+
#include <Windows.h>
22+
#include <stdlib.h>
23+
#include <stdint.h>
24+
#include <fcntl.h>
25+
#include <io.h>
26+
#include "interface.h"
27+
28+
/*
29+
* POSIX IO emulation tailored for in_tail's usage.
30+
*
31+
* open(2) that does not acquire an exclusive lock.
32+
*/
33+
34+
int win32_open(const char *path, int flags)
35+
{
36+
HANDLE h;
37+
h = CreateFileA(path,
38+
GENERIC_READ,
39+
FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
40+
NULL, /* lpSecurityAttributes */
41+
OPEN_EXISTING, /* dwCreationDisposition */
42+
0, /* dwFlagsAndAttributes */
43+
NULL); /* hTemplateFile */
44+
if (h == INVALID_HANDLE_VALUE) {
45+
return -1;
46+
}
47+
return _open_osfhandle((intptr_t) h, _O_RDONLY);
48+
}

plugins/in_tail/win32/stat.c

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2+
3+
/* Fluent Bit
4+
* ==========
5+
* Copyright (C) 2019-2020 The Fluent Bit Authors
6+
* Copyright (C) 2015-2018 Treasure Data Inc.
7+
*
8+
* Licensed under the Apache License, Version 2.0 (the "License");
9+
* you may not use this file except in compliance with the License.
10+
* You may obtain a copy of the License at
11+
*
12+
* http://www.apache.org/licenses/LICENSE-2.0
13+
*
14+
* Unless required by applicable law or agreed to in writing, software
15+
* distributed under the License is distributed on an "AS IS" BASIS,
16+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17+
* See the License for the specific language governing permissions and
18+
* limitations under the License.
19+
*/
20+
21+
#include <Windows.h>
22+
#include <stdlib.h>
23+
#include <stdint.h>
24+
#include <io.h>
25+
#include "interface.h"
26+
27+
/*
28+
* NTFS stat(2) emulation tailored for in_tail's usage.
29+
*
30+
* (1) Support st_ino (inode) for Windows NTFS.
31+
* (2) Support NTFS symlinks.
32+
* (3) Support large files >= 2GB.
33+
*
34+
* To use it, include "win32.h" and it will transparently
35+
* replace stat(), lstat() and fstat().
36+
*/
37+
38+
#define UINT64(high, low) ((uint64_t) (high) << 32 | (low))
39+
40+
static int get_mode(unsigned int attr)
41+
{
42+
if (attr & FILE_ATTRIBUTE_DIRECTORY) {
43+
return WIN32_S_IFDIR;
44+
}
45+
return WIN32_S_IFREG;
46+
}
47+
48+
static int is_symlink(const char *path)
49+
{
50+
WIN32_FIND_DATA data;
51+
HANDLE h;
52+
53+
h = FindFirstFileA(path, &data);
54+
if (h == INVALID_HANDLE_VALUE) {
55+
return 0;
56+
}
57+
FindClose(h);
58+
59+
/*
60+
* A NTFS symlink is a file with a bit of metadata ("reparse point"),
61+
* So (1) check if the file has metadata and then (2) confirm that
62+
* it is indeed a symlink.
63+
*/
64+
if (data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
65+
if (data.dwReserved0 == IO_REPARSE_TAG_SYMLINK) {
66+
return 1;
67+
}
68+
}
69+
return 0;
70+
}
71+
72+
static int hstat(HANDLE h, struct win32_stat *wst)
73+
{
74+
BY_HANDLE_FILE_INFORMATION info;
75+
FILE_STANDARD_INFO std;
76+
FILETIME time;
77+
78+
if (!GetFileInformationByHandle(h, &info)) {
79+
return -1;
80+
}
81+
82+
if (!GetFileInformationByHandleEx(h, FileStandardInfo,
83+
&std, sizeof(std))) {
84+
return -1;
85+
}
86+
87+
wst->st_nlink = std.NumberOfLinks;
88+
if (std.DeletePending) {
89+
wst->st_nlink = 0;
90+
}
91+
time = info.ftLastWriteTime;
92+
93+
wst->st_mode = get_mode(info.dwFileAttributes);
94+
wst->st_size = UINT64(info.nFileSizeHigh, info.nFileSizeLow);
95+
wst->st_ino = UINT64(info.nFileIndexHigh, info.nFileIndexLow);
96+
wst->st_mtime = UINT64(time.dwHighDateTime, time.dwLowDateTime);
97+
98+
return 0;
99+
}
100+
101+
int win32_stat(const char *path, struct win32_stat *wst)
102+
{
103+
HANDLE h;
104+
105+
h = CreateFileA(path,
106+
GENERIC_READ,
107+
FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
108+
NULL, /* lpSecurityAttributes */
109+
OPEN_EXISTING, /* dwCreationDisposition */
110+
0, /* dwFlagsAndAttributes */
111+
NULL); /* hTemplateFile */
112+
113+
if (h == INVALID_HANDLE_VALUE) {
114+
return -1;
115+
}
116+
117+
if (hstat(h, wst)) {
118+
CloseHandle(h);
119+
return -1;
120+
}
121+
122+
CloseHandle(h);
123+
return 0;
124+
}
125+
126+
int win32_lstat(const char *path, struct win32_stat *wst)
127+
{
128+
HANDLE h;
129+
130+
h = CreateFileA(path,
131+
GENERIC_READ,
132+
FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
133+
NULL, /* lpSecurityAttributes */
134+
OPEN_EXISTING, /* dwCreationDisposition */
135+
FILE_FLAG_OPEN_REPARSE_POINT,
136+
NULL); /* hTemplateFile */
137+
138+
if (h == INVALID_HANDLE_VALUE) {
139+
return -1;
140+
}
141+
142+
if (hstat(h, wst)) {
143+
CloseHandle(h);
144+
return -1;
145+
}
146+
147+
if (is_symlink(path)) {
148+
wst->st_mode = WIN32_S_IFLNK;
149+
}
150+
151+
CloseHandle(h);
152+
return 0;
153+
}
154+
155+
int win32_fstat(int fd, struct win32_stat *wst)
156+
{
157+
HANDLE h;
158+
159+
h = (HANDLE) _get_osfhandle(fd);
160+
if (h == INVALID_HANDLE_VALUE) {
161+
return -1;
162+
}
163+
164+
return hstat(h, wst);
165+
}

plugins/in_tail/win32/stat.h

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2+
3+
/* Fluent Bit
4+
* ==========
5+
* Copyright (C) 2019-2020 The Fluent Bit Authors
6+
* Copyright (C) 2015-2018 Treasure Data Inc.
7+
*
8+
* Licensed under the Apache License, Version 2.0 (the "License");
9+
* you may not use this file except in compliance with the License.
10+
* You may obtain a copy of the License at
11+
*
12+
* http://www.apache.org/licenses/LICENSE-2.0
13+
*
14+
* Unless required by applicable law or agreed to in writing, software
15+
* distributed under the License is distributed on an "AS IS" BASIS,
16+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17+
* See the License for the specific language governing permissions and
18+
* limitations under the License.
19+
*/
20+
21+
#ifndef FLB_TAIL_WIN32_STAT_H
22+
#define FLB_TAIL_WIN32_STAT_H
23+
24+
struct win32_stat {
25+
uint64_t st_ino;
26+
uint16_t st_mode;
27+
int32_t st_nlink;
28+
int64_t st_size;
29+
};
30+
31+
int win32_stat(const char *path, struct win32_stat *wst);
32+
int win32_lstat(const char *path, struct win32_stat *wst);
33+
int win32_fstat(const char *path, struct win32_stat *wst);
34+
35+
#define WIN32_S_IFDIR 0x1000
36+
#define WIN32_S_IFCHR 0x2000
37+
#define WIN32_S_IFIFO 0x4000
38+
#define WIN32_S_IFREG 0x8000
39+
#define WIN32_S_IFLNK 0xc000
40+
#define WIN32_S_IFMT 0xf000
41+
42+
#endif

0 commit comments

Comments
 (0)