1 /*
2 Copyright (C) 2015-2021, Dirk Krause
3 SPDX-License-Identifier: BSD-3-Clause
4 */
5 
6 /*
7 	WARNING: This file was generated by the dkct program (see
8 	http://dktools.sourceforge.net/ for details).
9 	Changes you make here will be lost if dkct is run again!
10 	You should modify the original source and run dkct on it.
11 	Original source: dk4dirwc.ctr
12 */
13 
14 /**	@file dk4dirwc.c The dk4dirwc module.
15 */
16 
17 
18 #include "dk4conf.h"
19 
20 #if DK4_ON_WINDOWS
21 #ifndef WINDOWS_H_INCLUDED
22 #include <windows.h>
23 #define	WINDOWS_H_INCLUDED 1
24 #endif
25 #endif
26 
27 #include <libdk4c/dk4dirwc.h>
28 
29 #ifndef DK4DIR_H_INCLUDED
30 #include <libdk4c/dk4dir.h>
31 #endif
32 
33 #ifndef	DK4PATHW_H_INCLUDED
34 #include <libdk4c/dk4pathw.h>
35 #endif
36 
37 #ifndef DK4STR8_H_INCLUDED
38 #include <libdk4base/dk4strw.h>
39 #endif
40 
41 #ifndef DK4STAT_H_INCLUDED
42 #include <libdk4c/dk4stat.h>
43 #endif
44 
45 #ifndef DK4STAT8_H_INCLUDED
46 #include <libdk4c/dk4statw.h>
47 #endif
48 
49 #ifndef DK4MEM_H_INCLUDED
50 #include <libdk4base/dk4mem.h>
51 #endif
52 
53 #ifndef DK4MPL_H_INCLUDED
54 #include <libdk4base/dk4mpl.h>
55 #endif
56 
57 #ifndef DK4MAASZ_H_INCLUDED
58 #include <libdk4ma/dk4maasz.h>
59 #endif
60 
61 #if DK4_HAVE_SYS_TYPES_H
62 #ifndef SYS_TYPES_H_INCLUDED
63 #include <sys/types.h>
64 #define	SYS_TYPES_H_INCLUDED 1
65 #endif
66 #endif
67 
68 #if DK4_HAVE_WCHAR_H
69 #ifndef WCHAR_H_INCLUDED
70 #include <wchar.h>
71 #define WCHAR_H_INCLUDED 1
72 #endif
73 #endif
74 
75 #if DK4_HAVE_DIRENT_H
76 #ifndef DIRENT_H_INCLUDED
77 #include <dirent.h>
78 #define	DIRENT_H_INCLUDED 1
79 #endif
80 #endif
81 
82 #if DK4_HAVE_ERRNO_H
83 #ifndef ERRNO_H_INCLUDED
84 #include <errno.h>
85 #define	ERRNO_H_INCLUDED 1
86 #endif
87 #endif
88 
89 #if	DK4_HAVE_ASSERT_H
90 #ifndef	ASSERT_H_INCLUDED
91 #include <assert.h>
92 #define	ASSERT_H_INCLUDED 1
93 #endif
94 #endif
95 
96 #include <libdk4base/dk4unused.h>
97 
98 
99 
100 
101 
102 
103 
104 
105 #if DK4_ON_WINDOWS
106 
107 int
dk4dir_wc_compare(const void * l,const void * r,int DK4_ARG_UNUSED (cr))108 dk4dir_wc_compare(const void *l, const void *r, int DK4_ARG_UNUSED(cr))
109 {
110   int		back = 0;
111   DK4_UNUSED_ARG(cr)
112   if (NULL != l) {
113     if (NULL != r) {
114       back = dk4strw_pathcmp((const wchar_t *)l, (const wchar_t *)r);
115     } else {
116       back = 1;
117     }
118   } else {
119     if (NULL != r) { back = -1; }
120   }
121   return back;
122 }
123 
124 #endif
125 
126 
127 
128 static
129 void
dk4dir_wc_clean_storage(dk4_sto_t * s,dk4_sto_it_t * i)130 dk4dir_wc_clean_storage(dk4_sto_t *s, dk4_sto_it_t *i)
131 {
132   wchar_t	*n;
133   if (NULL != s) {
134     if (NULL != i) {
135       dk4sto_it_reset(i);
136       while (NULL != (n = (wchar_t *)dk4sto_it_next(i))) {
137         dk4mem_free(n);
138       }
139       dk4sto_it_close(i);
140     }
141     dk4sto_close(s);
142   }
143 }
144 
145 
146 
147 void
dk4dir_wc_close(dk4_dir_wc_t * dptr)148 dk4dir_wc_close(dk4_dir_wc_t *dptr)
149 {
150 #if	DK4_USE_ASSERT
151   assert(NULL != dptr);
152 #endif
153   if (NULL != dptr) {
154     dk4mem_release(dptr->path);
155     dk4dir_wc_clean_storage(dptr->s_dir, dptr->i_dir);
156     dptr->s_dir = NULL; dptr->i_dir = NULL;
157     dk4dir_wc_clean_storage(dptr->s_file, dptr->i_file);
158     dptr->s_file = NULL; dptr->i_file = NULL;
159     dk4mem_free(dptr);
160   }
161 }
162 
163 
164 
165 #if DK4_ON_WINDOWS
166 /**	Fixed texts used by the module.
167 */
168 static const wchar_t * const	dk4dir_wc_kw[] = {
169 /* 0 */
170 L".",
171 
172 /* 1 */
173 L"..",
174 
175 /* 2 */
176 L"/",
177 
178 /* 3 */
179 L"\\",
180 
181 /* 4 */
182 L"*",
183 
184 NULL
185 
186 };
187 
188 
189 
190 static
191 int
dk4dir_wc_fill_with_pab(dk4_dir_wc_t * dptr,int om,wchar_t * pab,size_t szpab,dk4_er_t * erp)192 dk4dir_wc_fill_with_pab(
193   dk4_dir_wc_t	*dptr,
194   int		 om,
195   wchar_t	*pab,
196   size_t	 szpab,
197   dk4_er_t	*erp
198 )
199 {
200   WIN32_FIND_DATAW	 ffdata;		/* Find result */
201   HANDLE		 ffres;			/* Result from findfirst */
202   dkChar		*nn;			/* Copy of name, dyn */
203   DWORD			 attr;			/* File attributes */
204   size_t		 slen;			/* Entry name length. */
205   int			 isdir;			/* Flag: Entry is directory */
206   int			 back	= 0;
207 
208 #if	DK4_USE_ASSERT
209   assert(NULL != dptr);
210   assert(NULL != pab);
211   assert(0 < szpab);
212 #endif
213   if (dk4strw_cpy_s(pab, szpab, dptr->path, erp)) {
214     if (dk4strw_cat_s(pab, szpab, dk4dir_wc_kw[3], erp)) {
215       if (dk4strw_cat_s(pab, szpab, dk4dir_wc_kw[4], erp)) {
216 	ffres = FindFirstFileW(pab, &ffdata);
217 	if (INVALID_HANDLE_VALUE != ffres) {
218 	  back = 1;
219 	  do {
220 	    if (0 != dk4strw_cmp(dk4dir_wc_kw[0], ffdata.cFileName)) {
221 	      if (0 != dk4strw_cmp(dk4dir_wc_kw[1], ffdata.cFileName)) {
222 	        slen = dk4strw_len(ffdata.cFileName);
223 		if (slen > dptr->maxlen) { dptr->maxlen = slen; }
224 	        nn = dk4strw_dup(ffdata.cFileName, erp);
225 		if (NULL != nn) {
226 		  isdir = 0;
227 		  attr = ffdata.dwFileAttributes;
228 		  if (0 != (FILE_ATTRIBUTE_DIRECTORY & attr)) {
229 		    isdir = 1;
230 		    if (0 != (FILE_ATTRIBUTE_REPARSE_POINT & attr)) {
231 		      if (0 != (DK4_DIR_SYMLINK_DIR_AS_FILE & om)) {
232 		        isdir = 0;
233 		      }
234 		    }
235 		  }
236 		  if (0 != isdir) {
237 		    if (0 == dk4sto_add(dptr->s_dir, (void *)nn, erp)) {
238 		      back = 0;
239 		      dk4mem_free(nn);
240 		    }
241 		  } else {
242 		    if (0 == dk4sto_add(dptr->s_file, (void *)nn, erp)) {
243 		      back = 0;
244 		      dk4mem_free(nn);
245 		    }
246 		  }
247 		} else {
248 		  back = 0;
249 		}
250 	      }
251 	    }
252 	  } while(FindNextFileW(ffres, &ffdata));
253 	  FindClose(ffres);
254 	} else {
255 	  /* ERROR: FindFirstFile failed */
256 	  dk4error_set_ldetails(
257 	    erp, DK4_E_FINDFIRSTFILE_FAILED,
258 	    (long)((unsigned long)GetLastError())
259 	  );
260 	}
261       }
262     }
263   }
264 
265   return back;
266 }
267 
268 
269 
270 static
271 int
dk4dir_wc_fill_with_local(dk4_dir_wc_t * dptr,int om,dk4_er_t * erp)272 dk4dir_wc_fill_with_local(dk4_dir_wc_t *dptr, int om, dk4_er_t *erp)
273 {
274   wchar_t	pab[DK4_MAX_PATH];
275 #if	DK4_USE_ASSERT
276   assert(NULL != dptr);
277 #endif
278   return (dk4dir_wc_fill_with_pab(dptr, om, pab, DK4_SIZEOF(pab,wchar_t), erp));
279 }
280 
281 
282 
283 /**	Fill directory structure with data about subdirectories and files.
284 	@param	dptr	Directory structure to fill.
285 	@param	om	Opening mode.
286 	@param	erp	Error report, may be NULL.
287 	@return	1 on success, 0 on errors.
288 */
289 static
290 int
dk4dir_wc_fill_directory(dk4_dir_wc_t * dptr,int om,dk4_er_t * erp)291 dk4dir_wc_fill_directory(dk4_dir_wc_t *dptr, int om, dk4_er_t *erp)
292 {
293   dk4_er_t	 er;
294   wchar_t	*pab;
295   size_t	 dptrlgt;
296   int		 back	= 0;
297 
298 #if	DK4_USE_ASSERT
299   assert(NULL != dptr);
300 #endif
301   dptrlgt = dk4strw_len(dptr->path);
302   if ((DK4_MAX_PATH - 2) > dptrlgt) {
303     back = dk4dir_wc_fill_with_local(dptr, om, erp);
304   } else {
305     dk4error_init(&er);
306     dptrlgt = dk4ma_size_t_add(dptrlgt, 3, &er);
307     if (DK4_E_NONE == er.ec) {
308       pab = dk4mem_new(wchar_t, dptrlgt, erp);
309       if (NULL != pab) {
310         back = dk4dir_wc_fill_with_pab(dptr, om, pab, dptrlgt, erp);
311         dk4mem_free(pab);
312       }
313     } else {
314       dk4error_copy(erp, &er);
315     }
316   }
317   return back;
318 }
319 
320 #endif
321 
322 
323 
324 dk4_dir_wc_t *
dk4dir_wc_open(const wchar_t * path,int om,dk4_er_t * erp)325 dk4dir_wc_open(
326   const wchar_t	*path,
327 #if DK4_ON_WINDOWS
328   int		 om,
329 #else
330   int		 DK4_ARG_UNUSED(om),
331 #endif
332   dk4_er_t	*erp
333 )
334 {
335   dk4_dir_wc_t	*back	= NULL;
336 #if DK4_ON_WINDOWS
337   int		 ok	= 0;
338 #endif
339 #if	DK4_USE_ASSERT
340   assert(NULL != path);
341 #endif
342   if (NULL != path) {
343 #if DK4_ON_WINDOWS
344     back = dk4mem_new(dk4_dir_wc_t, 1, erp);
345     if (NULL != back) {
346       back->path = NULL;
347       back->s_dir = NULL;
348       back->i_dir = NULL;
349       back->s_file = NULL;
350       back->i_file = NULL;
351       back->path = dk4strw_dup(path, erp);
352       back->maxlen = 0;
353       if (NULL != back->path) {
354         back->s_dir = dk4sto_open(erp);
355 	if (NULL != back->s_dir) {
356 	  if (0 != (DK4_DIR_OPEN_SORTED & om)) {
357 	    dk4sto_set_comp(back->s_dir, dk4dir_wc_compare, 0);
358 	  }
359 	  back->i_dir = dk4sto_it_open(back->s_dir, erp);
360 	  if (NULL != back->i_dir) {
361 	    back->s_file = dk4sto_open(erp);
362 	    if (NULL != back->s_file) {
363 	      if (0 != (DK4_DIR_OPEN_SORTED & om)) {
364 	        dk4sto_set_comp(back->s_file, dk4dir_wc_compare, 0);
365 	      }
366 	      back->i_file = dk4sto_it_open(back->s_file, erp);
367 	      if (NULL != back->i_file) {
368 	        ok = dk4dir_wc_fill_directory(back, om, erp);
369 	      }
370 	    }
371 	  }
372 	}
373       }
374       if (0 == ok) {
375         dk4dir_wc_close(back);
376 	back = NULL;
377       }
378     }
379 #else
380     DK4_UNUSED_ARG(om)
381     dk4error_set_simple_error_code(erp, DK4_E_NOT_SUPPORTED);
382 #endif
383   } else {
384     dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
385   }
386   return back;
387 }
388 
389 
390 
391 void
dk4dir_wc_reset(dk4_dir_wc_t * dptr)392 dk4dir_wc_reset(dk4_dir_wc_t *dptr)
393 {
394 #if	DK4_USE_ASSERT
395   assert(NULL != dptr);
396 #endif
397   if (NULL != dptr) {
398     if ((NULL != dptr->s_dir) && (NULL != dptr->i_dir)) {
399       dk4sto_it_reset(dptr->i_dir);
400     }
401     if ((NULL != dptr->s_file) && (NULL != dptr->i_file)) {
402       dk4sto_it_reset(dptr->i_file);
403     }
404   }
405 }
406 
407 
408 
409 const wchar_t *
dk4dir_wc_get_path(dk4_dir_wc_t const * dptr)410 dk4dir_wc_get_path(dk4_dir_wc_t const *dptr)
411 {
412   const wchar_t	*back	= NULL;
413 #if	DK4_USE_ASSERT
414   assert(NULL != dptr);
415 #endif
416   if (NULL != dptr) {
417     back = (const wchar_t *)(dptr->path);
418   }
419   return back;
420 }
421 
422 
423 
424 const wchar_t *
dk4dir_wc_next_dir(dk4_dir_wc_t * dptr)425 dk4dir_wc_next_dir(dk4_dir_wc_t *dptr)
426 {
427   const wchar_t	*back = NULL;
428 #if	DK4_USE_ASSERT
429   assert(NULL != dptr);
430 #endif
431   if (NULL != dptr) {
432     if ((NULL != dptr->s_dir) && (NULL != dptr->i_dir)) {
433       back = (const wchar_t *)dk4sto_it_next(dptr->i_dir);
434     }
435   }
436   return back;
437 }
438 
439 
440 
441 const wchar_t *
dk4dir_wc_next_file(dk4_dir_wc_t * dptr)442 dk4dir_wc_next_file(dk4_dir_wc_t *dptr)
443 {
444   const wchar_t	*back = NULL;
445 #if	DK4_USE_ASSERT
446   assert(NULL != dptr);
447 #endif
448   if (NULL != dptr) {
449     if ((NULL != dptr->s_file) && (NULL != dptr->i_file)) {
450       back = (const wchar_t *)dk4sto_it_next(dptr->i_file);
451     }
452   }
453   return back;
454 }
455 
456 
457 
458 void
dk4dir_wc_skip_files(dk4_dir_wc_t * dptr)459 dk4dir_wc_skip_files(dk4_dir_wc_t *dptr)
460 {
461 #if	DK4_USE_ASSERT
462   assert(NULL != dptr);
463 #endif
464   if (NULL != dptr) {
465     dk4dir_wc_clean_storage(dptr->s_file, dptr->i_file);
466     dptr->s_file = NULL; dptr->i_file = NULL;
467   }
468 }
469 
470 
471 
472 size_t
dk4dir_wc_get_max_entry_length(dk4_dir_wc_t const * dptr)473 dk4dir_wc_get_max_entry_length(dk4_dir_wc_t const *dptr)
474 {
475   size_t	 back = 0;
476 #if	DK4_USE_ASSERT
477   assert(NULL != dptr);
478 #endif
479   if (NULL != dptr) {
480     back = dptr->maxlen;
481   }
482   return back;
483 }
484 
485 
486 
487 int
dk4dir_wc_full_name_buffer(wchar_t * buffer,size_t szbuf,dk4_dir_wc_t const * pdir,wchar_t const * fn,dk4_er_t * erp)488 dk4dir_wc_full_name_buffer(
489   wchar_t		*buffer,
490   size_t		 szbuf,
491   dk4_dir_wc_t	const	*pdir,
492   wchar_t	const	*fn,
493   dk4_er_t		*erp
494 )
495 {
496   int		 back	= 0;
497 #if	DK4_USE_ASSERT
498   assert(NULL != pdir);
499   assert(NULL != fn);
500   assert(NULL != buffer);
501   assert(0 < szbuf);
502 #endif
503   if ((NULL != buffer) && (NULL != pdir) && (NULL != fn) && (0 < szbuf)) {
504     back = dk4pathw_concatenate_buffer(buffer, szbuf, pdir->path, fn, erp);
505   }
506   else {
507     dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
508   }
509   return back;
510 }
511 
512 
513 
514 wchar_t *
dk4dir_wc_full_name_new(dk4_dir_wc_t const * pdir,wchar_t const * fn,dk4_er_t * erp)515 dk4dir_wc_full_name_new(
516   dk4_dir_wc_t	const	*pdir,
517   wchar_t	const	*fn,
518   dk4_er_t	*	erp
519 )
520 {
521   wchar_t *back	= NULL;
522 #if	DK4_USE_ASSERT
523   assert(NULL != pdir);
524   assert(NULL != fn);
525 #endif
526   if ((NULL != pdir) && (NULL != fn)) {
527     back = dk4pathw_concatenate_new(pdir->path, fn, erp);
528   }
529   else {
530     dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
531   }
532   return back;
533 }
534 
535