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