1 /*
2 ** Zabbix
3 ** Copyright (C) 2001-2021 Zabbix SIA
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18 **/
19 
20 #include "common.h"
21 #include "zbxtypes.h"
22 
23 #if defined(_WINDOWS) || defined(__MINGW32__)
24 #include "symbols.h"
25 
__zbx_open(const char * pathname,int flags)26 int	__zbx_open(const char *pathname, int flags)
27 {
28 	int	ret;
29 	wchar_t	*wpathname;
30 
31 	wpathname = zbx_utf8_to_unicode(pathname);
32 	ret = _wopen(wpathname, flags);
33 	zbx_free(wpathname);
34 
35 	return ret;
36 }
37 #endif
38 
find_cr_lf_szbyte(const char * encoding,const char ** cr,const char ** lf,size_t * szbyte)39 void	find_cr_lf_szbyte(const char *encoding, const char **cr, const char **lf, size_t *szbyte)
40 {
41 	/* default is single-byte character set */
42 	*cr = "\r";
43 	*lf = "\n";
44 	*szbyte = 1;
45 
46 	if ('\0' != *encoding)
47 	{
48 		if (0 == strcasecmp(encoding, "UNICODE") || 0 == strcasecmp(encoding, "UNICODELITTLE") ||
49 				0 == strcasecmp(encoding, "UTF-16") || 0 == strcasecmp(encoding, "UTF-16LE") ||
50 				0 == strcasecmp(encoding, "UTF16") || 0 == strcasecmp(encoding, "UTF16LE") ||
51 				0 == strcasecmp(encoding, "UCS-2") || 0 == strcasecmp(encoding, "UCS-2LE"))
52 		{
53 			*cr = "\r\0";
54 			*lf = "\n\0";
55 			*szbyte = 2;
56 		}
57 		else if (0 == strcasecmp(encoding, "UNICODEBIG") || 0 == strcasecmp(encoding, "UNICODEFFFE") ||
58 				0 == strcasecmp(encoding, "UTF-16BE") || 0 == strcasecmp(encoding, "UTF16BE") ||
59 				0 == strcasecmp(encoding, "UCS-2BE"))
60 		{
61 			*cr = "\0\r";
62 			*lf = "\0\n";
63 			*szbyte = 2;
64 		}
65 		else if (0 == strcasecmp(encoding, "UTF-32") || 0 == strcasecmp(encoding, "UTF-32LE") ||
66 				0 == strcasecmp(encoding, "UTF32") || 0 == strcasecmp(encoding, "UTF32LE"))
67 		{
68 			*cr = "\r\0\0\0";
69 			*lf = "\n\0\0\0";
70 			*szbyte = 4;
71 		}
72 		else if (0 == strcasecmp(encoding, "UTF-32BE") || 0 == strcasecmp(encoding, "UTF32BE"))
73 		{
74 			*cr = "\0\0\0\r";
75 			*lf = "\0\0\0\n";
76 			*szbyte = 4;
77 		}
78 	}
79 }
80 
81 /******************************************************************************
82  *                                                                            *
83  * Function: zbx_read                                                         *
84  *                                                                            *
85  * Purpose: Read one text line from a file descriptor into buffer             *
86  *                                                                            *
87  * Parameters: fd       - [IN] file descriptor to read from                   *
88  *             buf      - [IN] buffer to read into                            *
89  *             count    - [IN] buffer size in bytes                           *
90  *             encoding - [IN] pointer to a text string describing encoding.  *
91  *                        See function find_cr_lf_szbyte() for supported      *
92  *                        encodings.                                          *
93  *                        "" (empty string) means a single-byte character set.*
94  *                                                                            *
95  * Return value: On success, the number of bytes read is returned (0 (zero)   *
96  *               indicates end of file).                                      *
97  *               On error, -1 is returned and errno is set appropriately.     *
98  *                                                                            *
99  * Comments: Reading stops after a newline. If the newline is read, it is     *
100  *           stored into the buffer.                                          *
101  *                                                                            *
102  ******************************************************************************/
zbx_read(int fd,char * buf,size_t count,const char * encoding)103 int	zbx_read(int fd, char *buf, size_t count, const char *encoding)
104 {
105 	size_t		i, szbyte;
106 	ssize_t		nbytes;
107 	const char	*cr, *lf;
108 	zbx_offset_t	offset;
109 
110 	if ((zbx_offset_t)-1 == (offset = zbx_lseek(fd, 0, SEEK_CUR)))
111 		return -1;
112 
113 	if (0 >= (nbytes = read(fd, buf, count)))
114 		return (int)nbytes;
115 
116 	find_cr_lf_szbyte(encoding, &cr, &lf, &szbyte);
117 
118 	for (i = 0; i <= (size_t)nbytes - szbyte; i += szbyte)
119 	{
120 		if (0 == memcmp(&buf[i], lf, szbyte))	/* LF (Unix) */
121 		{
122 			i += szbyte;
123 			break;
124 		}
125 
126 		if (0 == memcmp(&buf[i], cr, szbyte))	/* CR (Mac) */
127 		{
128 			/* CR+LF (Windows) ? */
129 			if (i < (size_t)nbytes - szbyte && 0 == memcmp(&buf[i + szbyte], lf, szbyte))
130 				i += szbyte;
131 
132 			i += szbyte;
133 			break;
134 		}
135 	}
136 
137 	if ((zbx_offset_t)-1 == zbx_lseek(fd, offset + (zbx_offset_t)i, SEEK_SET))
138 		return -1;
139 
140 	return (int)i;
141 }
142 
zbx_is_regular_file(const char * path)143 int	zbx_is_regular_file(const char *path)
144 {
145 	zbx_stat_t	st;
146 
147 	if (0 == zbx_stat(path, &st) && 0 != S_ISREG(st.st_mode))
148 		return SUCCEED;
149 
150 	return FAIL;
151 }
152 
153 #ifndef _WINDOWS
zbx_get_file_time(const char * path,zbx_file_time_t * time)154 int	zbx_get_file_time(const char *path, zbx_file_time_t *time)
155 {
156 	zbx_stat_t	buf;
157 
158 	if (0 != zbx_stat(path, &buf))
159 		return FAIL;
160 
161 	time->access_time = (zbx_fs_time_t)buf.st_atime;
162 	time->modification_time = (zbx_fs_time_t)buf.st_mtime;
163 	time->change_time = (zbx_fs_time_t)buf.st_ctime;
164 
165 	return SUCCEED;
166 }
167 
zbx_fgets(char * buffer,int size,FILE * fp)168 char	*zbx_fgets(char *buffer, int size, FILE *fp)
169 {
170 	char	*s;
171 
172 	do
173 	{
174 		errno = 0;
175 		s = fgets(buffer, size, fp);
176 	}
177 	while (EINTR == errno && NULL == s);
178 
179 	return s;
180 }
181 #else	/* _WINDOWS */
get_file_time_stat(const char * path,zbx_file_time_t * time)182 static	int	get_file_time_stat(const char *path, zbx_file_time_t *time)
183 {
184 	zbx_stat_t	buf;
185 
186 	if (0 != zbx_stat(path, &buf))
187 		return FAIL;
188 
189 	time->modification_time = buf.st_mtime;
190 	time->access_time = buf.st_atime;
191 
192 	/* On Windows st_ctime stores file creation time, not the last change timestamp. */
193 	/* Assigning st_atime to change_time as the closest one.                         */
194 	time->change_time = buf.st_atime;
195 
196 	return SUCCEED;
197 }
198 
zbx_get_file_time(const char * path,zbx_file_time_t * time)199 int	zbx_get_file_time(const char *path, zbx_file_time_t *time)
200 {
201 	int			f = -1, ret = SUCCEED;
202 	intptr_t		h;
203 	ZBX_FILE_BASIC_INFO	info;
204 
205 	if (NULL == zbx_GetFileInformationByHandleEx || -1 == (f = zbx_open(path, O_RDONLY)))
206 		return get_file_time_stat(path, time); /* fall back to stat() */
207 
208 	if (-1 == (h = _get_osfhandle(f)) ||
209 			0 == zbx_GetFileInformationByHandleEx((HANDLE)h, zbx_FileBasicInfo, &info, sizeof(info)))
210 	{
211 		ret = FAIL;
212 		goto out;
213 	}
214 
215 #define WINDOWS_TICK 10000000
216 #define SEC_TO_UNIX_EPOCH 11644473600LL
217 
218 	/* Convert 100-nanosecond intervals since January 1, 1601 (UTC) to epoch */
219 	time->modification_time = info.LastWriteTime.QuadPart / WINDOWS_TICK - SEC_TO_UNIX_EPOCH;
220 	time->access_time = info.LastAccessTime.QuadPart / WINDOWS_TICK - SEC_TO_UNIX_EPOCH;
221 	time->change_time = info.ChangeTime.QuadPart / WINDOWS_TICK - SEC_TO_UNIX_EPOCH;
222 
223 #undef WINDOWS_TICK
224 #undef SEC_TO_UNIX_EPOCH
225 
226 out:
227 	if (-1 != f)
228 		close(f);
229 
230 	return ret;
231 }
232 #endif	/* _WINDOWS */
233