xref: /nrf52832-nimble/rt-thread/components/net/lwip-2.1.0/src/apps/http/makefsdata/tinydir.h (revision 104654410c56c573564690304ae786df310c91fc)
1*10465441SEvalZero /*
2*10465441SEvalZero Copyright (c) 2013-2017, tinydir authors:
3*10465441SEvalZero - Cong Xu
4*10465441SEvalZero - Lautis Sun
5*10465441SEvalZero - Baudouin Feildel
6*10465441SEvalZero - Andargor <[email protected]>
7*10465441SEvalZero All rights reserved.
8*10465441SEvalZero 
9*10465441SEvalZero Redistribution and use in source and binary forms, with or without
10*10465441SEvalZero modification, are permitted provided that the following conditions are met:
11*10465441SEvalZero 
12*10465441SEvalZero 1. Redistributions of source code must retain the above copyright notice, this
13*10465441SEvalZero    list of conditions and the following disclaimer.
14*10465441SEvalZero 2. Redistributions in binary form must reproduce the above copyright notice,
15*10465441SEvalZero    this list of conditions and the following disclaimer in the documentation
16*10465441SEvalZero    and/or other materials provided with the distribution.
17*10465441SEvalZero 
18*10465441SEvalZero THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19*10465441SEvalZero ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20*10465441SEvalZero WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21*10465441SEvalZero DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
22*10465441SEvalZero ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23*10465441SEvalZero (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24*10465441SEvalZero LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25*10465441SEvalZero ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26*10465441SEvalZero (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27*10465441SEvalZero SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*10465441SEvalZero */
29*10465441SEvalZero #ifndef TINYDIR_H
30*10465441SEvalZero #define TINYDIR_H
31*10465441SEvalZero 
32*10465441SEvalZero #ifdef __cplusplus
33*10465441SEvalZero extern "C" {
34*10465441SEvalZero #endif
35*10465441SEvalZero 
36*10465441SEvalZero #if ((defined _UNICODE) && !(defined UNICODE))
37*10465441SEvalZero #define UNICODE
38*10465441SEvalZero #endif
39*10465441SEvalZero 
40*10465441SEvalZero #if ((defined UNICODE) && !(defined _UNICODE))
41*10465441SEvalZero #define _UNICODE
42*10465441SEvalZero #endif
43*10465441SEvalZero 
44*10465441SEvalZero #include <errno.h>
45*10465441SEvalZero #include <stdlib.h>
46*10465441SEvalZero #include <string.h>
47*10465441SEvalZero #ifdef _MSC_VER
48*10465441SEvalZero # define WIN32_LEAN_AND_MEAN
49*10465441SEvalZero # include <windows.h>
50*10465441SEvalZero # include <tchar.h>
51*10465441SEvalZero # pragma warning(push)
52*10465441SEvalZero # pragma warning (disable : 4996)
53*10465441SEvalZero #else
54*10465441SEvalZero # include <dirent.h>
55*10465441SEvalZero # include <libgen.h>
56*10465441SEvalZero # include <sys/stat.h>
57*10465441SEvalZero # include <stddef.h>
58*10465441SEvalZero #endif
59*10465441SEvalZero #ifdef __MINGW32__
60*10465441SEvalZero # include <tchar.h>
61*10465441SEvalZero #endif
62*10465441SEvalZero 
63*10465441SEvalZero 
64*10465441SEvalZero /* types */
65*10465441SEvalZero 
66*10465441SEvalZero /* Windows UNICODE wide character support */
67*10465441SEvalZero #if defined _MSC_VER || defined __MINGW32__
68*10465441SEvalZero #define _tinydir_char_t TCHAR
69*10465441SEvalZero #define TINYDIR_STRING(s) _TEXT(s)
70*10465441SEvalZero #define _tinydir_strlen _tcslen
71*10465441SEvalZero #define _tinydir_strcpy _tcscpy
72*10465441SEvalZero #define _tinydir_strcat _tcscat
73*10465441SEvalZero #define _tinydir_strcmp _tcscmp
74*10465441SEvalZero #define _tinydir_strrchr _tcsrchr
75*10465441SEvalZero #define _tinydir_strncmp _tcsncmp
76*10465441SEvalZero #else
77*10465441SEvalZero #define _tinydir_char_t char
78*10465441SEvalZero #define TINYDIR_STRING(s) s
79*10465441SEvalZero #define _tinydir_strlen strlen
80*10465441SEvalZero #define _tinydir_strcpy strcpy
81*10465441SEvalZero #define _tinydir_strcat strcat
82*10465441SEvalZero #define _tinydir_strcmp strcmp
83*10465441SEvalZero #define _tinydir_strrchr strrchr
84*10465441SEvalZero #define _tinydir_strncmp strncmp
85*10465441SEvalZero #endif
86*10465441SEvalZero 
87*10465441SEvalZero #if (defined _MSC_VER || defined __MINGW32__)
88*10465441SEvalZero #include <windows.h>
89*10465441SEvalZero #define _TINYDIR_PATH_MAX MAX_PATH
90*10465441SEvalZero #elif defined  __linux__
91*10465441SEvalZero #include <linux/limits.h>
92*10465441SEvalZero #define _TINYDIR_PATH_MAX PATH_MAX
93*10465441SEvalZero #else
94*10465441SEvalZero #define _TINYDIR_PATH_MAX 4096
95*10465441SEvalZero #endif
96*10465441SEvalZero 
97*10465441SEvalZero #ifdef _MSC_VER
98*10465441SEvalZero /* extra chars for the "\\*" mask */
99*10465441SEvalZero # define _TINYDIR_PATH_EXTRA 2
100*10465441SEvalZero #else
101*10465441SEvalZero # define _TINYDIR_PATH_EXTRA 0
102*10465441SEvalZero #endif
103*10465441SEvalZero 
104*10465441SEvalZero #define _TINYDIR_FILENAME_MAX 256
105*10465441SEvalZero 
106*10465441SEvalZero #if (defined _MSC_VER || defined __MINGW32__)
107*10465441SEvalZero #define _TINYDIR_DRIVE_MAX 3
108*10465441SEvalZero #endif
109*10465441SEvalZero 
110*10465441SEvalZero #ifdef _MSC_VER
111*10465441SEvalZero # define _TINYDIR_FUNC static __inline
112*10465441SEvalZero #elif !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L
113*10465441SEvalZero # define _TINYDIR_FUNC static __inline__
114*10465441SEvalZero #else
115*10465441SEvalZero # define _TINYDIR_FUNC static inline
116*10465441SEvalZero #endif
117*10465441SEvalZero 
118*10465441SEvalZero /* readdir_r usage; define TINYDIR_USE_READDIR_R to use it (if supported) */
119*10465441SEvalZero #ifdef TINYDIR_USE_READDIR_R
120*10465441SEvalZero 
121*10465441SEvalZero /* readdir_r is a POSIX-only function, and may not be available under various
122*10465441SEvalZero  * environments/settings, e.g. MinGW. Use readdir fallback */
123*10465441SEvalZero #if _POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _BSD_SOURCE || _SVID_SOURCE ||\
124*10465441SEvalZero 	_POSIX_SOURCE
125*10465441SEvalZero # define _TINYDIR_HAS_READDIR_R
126*10465441SEvalZero #endif
127*10465441SEvalZero #if _POSIX_C_SOURCE >= 200112L
128*10465441SEvalZero # define _TINYDIR_HAS_FPATHCONF
129*10465441SEvalZero # include <unistd.h>
130*10465441SEvalZero #endif
131*10465441SEvalZero #if _BSD_SOURCE || _SVID_SOURCE || \
132*10465441SEvalZero 	(_POSIX_C_SOURCE >= 200809L || _XOPEN_SOURCE >= 700)
133*10465441SEvalZero # define _TINYDIR_HAS_DIRFD
134*10465441SEvalZero # include <sys/types.h>
135*10465441SEvalZero #endif
136*10465441SEvalZero #if defined _TINYDIR_HAS_FPATHCONF && defined _TINYDIR_HAS_DIRFD &&\
137*10465441SEvalZero 	defined _PC_NAME_MAX
138*10465441SEvalZero # define _TINYDIR_USE_FPATHCONF
139*10465441SEvalZero #endif
140*10465441SEvalZero #if defined __MINGW32__ || !defined _TINYDIR_HAS_READDIR_R ||\
141*10465441SEvalZero 	!(defined _TINYDIR_USE_FPATHCONF || defined NAME_MAX)
142*10465441SEvalZero # define _TINYDIR_USE_READDIR
143*10465441SEvalZero #endif
144*10465441SEvalZero 
145*10465441SEvalZero /* Use readdir by default */
146*10465441SEvalZero #else
147*10465441SEvalZero # define _TINYDIR_USE_READDIR
148*10465441SEvalZero #endif
149*10465441SEvalZero 
150*10465441SEvalZero /* MINGW32 has two versions of dirent, ASCII and UNICODE*/
151*10465441SEvalZero #ifndef _MSC_VER
152*10465441SEvalZero #if (defined __MINGW32__) && (defined _UNICODE)
153*10465441SEvalZero #define _TINYDIR_DIR _WDIR
154*10465441SEvalZero #define _tinydir_dirent _wdirent
155*10465441SEvalZero #define _tinydir_opendir _wopendir
156*10465441SEvalZero #define _tinydir_readdir _wreaddir
157*10465441SEvalZero #define _tinydir_closedir _wclosedir
158*10465441SEvalZero #else
159*10465441SEvalZero #define _TINYDIR_DIR DIR
160*10465441SEvalZero #define _tinydir_dirent dirent
161*10465441SEvalZero #define _tinydir_opendir opendir
162*10465441SEvalZero #define _tinydir_readdir readdir
163*10465441SEvalZero #define _tinydir_closedir closedir
164*10465441SEvalZero #endif
165*10465441SEvalZero #endif
166*10465441SEvalZero 
167*10465441SEvalZero /* Allow user to use a custom allocator by defining _TINYDIR_MALLOC and _TINYDIR_FREE. */
168*10465441SEvalZero #if    defined(_TINYDIR_MALLOC) &&  defined(_TINYDIR_FREE)
169*10465441SEvalZero #elif !defined(_TINYDIR_MALLOC) && !defined(_TINYDIR_FREE)
170*10465441SEvalZero #else
171*10465441SEvalZero #error "Either define both alloc and free or none of them!"
172*10465441SEvalZero #endif
173*10465441SEvalZero 
174*10465441SEvalZero #if !defined(_TINYDIR_MALLOC)
175*10465441SEvalZero 	#define _TINYDIR_MALLOC(_size) malloc(_size)
176*10465441SEvalZero 	#define _TINYDIR_FREE(_ptr)    free(_ptr)
177*10465441SEvalZero #endif /* !defined(_TINYDIR_MALLOC) */
178*10465441SEvalZero 
179*10465441SEvalZero typedef struct tinydir_file
180*10465441SEvalZero {
181*10465441SEvalZero 	_tinydir_char_t path[_TINYDIR_PATH_MAX];
182*10465441SEvalZero 	_tinydir_char_t name[_TINYDIR_FILENAME_MAX];
183*10465441SEvalZero 	_tinydir_char_t *extension;
184*10465441SEvalZero 	int is_dir;
185*10465441SEvalZero 	int is_reg;
186*10465441SEvalZero 
187*10465441SEvalZero #ifndef _MSC_VER
188*10465441SEvalZero #ifdef __MINGW32__
189*10465441SEvalZero 	struct _stat _s;
190*10465441SEvalZero #else
191*10465441SEvalZero 	struct stat _s;
192*10465441SEvalZero #endif
193*10465441SEvalZero #endif
194*10465441SEvalZero } tinydir_file;
195*10465441SEvalZero 
196*10465441SEvalZero typedef struct tinydir_dir
197*10465441SEvalZero {
198*10465441SEvalZero 	_tinydir_char_t path[_TINYDIR_PATH_MAX];
199*10465441SEvalZero 	int has_next;
200*10465441SEvalZero 	size_t n_files;
201*10465441SEvalZero 
202*10465441SEvalZero 	tinydir_file *_files;
203*10465441SEvalZero #ifdef _MSC_VER
204*10465441SEvalZero 	HANDLE _h;
205*10465441SEvalZero 	WIN32_FIND_DATA _f;
206*10465441SEvalZero #else
207*10465441SEvalZero 	_TINYDIR_DIR *_d;
208*10465441SEvalZero 	struct _tinydir_dirent *_e;
209*10465441SEvalZero #ifndef _TINYDIR_USE_READDIR
210*10465441SEvalZero 	struct _tinydir_dirent *_ep;
211*10465441SEvalZero #endif
212*10465441SEvalZero #endif
213*10465441SEvalZero } tinydir_dir;
214*10465441SEvalZero 
215*10465441SEvalZero 
216*10465441SEvalZero /* declarations */
217*10465441SEvalZero 
218*10465441SEvalZero _TINYDIR_FUNC
219*10465441SEvalZero int tinydir_open(tinydir_dir *dir, const _tinydir_char_t *path);
220*10465441SEvalZero _TINYDIR_FUNC
221*10465441SEvalZero int tinydir_open_sorted(tinydir_dir *dir, const _tinydir_char_t *path);
222*10465441SEvalZero _TINYDIR_FUNC
223*10465441SEvalZero void tinydir_close(tinydir_dir *dir);
224*10465441SEvalZero 
225*10465441SEvalZero _TINYDIR_FUNC
226*10465441SEvalZero int tinydir_next(tinydir_dir *dir);
227*10465441SEvalZero _TINYDIR_FUNC
228*10465441SEvalZero int tinydir_readfile(const tinydir_dir *dir, tinydir_file *file);
229*10465441SEvalZero _TINYDIR_FUNC
230*10465441SEvalZero int tinydir_readfile_n(const tinydir_dir *dir, tinydir_file *file, size_t i);
231*10465441SEvalZero _TINYDIR_FUNC
232*10465441SEvalZero int tinydir_open_subdir_n(tinydir_dir *dir, size_t i);
233*10465441SEvalZero 
234*10465441SEvalZero _TINYDIR_FUNC
235*10465441SEvalZero int tinydir_file_open(tinydir_file *file, const _tinydir_char_t *path);
236*10465441SEvalZero _TINYDIR_FUNC
237*10465441SEvalZero void _tinydir_get_ext(tinydir_file *file);
238*10465441SEvalZero _TINYDIR_FUNC
239*10465441SEvalZero int _tinydir_file_cmp(const void *a, const void *b);
240*10465441SEvalZero #ifndef _MSC_VER
241*10465441SEvalZero #ifndef _TINYDIR_USE_READDIR
242*10465441SEvalZero _TINYDIR_FUNC
243*10465441SEvalZero size_t _tinydir_dirent_buf_size(_TINYDIR_DIR *dirp);
244*10465441SEvalZero #endif
245*10465441SEvalZero #endif
246*10465441SEvalZero 
247*10465441SEvalZero 
248*10465441SEvalZero /* definitions*/
249*10465441SEvalZero 
250*10465441SEvalZero _TINYDIR_FUNC
tinydir_open(tinydir_dir * dir,const _tinydir_char_t * path)251*10465441SEvalZero int tinydir_open(tinydir_dir *dir, const _tinydir_char_t *path)
252*10465441SEvalZero {
253*10465441SEvalZero #ifndef _MSC_VER
254*10465441SEvalZero #ifndef _TINYDIR_USE_READDIR
255*10465441SEvalZero 	int error;
256*10465441SEvalZero 	int size;	/* using int size */
257*10465441SEvalZero #endif
258*10465441SEvalZero #else
259*10465441SEvalZero 	_tinydir_char_t path_buf[_TINYDIR_PATH_MAX];
260*10465441SEvalZero #endif
261*10465441SEvalZero 	_tinydir_char_t *pathp;
262*10465441SEvalZero 
263*10465441SEvalZero 	if (dir == NULL || path == NULL || _tinydir_strlen(path) == 0)
264*10465441SEvalZero 	{
265*10465441SEvalZero 		errno = EINVAL;
266*10465441SEvalZero 		return -1;
267*10465441SEvalZero 	}
268*10465441SEvalZero 	if (_tinydir_strlen(path) + _TINYDIR_PATH_EXTRA >= _TINYDIR_PATH_MAX)
269*10465441SEvalZero 	{
270*10465441SEvalZero 		errno = ENAMETOOLONG;
271*10465441SEvalZero 		return -1;
272*10465441SEvalZero 	}
273*10465441SEvalZero 
274*10465441SEvalZero 	/* initialise dir */
275*10465441SEvalZero 	dir->_files = NULL;
276*10465441SEvalZero #ifdef _MSC_VER
277*10465441SEvalZero 	dir->_h = INVALID_HANDLE_VALUE;
278*10465441SEvalZero #else
279*10465441SEvalZero 	dir->_d = NULL;
280*10465441SEvalZero #ifndef _TINYDIR_USE_READDIR
281*10465441SEvalZero 	dir->_ep = NULL;
282*10465441SEvalZero #endif
283*10465441SEvalZero #endif
284*10465441SEvalZero 	tinydir_close(dir);
285*10465441SEvalZero 
286*10465441SEvalZero 	_tinydir_strcpy(dir->path, path);
287*10465441SEvalZero 	/* Remove trailing slashes */
288*10465441SEvalZero 	pathp = &dir->path[_tinydir_strlen(dir->path) - 1];
289*10465441SEvalZero 	while (pathp != dir->path && (*pathp == TINYDIR_STRING('\\') || *pathp == TINYDIR_STRING('/')))
290*10465441SEvalZero 	{
291*10465441SEvalZero 		*pathp = TINYDIR_STRING('\0');
292*10465441SEvalZero 		pathp++;
293*10465441SEvalZero 	}
294*10465441SEvalZero #ifdef _MSC_VER
295*10465441SEvalZero 	_tinydir_strcpy(path_buf, dir->path);
296*10465441SEvalZero 	_tinydir_strcat(path_buf, TINYDIR_STRING("\\*"));
297*10465441SEvalZero #if (defined WINAPI_FAMILY) && (WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP)
298*10465441SEvalZero 	dir->_h = FindFirstFileEx(path_buf, FindExInfoStandard, &dir->_f, FindExSearchNameMatch, NULL, 0);
299*10465441SEvalZero #else
300*10465441SEvalZero 	dir->_h = FindFirstFile(path_buf, &dir->_f);
301*10465441SEvalZero #endif
302*10465441SEvalZero 	if (dir->_h == INVALID_HANDLE_VALUE)
303*10465441SEvalZero 	{
304*10465441SEvalZero 		errno = ENOENT;
305*10465441SEvalZero #else
306*10465441SEvalZero 	dir->_d = _tinydir_opendir(path);
307*10465441SEvalZero 	if (dir->_d == NULL)
308*10465441SEvalZero 	{
309*10465441SEvalZero #endif
310*10465441SEvalZero 		goto bail;
311*10465441SEvalZero 	}
312*10465441SEvalZero 
313*10465441SEvalZero 	/* read first file */
314*10465441SEvalZero 	dir->has_next = 1;
315*10465441SEvalZero #ifndef _MSC_VER
316*10465441SEvalZero #ifdef _TINYDIR_USE_READDIR
317*10465441SEvalZero 	dir->_e = _tinydir_readdir(dir->_d);
318*10465441SEvalZero #else
319*10465441SEvalZero 	/* allocate dirent buffer for readdir_r */
320*10465441SEvalZero 	size = _tinydir_dirent_buf_size(dir->_d); /* conversion to int */
321*10465441SEvalZero 	if (size == -1) return -1;
322*10465441SEvalZero 	dir->_ep = (struct _tinydir_dirent*)_TINYDIR_MALLOC(size);
323*10465441SEvalZero 	if (dir->_ep == NULL) return -1;
324*10465441SEvalZero 
325*10465441SEvalZero 	error = readdir_r(dir->_d, dir->_ep, &dir->_e);
326*10465441SEvalZero 	if (error != 0) return -1;
327*10465441SEvalZero #endif
328*10465441SEvalZero 	if (dir->_e == NULL)
329*10465441SEvalZero 	{
330*10465441SEvalZero 		dir->has_next = 0;
331*10465441SEvalZero 	}
332*10465441SEvalZero #endif
333*10465441SEvalZero 
334*10465441SEvalZero 	return 0;
335*10465441SEvalZero 
336*10465441SEvalZero bail:
337*10465441SEvalZero 	tinydir_close(dir);
338*10465441SEvalZero 	return -1;
339*10465441SEvalZero }
340*10465441SEvalZero 
341*10465441SEvalZero _TINYDIR_FUNC
342*10465441SEvalZero int tinydir_open_sorted(tinydir_dir *dir, const _tinydir_char_t *path)
343*10465441SEvalZero {
344*10465441SEvalZero 	/* Count the number of files first, to pre-allocate the files array */
345*10465441SEvalZero 	size_t n_files = 0;
346*10465441SEvalZero 	if (tinydir_open(dir, path) == -1)
347*10465441SEvalZero 	{
348*10465441SEvalZero 		return -1;
349*10465441SEvalZero 	}
350*10465441SEvalZero 	while (dir->has_next)
351*10465441SEvalZero 	{
352*10465441SEvalZero 		n_files++;
353*10465441SEvalZero 		if (tinydir_next(dir) == -1)
354*10465441SEvalZero 		{
355*10465441SEvalZero 			goto bail;
356*10465441SEvalZero 		}
357*10465441SEvalZero 	}
358*10465441SEvalZero 	tinydir_close(dir);
359*10465441SEvalZero 
360*10465441SEvalZero 	if (tinydir_open(dir, path) == -1)
361*10465441SEvalZero 	{
362*10465441SEvalZero 		return -1;
363*10465441SEvalZero 	}
364*10465441SEvalZero 
365*10465441SEvalZero 	dir->n_files = 0;
366*10465441SEvalZero 	dir->_files = (tinydir_file *)_TINYDIR_MALLOC(sizeof *dir->_files * n_files);
367*10465441SEvalZero 	if (dir->_files == NULL)
368*10465441SEvalZero 	{
369*10465441SEvalZero 		goto bail;
370*10465441SEvalZero 	}
371*10465441SEvalZero 	while (dir->has_next)
372*10465441SEvalZero 	{
373*10465441SEvalZero 		tinydir_file *p_file;
374*10465441SEvalZero 		dir->n_files++;
375*10465441SEvalZero 
376*10465441SEvalZero 		p_file = &dir->_files[dir->n_files - 1];
377*10465441SEvalZero 		if (tinydir_readfile(dir, p_file) == -1)
378*10465441SEvalZero 		{
379*10465441SEvalZero 			goto bail;
380*10465441SEvalZero 		}
381*10465441SEvalZero 
382*10465441SEvalZero 		if (tinydir_next(dir) == -1)
383*10465441SEvalZero 		{
384*10465441SEvalZero 			goto bail;
385*10465441SEvalZero 		}
386*10465441SEvalZero 
387*10465441SEvalZero 		/* Just in case the number of files has changed between the first and
388*10465441SEvalZero 		second reads, terminate without writing into unallocated memory */
389*10465441SEvalZero 		if (dir->n_files == n_files)
390*10465441SEvalZero 		{
391*10465441SEvalZero 			break;
392*10465441SEvalZero 		}
393*10465441SEvalZero 	}
394*10465441SEvalZero 
395*10465441SEvalZero 	qsort(dir->_files, dir->n_files, sizeof(tinydir_file), _tinydir_file_cmp);
396*10465441SEvalZero 
397*10465441SEvalZero 	return 0;
398*10465441SEvalZero 
399*10465441SEvalZero bail:
400*10465441SEvalZero 	tinydir_close(dir);
401*10465441SEvalZero 	return -1;
402*10465441SEvalZero }
403*10465441SEvalZero 
404*10465441SEvalZero _TINYDIR_FUNC
405*10465441SEvalZero void tinydir_close(tinydir_dir *dir)
406*10465441SEvalZero {
407*10465441SEvalZero 	if (dir == NULL)
408*10465441SEvalZero 	{
409*10465441SEvalZero 		return;
410*10465441SEvalZero 	}
411*10465441SEvalZero 
412*10465441SEvalZero 	memset(dir->path, 0, sizeof(dir->path));
413*10465441SEvalZero 	dir->has_next = 0;
414*10465441SEvalZero 	dir->n_files = 0;
415*10465441SEvalZero 	_TINYDIR_FREE(dir->_files);
416*10465441SEvalZero 	dir->_files = NULL;
417*10465441SEvalZero #ifdef _MSC_VER
418*10465441SEvalZero 	if (dir->_h != INVALID_HANDLE_VALUE)
419*10465441SEvalZero 	{
420*10465441SEvalZero 		FindClose(dir->_h);
421*10465441SEvalZero 	}
422*10465441SEvalZero 	dir->_h = INVALID_HANDLE_VALUE;
423*10465441SEvalZero #else
424*10465441SEvalZero 	if (dir->_d)
425*10465441SEvalZero 	{
426*10465441SEvalZero 		_tinydir_closedir(dir->_d);
427*10465441SEvalZero 	}
428*10465441SEvalZero 	dir->_d = NULL;
429*10465441SEvalZero 	dir->_e = NULL;
430*10465441SEvalZero #ifndef _TINYDIR_USE_READDIR
431*10465441SEvalZero 	_TINYDIR_FREE(dir->_ep);
432*10465441SEvalZero 	dir->_ep = NULL;
433*10465441SEvalZero #endif
434*10465441SEvalZero #endif
435*10465441SEvalZero }
436*10465441SEvalZero 
437*10465441SEvalZero _TINYDIR_FUNC
438*10465441SEvalZero int tinydir_next(tinydir_dir *dir)
439*10465441SEvalZero {
440*10465441SEvalZero 	if (dir == NULL)
441*10465441SEvalZero 	{
442*10465441SEvalZero 		errno = EINVAL;
443*10465441SEvalZero 		return -1;
444*10465441SEvalZero 	}
445*10465441SEvalZero 	if (!dir->has_next)
446*10465441SEvalZero 	{
447*10465441SEvalZero 		errno = ENOENT;
448*10465441SEvalZero 		return -1;
449*10465441SEvalZero 	}
450*10465441SEvalZero 
451*10465441SEvalZero #ifdef _MSC_VER
452*10465441SEvalZero 	if (FindNextFile(dir->_h, &dir->_f) == 0)
453*10465441SEvalZero #else
454*10465441SEvalZero #ifdef _TINYDIR_USE_READDIR
455*10465441SEvalZero 	dir->_e = _tinydir_readdir(dir->_d);
456*10465441SEvalZero #else
457*10465441SEvalZero 	if (dir->_ep == NULL)
458*10465441SEvalZero 	{
459*10465441SEvalZero 		return -1;
460*10465441SEvalZero 	}
461*10465441SEvalZero 	if (readdir_r(dir->_d, dir->_ep, &dir->_e) != 0)
462*10465441SEvalZero 	{
463*10465441SEvalZero 		return -1;
464*10465441SEvalZero 	}
465*10465441SEvalZero #endif
466*10465441SEvalZero 	if (dir->_e == NULL)
467*10465441SEvalZero #endif
468*10465441SEvalZero 	{
469*10465441SEvalZero 		dir->has_next = 0;
470*10465441SEvalZero #ifdef _MSC_VER
471*10465441SEvalZero 		if (GetLastError() != ERROR_SUCCESS &&
472*10465441SEvalZero 			GetLastError() != ERROR_NO_MORE_FILES)
473*10465441SEvalZero 		{
474*10465441SEvalZero 			tinydir_close(dir);
475*10465441SEvalZero 			errno = EIO;
476*10465441SEvalZero 			return -1;
477*10465441SEvalZero 		}
478*10465441SEvalZero #endif
479*10465441SEvalZero 	}
480*10465441SEvalZero 
481*10465441SEvalZero 	return 0;
482*10465441SEvalZero }
483*10465441SEvalZero 
484*10465441SEvalZero _TINYDIR_FUNC
485*10465441SEvalZero int tinydir_readfile(const tinydir_dir *dir, tinydir_file *file)
486*10465441SEvalZero {
487*10465441SEvalZero 	if (dir == NULL || file == NULL)
488*10465441SEvalZero 	{
489*10465441SEvalZero 		errno = EINVAL;
490*10465441SEvalZero 		return -1;
491*10465441SEvalZero 	}
492*10465441SEvalZero #ifdef _MSC_VER
493*10465441SEvalZero 	if (dir->_h == INVALID_HANDLE_VALUE)
494*10465441SEvalZero #else
495*10465441SEvalZero 	if (dir->_e == NULL)
496*10465441SEvalZero #endif
497*10465441SEvalZero 	{
498*10465441SEvalZero 		errno = ENOENT;
499*10465441SEvalZero 		return -1;
500*10465441SEvalZero 	}
501*10465441SEvalZero 	if (_tinydir_strlen(dir->path) +
502*10465441SEvalZero 		_tinydir_strlen(
503*10465441SEvalZero #ifdef _MSC_VER
504*10465441SEvalZero 			dir->_f.cFileName
505*10465441SEvalZero #else
506*10465441SEvalZero 			dir->_e->d_name
507*10465441SEvalZero #endif
508*10465441SEvalZero 		) + 1 + _TINYDIR_PATH_EXTRA >=
509*10465441SEvalZero 		_TINYDIR_PATH_MAX)
510*10465441SEvalZero 	{
511*10465441SEvalZero 		/* the path for the file will be too long */
512*10465441SEvalZero 		errno = ENAMETOOLONG;
513*10465441SEvalZero 		return -1;
514*10465441SEvalZero 	}
515*10465441SEvalZero 	if (_tinydir_strlen(
516*10465441SEvalZero #ifdef _MSC_VER
517*10465441SEvalZero 			dir->_f.cFileName
518*10465441SEvalZero #else
519*10465441SEvalZero 			dir->_e->d_name
520*10465441SEvalZero #endif
521*10465441SEvalZero 		) >= _TINYDIR_FILENAME_MAX)
522*10465441SEvalZero 	{
523*10465441SEvalZero 		errno = ENAMETOOLONG;
524*10465441SEvalZero 		return -1;
525*10465441SEvalZero 	}
526*10465441SEvalZero 
527*10465441SEvalZero 	_tinydir_strcpy(file->path, dir->path);
528*10465441SEvalZero 	_tinydir_strcat(file->path, TINYDIR_STRING("/"));
529*10465441SEvalZero 	_tinydir_strcpy(file->name,
530*10465441SEvalZero #ifdef _MSC_VER
531*10465441SEvalZero 		dir->_f.cFileName
532*10465441SEvalZero #else
533*10465441SEvalZero 		dir->_e->d_name
534*10465441SEvalZero #endif
535*10465441SEvalZero 	);
536*10465441SEvalZero 	_tinydir_strcat(file->path, file->name);
537*10465441SEvalZero #ifndef _MSC_VER
538*10465441SEvalZero #ifdef __MINGW32__
539*10465441SEvalZero 	if (_tstat(
540*10465441SEvalZero #else
541*10465441SEvalZero 	if (stat(
542*10465441SEvalZero #endif
543*10465441SEvalZero 		file->path, &file->_s) == -1)
544*10465441SEvalZero 	{
545*10465441SEvalZero 		return -1;
546*10465441SEvalZero 	}
547*10465441SEvalZero #endif
548*10465441SEvalZero 	_tinydir_get_ext(file);
549*10465441SEvalZero 
550*10465441SEvalZero 	file->is_dir =
551*10465441SEvalZero #ifdef _MSC_VER
552*10465441SEvalZero 		!!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
553*10465441SEvalZero #else
554*10465441SEvalZero 		S_ISDIR(file->_s.st_mode);
555*10465441SEvalZero #endif
556*10465441SEvalZero 	file->is_reg =
557*10465441SEvalZero #ifdef _MSC_VER
558*10465441SEvalZero 		!!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_NORMAL) ||
559*10465441SEvalZero 		(
560*10465441SEvalZero 			!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DEVICE) &&
561*10465441SEvalZero 			!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
562*10465441SEvalZero 			!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) &&
563*10465441SEvalZero #ifdef FILE_ATTRIBUTE_INTEGRITY_STREAM
564*10465441SEvalZero 			!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_INTEGRITY_STREAM) &&
565*10465441SEvalZero #endif
566*10465441SEvalZero #ifdef FILE_ATTRIBUTE_NO_SCRUB_DATA
567*10465441SEvalZero 			!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_NO_SCRUB_DATA) &&
568*10465441SEvalZero #endif
569*10465441SEvalZero 			!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_OFFLINE) &&
570*10465441SEvalZero 			!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY));
571*10465441SEvalZero #else
572*10465441SEvalZero 		S_ISREG(file->_s.st_mode);
573*10465441SEvalZero #endif
574*10465441SEvalZero 
575*10465441SEvalZero 	return 0;
576*10465441SEvalZero }
577*10465441SEvalZero 
578*10465441SEvalZero _TINYDIR_FUNC
579*10465441SEvalZero int tinydir_readfile_n(const tinydir_dir *dir, tinydir_file *file, size_t i)
580*10465441SEvalZero {
581*10465441SEvalZero 	if (dir == NULL || file == NULL)
582*10465441SEvalZero 	{
583*10465441SEvalZero 		errno = EINVAL;
584*10465441SEvalZero 		return -1;
585*10465441SEvalZero 	}
586*10465441SEvalZero 	if (i >= dir->n_files)
587*10465441SEvalZero 	{
588*10465441SEvalZero 		errno = ENOENT;
589*10465441SEvalZero 		return -1;
590*10465441SEvalZero 	}
591*10465441SEvalZero 
592*10465441SEvalZero 	memcpy(file, &dir->_files[i], sizeof(tinydir_file));
593*10465441SEvalZero 	_tinydir_get_ext(file);
594*10465441SEvalZero 
595*10465441SEvalZero 	return 0;
596*10465441SEvalZero }
597*10465441SEvalZero 
598*10465441SEvalZero _TINYDIR_FUNC
599*10465441SEvalZero int tinydir_open_subdir_n(tinydir_dir *dir, size_t i)
600*10465441SEvalZero {
601*10465441SEvalZero 	_tinydir_char_t path[_TINYDIR_PATH_MAX];
602*10465441SEvalZero 	if (dir == NULL)
603*10465441SEvalZero 	{
604*10465441SEvalZero 		errno = EINVAL;
605*10465441SEvalZero 		return -1;
606*10465441SEvalZero 	}
607*10465441SEvalZero 	if (i >= dir->n_files || !dir->_files[i].is_dir)
608*10465441SEvalZero 	{
609*10465441SEvalZero 		errno = ENOENT;
610*10465441SEvalZero 		return -1;
611*10465441SEvalZero 	}
612*10465441SEvalZero 
613*10465441SEvalZero 	_tinydir_strcpy(path, dir->_files[i].path);
614*10465441SEvalZero 	tinydir_close(dir);
615*10465441SEvalZero 	if (tinydir_open_sorted(dir, path) == -1)
616*10465441SEvalZero 	{
617*10465441SEvalZero 		return -1;
618*10465441SEvalZero 	}
619*10465441SEvalZero 
620*10465441SEvalZero 	return 0;
621*10465441SEvalZero }
622*10465441SEvalZero 
623*10465441SEvalZero /* Open a single file given its path */
624*10465441SEvalZero _TINYDIR_FUNC
625*10465441SEvalZero int tinydir_file_open(tinydir_file *file, const _tinydir_char_t *path)
626*10465441SEvalZero {
627*10465441SEvalZero 	tinydir_dir dir;
628*10465441SEvalZero 	int result = 0;
629*10465441SEvalZero 	int found = 0;
630*10465441SEvalZero 	_tinydir_char_t dir_name_buf[_TINYDIR_PATH_MAX];
631*10465441SEvalZero 	_tinydir_char_t file_name_buf[_TINYDIR_FILENAME_MAX];
632*10465441SEvalZero 	_tinydir_char_t *dir_name;
633*10465441SEvalZero 	_tinydir_char_t *base_name;
634*10465441SEvalZero #if (defined _MSC_VER || defined __MINGW32__)
635*10465441SEvalZero 	_tinydir_char_t drive_buf[_TINYDIR_PATH_MAX];
636*10465441SEvalZero 	_tinydir_char_t ext_buf[_TINYDIR_FILENAME_MAX];
637*10465441SEvalZero #endif
638*10465441SEvalZero 
639*10465441SEvalZero 	if (file == NULL || path == NULL || _tinydir_strlen(path) == 0)
640*10465441SEvalZero 	{
641*10465441SEvalZero 		errno = EINVAL;
642*10465441SEvalZero 		return -1;
643*10465441SEvalZero 	}
644*10465441SEvalZero 	if (_tinydir_strlen(path) + _TINYDIR_PATH_EXTRA >= _TINYDIR_PATH_MAX)
645*10465441SEvalZero 	{
646*10465441SEvalZero 		errno = ENAMETOOLONG;
647*10465441SEvalZero 		return -1;
648*10465441SEvalZero 	}
649*10465441SEvalZero 
650*10465441SEvalZero 	/* Get the parent path */
651*10465441SEvalZero #if (defined _MSC_VER || defined __MINGW32__)
652*10465441SEvalZero #if ((defined _MSC_VER) && (_MSC_VER >= 1400))
653*10465441SEvalZero 		_tsplitpath_s(
654*10465441SEvalZero 			path,
655*10465441SEvalZero 			drive_buf, _TINYDIR_DRIVE_MAX,
656*10465441SEvalZero 			dir_name_buf, _TINYDIR_FILENAME_MAX,
657*10465441SEvalZero 			file_name_buf, _TINYDIR_FILENAME_MAX,
658*10465441SEvalZero 			ext_buf, _TINYDIR_FILENAME_MAX);
659*10465441SEvalZero #else
660*10465441SEvalZero 		_tsplitpath(
661*10465441SEvalZero 			path,
662*10465441SEvalZero 			drive_buf,
663*10465441SEvalZero 			dir_name_buf,
664*10465441SEvalZero 			file_name_buf,
665*10465441SEvalZero 			ext_buf);
666*10465441SEvalZero #endif
667*10465441SEvalZero 
668*10465441SEvalZero /* _splitpath_s not work fine with only filename and widechar support */
669*10465441SEvalZero #ifdef _UNICODE
670*10465441SEvalZero 		if (drive_buf[0] == L'\xFEFE')
671*10465441SEvalZero 			drive_buf[0] = '\0';
672*10465441SEvalZero 		if (dir_name_buf[0] == L'\xFEFE')
673*10465441SEvalZero 			dir_name_buf[0] = '\0';
674*10465441SEvalZero #endif
675*10465441SEvalZero 
676*10465441SEvalZero 	if (errno)
677*10465441SEvalZero 	{
678*10465441SEvalZero 		errno = EINVAL;
679*10465441SEvalZero 		return -1;
680*10465441SEvalZero 	}
681*10465441SEvalZero 	/* Emulate the behavior of dirname by returning "." for dir name if it's
682*10465441SEvalZero 	empty */
683*10465441SEvalZero 	if (drive_buf[0] == '\0' && dir_name_buf[0] == '\0')
684*10465441SEvalZero 	{
685*10465441SEvalZero 		_tinydir_strcpy(dir_name_buf, TINYDIR_STRING("."));
686*10465441SEvalZero 	}
687*10465441SEvalZero 	/* Concatenate the drive letter and dir name to form full dir name */
688*10465441SEvalZero 	_tinydir_strcat(drive_buf, dir_name_buf);
689*10465441SEvalZero 	dir_name = drive_buf;
690*10465441SEvalZero 	/* Concatenate the file name and extension to form base name */
691*10465441SEvalZero 	_tinydir_strcat(file_name_buf, ext_buf);
692*10465441SEvalZero 	base_name = file_name_buf;
693*10465441SEvalZero #else
694*10465441SEvalZero 	_tinydir_strcpy(dir_name_buf, path);
695*10465441SEvalZero 	dir_name = dirname(dir_name_buf);
696*10465441SEvalZero 	_tinydir_strcpy(file_name_buf, path);
697*10465441SEvalZero 	base_name =basename(file_name_buf);
698*10465441SEvalZero #endif
699*10465441SEvalZero 
700*10465441SEvalZero 	/* Open the parent directory */
701*10465441SEvalZero 	if (tinydir_open(&dir, dir_name) == -1)
702*10465441SEvalZero 	{
703*10465441SEvalZero 		return -1;
704*10465441SEvalZero 	}
705*10465441SEvalZero 
706*10465441SEvalZero 	/* Read through the parent directory and look for the file */
707*10465441SEvalZero 	while (dir.has_next)
708*10465441SEvalZero 	{
709*10465441SEvalZero 		if (tinydir_readfile(&dir, file) == -1)
710*10465441SEvalZero 		{
711*10465441SEvalZero 			result = -1;
712*10465441SEvalZero 			goto bail;
713*10465441SEvalZero 		}
714*10465441SEvalZero 		if (_tinydir_strcmp(file->name, base_name) == 0)
715*10465441SEvalZero 		{
716*10465441SEvalZero 			/* File found */
717*10465441SEvalZero 			found = 1;
718*10465441SEvalZero 			break;
719*10465441SEvalZero 		}
720*10465441SEvalZero 		tinydir_next(&dir);
721*10465441SEvalZero 	}
722*10465441SEvalZero 	if (!found)
723*10465441SEvalZero 	{
724*10465441SEvalZero 		result = -1;
725*10465441SEvalZero 		errno = ENOENT;
726*10465441SEvalZero 	}
727*10465441SEvalZero 
728*10465441SEvalZero bail:
729*10465441SEvalZero 	tinydir_close(&dir);
730*10465441SEvalZero 	return result;
731*10465441SEvalZero }
732*10465441SEvalZero 
733*10465441SEvalZero _TINYDIR_FUNC
734*10465441SEvalZero void _tinydir_get_ext(tinydir_file *file)
735*10465441SEvalZero {
736*10465441SEvalZero 	_tinydir_char_t *period = _tinydir_strrchr(file->name, TINYDIR_STRING('.'));
737*10465441SEvalZero 	if (period == NULL)
738*10465441SEvalZero 	{
739*10465441SEvalZero 		file->extension = &(file->name[_tinydir_strlen(file->name)]);
740*10465441SEvalZero 	}
741*10465441SEvalZero 	else
742*10465441SEvalZero 	{
743*10465441SEvalZero 		file->extension = period + 1;
744*10465441SEvalZero 	}
745*10465441SEvalZero }
746*10465441SEvalZero 
747*10465441SEvalZero _TINYDIR_FUNC
748*10465441SEvalZero int _tinydir_file_cmp(const void *a, const void *b)
749*10465441SEvalZero {
750*10465441SEvalZero 	const tinydir_file *fa = (const tinydir_file *)a;
751*10465441SEvalZero 	const tinydir_file *fb = (const tinydir_file *)b;
752*10465441SEvalZero 	if (fa->is_dir != fb->is_dir)
753*10465441SEvalZero 	{
754*10465441SEvalZero 		return -(fa->is_dir - fb->is_dir);
755*10465441SEvalZero 	}
756*10465441SEvalZero 	return _tinydir_strncmp(fa->name, fb->name, _TINYDIR_FILENAME_MAX);
757*10465441SEvalZero }
758*10465441SEvalZero 
759*10465441SEvalZero #ifndef _MSC_VER
760*10465441SEvalZero #ifndef _TINYDIR_USE_READDIR
761*10465441SEvalZero /*
762*10465441SEvalZero The following authored by Ben Hutchings <[email protected]>
763*10465441SEvalZero from https://womble.decadent.org.uk/readdir_r-advisory.html
764*10465441SEvalZero */
765*10465441SEvalZero /* Calculate the required buffer size (in bytes) for directory      *
766*10465441SEvalZero * entries read from the given directory handle.  Return -1 if this  *
767*10465441SEvalZero * this cannot be done.                                              *
768*10465441SEvalZero *                                                                   *
769*10465441SEvalZero * This code does not trust values of NAME_MAX that are less than    *
770*10465441SEvalZero * 255, since some systems (including at least HP-UX) incorrectly    *
771*10465441SEvalZero * define it to be a smaller value.                                  */
772*10465441SEvalZero _TINYDIR_FUNC
773*10465441SEvalZero size_t _tinydir_dirent_buf_size(_TINYDIR_DIR *dirp)
774*10465441SEvalZero {
775*10465441SEvalZero 	long name_max;
776*10465441SEvalZero 	size_t name_end;
777*10465441SEvalZero 	/* parameter may be unused */
778*10465441SEvalZero 	(void)dirp;
779*10465441SEvalZero 
780*10465441SEvalZero #if defined _TINYDIR_USE_FPATHCONF
781*10465441SEvalZero 	name_max = fpathconf(dirfd(dirp), _PC_NAME_MAX);
782*10465441SEvalZero 	if (name_max == -1)
783*10465441SEvalZero #if defined(NAME_MAX)
784*10465441SEvalZero 		name_max = (NAME_MAX > 255) ? NAME_MAX : 255;
785*10465441SEvalZero #else
786*10465441SEvalZero 		return (size_t)(-1);
787*10465441SEvalZero #endif
788*10465441SEvalZero #elif defined(NAME_MAX)
789*10465441SEvalZero  	name_max = (NAME_MAX > 255) ? NAME_MAX : 255;
790*10465441SEvalZero #else
791*10465441SEvalZero #error "buffer size for readdir_r cannot be determined"
792*10465441SEvalZero #endif
793*10465441SEvalZero 	name_end = (size_t)offsetof(struct _tinydir_dirent, d_name) + name_max + 1;
794*10465441SEvalZero 	return (name_end > sizeof(struct _tinydir_dirent) ?
795*10465441SEvalZero 		name_end : sizeof(struct _tinydir_dirent));
796*10465441SEvalZero }
797*10465441SEvalZero #endif
798*10465441SEvalZero #endif
799*10465441SEvalZero 
800*10465441SEvalZero #ifdef __cplusplus
801*10465441SEvalZero }
802*10465441SEvalZero #endif
803*10465441SEvalZero 
804*10465441SEvalZero # if defined (_MSC_VER)
805*10465441SEvalZero # pragma warning(pop)
806*10465441SEvalZero # endif
807*10465441SEvalZero 
808*10465441SEvalZero #endif
809