/* Copyright (C) 2011-2020, Dirk Krause SPDX-License-Identifier: BSD-3-Clause */ /* WARNING: This file was generated by the dkct program (see http://dktools.sourceforge.net/ for details). Changes you make here will be lost if dkct is run again! You should modify the original source and run dkct on it. Original source: dk3dir.ctr */ /** @file dk3dir.c The dk3dir module. */ #line 124 "dk3dir.ctr" #include "dk3all.h" #include "dk3unused.h" #line 131 "dk3dir.ctr" /* Error flags used in ec: 1 Failed to allocate memory for name to save. 2 Failed to save name to storage. 4 Directory name too long. 8 stat() failed for full name. 16 Failed to list directory contents. */ /** Keywords and texts used in this module. */ static dkChar const * const kw[] = { /* 0 */ dkT("."), /* 1 */ dkT(".."), #if DK3_ON_WINDOWS || DK3_HAVE_BACKSLASH /* 2 */ dkT("\\"), /* 3 */ dkT("\\*"), #else /* 2 */ dkT("/"), /* 3 */ dkT("/*"), #endif /* 4 */ dkT("*"), NULL }; /** Compare two directory entries by name. @param l Left name. @param r Right name. @param cr Comparison criteria (ignored). @return Comparison result. */ static int dk3dir_compare_by_name(void const *l, void const *r, int DK3_ARG_UNUSED(cr) ) { int back = 0; DK3_UNUSED_ARG(cr) if(l) { if(r) { #if DK3_ON_WINDOWS || DK3_HAVE_FNCASEINS back = dk3str_casecmp((dkChar const *)l,(dkChar const *)r); #else back = dk3str_cmp((dkChar const *)l,(dkChar const *)r); #endif } else { back = 1; } } else { if(r) { back = -1; } } return back; } /** Release all directory entries in a storage. @param s Storage to clean up. @param i Iterator for \a s. */ static void dk3dir_release_entries(dk3_sto_t *s, dk3_sto_it_t *i) { dkChar *p = NULL; /* Current name to release. */ #line 199 "dk3dir.ctr" if(s) { if(i) { dk3sto_it_reset(i); while((p = (dkChar *)dk3sto_it_next(i)) != NULL) { #line 204 "dk3dir.ctr" dk3_delete(p); } dk3sto_it_close(i); } dk3sto_close(s); } #line 210 "dk3dir.ctr" } /** Close directory. @param dp Directory to close. */ void dk3dir_close(dk3_dir_t *dp) { #line 221 "dk3dir.ctr" if(dp) { dk3dir_release_entries(dp->sdi, dp->idi); dk3dir_release_entries(dp->sfi, dp->ifi); dp->sdi = NULL; dp->sfi = NULL; dp->idi = NULL; dp->ifi = NULL; dk3_release(dp->dirname); dk3_release(dp->fullname); dp->app = NULL; dp->ndir = dp->nfi = DK3_UM_0; dk3_delete(dp); } #line 231 "dk3dir.ctr" } /** Create new dir structure. @param dn Directory name. @param app Application structure for diagnostics, may be NULL. @return Pointer to new structure on success, NULL on error. */ static dk3_dir_t * dk3dir_new(dkChar const *dn, dk3_app_t *app) { dk3_dir_t *back = NULL; int ok = 0; /* Flag: Success. */ #line 247 "dk3dir.ctr" back = dk3_new_app(dk3_dir_t,1,app); if(back) { back->sdi = NULL; back->sfi = NULL; back->idi = NULL; back->ifi = NULL; back->dirname = NULL; back->fullname = NULL; back->app = app; back->ndir = back->nfi = DK3_UM_0; back->sdi = dk3sto_open_app(app); if(back->sdi) { back->idi = dk3sto_it_open(back->sdi); if(back->idi) { back->sfi = dk3sto_open_app(app); if(back->sfi) { back->ifi = dk3sto_it_open(back->sfi); if(back->ifi) { dk3sto_set_comp(back->sdi,dk3dir_compare_by_name,0); dk3sto_set_comp(back->sfi,dk3dir_compare_by_name,0); back->dirname = dk3str_dup_app(dn, NULL); if(back->dirname) { back->fullname = dk3_new_app(dkChar,DK3_MAX_PATH,app); if(back->fullname) { ok = 1; } } } } } } if(!ok) { dk3dir_close(back); back = NULL; } } #line 277 "dk3dir.ctr" return back; } dkChar const * dk3dir_get_directory_name(dk3_dir_t const *dir) { dkChar const *back = NULL; #line 287 "dk3dir.ctr" if(dir) { back = dir->dirname; } #line 290 "dk3dir.ctr" return back; } void dk3dir_reset(dk3_dir_t *d) { #line 299 "dk3dir.ctr" if(d) { dk3sto_it_reset(d->idi); dk3sto_it_reset(d->ifi); d->shortname = NULL; } #line 304 "dk3dir.ctr" } dk3_um_t dk3dir_get_number_of_directories(dk3_dir_t const *d) { dk3_um_t back = DK3_UM_0; if(d) { back = d->ndir; } #line 315 "dk3dir.ctr" return back; } dk3_um_t dk3dir_get_number_of_files(dk3_dir_t const *d) { dk3_um_t back = DK3_UM_0; if(d) { back = d->nfi; } #line 327 "dk3dir.ctr" return back; } dkChar const * dk3dir_get_fullname(dk3_dir_t const *d) { dkChar const *back = NULL; #line 337 "dk3dir.ctr" if(d) { back = (dkChar const *)(d->fullname); } #line 340 "dk3dir.ctr" return back; } dk3_stat_t const * dk3dir_get_stat(dk3_dir_t *d) { dk3_stat_t *back = NULL; #line 350 "dk3dir.ctr" if(d) { back = &(d->stb); } #line 353 "dk3dir.ctr" return back; } dkChar const * dk3dir_get_shortname(dk3_dir_t const *d) { dkChar const *back = NULL; #line 363 "dk3dir.ctr" if(d) { back = (dkChar const *)(d->shortname); } #line 366 "dk3dir.ctr" return back; } /** Get next entry. @param d Directory structure. @param s Iterator for the storage. @param isdir Flag: Current entry is a directory. @return 1 on success, 0 on error. */ static int dk3dir_get_next_entry(dk3_dir_t *d, dk3_sto_it_t *s, int isdir) { int back = 0; int cc = 1; /* Flag: Can continue. */ size_t sz = 0; /* Directory name length. */ #line 385 "dk3dir.ctr" do { cc = 0; d->shortname = (dkChar *)dk3sto_it_next(s); if(d->shortname) { #line 389 "dk3dir.ctr" cc = 1; if(d->dirname) { if(dk3str_len(d->dirname)) { dk3str_cpy_not_overlapped(d->fullname, d->dirname); sz = dk3str_len(d->dirname); if(sz > 0) { if((d->dirname)[sz - 1] != DK3_CHAR_SEP) { dk3str_cat(d->fullname, kw[2]); } } else { dk3str_cat(d->fullname, kw[2]); } dk3str_cat(d->fullname, d->shortname); } else { dk3str_cpy_not_overlapped(d->fullname, d->shortname); } } else { dk3str_cpy_not_overlapped(d->fullname, d->shortname); } if(dk3sf_stat_app(&(d->stb), d->fullname, (dk3_app_t *)(d->app))) { switch(((d->stb).ft) & (~(DK3_FT_SYMLINK))) { case DK3_FT_DIRECTORY: { if(isdir) { back = 1; cc = 0; } } break; default: { if(!isdir) { back = 1; cc = 0; } } break; } } } #line 423 "dk3dir.ctr" } while(cc); #line 424 "dk3dir.ctr" return back; } int dk3dir_get_next_directory(dk3_dir_t *d) { int back = 0; #line 434 "dk3dir.ctr" if(d) { back = dk3dir_get_next_entry(d, d->idi, 1); } #line 437 "dk3dir.ctr" return back; } int dk3dir_get_next_file(dk3_dir_t *d) { int back = 0; #line 447 "dk3dir.ctr" if(d) { back = dk3dir_get_next_entry(d, d->ifi, 0); } #line 450 "dk3dir.ctr" return back; } /** Add a found item to a storage. @param s Storage to add item to. @param n Item name. @param c Pointer to variable to increase to. @param ec Pointer to error code variable. @param app Application structure for diagnostics. */ static void dk3dir_add(dk3_sto_t *s, dkChar const *n, dk3_um_t *c, int *ec, dk3_app_t *app) { dkChar *newname = NULL; /* New copy of name. */ dk3_um_t mu = DK3_UM_0; /* Number of entries. */ #line 469 "dk3dir.ctr" newname = dk3str_dup_app(n,(((*ec) & 1) ? NULL : app)); if(newname) { if(dk3sto_add(s, newname)) { mu = *c; mu++; *c = mu; } else { dk3_delete(newname); *ec |= 2; #line 478 "dk3dir.ctr" } } else { *ec |= 1; #line 481 "dk3dir.ctr" } #line 482 "dk3dir.ctr" } #if DK3_ON_WINDOWS /* +++ Windows +++ */ #if DK3_CHAR_SIZE > 1 /* +++ Windows > 8 bit +++ */ #if VERSION_BEFORE_2012_04_13 dk3_dir_t * dk3dir_open_app(dkChar const *dn, dk3_app_t *app) { dk3_dir_t *back = NULL; int ec = 0; /* Error code. */ dkChar buffer[DK3_MAX_PATH]; /* Buffer for entry names. */ intptr_t ffres; /* Result of findfirst(). */ dkChar *namecopy = NULL; /* New copy of name. */ struct _wfinddata64_t ffdata; /* Find data. */ if(dn) { if((dk3str_len(kw[3]) + dk3str_len(dn)) < DK3_SIZEOF(buffer,dkChar)) { dk3str_cpy_not_overlapped(buffer, dn); dk3str_cat(buffer, kw[3]); back = dk3dir_new(dn, app); if(back) { ffres = _wfindfirst64(buffer, &ffdata); if(ffres != -1) { do { if(dk3str_cmp(ffdata.name, kw[0])) { if(dk3str_cmp(ffdata.name, kw[1])) { if((ffdata.attrib) & _A_SUBDIR) { dk3dir_add(back->sdi, ffdata.name, &(back->ndir), &ec, app); } else { dk3dir_add(back->sfi, ffdata.name, &(back->nfi), &ec, app); } } } } while(_wfindnext64(ffres, &ffdata) == 0); _findclose(ffres); } else { ec |= 16; if(app) { /* ERROR: Failed to open directory! */ dk3app_log_i3(app, DK3_LL_ERROR, 63, 64, dn); } } } if(ec) { if(3 & ec) { if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 9); } } dk3dir_close(back); back = NULL; } } else { if(app) { /* ERROR: Directory name too long! */ dk3app_log_i3(app, DK3_LL_ERROR, 59, 60, dn); } } } return back; } dk3_dir_t * dk3dir_fne_open_app(dkChar const *fn, dk3_app_t *app) { dk3_dir_t *back = NULL; int ec = 0; /* Error code. */ dkChar mybuffer[DK3_MAX_PATH]; /* Buffer for entry names. */ dkChar myb2[2]; /* Search pattern. */ dkChar *ptr = NULL; /* Last separator. */ dkChar *namecopy = NULL; /* New copy of entry name. */ intptr_t ffres; /* Result from findfirst(). */ struct _wfinddata64_t ffdata; /* Find data. */ #line 562 "dk3dir.ctr" if(fn) { if(dk3str_len(fn) < DK3_MAX_PATH) { dk3str_cpy_not_overlapped(mybuffer, fn); ptr = dk3str_rchr(mybuffer, DK3_CHAR_SEP); if(ptr) { *ptr = DK3_CHAR_0; back = dk3dir_new(mybuffer, app); *ptr = DK3_CHAR_SEP; } else { myb2[0] = DK3_CHAR_0; back = dk3dir_new(myb2, app); } if(back) { #line 575 "dk3dir.ctr" ffres = _wfindfirst64(mybuffer, &ffdata); if(ffres != -1) { do { #line 578 "dk3dir.ctr" if(dk3str_cmp(ffdata.name, kw[0])) { #line 579 "dk3dir.ctr" if(dk3str_cmp(ffdata.name, kw[1])) { #line 580 "dk3dir.ctr" if((ffdata.attrib) & _A_SUBDIR) { #line 581 "dk3dir.ctr" dk3dir_add(back->sdi, ffdata.name, &(back->ndir), &ec, app); } else { #line 583 "dk3dir.ctr" dk3dir_add(back->sfi, ffdata.name, &(back->nfi), &ec, app); } } } } while(_wfindnext64(ffres, &ffdata) == 0); _findclose(ffres); } else { ec |= 16; if(app) { /* ERROR: Failed to open directory! */ dk3app_log_i3(app, DK3_LL_ERROR, 215, 216, mybuffer); } } } if(ec) { if(3 & ec) { if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 9); } } dk3dir_close(back); back = NULL; } } else { /* ERROR: Pattern too long! */ dk3app_log_i3(app, DK3_LL_ERROR, 65, 66, fn); } } #line 610 "dk3dir.ctr" return back; } #else static dk3_dir_t * dk3dir_my_open_app(dkChar const *dn, int usefne, dk3_app_t *app) { WIN32_FIND_DATAW wfd; /* Details for file. */ dkChar b1[DK3_MAX_PATH]; /* Directory base. */ dkChar b2[DK3_MAX_PATH]; /* Pattern. */ dkChar *p1; /* Separator. */ dk3_dir_t *back = NULL; HANDLE hSearch; /* File search handle. */ size_t sz; /* String length. */ int ok; /* Flag: No error yet. */ int ec; /* Error code. */ int isDir; /* Flag: Entry is dir. */ #line 632 "dk3dir.ctr" ec = 0; if(dn) { ok = 0; if(usefne) { if(dk3str_len(dn) < DK3_SIZEOF(b1,dkChar)) { ok = 1; #line 638 "dk3dir.ctr" dk3str_cpy_not_overlapped(b1, dn); dk3str_cpy_not_overlapped(b2, dn); p1 = dk3str_rchr(b1, DK3_CHAR_SEP); if(p1) { *p1 = dkT('\0'); } else { b1[0] = dkT('\0'); } } else { #line 647 "dk3dir.ctr" /* ERROR: Name too long! */ if(app) { dk3app_log_i3(app, DK3_LL_ERROR, 65, 66, dn); } } } else { sz = dk3str_len(dn) + dk3str_len(kw[3]); if(sz < DK3_SIZEOF(b1,dkChar)) { ok = 1; #line 656 "dk3dir.ctr" dk3str_cpy_not_overlapped(b1, dn); dk3str_cpy_not_overlapped(b2, dn); sz = dk3str_len(b2); if(sz > 1) { dk3str_cat(b2, kw[(DK3_CHAR_SEP == b2[sz - 1]) ? 4 : 3]); } else { dk3str_cat(b2, kw[3]); } } else { #line 665 "dk3dir.ctr" /* Name too long! */ if(app) { dk3app_log_i3(app, DK3_LL_ERROR, 59, 60, dn); } } } if(ok) { #line 672 "dk3dir.ctr" back = dk3dir_new(b1, app); if(back) { #line 674 "dk3dir.ctr" hSearch = FindFirstFileW(b2, &wfd); if(INVALID_HANDLE_VALUE != hSearch) { #line 676 "dk3dir.ctr" do { isDir = 0; #line 678 "dk3dir.ctr" if(dk3str_cmp(wfd.cFileName, kw[0])) { if(dk3str_cmp(wfd.cFileName, kw[1])) { #line 680 "dk3dir.ctr" if((wfd.dwFileAttributes) & FILE_ATTRIBUTE_DIRECTORY) { isDir = 1; #if 0 if((wfd.dwFileAttributes) & FILE_ATTRIBUTE_REPARSE_POINT) { switch(wfd.dwReserved0) { case IO_REPARSE_TAG_MOUNT_POINT: { isDir = 0; } break; } } #endif } if(isDir) { #line 693 "dk3dir.ctr" dk3dir_add(back->sdi, wfd.cFileName, &(back->ndir), &ec, app); } else { #line 695 "dk3dir.ctr" dk3dir_add(back->sfi, wfd.cFileName, &(back->nfi), &ec, app); } } } } while(FindNextFileW(hSearch, &wfd)); FindClose(hSearch); } else { #line 702 "dk3dir.ctr" /* ERROR: Failed to search for pattern! */ ec |= 16; if(app) { if(usefne) { dk3app_log_i3(app, DK3_LL_ERROR, 215, 216, dn); } else { dk3app_log_i3(app, DK3_LL_ERROR, 63, 64, dn); } } } if(ec) { if(3 & ec) { if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 9); } } dk3dir_close(back); back = NULL; } } else { #line 721 "dk3dir.ctr" } } } else { #line 724 "dk3dir.ctr" } #line 725 "dk3dir.ctr" return back; } dk3_dir_t * dk3dir_open_app(dkChar const *dn, dk3_app_t *app) { dk3_dir_t *back; #line 735 "dk3dir.ctr" back = dk3dir_my_open_app(dn, 0, app); #line 737 "dk3dir.ctr" return back; } dk3_dir_t * dk3dir_fne_open_app(dkChar const *fn, dk3_app_t *app) { dk3_dir_t *back; #line 746 "dk3dir.ctr" back = dk3dir_my_open_app(fn, 1, app); #line 748 "dk3dir.ctr" return back; } #endif /* --- Windows > 8 bit --- */ #else /* +++ Windows, 8 bit +++ */ #if VERSION_BEFORE_2012_04_13 dk3_dir_t * dk3dir_open_app(dkChar const *dn, dk3_app_t *app) { dk3_dir_t *back = NULL; int ec = 0; /* Error code. */ dkChar buffer[DK3_MAX_PATH]; /* Buffer for entry names. */ intptr_t ffres; /* Result from findfirst(). */ dkChar *namecopy = NULL; /* New copy of entry name. */ struct __finddata64_t ffdata; /* Find data. */ if(dn) { if((dk3str_len(kw[3]) + dk3str_len(dn)) < DK3_SIZEOF(buffer,dkChar)) { dk3str_cpy_not_overlapped(buffer, dn); dk3str_cat(buffer, kw[3]); back = dk3dir_new(dn, app); if(back) { ffres = _findfirst64(buffer, &ffdata); if(ffres != -1) { do { if(dk3str_cmp(ffdata.name, kw[0])) { if(dk3str_cmp(ffdata.name, kw[1])) { if((ffdata.attrib) & _A_SUBDIR) { dk3dir_add(back->sdi, ffdata.name, &(back->ndir), &ec, app); } else { dk3dir_add(back->sfi, ffdata.name, &(back->nfi), &ec, app); } } } } while(_findnext64(ffres, &ffdata) == 0); _findclose(ffres); } else { ec |= 16; /* Findfirst failed */ if(app) { /* ERROR: Findfirst failed! */ dk3app_log_i3(app, DK3_LL_ERROR, 63, 64, dn); } } } if(ec) { if(3 & ec) { if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 9); } } dk3dir_close(back); back = NULL; } } else { if(app) { /* ERROR: Directory name too long! */ dk3app_log_i3(app, DK3_LL_ERROR, 59, 60, dn); } } } return back; } dk3_dir_t * dk3dir_fne_open_app(dkChar const *fn, dk3_app_t *app) { dk3_dir_t *back = NULL; int ec = 0; /* Error code. */ dkChar mybuffer[DK3_MAX_PATH]; /* Buffer for entry name. */ dkChar myb2[2]; /* Buffer for pattern. */ dkChar *ptr = NULL; /* Last separator. */ dkChar *namecopy = NULL; /* New copy of entry name. */ intptr_t ffres; /* Result from findfirst(). */ struct __finddata64_t ffdata; /* Find data. */ #line 832 "dk3dir.ctr" if(fn) { if(dk3str_len(fn) < DK3_MAX_PATH) { dk3str_cpy_not_overlapped(mybuffer, fn); ptr = dk3str_rchr(mybuffer, DK3_CHAR_SEP); if(ptr) { *ptr = DK3_CHAR_0; back = dk3dir_new(mybuffer, app); *ptr = DK3_CHAR_SEP; } else { myb2[0] = DK3_CHAR_0; back = dk3dir_new(myb2, app); } if(back) { ffres = _findfirst64(mybuffer, &ffdata); if(ffres != -1) { do { if(dk3str_cmp(ffdata.name, kw[0])) { if(dk3str_cmp(ffdata.name, kw[1])) { if((ffdata.attrib) & _A_SUBDIR) { dk3dir_add(back->sdi, ffdata.name, &(back->ndir), &ec, app); } else { dk3dir_add(back->sfi, ffdata.name, &(back->nfi), &ec, app); } } } } while(_findnext64(ffres, &ffdata) == 0); _findclose(ffres); } else { ec |= 16; if(app) { /* ERROR: Failed to open directory! */ dk3app_log_i3(app, DK3_LL_ERROR, 215, 216, mybuffer); } } } if(ec) { if(3 & ec) { if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 9); } } dk3dir_close(back); back = NULL; } } else { if(app) { /* ERROR: Pattern too long! */ dk3app_log_i3(app, DK3_LL_ERROR, 65, 66, fn); } } } #line 882 "dk3dir.ctr" return back; } #else static dk3_dir_t * dk3dir_my_open_app(dkChar const *dn, int usefne, dk3_app_t *app) { WIN32_FIND_DATAA wfd; /* Details for file. */ dkChar b1[DK3_MAX_PATH]; /* Directory base. */ dkChar b2[DK3_MAX_PATH]; /* Pattern. */ dkChar *p1; /* Separator. */ dk3_dir_t *back = NULL; HANDLE hSearch; /* File search handle. */ size_t sz; /* String length. */ int ok; /* Flag: No error yet. */ int ec; /* Error code. */ int isDir; /* Flag: Entry is dir. */ #line 905 "dk3dir.ctr" ec = 0; if(dn) { ok = 0; if(usefne) { if(dk3str_len(dn) < DK3_SIZEOF(b1,dkChar)) { ok = 1; #line 911 "dk3dir.ctr" dk3str_cpy_not_overlapped(b1, dn); dk3str_cpy_not_overlapped(b2, dn); p1 = dk3str_rchr(b1, DK3_CHAR_SEP); if(p1) { *p1 = dkT('\0'); } else { b1[0] = dkT('\0'); } } else { #line 920 "dk3dir.ctr" /* ERROR: Name too long! */ if(app) { dk3app_log_i3(app, DK3_LL_ERROR, 65, 66, dn); } } } else { sz = dk3str_len(dn) + dk3str_len(kw[3]); if(sz < DK3_SIZEOF(b1,dkChar)) { ok = 1; #line 929 "dk3dir.ctr" dk3str_cpy_not_overlapped(b1, dn); dk3str_cpy_not_overlapped(b2, dn); sz = dk3str_len(b2); if(sz > 1) { dk3str_cat(b2, kw[(DK3_CHAR_SEP == b2[sz - 1]) ? 4 : 3]); } else { dk3str_cat(b2, kw[3]); } } else { #line 938 "dk3dir.ctr" /* ERROR: Name too long! */ if(app) { dk3app_log_i3(app, DK3_LL_ERROR, 59, 60, dn); } } } if(ok) { #line 945 "dk3dir.ctr" back = dk3dir_new(b1, app); if(back) { #line 947 "dk3dir.ctr" hSearch = FindFirstFileA(b2, &wfd); if(INVALID_HANDLE_VALUE != hSearch) { #line 949 "dk3dir.ctr" do { isDir = 0; #line 951 "dk3dir.ctr" if(dk3str_cmp(wfd.cFileName, kw[0])) { if(dk3str_cmp(wfd.cFileName, kw[1])) { #line 953 "dk3dir.ctr" if((wfd.dwFileAttributes) & FILE_ATTRIBUTE_DIRECTORY) { isDir = 1; #if 0 if((wfd.dwFileAttributes) & FILE_ATTRIBUTE_REPARSE_POINT) { switch(wfd.dwReserved0) { case IO_REPARSE_TAG_MOUNT_POINT: { isDir = 0; } break; } } #endif } if(isDir) { #line 966 "dk3dir.ctr" dk3dir_add(back->sdi, wfd.cFileName, &(back->ndir), &ec, app); } else { #line 968 "dk3dir.ctr" dk3dir_add(back->sfi, wfd.cFileName, &(back->nfi), &ec, app); } } } } while(FindNextFileA(hSearch, &wfd)); FindClose(hSearch); } else { #line 975 "dk3dir.ctr" /* ERROR: Failed to search for pattern! */ ec |= 16; if(app) { if(usefne) { dk3app_log_i3(app, DK3_LL_ERROR, 215, 216, dn); } else { dk3app_log_i3(app, DK3_LL_ERROR, 63, 64, dn); } } } if(ec) { if(3 & ec) { if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 9); } } dk3dir_close(back); back = NULL; } } else { #line 994 "dk3dir.ctr" } } } else { #line 997 "dk3dir.ctr" } #line 998 "dk3dir.ctr" return back; } dk3_dir_t * dk3dir_open_app(dkChar const *dn, dk3_app_t *app) { dk3_dir_t *back; #line 1008 "dk3dir.ctr" back = dk3dir_my_open_app(dn, 0, app); #line 1010 "dk3dir.ctr" return back; } dk3_dir_t * dk3dir_fne_open_app(dkChar const *fn, dk3_app_t *app) { dk3_dir_t *back; #line 1019 "dk3dir.ctr" back = dk3dir_my_open_app(fn, 1, app); #line 1021 "dk3dir.ctr" return back; } #endif /* --- Windows, 8 bit --- */ #endif /* --- Windows --- */ #else /* +++ non-Windows +++ */ #if DK3_CHAR_SIZE > 1 /* +++ non-Windows > 8 bit +++ */ #error "16/32-bit file names only available on Windows!" /* --- non-Windows > 8 bit --- */ #else /* +++ non-Windows, 8 bit +++ */ /** Function names used in error messages. */ static dkChar const * const dk3dir_function_names[] = { /* 0 */ dkT("opendir: "), NULL #line 1051 "dk3dir.ctr" }; #if DK3_HAVE_OPENDIR && DK3_HAVE_READDIR && DK3_HAVE_CLOSEDIR dk3_dir_t * dk3dir_open_app(dkChar const *dn, dk3_app_t *app) { dk3_dir_t *back = NULL; int ec = 0; /* Error code. */ struct dirent *de = NULL; /* Directory entry from readdir(). */ DIR *d = NULL; /* Directory structure from opendir(). */ size_t sz = 0; /* Length of entire file name. */ size_t dns = 0; /* Directory name length. */ size_t kw2l = 0; /* Length of separator string. */ dk3_stat_t stb; /* Buffer for stat() result. */ #line 1071 "dk3dir.ctr" if(dn) { back = dk3dir_new(dn, app); if(back) { d = opendir(dn); if(d) { dns = dk3str_len(dn); kw2l = dk3str_len(kw[2]); while((de = readdir(d)) != NULL) { if(dk3str_cmp(de->d_name, kw[0])) { if(dk3str_cmp(de->d_name, kw[1])) { sz = dns + kw2l + dk3str_len(de->d_name); if(sz < DK3_MAX_PATH) { dk3str_cpy_not_overlapped(back->fullname, dn); dk3str_cat(back->fullname, kw[2]); dk3str_cat(back->fullname, de->d_name); if(dk3sf_stat_app(&stb, back->fullname, NULL)) { switch((stb.ft) & (~(DK3_FT_SYMLINK))) { case DK3_FT_DIRECTORY: { dk3dir_add(back->sdi,de->d_name,&(back->ndir),&ec,app); } break; default: { dk3dir_add(back->sfi,de->d_name,&(back->nfi),&ec,app); } break; } } else { if(!(ec & 8)) { if(app) { /* Stat failed! */ dk3app_log_i3(app,DK3_LL_ERROR,61,62,back->fullname); } } ec |= 8; } } else { if(!(ec & 4)) { if(app) { /* Directory name too long! */ dk3app_log_i3(app, DK3_LL_ERROR, 59, 60, dn); } } ec |= 4; } } } } closedir(d); } else { ec |= 16; if(app) { /* Failed to open directory! */ dk3app_log_i3(app, DK3_LL_ERROR, 63, 64, dn); dk3sf_report_errno(app, errno, dk3dir_function_names[0]); } } if(ec) { if(3 & ec) { if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 9); } } dk3dir_close(back); back = NULL; } } } #line 1132 "dk3dir.ctr" return back; } dk3_dir_t * dk3dir_fne_open_app(dkChar const *fn, dk3_app_t *app) { dk3_dir_t *back = NULL; int ec = 0; /* Error code. */ dk3_stat_t stb; /* Stat buffer. */ dkChar mybuffer[DK3_MAX_PATH]; /* Buffer for entire file name. */ dkChar myb2[2]; /* Pattern buffer. */ dkChar *ptr; /* Last separator in pattern. */ #line 1147 "dk3dir.ctr" if(fn) { if(dk3str_len(fn) < DK3_MAX_PATH) { dk3str_cpy_not_overlapped(mybuffer, fn); if(dk3sf_stat_app(&stb, fn, app)) { ptr = dk3str_rchr(mybuffer, DK3_CHAR_SEP); if(ptr) { *(ptr++) = DK3_CHAR_0; back = dk3dir_new(mybuffer, app); } else { myb2[0] = DK3_CHAR_0; back = dk3dir_new(myb2, app); ptr = mybuffer; } if(back) { switch((stb.ft) & (~(DK3_FT_SYMLINK))) { case DK3_FT_DIRECTORY: { dk3dir_add(back->sdi, ptr, &(back->ndir), &ec, app); } break; default: { dk3dir_add(back->sfi, ptr, &(back->nfi), &ec, app); } break; } if(ec) { if(3 & ec) { if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 9); } } dk3dir_close(back); back = NULL; } } } } else { if(app) { /* Name too long! */ dk3app_log_i3(app, DK3_LL_ERROR, 65, 66, fn); } } } #line 1186 "dk3dir.ctr" return back; } #else #error "No opendir()/readdir()/closedir() function set!" #endif /* --- non-Windows, 8 bit --- */ #endif /* --- non-Windows --- */ #endif /** Directory chain cell. */ struct _dk3_dir_cell_t_ { struct _dk3_dir_cell_t_ *parent; /**< Parent cell. */ dk3_dir_t *dir; /**< Directory structure. */ }; /** Directory chain cell. */ typedef struct _dk3_dir_cell_t_ DK3_DIR_CELL; /** Destroy chain cell, release memory. @param c Cell to destroy. */ static void dk3dir_cell_delete(DK3_DIR_CELL *c) { if(c) { if(c->dir) { dk3dir_close(c->dir); } c->dir = NULL; c->parent = NULL; dk3_delete(c); } } /** Create directory cell, allocate memory. @param n Directory name. @param p Parent cell in chain. @param app Application structure for diagnostics. @return Pointer to new cell on success, NULL on error. */ static DK3_DIR_CELL * dk3dir_cell_new(dkChar const *n, DK3_DIR_CELL *p, dk3_app_t *app) { DK3_DIR_CELL *back = NULL; back = dk3_new_app(DK3_DIR_CELL,1,app); if(back) { back->parent = p; back->dir = dk3dir_open_app(n, app); if(!(back->dir)) { dk3dir_cell_delete(back); back = NULL; } } return back; } #if DK3_ON_WINDOWS /** Remove a directory reparse point. @param dn Directory to remove. @param app Application structure for diagnostics, may be NULL. @return 1 on success, 0 on error. */ static int dk3dir_remove_reparse_point(dkChar const *dn, dk3_app_t *app) { int back = 0; if(dk3sf_remove_dir_app(dn, app)) { back = 1; } else { if(dk3sf_remove_file_app(dn, app)) { back = 1; } } return back; } #endif int dk3dir_remove_app(dkChar const *dn, dk3_app_t *app) { int back = 0; dk3_stat_t stb; /* Stat buffer. */ dkChar const *en = NULL; /* Entry name. */ dkChar const *xdn; /* Current dir to delete. */ dk3_stat_t const *es = NULL; /* Entry stat buffer. */ DK3_DIR_CELL *ccell = NULL; /* Current cell. */ DK3_DIR_CELL *ncell = NULL; /* New cell or next cell. */ #if VERSION_BEFORE_20150821 int ft; /* File type. */ #endif if(dn) { if(dk3sf_stat_app(&stb, dn, app)) { if((stb.ft) & DK3_FT_SYMLINK) { /* symbolic link */ /* Removing symbolic link only, not target! */ back = dk3sf_remove_file_app(dn, app); } else { if(stb.ft == DK3_FT_DIRECTORY) { #if DK3_ON_WINDOWS if(0x00 == stb.cReparse) { #endif ccell = dk3dir_cell_new(dn, NULL, app); if(ccell) { back = 1; while(ccell) { if(dk3dir_get_next_directory(ccell->dir)) { en = dk3dir_get_fullname(ccell->dir); if(en) { es = dk3dir_get_stat(ccell->dir); if(es) { if((es->ft) & DK3_FT_SYMLINK) { if(!dk3sf_remove_file_app(en, app)) { back = 0; } } else { #if DK3_ON_WINDOWS if(0x00 == es->cReparse) { #endif ncell = dk3dir_cell_new(en, ccell, app); if(ncell) { ccell = ncell; } else { back = 0; } #if DK3_ON_WINDOWS } else { if(!dk3dir_remove_reparse_point(en, app)) { back = 0; } } #endif } } else { back = 0; /* BUG: Internal error. */ } } else { back = 0; /* BUG: Internal error. */ } } else { while(dk3dir_get_next_file(ccell->dir)) { #if VERSION_BEFORE_20150821 ft = DK3_FT_REGULAR; #endif en = dk3dir_get_fullname(ccell->dir); #if VERSION_BEFORE_20150821 es = dk3dir_get_stat(ccell->dir); if(es) { ft = es->ft; } #endif if(en) { if(!dk3sf_remove_file_app(en, app)) { back = 0; } } else { back = 0; /* BUG: Internal error. */ } } ncell = ccell->parent; if(ccell->dir) { xdn = dk3dir_get_directory_name(ccell->dir); if(xdn) { if(!dk3sf_remove_dir_app(xdn, app)) { back = 0; } } } dk3dir_cell_delete(ccell); ccell = ncell; } } } #if DK3_ON_WINDOWS } else { if(!dk3dir_remove_reparse_point(dn, app)) { back = 0; } } #endif } else { /* ERROR: Not a directory! */ dk3app_log_i3(app, DK3_LL_ERROR, 202, 203, dn); } } } } return back; } /* vim: set ai sw=2 : */