/* WARNING: This file was generated by dkct. 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 */ /* Copyright (C) 2011-2017, Dirk Krause Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above opyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the author nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @file dk3dir.c The dk3dir module. */ #line 124 "dk3dir.ctr" #include "dk3all.h" #line 130 "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 cr) { int back = 0; 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 196 "dk3dir.ctr" if(s) { if(i) { dk3sto_it_reset(i); while((p = (dkChar *)dk3sto_it_next(i)) != NULL) { #line 201 "dk3dir.ctr" dk3_delete(p); } dk3sto_it_close(i); } dk3sto_close(s); } #line 207 "dk3dir.ctr" } /** Close directory. @param dp Directory to close. */ void dk3dir_close(dk3_dir_t *dp) { #line 218 "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 228 "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 244 "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 274 "dk3dir.ctr" return back; } dkChar const * dk3dir_get_directory_name(dk3_dir_t const *dir) { dkChar const *back = NULL; #line 284 "dk3dir.ctr" if(dir) { back = dir->dirname; } #line 287 "dk3dir.ctr" return back; } void dk3dir_reset(dk3_dir_t *d) { #line 296 "dk3dir.ctr" if(d) { dk3sto_it_reset(d->idi); dk3sto_it_reset(d->ifi); d->shortname = NULL; } #line 301 "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 312 "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 324 "dk3dir.ctr" return back; } dkChar const * dk3dir_get_fullname(dk3_dir_t const *d) { dkChar const *back = NULL; #line 334 "dk3dir.ctr" if(d) { back = (dkChar const *)(d->fullname); } #line 337 "dk3dir.ctr" return back; } dk3_stat_t const * dk3dir_get_stat(dk3_dir_t *d) { dk3_stat_t *back = NULL; #line 347 "dk3dir.ctr" if(d) { back = &(d->stb); } #line 350 "dk3dir.ctr" return back; } dkChar const * dk3dir_get_shortname(dk3_dir_t const *d) { dkChar const *back = NULL; #line 360 "dk3dir.ctr" if(d) { back = (dkChar const *)(d->shortname); } #line 363 "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 382 "dk3dir.ctr" do { cc = 0; d->shortname = (dkChar *)dk3sto_it_next(s); if(d->shortname) { #line 386 "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 420 "dk3dir.ctr" } while(cc); #line 421 "dk3dir.ctr" return back; } int dk3dir_get_next_directory(dk3_dir_t *d) { int back = 0; #line 431 "dk3dir.ctr" if(d) { back = dk3dir_get_next_entry(d, d->idi, 1); } #line 434 "dk3dir.ctr" return back; } int dk3dir_get_next_file(dk3_dir_t *d) { int back = 0; #line 444 "dk3dir.ctr" if(d) { back = dk3dir_get_next_entry(d, d->ifi, 0); } #line 447 "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 466 "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 475 "dk3dir.ctr" } } else { *ec |= 1; #line 478 "dk3dir.ctr" } #line 479 "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 559 "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 572 "dk3dir.ctr" ffres = _wfindfirst64(mybuffer, &ffdata); if(ffres != -1) { do { #line 575 "dk3dir.ctr" if(dk3str_cmp(ffdata.name, kw[0])) { #line 576 "dk3dir.ctr" if(dk3str_cmp(ffdata.name, kw[1])) { #line 577 "dk3dir.ctr" if((ffdata.attrib) & _A_SUBDIR) { #line 578 "dk3dir.ctr" dk3dir_add(back->sdi, ffdata.name, &(back->ndir), &ec, app); } else { #line 580 "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 607 "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 629 "dk3dir.ctr" ec = 0; if(dn) { ok = 0; if(usefne) { if(dk3str_len(dn) < DK3_SIZEOF(b1,dkChar)) { ok = 1; #line 635 "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 644 "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 653 "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 662 "dk3dir.ctr" /* Name too long! */ if(app) { dk3app_log_i3(app, DK3_LL_ERROR, 59, 60, dn); } } } if(ok) { #line 669 "dk3dir.ctr" back = dk3dir_new(b1, app); if(back) { #line 671 "dk3dir.ctr" hSearch = FindFirstFileW(b2, &wfd); if(INVALID_HANDLE_VALUE != hSearch) { #line 673 "dk3dir.ctr" do { isDir = 0; #line 675 "dk3dir.ctr" if(dk3str_cmp(wfd.cFileName, kw[0])) { if(dk3str_cmp(wfd.cFileName, kw[1])) { #line 677 "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 690 "dk3dir.ctr" dk3dir_add(back->sdi, wfd.cFileName, &(back->ndir), &ec, app); } else { #line 692 "dk3dir.ctr" dk3dir_add(back->sfi, wfd.cFileName, &(back->nfi), &ec, app); } } } } while(FindNextFileW(hSearch, &wfd)); FindClose(hSearch); } else { #line 699 "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 718 "dk3dir.ctr" } } } else { #line 721 "dk3dir.ctr" } #line 722 "dk3dir.ctr" return back; } dk3_dir_t * dk3dir_open_app(dkChar const *dn, dk3_app_t *app) { dk3_dir_t *back; #line 732 "dk3dir.ctr" back = dk3dir_my_open_app(dn, 0, app); #line 734 "dk3dir.ctr" return back; } dk3_dir_t * dk3dir_fne_open_app(dkChar const *fn, dk3_app_t *app) { dk3_dir_t *back; #line 743 "dk3dir.ctr" back = dk3dir_my_open_app(fn, 1, app); #line 745 "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 829 "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 879 "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 902 "dk3dir.ctr" ec = 0; if(dn) { ok = 0; if(usefne) { if(dk3str_len(dn) < DK3_SIZEOF(b1,dkChar)) { ok = 1; #line 908 "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 917 "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 926 "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 935 "dk3dir.ctr" /* ERROR: Name too long! */ if(app) { dk3app_log_i3(app, DK3_LL_ERROR, 59, 60, dn); } } } if(ok) { #line 942 "dk3dir.ctr" back = dk3dir_new(b1, app); if(back) { #line 944 "dk3dir.ctr" hSearch = FindFirstFileA(b2, &wfd); if(INVALID_HANDLE_VALUE != hSearch) { #line 946 "dk3dir.ctr" do { isDir = 0; #line 948 "dk3dir.ctr" if(dk3str_cmp(wfd.cFileName, kw[0])) { if(dk3str_cmp(wfd.cFileName, kw[1])) { #line 950 "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 963 "dk3dir.ctr" dk3dir_add(back->sdi, wfd.cFileName, &(back->ndir), &ec, app); } else { #line 965 "dk3dir.ctr" dk3dir_add(back->sfi, wfd.cFileName, &(back->nfi), &ec, app); } } } } while(FindNextFileA(hSearch, &wfd)); FindClose(hSearch); } else { #line 972 "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 991 "dk3dir.ctr" } } } else { #line 994 "dk3dir.ctr" } #line 995 "dk3dir.ctr" return back; } dk3_dir_t * dk3dir_open_app(dkChar const *dn, dk3_app_t *app) { dk3_dir_t *back; #line 1005 "dk3dir.ctr" back = dk3dir_my_open_app(dn, 0, app); #line 1007 "dk3dir.ctr" return back; } dk3_dir_t * dk3dir_fne_open_app(dkChar const *fn, dk3_app_t *app) { dk3_dir_t *back; #line 1016 "dk3dir.ctr" back = dk3dir_my_open_app(fn, 1, app); #line 1018 "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 1048 "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 1068 "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 1129 "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 1144 "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 1183 "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 : */