/* 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: dk4appdeltree.ctr */ /* Copyright (C) 2015-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 dk4appdeltree.c The dk4appdeltree module. */ #line 10 "dk4appdeltree.ctr" #include "dk4conf.h" #include "dk4types.h" #if DK4_ON_WINDOWS #ifndef WINDOWS_H_INCLUDED #include #define WINDOWS_H_INCLUDED 1 #endif #endif #ifndef DK4APP_H_INCLUDED #include "dk4app.h" #endif #ifndef DK4CONST_H_INCLUDED #include "dk4const.h" #endif #ifndef DK4STATD_H_INCLUDED #include "dk4statd.h" #endif #ifndef DK4STAT_H_INCLUDED #include "dk4stat.h" #endif #ifndef DK4DIR_H_INCLUDED #include "dk4dir.h" #endif #ifndef DK4DIRA_H_INCLUDED #include "dk4dira.h" #endif #ifndef DK4MEM_H_INCLUDED #include "dk4mem.h" #endif #ifndef DK4MEMA_H_INCLUDED #include "dk4mema.h" #endif #ifndef DK4MPL_H_INCLUDED #include "dk4mpl.h" #endif #ifndef DK4STR_H_INCLUDED #include "dk4strd.h" #endif #ifndef DK4MAASZ_H_INCLUDED #include "dk4maasz.h" #endif #if DK4_HAVE_SYS_TYPES_H #ifndef SYS_TYPES_H_INCLUDED #include #define SYS_TYPES_H_INCLUDED 1 #endif #endif #if DK4_HAVE_DIRENT_H #ifndef DIRENT_H_INCLUDED #include #define DIRENT_H_INCLUDED 1 #endif #endif #if DK4_CHAR_SIZE > 1 #if DK4_HAVE_WCHAR_H #ifndef WCHAR_H_INCLUDED #include #define WCHAR_H_INCLUDED 1 #endif #endif #endif #line 91 "dk4appdeltree.ctr" /** Information about failed removals of files or directories. */ enum { /** No errors yet. */ NE_NO_ERROR = 0, /** Failed to remove one file. */ NE_ONE_FILE_REMOVAL_FAILED , /** Failed to remove multiple files. */ NE_MULTIPLE_FILE_REMOVALS_FAILED , /** Failed to remove one directory. */ NE_ONE_DIRECTORY_REMOVAL_FAILED , /** Failed to remove multiple dirs. */ NE_MULTIPLE_DIRECTORY_REMOVALS_FAILED }; /** One node in tree to delete. */ typedef struct _dk4_del_tree_node_t_ { struct _dk4_del_tree_node_t_ *parent; /**< Parent node. */ dk4_dir_t *dir; /**< Directory contents. */ size_t dplen; /**< Directory path length. */ int ne; /**< Flag: Not empty. */ } dk4_del_tree_node_t; /** Job structure (information passed downwards). */ typedef struct { dkChar *sbptr; /**< Static buffer. */ dkChar *dbptr; /**< Dynamic buffer, may be NULL. */ size_t sbsz; /**< Static buffer size. */ size_t dbsz; /**< Dynamic buffer size. */ int result; /**< Suggested function result. */ } dk4_del_tree_job_t; #if DK4_ON_WINDOWS /* +++ Windows */ #if DK4_CHAR_SIZE > 1 /* +++ Windows, wchar_t */ /* --- Windows, wchar_t */ #else /* +++ Windows, char */ /* --- Windows, char */ #endif static int dk4app_del_tree_process_dir(const dkChar *dirname) { #if DK4_CHAR_SIZE > 1 WIN32_FIND_DATAW ff; #else WIN32_FIND_DATAA ff; #endif DWORD dwFileAttributes; HANDLE ha; int back = 1; #if DK4_CHAR_SIZE > 1 dwFileAttributes = GetFileAttributesW(dirname); #else dwFileAttributes = GetFileAttributesA(dirname); #endif if (INVALID_FILE_ATTRIBUTES == dwFileAttributes) { #if DK4_CHAR_SIZE > 1 ha = FindFirstFileW(dirname, &ff); #else ha = FindFirstFileA(dirname, &ff); #endif if (INVALID_HANDLE_VALUE != ha) { dwFileAttributes = ff.dwFileAttributes; FindClose(ha); } } if (INVALID_FILE_ATTRIBUTES != dwFileAttributes) { if (0 != (FILE_ATTRIBUTE_REPARSE_POINT & dwFileAttributes)) { #if DK4_CHAR_SIZE > 1 ha = FindFirstFileW(dirname, &ff); #else ha = FindFirstFileA(dirname, &ff); #endif if (INVALID_HANDLE_VALUE != ha) { if (0 != (FILE_ATTRIBUTE_REPARSE_POINT & ff.dwFileAttributes)) { if (IO_REPARSE_TAG_MOUNT_POINT == ff.dwReserved0) { back = 0; } if (IO_REPARSE_TAG_SYMLINK == ff.dwReserved0) { back = 0; } } FindClose(ha); } else { back = 0; } } } return back; } /* --- Windows */ #else /* +++ non-Windows */ #if DK4_CHAR_SIZE > 1 /* +++ non-Windows, wchar_t */ /* --- non-Windows, wchar_t */ #else /* +++ non-Windows, char */ /* --- non-Windows, char */ #endif /* --- non-Windows */ #endif #if DK4_HAVE_BACKSLASH_AS_SEP static const dkChar dk4appdeltree_fnsep[] = { dkT("\\") }; #else static const dkChar dk4appdeltree_fnsep[] = { dkT("/") }; #endif static void dk4app_del_tree_node_close(dk4_del_tree_node_t *ptr) { if (NULL != ptr) { ptr->parent = NULL; if (NULL != ptr->dir) { dk4dir_close(ptr->dir); ptr->dir = NULL; } ptr->dplen = 0; ptr->ne = 0; dk4mem_free(ptr); } } static dk4_del_tree_node_t * dk4app_del_tree_node_open( const dkChar *dn, dk4_del_tree_node_t *par, dk4_del_tree_job_t *job, dk4_app_t *app ) { dk4_er_t er; /* Error report */ const dkChar *fn; /* File name to process */ dkChar *nbptr; /* Buffer pointer */ dk4_del_tree_node_t *back = NULL; size_t lgt; /* Length of buffer */ #if VERSION_BEFORE_20150821 || TRACE_DEBUG int dfres; /* Result from file deletion */ #endif #line 270 "dk4appdeltree.ctr" back = dk4mem_new_app(dk4_del_tree_node_t,1,app); if (NULL != back) { #line 272 "dk4appdeltree.ctr" back->parent = par; back->ne = NE_NO_ERROR; back->dplen = dk4str_len(dn); dk4error_init(&er); back->dir = dk4dir_open_app(dn, DK4_DIR_OPEN_DELTREE, app); if (NULL != back->dir) { #line 278 "dk4appdeltree.ctr" dk4error_init(&er); lgt = dk4ma_size_t_add( dk4ma_size_t_add( back->dplen, dk4dir_get_max_entry_length(back->dir), &er ), 2, &er ); if (DK4_E_NONE == er.ec) { #line 287 "dk4appdeltree.ctr" if ((lgt > job->sbsz) && (lgt > job->dbsz)) { #line 289 "dk4appdeltree.ctr" nbptr = dk4mem_new_app(dkChar,lgt,app); if (NULL != nbptr) { #line 291 "dk4appdeltree.ctr" if (job->dbptr) { dk4mem_free(job->dbptr); #line 293 "dk4appdeltree.ctr" } job->dbptr = nbptr; job->dbsz = lgt; #line 295 "dk4appdeltree.ctr" } else { #line 296 "dk4appdeltree.ctr" dk4app_del_tree_node_close(back); back = NULL; job->result = 0; } } if (NULL != back) { if ((NULL != job->dbptr) && (0 < job->dbsz)) { nbptr = job->dbptr; #line 304 "dk4appdeltree.ctr" lgt = job->dbsz; } else { #line 306 "dk4appdeltree.ctr" nbptr = job->sbptr; lgt = job->sbsz; } #line 309 "dk4appdeltree.ctr" do { fn = dk4dir_next_file(back->dir); if (NULL != fn) { #line 312 "dk4appdeltree.ctr" if (dk4str_cpy_s(nbptr,lgt,dk4dir_get_path(back->dir),NULL)) { #line 314 "dk4appdeltree.ctr" if (dk4str_cat_s(nbptr, lgt, dk4appdeltree_fnsep, NULL)) { #line 316 "dk4appdeltree.ctr" if (dk4str_cat_s(nbptr, lgt, fn, NULL)) { #line 318 "dk4appdeltree.ctr" #line 319 "dk4appdeltree.ctr" switch (back->ne) { case NE_NO_ERROR : { if (0 == dk4app_del_file(nbptr, app)) { back->ne = NE_ONE_FILE_REMOVAL_FAILED; job->result = 0; #line 325 "dk4appdeltree.ctr" } } break; case NE_ONE_FILE_REMOVAL_FAILED : { if (0 == dk4app_del_file(nbptr, NULL)) { back->ne = NE_MULTIPLE_FILE_REMOVALS_FAILED; /* ERROR: Further file removals failed */ dk4app_log_base3( app,DK4_LL_ERROR,94,95,dk4dir_get_path(back->dir) ); #line 335 "dk4appdeltree.ctr" } } break; default : { #if TRACE_DEBUG dfres = dk4app_del_file(nbptr, NULL); if (0 == dfres) { #line 341 "dk4appdeltree.ctr" } #else dk4app_del_file(nbptr, NULL); #endif } break; } } else { #line 348 "dk4appdeltree.ctr" if (NE_ONE_FILE_REMOVAL_FAILED < back->ne) { back->ne = NE_ONE_FILE_REMOVAL_FAILED; } /* ERROR: Directory name too long */ dk4app_log_base3( app, DK4_LL_ERROR, 98, 99, dk4dir_get_path(back->dir) ); } } else { #line 357 "dk4appdeltree.ctr" if (NE_ONE_FILE_REMOVAL_FAILED < back->ne) { back->ne = NE_ONE_FILE_REMOVAL_FAILED; } /* ERROR: Directory name too long */ dk4app_log_base3( app, DK4_LL_ERROR, 98, 99, dk4dir_get_path(back->dir) ); } } else { #line 366 "dk4appdeltree.ctr" if (NE_ONE_FILE_REMOVAL_FAILED < back->ne) { back->ne = NE_ONE_FILE_REMOVAL_FAILED; } /* ERROR: Directory name too long */ dk4app_log_base3( app, DK4_LL_ERROR, 98, 99, dk4dir_get_path(back->dir) ); } } } while(NULL != fn); dk4dir_skip_files(back->dir); } else { #line 378 "dk4appdeltree.ctr" } } else { #line 380 "dk4appdeltree.ctr" /* ERROR: Math error in size calculation */ dk4app_log_base1(app, DK4_LL_ERROR, 82); dk4app_del_tree_node_close(back); back = NULL; job->result = 0; } } else { #line 387 "dk4appdeltree.ctr" dk4app_del_tree_node_close(back); back = NULL; job->result = 0; /* ERROR: Failed to open directory, already reported */ /* !!!!! TODO: Attempt to remove directory or file */ } } else { #line 394 "dk4appdeltree.ctr" } #line 396 "dk4appdeltree.ctr" return back; } static void dk4app_del_tree_debug_file_or_dir( dk4_app_t *app, const dkChar *fn, size_t ind ) { const dkChar *msg[3]; if ((NULL != app) && (NULL != fn)) { if (0 != dk4app_log_do(app, DK4_LL_DEBUG)) { if ((NULL != app->msg_debug) && (ind < app->sz_msg_debug)) { msg[0] = (app->msg_debug)[ind]; msg[1] = fn; msg[2] = NULL; dk4app_log_msg(app, DK4_LL_DEBUG, msg, 2); } } } } int dk4app_del_tree(const dkChar *fn, dk4_app_t *app) { dkChar sb[DK4_MAX_PATH]; dk4_del_tree_job_t job; /* Buffers */ dk4_del_tree_node_t *cn; /* Current node */ dk4_del_tree_node_t *nn; /* Next node */ dkChar *fnb; /* File name buffer */ const dkChar *dn; /* Directory name */ size_t fnbsz; /* File name buffer size */ int res; /* Operation result */ #if VERSION_BEFORE_20150821 || TRACE_DEBUG int dfres; /* Delete file result */ #endif int back = 0; #line 441 "dk4appdeltree.ctr" job.sbptr = sb; job.sbsz = DK4_SIZEOF(sb,dkChar); job.dbptr = NULL; job.dbsz = 0; job.result = 1; if (NULL != fn) { #line 447 "dk4appdeltree.ctr" cn = dk4app_del_tree_node_open(fn, NULL, &job, app); if (NULL != cn) { #line 449 "dk4appdeltree.ctr" while (NULL != cn) { #line 450 "dk4appdeltree.ctr" if ((NULL != job.dbptr) && (0 < job.dbsz)) { fnb = job.dbptr; fnbsz = job.dbsz; #line 452 "dk4appdeltree.ctr" } else { #line 453 "dk4appdeltree.ctr" fnb = job.sbptr; fnbsz = job.sbsz; } dn = dk4dir_next_dir(cn->dir); if (NULL != dn) { #line 457 "dk4appdeltree.ctr" if (0 != dk4str_cpy_s(fnb, fnbsz, dk4dir_get_path(cn->dir), NULL)) { if (0 != dk4str_cat_s(fnb, fnbsz, dk4appdeltree_fnsep, NULL)) { if (0 != dk4str_cat_s(fnb, fnbsz, dn, NULL)) { #line 460 "dk4appdeltree.ctr" #if DK4_ON_WINDOWS res = dk4app_del_tree_process_dir(fnb); #else res = 1; #endif if (0 != res) { #line 466 "dk4appdeltree.ctr" nn = dk4app_del_tree_node_open(fnb, cn, &job, app); if (NULL != nn) { cn = nn; } else { job.result = 0; } } else { #line 473 "dk4appdeltree.ctr" switch (cn->ne) { case NE_NO_ERROR: case NE_ONE_FILE_REMOVAL_FAILED: case NE_MULTIPLE_FILE_REMOVALS_FAILED: { dk4app_del_tree_debug_file_or_dir(app, fnb, 27); if (0 == dk4app_del_dir(fnb, NULL)) { if (0 == dk4app_del_file(fnb, NULL)) { job.result = 0; cn->ne = NE_ONE_DIRECTORY_REMOVAL_FAILED; dk4app_log_base3(app, DK4_LL_ERROR, 66, 77, fnb); #line 484 "dk4appdeltree.ctr" } } } break; case NE_ONE_DIRECTORY_REMOVAL_FAILED: { dk4app_del_tree_debug_file_or_dir(app, fnb, 27); if (0 == dk4app_del_dir(fnb, NULL)) { if (0 == dk4app_del_file(fnb, NULL)) { job.result = 0; cn->ne = NE_MULTIPLE_DIRECTORY_REMOVALS_FAILED; dk4app_log_base3( app, DK4_LL_ERROR, 96, 97, dk4dir_get_path(cn->dir) ); #line 497 "dk4appdeltree.ctr" } } } break; default: { dk4app_del_tree_debug_file_or_dir(app, fnb, 27); if (0 == dk4app_del_dir(fnb, NULL)) { #if TRACE_DEBUG dfres = dk4app_del_file(fnb, NULL); if (0 == dfres) { #line 506 "dk4appdeltree.ctr" } #else dk4app_del_file(fnb, NULL); #endif } } break; } } } else { #line 515 "dk4appdeltree.ctr" /* ERROR: Directory name too long! */ dk4app_log_base3(app, DK4_LL_ERROR, 98, 99, dn); job.result = 0; } } else { #line 520 "dk4appdeltree.ctr" /* ERROR: Directory name too long! */ dk4app_log_base3(app,DK4_LL_ERROR,98,99,dk4dir_get_path(cn->dir)); job.result = 0; } } else { #line 525 "dk4appdeltree.ctr" /* ERROR: Directory name too long! */ dk4app_log_base3(app,DK4_LL_ERROR,98,99,dk4dir_get_path(cn->dir)); job.result = 0; } } else { #line 530 "dk4appdeltree.ctr" nn = cn->parent; if (NULL != nn) { #line 532 "dk4appdeltree.ctr" switch (nn->ne) { case NE_NO_ERROR: case NE_ONE_FILE_REMOVAL_FAILED: case NE_MULTIPLE_FILE_REMOVALS_FAILED: { if (0 == dk4app_del_dir(dk4dir_get_path(cn->dir), app)) { job.result = 0; nn->ne = NE_ONE_DIRECTORY_REMOVAL_FAILED; } } break; case NE_ONE_DIRECTORY_REMOVAL_FAILED: { dk4app_del_tree_debug_file_or_dir( app, dk4dir_get_path(cn->dir), 25 ); if (0 == dk4app_del_dir(dk4dir_get_path(cn->dir), NULL)) { job.result = 0; nn->ne = NE_MULTIPLE_DIRECTORY_REMOVALS_FAILED; dk4app_log_base3( app, DK4_LL_ERROR, 96, 97, dk4dir_get_path(nn->dir) ); } } break; default: { dk4app_del_tree_debug_file_or_dir( app, dk4dir_get_path(cn->dir), 25 ); (void)dk4app_del_dir(dk4dir_get_path(cn->dir), NULL); } break; } } else { #line 561 "dk4appdeltree.ctr" if (0 == dk4app_del_dir(dk4dir_get_path(cn->dir), app)) { job.result = 0; } } dk4app_del_tree_node_close(cn); cn = nn; } } } else { #line 570 "dk4appdeltree.ctr" } } else { #line 572 "dk4appdeltree.ctr" } if ((NULL != job.dbptr) && (0 < job.dbsz)) { dk4mem_free(job.dbptr); #line 575 "dk4appdeltree.ctr" } back = job.result; #line 578 "dk4appdeltree.ctr" return back; }