diff options
author | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
commit | e0c6872cf40896c7be36b11dcc744620f10adf1d (patch) | |
tree | 60335e10d2f4354b0674ec22d7b53f0f8abee672 /support/dktools/dk-ls.ctr |
Initial commit
Diffstat (limited to 'support/dktools/dk-ls.ctr')
-rw-r--r-- | support/dktools/dk-ls.ctr | 3073 |
1 files changed, 3073 insertions, 0 deletions
diff --git a/support/dktools/dk-ls.ctr b/support/dktools/dk-ls.ctr new file mode 100644 index 0000000000..57786e6fa9 --- /dev/null +++ b/support/dktools/dk-ls.ctr @@ -0,0 +1,3073 @@ +%% options + +copyright owner = Dirk Krause +copyright year = 2015-xxxx +license = bsd + + + +%% header + +/** @file dk-ls.h Header file for dk-ls program. +*/ + +#include "dk4md.h" +#include "dk4fileit.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +/** Set message digest type and message digest encoding. + @param mdtype Address of message digest type variable. + @param mdenc Address of message digest encoding variable. + @param buffer Buffer containing textual description. + @param app Application structure for diagnostics, may be NULL. + @param msg Message string array. + @param szmsg Size of message string array. +*/ +void dk_ls_set_md( + int *mdtype, + int *mdenc, + dkChar *buffer, + dk4_app_t *app, + const dkChar * const *msg, + size_t szmsg +); + +/** Read information about symbolic link target. + @param bptr Buffer for path name. + @param szb Size of buffer (number of dkChar). + @param fn Link filename. + @return 1 on success, 0 on error. +*/ +int +dk_ls_readlink(dkChar *bptr, size_t szb, const dkChar *fn); + +/** Report error while attempting to read size. + @param app Application structure for diagnostics. + @param fn File name. + @param ch Data chooser. + @param msg Constant message texts. + @param szmsg Size of msg array. +*/ +void +dk_ls_report_fileinfo_size_error( + dk4_app_t *app, + const dkChar *fn, + int ch, + const dkChar * const *msg, + size_t szmsg +); + +/** Report error while attempting to read timestamp. + @param app Application structure for diagnostics. + @param fn File name. + @param ch Data chooser. + @param msg Constant message texts. + @param szmsg Size of msg array. +*/ +void +dk_ls_report_fileinfo_timestamp_error( + dk4_app_t *app, + const dkChar *fn, + int ch, + const dkChar * const *msg, + size_t szmsg +); + +#ifdef __cplusplus +} +#endif + + + +%% module + +#include "dk4conf.h" + +#if DK4_ON_WINDOWS +#ifndef WINDOWS_H_INCLUDED +#include <windows.h> +#define WINDOWS_H_INCLUDED +#endif +#endif + +#if DK4_HAVE_SYS_TYPES_H +#ifndef SYS_TYPES_H_INCLUDED +#include <sys/types.h> +#define SYS_TYPES_H_INCLUDED 1 +#endif +#endif + +#if DK4_HAVE_UNISTD_H +#ifndef UNISTD_H_INCLUDED +#include <unistd.h> +#define UNISTD_H_INCLUDED 1 +#endif +#endif + +#if DK4_HAVE_PROCESS_H +#ifndef PROCESS_H_INCLUDED +#include <process.h> +#define PROCESS_H_INCLUDED 1 +#endif +#endif + +#if DK4_HAVE_IO_H +#ifndef IO_H_INCLUDED +#include <io.h> +#define IO_H_INCLUDED 1 +#endif +#endif + +#if DK4_HAVE_FCNTL_H +#ifndef FCNTL_H_INCLUDED +#include <fcntl.h> +#define FCNTL_H_INCLUDED 1 +#endif +#endif + +#if DK4_HAVE_SIGNAL_H +#ifndef SIGNAL_H_INCLUDED +#include <signal.h> +#define SIGNAL_H_INCLUDED 1 +#endif +#endif + +#include "dk4types.h" +#include "dk4const.h" +#include "dk4vers.h" +#include "dk4app.h" +#include "dk4aopt.h" +#include "dk4mem.h" +#include "dk4mema.h" +#include "dk4fput.h" +#include "dk-ls.h" +#include "dk4mpl.h" +#include "dk4stat.h" +#include "dk4statd.h" +#include "dk4strd.h" +#include "dk4fileit.h" +#include "dk4filei.h" +#include "dk4fileia.h" +#include "dk4masz.h" +#include "dk4maadu.h" +#include "dk4maodd.h" +#include "dk4maodh.h" +#include "dk4numl.h" +#include "dk4dira.h" +#include "dk4pathd.h" +#include "dk4fopda.h" +#include "dk4symlink.h" + + + +$!trace-include + + + +/** Default help text, used if help text file is not found. +*/ +static const dkChar * const dk_ls_help_text[] = { +$!text macro=dkT,preprocessor + +List files + +dk-ls [<options>] [<file(s)>] + +Options: +-p ... Output column order, see below. -r Recursive listing. +-t ... File types to list. -m ... Message digest type. +-f Stay on current file system. -s Show summary at end. +--help Show this short help text. --manual *** SHOW FULL MANUAL. *** +--version Show version information. --license Show license information. + +Column order characters: n=name, s=size, t=type, p=permissions/attributes, +c=creation, m=modification, a=access, l=links, u=UID, g=GID, d=device, +i=inode, r=relative device, w=reparse tag (Widnows), x=message digest. +Default: ``mtpn'' (``mtn'' on Windows). + +File type characters: d=directories, f=non-directory entries. + +Message digest types: md5, sha-1, sha-224, sha-256, sha-384, sha-512, +ripemd-160. Optionally add encoding hex or a85, i.e. ``sha-1.hex''. + +http://dktools.sourceforge.net + +$!end +}; + + + +/** License conditions. +*/ +static const dkChar * const dk_ls_license_text[] = { +$!text macro=dkT,preprocessor +This software uses code from the following projects, either directly or as +a library: + +dktools Dirk Krause's tools and libraries. + See http://dktools.sourceforge.net/ for more information. +#if DK4_HAVE_ZLIB_H + +zlib Data compression library. + See http://www.zlib.net/ for more information. +#endif +#if DK4_HAVE_BZLIB_H + +bzip2 Data compression program and library. + See http://www.bzip.org/ for more information. +#endif +#if DK4_HAVE_OPENSSL_MD5_H && DK4_HAVE_OPENSSL_SHA_H && DK4_HAVE_OPENSSL_RIPEMD_H + +OpenSSL Cryptographic toolkit, used to build file checksums here. + See http://www.openssl.org/ for more information. + +This product includes software developed by the OpenSSL Project for use in +the OpenSSL Toolkit (http://www.openssl.org/). +This product includes cryptographic software written by +Eric Young (eay@cryptsoft.com). +This product includes software written by Tim Hudson (tjh@cryptsoft.com). +#endif + +All the licenses below apply to the program. +Licenses for used libraries are shown as found on my Scientific Linux 6.x +computer in the /usr/share/doc directory on 2015-04-01. Check the project +homepages of the used libraries for additional information and/or updated +license terms. + + +DK tools and libraries license +============================== +Copyright (c) 2015-2016, Dirk Krause +All rights reserved. + +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 copyright + 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 Dirk Krause 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. +#if DK4_HAVE_ZLIB_H + + +Zlib license +============ +(C) 1995-2004 Jean-loup Gailly and Mark Adler + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. + +Jean-loup Gailly Mark Adler +jloup@gzip.org madler@alumni.caltech.edu +#endif +#if DK4_HAVE_BZLIB_H + + +Bzip2 and libbzip2 library license +================================== +This program, "bzip2", the associated library "libbzip2", and all +documentation, are copyright (C) 1996-2007 Julian R Seward. All +rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. The origin of this software must not be misrepresented; you must + not claim that you wrote the original software. If you use this + software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + +3. Altered source versions must be plainly marked as such, and must + not be misrepresented as being the original software. + +4. The name of the author may not be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + +Julian Seward, jseward@bzip.org +bzip2/libbzip2 version 1.0.5 of 10 December 2007 +#endif +#if DK4_HAVE_OPENSSL_MD5_H && DK4_HAVE_OPENSSL_SHA_H && DK4_HAVE_OPENSSL_RIPEMD_H + + +OpenSSL license +=============== + +LICENSE ISSUES +-------------- + +The OpenSSL toolkit stays under a dual license, i.e. both the conditions of +the OpenSSL License and the original SSLeay license apply to the toolkit. +See below for the actual license texts. Actually both licenses are BSD-style +Open Source licenses. In case of any license issues related to OpenSSL +please contact openssl-core@openssl.org. + +OpenSSL License +--------------- + +Copyright (c) 1998-2011 The OpenSSL Project. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + +3. All advertising materials mentioning features or use of this + software must display the following acknowledgment: + "This product includes software developed by the OpenSSL Project + for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + +4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + endorse or promote products derived from this software without + prior written permission. For written permission, please contact + openssl-core@openssl.org. + +5. Products derived from this software may not be called "OpenSSL" + nor may "OpenSSL" appear in their names without prior written + permission of the OpenSSL Project. + +6. Redistributions of any form whatsoever must retain the following + acknowledgment: + "This product includes software developed by the OpenSSL Project + for use in the OpenSSL Toolkit (http://www.openssl.org/)" + +THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY +EXPRESSED 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 OpenSSL PROJECT OR +ITS 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. + +This product includes cryptographic software written by Eric Young +(eay@cryptsoft.com). This product includes software written by Tim +Hudson (tjh@cryptsoft.com). + + +Original SSLeay License +----------------------- + +Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) +All rights reserved. + +This package is an SSL implementation written +by Eric Young (eay@cryptsoft.com). +The implementation was written so as to conform with Netscapes SSL. + +This library is free for commercial and non-commercial use as long as +the following conditions are aheared to. The following conditions +apply to all code found in this distribution, be it the RC4, RSA, +lhash, DES, etc., code; not just the SSL code. The SSL documentation +included with this distribution is covered by the same copyright terms +except that the holder is Tim Hudson (tjh@cryptsoft.com). + +Copyright remains Eric Young's, and as such any Copyright notices in +the code are not to be removed. +If this package is used in a product, Eric Young should be given attribution +as the author of the parts of the library used. +This can be in the form of a textual message at program startup or +in documentation (online or textual) provided with the package. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. All advertising materials mentioning features or use of this software + must display the following acknowledgement: + "This product includes cryptographic software written by + Eric Young (eay@cryptsoft.com)" + The word 'cryptographic' can be left out if the rouines from the library + being used are not cryptographic related :-). +4. If you include any Windows specific code (or a derivative thereof) from + the apps directory (application code) you must include an acknowledgement: + "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + +THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 AUTHOR 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. + +The licence and distribution terms for any publically available version or +derivative of this code cannot be changed. i.e. this code cannot simply be +copied and put under another distribution licence +[including the GNU Public Licence.] + +#endif + +$!end +}; + + + +/** Constant texts used by program, not localized. +*/ +static const dkChar * const dk_ls_kwnl[] = { +$!string-table macro=dkT +# +# 0 Program group name +# +dktools +# +# 1 Help text file name +# +dk-ls.txt +# +# 2 String table file +# +dk-ls.str +# +# 3 Default set of information to show +# (type, permissions, modification time, size, name) +# +mtpn +# +# 4 Current directory +# +. +# +# 5 Path component separator on Windows +# +\\ +# +# 6 Path component separator on non-Windows +# +/ +# +# 7 String between link and target +# + -> +# +# 8 Default print order for Windows +# +mtn +# +# 9 Preference name for message digest +# +message.digest +# +# 10 Preference name for print order +# +print.order +# +# 11 Error message: Application startup failed! +# +ERROR: Application startup failed!\n +$!end +}; + + + +/** Constant texts used by program, replaced by localized texts + if available. +*/ +static const dkChar * const dk_ls_kw_def[] = { +$!string-table macro=dkT +# +# 0 Error message: Failed to set up signal handlers! +# +Failed to set up signal handlers! +# +# 1 Error message: Failed to restore previous signal handlers! +# +Failed to restore previous signal handlers! +# +# 2 Text "OVERFLOW" to show instead of the size +# +OVERFLOW +# +# 3 4 5 Failed to retrieve file size information. +# +Failed to obtain file size for symbolic link:\n\t" +Failed to obtain file size for target:\n\t" +"!\n\tInformation not available! +# +# 6 Path grows too long +# +Path grows too long while recursing directory! +# +# 7 8 9 Failed to obtain timestamp! +# +Failed to obtain timestamp for symbolic link:\n\t" +Failed to obtain timestamp for target:\n\t" +"!\nInformation not available! +# +# 10 +# +Failed to obtain file type and attributes (bug)! +# +# 11 +# +Invalid text in print order! +# +# 12 13 Failed to find target for symbolic link! +# +Failed to find target for symbolic link:\n\t" +"! +# +# 14 15 Failed to find unique file identifier +# +Failed to obtain unique file identifier:\n\t" +"! +# +# 16 17 18 File names too long in summary. +# +File names too long for expansion:\n\t" +",\n\t" +"! +# +# 19 Message digest type not supported! +# +Message digest type not supported! +# +# 20 21 Message digest type not supported! +# +Message digest type not supported: " +"! +# +# 22 23 Not a message digest type name! +# +Not a message digest type name: " +"! +# +# 24 25 Invalid encoding for message digest! +# +Invalid encoding for message digest: " +"! +# +# 26 Error message: Failed to init digest ctx +# +Failed to initialize digest context (error from library function)! +# +# 27 Error message: Failed to init message digest ctx +# +Failed to initialize message digest context! +# +# 28 Error message: Failed to add bytes to ctx +# +Failed to add data to message digest! +# +# 29 Error message: Failed to finish message digest +# +Failed to finish message digest! +# +# 30, 31, 32 +# +\# Number of directories: +\# Number of files: +\# Total number of bytes: +$!end +}; + + + +#if DK4_ON_WINDOWS +/** Buffer to store symbolic link destination. +*/ +static dkChar dk_ls_sl_target[32784]; +#else +/** Buffer to store symbolic link destination. +*/ +static dkChar dk_ls_sl_target[DK4_MAX_PATH]; +#endif + + + +/** Options used by program. +*/ +static const dk4_option_specification_t dk_ls_options[] = { + + /* Reset (ignore preferences). + */ + { dkT('R'), dkT("reset"), DK4_OPT_ARG_NONE }, + + /* Print order. + */ + { dkT('p'), dkT("print-order"), DK4_OPT_ARG_STRING }, + + /* Recursive listing. + */ + { dkT('r'), dkT("recursive"), DK4_OPT_ARG_NONE }, + + /* For recursive listings, stay on the current file system. + */ + { dkT('f'), dkT("stay-on-filesystem"), DK4_OPT_ARG_NONE }, + + /* File types to show (all others are ignored). + */ + { dkT('t'), dkT("types"), DK4_OPT_ARG_STRING }, + + { dkT('s'), dkT("summary"), DK4_OPT_ARG_NONE }, + +#if DK4_HAVE_OPENSSL_MD5_H && DK4_HAVE_OPENSSL_SHA_H && DK4_HAVE_OPENSSL_RIPEMD_H + { dkT('m'), dkT("message-digest"), DK4_OPT_ARG_STRING }, +#endif +}; + + + +/** Buffer for print order from command line. +*/ +static dkChar po_buf[32]; + + + +/** Application structure. +*/ +static dk4_app_t *app = NULL; + + + +/** Print order. +*/ +static const dkChar *print_order = NULL; + + +/** Message texts, uses localized texts if possible. +*/ +static const dkChar * const *dk_ls_msg = dk_ls_kw_def; + + +/** Error report for bytes counting. +*/ +static dk4_er_t er_bytes; + + +/** Error report for files counting. +*/ +static dk4_er_t er_files; + + +/** Error report for directory counting. +*/ +static dk4_er_t er_dirs; + + + +/** Size found so far. +*/ +static dk4_um_t size_bytes = (dk4_um_t)0UL; + + + +/** Number of files shown. +*/ +static dk4_um_t num_files = (dk4_um_t)0UL; + + + +/** Number of directories shown. +*/ +static dk4_um_t num_dirs = (dk4_um_t)0UL; + + + + +/** Number of elements in the dk_ls_kw_def array and in dk_ls_msg. +*/ +static size_t dk_ls_sz_msg = +(sizeof(dk_ls_kw_def)/sizeof(DK4_PDKCHAR) - 1); + + + +#if DK4_ON_WINDOWS +/** Limit for incrementing path construction buffer. + On Windows systems a special notation allows very long path names + up to 32767 characters. +*/ +static const size_t dk_ls_max_path = 32784U; +#else +/** Limit for incrementing path construction buffer. + On non-Windows systems the path is restricted to DK4_MAX_PATH. +*/ +static const size_t dk_ls_max_path = 2 * DK4_MAX_PATH; +#endif + + + +/** Number of elements in the dk_ls_options array. +*/ +static const size_t dk_ls_sz_options = +sizeof(dk_ls_options)/sizeof(dk4_option_specification_t); + + + +/** Flag: Size output wanted. +*/ +static int size_wanted = 0; + + + +/** Flag: Name output wanted. +*/ +static int name_wanted = 0; + + + +/** Flag: Show non-directories. +*/ +static int show_files = 1; + + + +/** Flag: Show directories. +*/ +static int show_dirs = 1; + + + +/** Flag: Recursive listing. +*/ +static int recursive = 0; + + + +/** Flag: Show summary. +*/ +static int show_summary = 0; + + + +/** Flag: Stay on file system when recursing directories. +*/ +static int stay_on_fs = 0; + + + +/** Message digest type. +*/ +static int digest_type = DK4_MD_SHA1; + + + +/** Message digest encoding. +*/ +static int digest_enco = DK4_BINARY_TO_TEXT_ENCODING_HEX; + + + +/** Flag: Unsupported digest type already reported. +*/ +static int digest_erep = 0; + + + +/** Flag: Write error occured while writing to standard output. +*/ +static int write_error = 0; + + + +/** Exit status code. +*/ +static int exval = EXIT_FAILURE; + + + +/** Flag: Illegal characters in print order reported. +*/ +static int print_order_error_reported = 0; + + + +#ifdef SIGPIPE +/** Indicator: SIGPIPE signal received. +*/ +static +DK4_VOLATILE +dk4_sig_atomic_t sig_had_pipe = 0; +#endif + +/** Indicator: SIGINT signal received. +*/ +static +DK4_VOLATILE +dk4_sig_atomic_t sig_had_int = 0; + +/** Indicator: SIGTERM signal received. +*/ +static +DK4_VOLATILE +dk4_sig_atomic_t sig_had_term = 0; + + + +/** Pass a volatile pointer to an atomic integer. + This function is necessary as some compilers mis-optimize + direct access to volatile variables (at least if you believe + one of the coding standards). + @param ptr Address of atomic integer variable. + @return The unmodified pointer. +*/ +static +DK4_VOLATILE +dk4_sig_atomic_t * +sig_pass_pointer(DK4_VOLATILE dk4_sig_atomic_t *ptr) +{ + return ptr; +} + + + +#ifdef SIGPIPE +/** Handler for SIGPIPE signal. + @param signo Signal number (always SIGPIPE, ignored). +*/ +static +void +sig_handler_pipe(int signo) +{ + *sig_pass_pointer(&sig_had_pipe) = 1; +} +#endif + +/** Handler for SIGINT signal. + @param signo Signal number (always SIGINT, ignored). +*/ +static +void +sig_handler_int(int signo) +{ + *sig_pass_pointer(&sig_had_int) = 1; +} + +/** Handler for SIGTERM signal. + @param signo Signal number (always SIGTERM, ignored). +*/ +static +void +sig_handler_term(int signo) +{ + *sig_pass_pointer(&sig_had_term) = 1; +} + +/** Read value from volatile atomic type. + This function is necessary as some compilers mis-optimize + direct access to volatile variables (at least if you believe + one of the coding standards). + @param ap Pointer to volatile atomic variable. + @return Contents of the variable. +*/ +static +dk4_sig_atomic_t +sig_read_atomic(DK4_VOLATILE dk4_sig_atomic_t *ap) +{ + return (*ap); +} + +/** Check whether we can continue or if a signal was received. + @param check_pipe Flag: Check for occured SIGPIPE signal too. + @return 1 if the program can continue, 0 if a signal was received. +*/ +static +int +sig_can_continue(int check_pipe) +{ + int back = 1; +#ifdef SIGPIPE + if (0 != check_pipe) { + if (0 != sig_read_atomic(&sig_had_pipe)) { back = 0; } + } +#endif + if (0 != sig_read_atomic(&sig_had_int )) { back = 0; } + if (0 != sig_read_atomic(&sig_had_term)) { back = 0; } + return back; +} + + + +/** Check whether we can continue. + @return 1 for yes, 0 for no. +*/ +static +int +dk_ls_can_continue(void) +{ + int back = 1; + if (0 == sig_can_continue(1)) { + back = 0; + } + return back; +} + + + +/** Node type for a directory. +*/ +typedef struct _dk_ls_node_t_ { + struct _dk_ls_node_t_ *parent; /**< Pointer to parent node. */ + struct _dk_ls_node_t_ *child; /**< Pointer to current child. */ + dk4_dir_t *dirptr; /**< Directory. */ + dk4_file_info_t fi; /**< File information. */ + dk4_um_t size; /**< Directory size. */ + int level; /**< Processing level. */ + int ovsize; /**< Flag: Overflow in size calc. */ +} dk_ls_node_t; + + + +/** Destroy node object, release memory. + @param cn Node to destroy. +*/ +static +void +dk_ls_delete_node(dk_ls_node_t *cn) +{ + $? "+ dk_ls_delete_node" + if (NULL != cn) { + cn->parent = NULL; + cn->child = NULL; + if (NULL != cn->dirptr) { + dk4dir_close(cn->dirptr); + } + cn->dirptr = NULL; + dk4mem_free(cn); + } $? "- dk_ls_delete_node" +} + + + +/** Create new new directory node. + @param dn Directory name for node. + @param pa Parent node. + @param level Processing level. + @return Pointer to new node on success, NULL on error. +*/ +static +dk_ls_node_t * +dk_ls_new_node(const dkChar *dn, dk_ls_node_t *pa, int level) +{ + dk4_er_t er; + dk_ls_node_t *back = NULL; + int om = DK4_DIR_OPEN_SORTED; + int ch = DK4_FILE_INFO_CONTENTS_DATA_TARGET; + $? "+ dk_ls_new_node \"%!ds\" PTR=%d", TR_STR(dn), TR_IPTR(pa) + back = dk4mem_new_app(dk_ls_node_t,1,app); + if (NULL != back) { + DK4_MEMRES(back, sizeof(dk_ls_node_t)); + back->parent = pa; + back->child = NULL; + back->dirptr = NULL; + back->level = level; + back->size = (dk4_um_t)0UL; + back->ovsize = 0; + if (3 < back->level) { back->level = 3; } + om |= DK4_DIR_SYMLINK_DIR_AS_FILE; + dk4error_init(&er); + back->dirptr = dk4dir_open_app(dn, om, app); + if (NULL == back->dirptr) { $? "! back->dirptr" + exval = EXIT_FAILURE; + dk_ls_delete_node(back); + back = NULL; + } + if (NULL != back) { $? ". node ok, retrieve file info" + dk4fileinfo_init(&(back->fi)); + if (0 != dk4fileinfo_app(&(back->fi), dn, app)) { + if (0 == dk4fileinfo_size(&(back->size), &(back->fi), ch, NULL)) { + back->size = (dk4_um_t)0UL; $? "! file size" + /* ERROR: Failed to retrieve directory size */ + dk_ls_report_fileinfo_size_error(app,dn,ch,dk_ls_msg,dk_ls_sz_msg); + exval = EXIT_FAILURE; + } + } else { $? "! fileinfo" + /* ERROR: Failed to retrieve file information, already reported */ + exval = EXIT_FAILURE; + } + } else { $? "! directory" + /* ERROR: Failed to open directory, already reported */ + exval = EXIT_FAILURE; + } + } else { $? "! allocation" + /* ERROR: Allocation failed, already reported */ + exval = EXIT_FAILURE; + } + $? "- dk_ls_new_node PTR=%d", TR_IPTR(back) + return back; +} + + + +/** Construct a path name consisting of directory and + file or subdirectory name into an existing buffer. + @param bufptr Buffer address. + @param szbuf Size of buffer. + @param dirname Leading part of path name. + @param filename Trailing part of path name. + @param erp Error report, may be NULL. + @return 1 on success, 0 on error (buffer too short). +*/ +static +int +dk_ls_dir_and_file( + dkChar *bufptr, + size_t szbuf, + const dkChar *dirname, + const dkChar *filename +) +{ + int back = 0; + int nsep = 1; /* Flag: Separator needed */ + $? "+ dk_ls_dir_and_file \"%!ds\" \"%!ds\"", TR_STR(dirname), TR_STR(filename) + if (NULL != dirname) { + if (0 != dk4str_cpy_s(bufptr, szbuf, dirname, NULL)) { + while(dkT('\0') != *dirname) { +#if DK4_ON_WINDOWS + if (dkT('\\') == *dirname) +#else + if (dkT('/') == *dirname) +#endif + { + nsep = 0; + } else { + nsep = 1; + } + dirname++; + } + if (0 != nsep) { +#if DK4_ON_WINDOWS + if (0 != dk4str_cat_s(bufptr, szbuf, dk_ls_kwnl[5], NULL)) +#else + if (0 != dk4str_cat_s(bufptr, szbuf, dk_ls_kwnl[6], NULL)) +#endif + { + back = 1; + } + } else { + back = 1; + } + if (0 != back) { + back = 0; + if (0 != dk4str_cat_s(bufptr, szbuf, filename, NULL)) { + back = 1; + } else { $? "! BUG: Buffer too small" + /* BUG: Buffer too small */ + exval = EXIT_FAILURE; + } + } else { $? "! BUG: Buffer too small" + /* BUG: Buffer too small */ + exval = EXIT_FAILURE; + } + } else { $? "! BUG: Buffer too small" + /* BUG: Buffer too small */ + exval = EXIT_FAILURE; + } + } else { + back = dk4str_cpy_s(bufptr, szbuf, filename, NULL); + if (0 == back) { $? "! BUG: Buffer too small" + /* BUG: Buffer too small */ + exval = EXIT_FAILURE; + } + } $? "- dk_ls_dir_and_file %d", back + return back; +} + + + +/** Construct a file or directory name, resize buffer if + necessary. + @param bufptr Address of pointer to buffer. + @param szbufptr Address of buffer size variable. + @param dirname Directory part of path to construct. + @param filename File name part of path to construct. + @return 1 on success, 0 on error. +*/ +static +int +dk_ls_construct_path( + dkChar **bufptr, + size_t *szbufptr, + const dkChar *dirname, + const dkChar *filename +) +{ + dk4_er_t er; /* Error code */ + dkChar *nb; /* New buffer */ + size_t lgt; /* Required buffer size */ + int back = 0; + $? "+ dk_ls_construct_path \"%!ds\" \"%!ds\"",TR_STR(dirname),TR_STR(filename) + dk4error_init(&er); + lgt = dk4str_len(filename); + if (NULL != dirname) { + lgt = dk4ma_size_t_add(lgt, dk4str_len(dirname), &er); + lgt = dk4ma_size_t_add(lgt, 2, &er); + } + if (DK4_E_NONE == er.ec) { + if (lgt <= *szbufptr) { + /* + Keep current buffer. + */ + $? ". can keep current buffer" + back = dk_ls_dir_and_file(*bufptr, *szbufptr, dirname, filename); + } else { + if (dk_ls_max_path > lgt) { + /* + Allocate new larger buffer. + */ + $? ". need new buffer" + nb = dk4mem_new_app(dkChar, lgt, app); + if (NULL != nb) { $? ". allocation" + dk4mem_release(*bufptr); + *bufptr = nb; + *szbufptr = lgt; + back = dk_ls_dir_and_file(*bufptr, *szbufptr, dirname, filename); + } else { $? "! allocation" + /* ERROR: Memory allocation failed, already reported */ + exval = EXIT_FAILURE; + } + } else { + /* ERROR: Path size too long */ + dk4app_log_1(app, dk_ls_msg, dk_ls_sz_msg, DK4_LL_ERROR, 6); + exval = EXIT_FAILURE; + } + } + } else { + /* ERROR: Overflow in size calculation */ + dk4app_log_base1(app, DK4_LL_ERROR, 82); + exval = EXIT_FAILURE; + } + $? "- dk_ls_construct_path %d", back + return back; +} + + + +static +void +dk_ls_write_decimal_number(dk4_um_t value, size_t width) +{ + dkChar buf[16 + 8 * sizeof(dk4_um_t)]; + dk4_er_t er; + size_t sl; + int res; + dk4error_init(&er); + res = dk4ma_write_decimal_unsigned( + buf, DK4_SIZEOF(buf,dkChar), value, 0, &er + ); + if (0 != res) { + sl = dk4str_len(buf); + while (sl++ < width) { + if (0 == dk4fputc(dkT(' '), stdout, NULL)) { + write_error = 1; exval = EXIT_FAILURE; + } + } + if (0 == dk4fputs(buf, stdout, NULL)) { + write_error = 1; exval = EXIT_FAILURE; + } + } else { $? "! BUG: Failed to write decimal to buffer" + /* ERROR: Failed to write decimal number to buffer (bug) */ + exval = EXIT_FAILURE; + } +} + + + +static +void +dk_ls_write_hexadecimal_number(dk4_um_t value, size_t width) +{ + dkChar buf[16 + 8 * sizeof(dk4_um_t)]; + dk4_er_t er; + size_t sl; + int res; + $? "+ dk_ls_write_hexadecimal_number" + dk4error_init(&er); + res = dk4ma_write_hex_unsigned( + buf, DK4_SIZEOF(buf,dkChar), value, width, &er + ); + if (0 != res) { $? ". string created" + sl = dk4str_len(buf); + while (sl++ < width) { $? ". fill text" + if (0 == dk4fputc(dkT('0'), stdout, NULL)) { + write_error = 1; exval = EXIT_FAILURE; + } + } + if (0 == dk4fputs(buf, stdout, NULL)) { $? "! dk4fputs" + write_error = 1; exval = EXIT_FAILURE; + } + } else { $? "! dk4ma_write_hex_unsigned" + /* BUG: Failed to write hexadecimal number to buffer */ + exval = EXIT_FAILURE; + } + $? "- dk_ls_write_hexadecimal_number" +} + + + +/** Write file timestamp. + @param fiptr File information. + @param fn File name. + @param what Choose the timestamp. + @param issl Flag: Object is symbolic link. +*/ +static +void +dk_ls_write_timestamp( + dk4_file_info_t *fiptr, const dkChar *fn, int what, int issl +) +{ + dk4_er_t er; + dkChar buf[64]; + int ch; + int res; + + dk4error_init(&er); + ch = ( + (0 != issl) + ? DK4_FILE_INFO_CONTENTS_DATA_LINK + : DK4_FILE_INFO_CONTENTS_DATA_TARGET + ); + res = dk4fileinfo_timestamp(buf,DK4_SIZEOF(buf,dkChar),fiptr,ch,what,&er); + if (0 != res) { + if (0 == dk4fputs(buf, stdout, &er)) { + write_error = 1; exval = EXIT_FAILURE; + } + } else { + /* ERRROR: Failed to obtain time */ + dk_ls_report_fileinfo_timestamp_error( + app, fn, ch, dk_ls_msg, dk_ls_sz_msg + ); + exval = EXIT_FAILURE; + } +} + + + +/** Write indicator for unkown data. + @param width Field width. + @param compl Fill complete field. +*/ +static +void +dk_ls_write_unknown(size_t width, int compl) +{ + if (0 != compl) { + while (0 < width--) { + if (0 == dk4fputc(dkT('?'), stdout, NULL)) { + write_error = 1; exval = EXIT_FAILURE; + } + } + } else { + while (1 < width--) { + if (0 == dk4fputc(dkT(' '), stdout, NULL)) { + write_error = 1; exval = EXIT_FAILURE; + } + } + if (0 == dk4fputc(dkT('?'), stdout, NULL)) { + write_error = 1; exval = EXIT_FAILURE; + } + } +} + + + +static +int +dk_ls_can_create_md(const dkChar *fn, dk4_file_info_t *fiptr) +{ + int back = 0; + if (0 == dk4fileinfo_is_symlink(fiptr)) { +#if DK4_ON_WINDOWS + if (0 == (FILE_ATTRIBUTE_REPARSE_POINT & (fiptr->fattr))) { + if (0 == (FILE_ATTRIBUTE_DIRECTORY & (fiptr->fattr))) { + if (0 == (FILE_ATTRIBUTE_DEVICE & (fiptr->fattr))) { + back = 1; + } + } + } +#else + if (0 != (DK4_FILE_INFO_CONTENTS_DATA_TARGET & (fiptr->contents))) { + if (S_IFREG == (S_IFMT & ((fiptr->tstb).st_mode))) { + back = 1; + } + } +#endif + } + return back; +} + + + +/** Write message digest. + @param fn File name. + @param fiptr File information pointer. + @param digest_type Message digest type. + @param digest_enco Message digest encoding. + @param app Application structure for diagnostics. + @param dk_ls_msg Message texts array. + @param dk_ls_sz_msg Size of message texts error. +*/ +static +void +dk_ls_write_md( + const dkChar *fn, + dk4_file_info_t *fiptr, + int digest_type, + int digest_enco, + dk4_app_t *app, + const dkChar * const *dk_ls_msg, + size_t dk_ls_sz_msg +) +{ + char buf[4096]; /* Buffer to read file */ + dk4_md_ctx_t ctx; /* Message digest context */ + dk4_er_t er; /* Error report */ + FILE *fipo; /* Input file to process */ + const char *resptr; /* Pointer to encoded digest buffer */ + size_t rdbytes; /* Number of bytes read */ + int mdok = 0; /* Flag: Digesting ok so far */ + if (0 != dk_ls_can_create_md(fn, fiptr)) { $? ". can create md" + dk4error_init(&er); + if (0 != dk4md_ctx_init(&ctx, digest_type, digest_enco, &er)) { + $? ". ctx initialized" + fipo = dk4fopen_app(fn, dkT("rb"), DK4_FOPEN_SC_IS_REGULAR, app); + if (NULL != fipo) { $? ". file opened" + mdok = 1; + do { + if (0 != dk_ls_can_continue()) { + rdbytes = fread(buf, 1, sizeof(buf), fipo); + if (0 < rdbytes) { $? ". bytes found" + dk4error_init(&er); + if (1 != dk4md_ctx_add(&ctx, buf, rdbytes, &er)) { + mdok = 0; $? "! ctx add" + /* ERROR: Digest failed */ + switch (er.ec) { + case DK4_E_NOT_SUPPORTED : { + dk4app_log_1(app,dk_ls_msg,dk_ls_sz_msg,DK4_LL_ERROR,19); + } break; + default : { + dk4app_log_1(app,dk_ls_msg,dk_ls_sz_msg,DK4_LL_ERROR,28); + } break; + } + } + } + } else { + mdok = 0; + rdbytes = 0; + } + } while((0 < rdbytes) && (1 == mdok)); + fclose(fipo); + if (1 == mdok) { $? ". mdok" + resptr = NULL; rdbytes = 0; + dk4error_init(&er); + if (1 == dk4md_ctx_finish(&resptr, &rdbytes, &ctx, &er)) { + $? ". ctx finished" + if ((NULL != resptr) && (0 < rdbytes)) { $? ". results" + while(rdbytes--) { + if (0 == dk4fputc((dkChar)(*(resptr++)), stdout, NULL)) { + write_error = 1; exval = EXIT_FAILURE; $? "! write error" + } + } + } else { $? "! results" + mdok = 0; + /* ERROR: No digest obtained */ + dk4app_log_1(app, dk_ls_msg, dk_ls_sz_msg, DK4_LL_ERROR, 29); + } + } else { $? "! ctx finish" + mdok = 0; + /* ERROR: Failed to obtain digest */ + dk4app_log_1(app, dk_ls_msg, dk_ls_sz_msg, DK4_LL_ERROR, 29); + } + } else { $? "! mdok" + } + } else { $? "! fopen" + /* ERROR: Failed to open file, already reported */ + } + } else { $? "! ctx init" + /* ERROR: Failed to initialize digest ctx */ + switch (er.ec) { + case DK4_E_NOT_SUPPORTED : { + dk4app_log_1(app, dk_ls_msg, dk_ls_sz_msg, DK4_LL_ERROR, 19); + } break; + case DK4_E_SYSTEM : { + dk4app_log_1(app, dk_ls_msg, dk_ls_sz_msg, DK4_LL_ERROR, 26); + } break; + default : { + dk4app_log_1(app, dk_ls_msg, dk_ls_sz_msg, DK4_LL_ERROR, 27); + } break; + } + } + } else { $? ". do not create md" + } + if (0 == mdok) { + rdbytes = dk4md_size(digest_type, digest_enco, NULL); + while (rdbytes--) { + if (0 == dk4fputc(dkT('x'), stdout, NULL)) { + write_error = 1; exval = EXIT_FAILURE; + } + } + } +} + + +/** Write information about file to standard output. + @param fn File name. + @param fiptr File information. + @param use_size Flag: Use specified size. + @param size Size to use. + @param ovsize Flag: Numeric overflow in size calculation. +*/ +static +void +dk_ls_process_item_information( + const dkChar *fn, + dk4_file_info_t *fiptr, + int use_size, + dk4_um_t size, + int ovsize +) +{ + dkChar abuf[8*sizeof(dk4_um_t) + 16]; /* Attributes */ + dkChar buf[8*sizeof(dk4_um_t) + 16]; /* Numbers */ + dk4_er_t er; /* Error report */ + const dkChar *piptr; /* Print order */ + dk4_um_t fs; /* File size */ + size_t numl; /* Number length */ + size_t slen; /* String length */ + size_t tlen; /* First part length */ + size_t i; /* Index variable */ + int issl; /* Flag: Is symbolic link */ + int res; /* Result from information retrieval */ + int showi; /* Flag: Show this item */ + int habuf; /* Flag: Data in abuf */ + int last_was_n; /* Flag: n was last character */ + dkChar lasti; /* Last information printed */ + $? "+ dk_ls_process_item_information \"%!ds\" PTR=%d", TR_STR(fn), TR_IPTR(fiptr) + last_was_n = habuf = 0; + if ((NULL != fn) && (NULL != fiptr)) { $? ". args ok" + showi = 1; + res = dk4fileinfo_type_attributes( + buf, DK4_SIZEOF(buf,dkChar), fiptr, &er + ); + if (0 != res) { + showi = 0; + if (dkT('d') == buf[1]) { + if (0 != show_dirs) { + showi = 1; + if (0 != show_summary) { + num_dirs = dk4ma_um_add(num_dirs, 1, &er_dirs); + } + } + } else { + if (0 != show_files) { + showi = 1; + if (0 != show_summary) { + num_files = dk4ma_um_add(num_files, 1, &er_files); + } + } + } + } else { $? "! BUG: Failed to write attributes to buffer" + /* BUG: Failed to write file attributes to buffer */ + dk4app_log_1(app, dk_ls_msg, dk_ls_sz_msg, DK4_LL_ERROR, 10); + exval = EXIT_FAILURE; + } + if (0 != showi) { $? ". show file details" + issl = dk4fileinfo_is_symlink(fiptr); + lasti = dkT('\0'); + piptr = print_order; + while (dkT('\0') != *piptr) { $? ". piptr %!dc", *piptr + last_was_n = 0; + if ((int)(*piptr) <= 255) { $? ". ok" + switch ((char)(*piptr)) { + case 'n' : { $? ". name" + if (dkT('\0') != lasti) { + if (0 == dk4fputc(dkT(' '), stdout, NULL)) { + write_error = 1; exval = EXIT_FAILURE; + } + } + if (0 == dk4fputs(fn, stdout, NULL)) { + write_error = 1; exval = EXIT_FAILURE; + } + last_was_n = 1; + } break; + case 'N' : { $? ". name" + if (dkT('\0') != lasti) { + if (0 == dk4fputc(dkT(' '), stdout, NULL)) { + write_error = 1; exval = EXIT_FAILURE; + } + } + if (0 == dk4fputs(fn, stdout, NULL)) { + write_error = 1; exval = EXIT_FAILURE; + } + } break; + case 's' : { $? ". size" + if (dkT('\0') != lasti) { + if (0 == dk4fputc(dkT(' '), stdout, NULL)) { + write_error = 1; exval = EXIT_FAILURE; + } + } + res = 0; + if (0 != use_size) { + if (0 != ovsize) { + /* Show Overflow */ + dk4error_set_simple_error_code(&er_bytes, DK4_E_MATH_OVERFLOW); + slen = dk4str_len(dk_ls_msg[2]); + numl = dk4numlength(sizeof(dk4_um_t), 0); + tlen = (numl - slen) / 2; + for (i = 0; i < tlen; i++) { + if (0 == dk4fputc(dkT('-'), stdout, NULL)) { + write_error = 1; exval = EXIT_FAILURE; + } + } + if (0 == dk4fputs(dk_ls_msg[2], stdout, NULL)) { + write_error = 1; exval = EXIT_FAILURE; + } + for (i = (tlen + slen); i < numl; i++) { + if (0 == dk4fputc(dkT('-'), stdout, NULL)) { + write_error = 1; exval = EXIT_FAILURE; + } + } + } else { + /* Show size */ + fs = size; + res = 1; + } + } else { + dk4error_init(&er); + res = dk4fileinfo_size( + &fs, fiptr, + ( + (0 != issl) + ? (DK4_FILE_INFO_CONTENTS_DATA_LINK) + : (DK4_FILE_INFO_CONTENTS_DATA_TARGET) + ), + &er + ); + if (0 == res) { + /* ERROR: Failed to obtain size */ + $? "! file size" + dk_ls_report_fileinfo_size_error( + app, fn, + ( + (0 != issl) + ? (DK4_FILE_INFO_CONTENTS_DATA_LINK) + : (DK4_FILE_INFO_CONTENTS_DATA_TARGET) + ), + dk_ls_msg, dk_ls_sz_msg + ); + } + } + if (0 != res) { + numl = dk4numlength(sizeof(dk4_um_t), 0); + dk_ls_write_decimal_number(fs, numl); + if (0 != show_summary) { + size_bytes = dk4ma_um_add(size_bytes, fs, &er_bytes); + } + } + } break; + case 't' : { $? ". type, permissions" + dk4error_init(&er); + if (0 == habuf) { + habuf = dk4fileinfo_type_attributes( + abuf, DK4_SIZEOF(abuf,dkChar), fiptr, &er + ); + } + if (0 != habuf) { + if (dkT('\0') != lasti) { + if (0 == dk4fputc(dkT(' '), stdout, &er)) { + write_error = 1; exval = EXIT_FAILURE; + } + } + if (0 == dk4fputc(abuf[0], stdout, &er)) { + write_error = 1; exval = EXIT_FAILURE; + } + if (0 == dk4fputc(abuf[1], stdout, &er)) { + write_error = 1; exval = EXIT_FAILURE; + } + } else { + /* ERROR: Failed to obtain file type */ + dk4app_log_1(app, dk_ls_msg, dk_ls_sz_msg, DK4_LL_ERROR, 10); + } + } break; + case 'p' : { + if (0 == habuf) { + habuf = dk4fileinfo_type_attributes( + abuf, DK4_SIZEOF(abuf,dkChar), fiptr, &er + ); + } + if (0 != habuf) { + if ((dkT('\0') != lasti) && (dkT('t') != lasti)) { + if (0 == dk4fputc(dkT(' '), stdout, &er)) { + write_error = 1; exval = EXIT_FAILURE; + } + } + if (0 == dk4fputs(&(abuf[2]), stdout, &er)) { + write_error = 1; exval = EXIT_FAILURE; + } + } else { + /* ERROR: Failed to obtain file type */ + dk4app_log_1(app, dk_ls_msg, dk_ls_sz_msg, DK4_LL_ERROR, 10); + } + } break; + case 'l' : { $? ". number of links" + fs = (dk4_um_t)1UL; + if (0 != issl) { + if (0 != (DK4_FILE_INFO_CONTENTS_DATA_LINK & fiptr->contents)) + { +#if DK4_ON_WINDOWS + fs = (dk4_um_t)((fiptr->linfo).nNumberOfLinks); +#else + fs = (dk4_um_t)((fiptr->lstb).st_nlink); +#endif + } + } else { + if (0 != (DK4_FILE_INFO_CONTENTS_DATA_TARGET & fiptr->contents)) + { +#if DK4_ON_WINDOWS + fs = (dk4_um_t)((fiptr->tinfo).nNumberOfLinks); +#else + fs = (dk4_um_t)((fiptr->tstb).st_nlink); +#endif + } + } +#if DK4_ON_WINDOWS + if ((DWORD)0UL == fiptr->resio) { +#endif + dk_ls_write_decimal_number( + fs, +#if DK4_ON_WINDOWS + dk4numlength(sizeof(DWORD), 0) +#else + dk4numlength(sizeof(nlink_t), 0) +#endif + ); +#if DK4_ON_WINDOWS + } else { + slen = dk4numlength(sizeof(DWORD), 0); + for (i = 1; i < slen; i++) { + if (0 == dk4fputc(dkT(' '), stdout, NULL)) { + write_error = 1; exval = EXIT_FAILURE; + } + } + if (0 == dk4fputc(dkT('?'), stdout, NULL)) { + write_error = 1; exval = EXIT_FAILURE; + } + } +#endif + } break; + case 'c' : { $? ". creation timestamp" + if (dkT('\0') != lasti) { + if (0 == dk4fputc(dkT(' '), stdout, NULL)) { + write_error = 1; exval = EXIT_FAILURE; + } + } + dk_ls_write_timestamp(fiptr, fn, DK4_FILE_INFO_TIME_CREATE, issl); + } break; + case 'm' : { $? ". modification timestamp" + if (dkT('\0') != lasti) { + if (0 == dk4fputc(dkT(' '), stdout, NULL)) { + write_error = 1; exval = EXIT_FAILURE; + } + } + dk_ls_write_timestamp(fiptr, fn, DK4_FILE_INFO_TIME_MODIFY, issl); + } break; + case 'a' : { $? ". access timestamp" + if (dkT('\0') != lasti) { + if (0 == dk4fputc(dkT(' '), stdout, NULL)) { + write_error = 1; exval = EXIT_FAILURE; + } + } + dk_ls_write_timestamp(fiptr, fn, DK4_FILE_INFO_TIME_ACCESS, issl); + } break; +#if !DK4_ON_WINDOWS + case 'u' : { $? ". owner UID" + if (dkT('\0') != lasti) { + if (0 == dk4fputc(dkT(' '), stdout, NULL)) { + write_error = 1; exval = EXIT_FAILURE; + } + } + if (0 != issl) { + if (0 != (DK4_FILE_INFO_CONTENTS_DATA_LINK & fiptr->contents)) + { + dk_ls_write_decimal_number( + (fiptr->lstb).st_uid, + dk4numlength(sizeof(uid_t), 0) + ); + } + else + { + dk_ls_write_unknown(dk4numlength(sizeof(uid_t), 0), 0); + } + } else { + if (0 != (DK4_FILE_INFO_CONTENTS_DATA_TARGET & fiptr->contents)) + { + dk_ls_write_decimal_number( + (fiptr->tstb).st_uid, + dk4numlength(sizeof(uid_t), 0) + ); + } + else + { + dk_ls_write_unknown(dk4numlength(sizeof(uid_t), 0), 0); + } + } + } break; +#endif +#if !DK4_ON_WINDOWS + case 'g' : { $? ". owner GID" + if (dkT('\0') != lasti) { + if (0 == dk4fputc(dkT(' '), stdout, NULL)) { + write_error = 1; exval = EXIT_FAILURE; + } + } + if (0 != issl) { + if (0 != (DK4_FILE_INFO_CONTENTS_DATA_LINK & fiptr->contents)) + { + dk_ls_write_decimal_number( + (fiptr->lstb).st_gid, + dk4numlength(sizeof(gid_t), 0) + ); + } + else + { + dk_ls_write_unknown(dk4numlength(sizeof(gid_t), 0), 0); + } + } else { + if (0 != (DK4_FILE_INFO_CONTENTS_DATA_TARGET & fiptr->contents)) + { + dk_ls_write_decimal_number( + (fiptr->tstb).st_gid, + dk4numlength(sizeof(gid_t), 0) + ); + } + else + { + dk_ls_write_unknown(dk4numlength(sizeof(gid_t), 0), 0); + } + } + } break; +#endif + case 'd' : { $? ". device number" + if (dkT('\0') != lasti) { + if (0 == dk4fputc(dkT(' '), stdout, NULL)) { + write_error = 1; exval = EXIT_FAILURE; + } + } +#if DK4_ON_WINDOWS + if (0 != issl) { + if (0 != (DK4_FILE_INFO_CONTENTS_DATA_LINK & fiptr->contents)) + { + if ((DWORD)0UL == fiptr->resio) { + dk_ls_write_hexadecimal_number( + (fiptr->linfo).dwVolumeSerialNumber, 2*sizeof(DWORD) + ); + } else { + dk_ls_write_unknown(2*sizeof(DWORD), 1); + } + } + else + { + dk_ls_write_unknown(2*sizeof(DWORD), 1); + } + } else { + if (0 != (DK4_FILE_INFO_CONTENTS_DATA_TARGET & fiptr->contents)) + { + if ((DWORD)0UL == fiptr->resio) { + dk_ls_write_hexadecimal_number( + (fiptr->tinfo).dwVolumeSerialNumber, 2*sizeof(DWORD) + ); + } else { + dk_ls_write_unknown(2*sizeof(DWORD), 1); + } + } + else + { + dk_ls_write_unknown(2*sizeof(DWORD), 1); + } + } +#else + if (0 != issl) { + if (0 != (DK4_FILE_INFO_CONTENTS_DATA_LINK & fiptr->contents)) + { + dk_ls_write_hexadecimal_number( + (fiptr->lstb).st_dev, 2*sizeof(dev_t) + ); + } + else + { + dk_ls_write_unknown(2*sizeof(dev_t), 1); + } + } else { + if (0 != (DK4_FILE_INFO_CONTENTS_DATA_TARGET & fiptr->contents)) + { + dk_ls_write_hexadecimal_number( + (fiptr->tstb).st_dev, 2*sizeof(dev_t) + ); + } + else + { + dk_ls_write_unknown(2*sizeof(dev_t), 1); + } + } +#endif + } break; + case 'r' : { $? ". relative device number" +#if DK4_ON_WINDOWS + if (0 != issl) { + if (0 != (DK4_FILE_INFO_CONTENTS_DATA_LINK & fiptr->contents)) + { + if ((DWORD)0UL == fiptr->resio) { + dk_ls_write_hexadecimal_number( + (fiptr->linfo).dwVolumeSerialNumber, 2*sizeof(DWORD) + ); + } else { + dk_ls_write_unknown(2*sizeof(DWORD), 1); + } + } + else + { + dk_ls_write_unknown(2*sizeof(DWORD), 1); + } + } else { + if (0 != (DK4_FILE_INFO_CONTENTS_DATA_TARGET & fiptr->contents)) + { + if ((DWORD)0UL == fiptr->resio) { + dk_ls_write_hexadecimal_number( + (fiptr->tinfo).dwVolumeSerialNumber, 2*sizeof(DWORD) + ); + } else { + dk_ls_write_unknown(2*sizeof(DWORD), 1); + } + } + else + { + dk_ls_write_unknown(2*sizeof(DWORD), 1); + } + } +#else + if (0 != issl) { + if (0 != (DK4_FILE_INFO_CONTENTS_DATA_LINK & fiptr->contents)) + { + dk_ls_write_hexadecimal_number( + (fiptr->lstb).st_rdev, 2*sizeof(dev_t) + ); + } + else + { + dk_ls_write_unknown(2*sizeof(dev_t), 1); + } + } else { + if (0 != (DK4_FILE_INFO_CONTENTS_DATA_TARGET & fiptr->contents)) + { + dk_ls_write_hexadecimal_number( + (fiptr->tstb).st_rdev, 2*sizeof(dev_t) + ); + } + else + { + dk_ls_write_unknown(2*sizeof(dev_t), 1); + } + } +#endif + } break; + case 'i' : { $? ". inode number" + if (dkT('\0') != lasti) { + if (dkT('d') != lasti) { + if (0 == dk4fputc(dkT(' '), stdout, NULL)) { + write_error = 1; exval = EXIT_FAILURE; + } + } else { + if (0 == dk4fputc(dkT(':'), stdout, NULL)) { + write_error = 1; exval = EXIT_FAILURE; + } + } + } +#if DK4_ON_WINDOWS + if (0 != issl) { + if (0 != (DK4_FILE_INFO_CONTENTS_DATA_LINK & fiptr->contents)) + { + if ((DWORD)0UL == fiptr->resio) { + dk_ls_write_hexadecimal_number( + (fiptr->linfo).nFileIndexHigh, 2*sizeof(DWORD) + ); + dk_ls_write_hexadecimal_number( + (fiptr->linfo).nFileIndexLow, 2*sizeof(DWORD) + ); + } else { + dk_ls_write_unknown(4*sizeof(DWORD), 1); + } + } + else + { + dk_ls_write_unknown(4*sizeof(DWORD), 1); + } + } else { + if (0 != (DK4_FILE_INFO_CONTENTS_DATA_TARGET & fiptr->contents)) + { + if ((DWORD)0UL == fiptr->resio) { + dk_ls_write_hexadecimal_number( + (fiptr->tinfo).nFileIndexHigh, 2*sizeof(DWORD) + ); + dk_ls_write_hexadecimal_number( + (fiptr->tinfo).nFileIndexLow, 2*sizeof(DWORD) + ); + } else { + dk_ls_write_unknown(4*sizeof(DWORD), 1); + } + } + else + { + dk_ls_write_unknown(4*sizeof(DWORD), 1); + } + } +#else + if (0 != issl) { + if (0 != (DK4_FILE_INFO_CONTENTS_DATA_LINK & fiptr->contents)) + { + dk_ls_write_hexadecimal_number( + (fiptr->lstb).st_ino, 2*sizeof(ino_t) + ); + } + else + { + dk_ls_write_unknown(2*sizeof(ino_t), 1); + } + } else { + if (0 != (DK4_FILE_INFO_CONTENTS_DATA_TARGET & fiptr->contents)) + { + dk_ls_write_hexadecimal_number( + (fiptr->tstb).st_ino, 2*sizeof(ino_t) + ); + } + else + { + dk_ls_write_unknown(2*sizeof(ino_t), 1); + } + } +#endif + } break; +#if DK4_ON_WINDOWS + case 'w' : { $? ". windows reparse point tag" + if (dkT('\0') != lasti) { + if (0 == dk4fputc(dkT(' '), stdout, NULL)) { + write_error = 1; exval = EXIT_FAILURE; + } + } + dk_ls_write_hexadecimal_number( + fiptr->rppnt, 2*sizeof(DWORD) + ); + } break; +#endif + case 'x' : { + if (0 != dk4md_check_type(digest_type)) { + if (dkT('\0') != lasti) { + if (0 == dk4fputc(dkT(' '), stdout, NULL)) { + write_error = 1; exval = EXIT_FAILURE; + } + } + dk_ls_write_md( + fn, fiptr, digest_type, digest_enco, app, + dk_ls_msg, dk_ls_sz_msg + ); + } else { + /* ERROR (once) Message digest type not supported */ + if (0 == digest_erep) { + dk4app_log_1(app, dk_ls_msg, dk_ls_sz_msg, DK4_LL_ERROR, 19); + digest_erep = 1; + } + } + } break; + default : { + /* ERROR (once): Invalid text in -p argument */ + if (0 == print_order_error_reported) { + dk4app_log_1(app, dk_ls_msg, dk_ls_sz_msg, DK4_LL_ERROR, 11); + print_order_error_reported = 1; + } + exval = EXIT_FAILURE; + } break; + } + } else { + /* ERROR (once): Invalid text in -p argument */ + if (0 == print_order_error_reported) { + dk4app_log_1(app, dk_ls_msg, dk_ls_sz_msg, DK4_LL_ERROR, 11); + print_order_error_reported = 1; + } + exval = EXIT_FAILURE; + } + lasti = *(piptr++); + } + if (0 != last_was_n) { + if (0 != dk4fileinfo_is_symlink(fiptr)) { + res = dk4symlink_target( + dk_ls_sl_target, DK4_SIZEOF(dk_ls_sl_target,dkChar), fn, NULL + ); + if (0 != res) { + if (0 == dk4fputs(dk_ls_kwnl[7], stdout, NULL)) { + write_error = 1; exval = EXIT_FAILURE; + } + if (0 == dk4fputs(dk_ls_sl_target, stdout, NULL)) { + write_error = 1; exval = EXIT_FAILURE; + } + } else { + /* ERROR: Failed to find symlink target */ + dk4app_log_3(app,dk_ls_msg,dk_ls_sz_msg,DK4_LL_ERROR,12,13,fn); + exval = EXIT_FAILURE; + } + } + } + if (0 == dk4fputc(dkT('\n'), stdout, NULL)) { + write_error = 1; exval = EXIT_FAILURE; + } + } else { $? ". skipping file" + } + } else { $? "! args" + } + $? "- dk_ls_process_item_information" +} + + + +/** Process non-directory file. + @param fn File name. + @param level Processing level (0=cmd line arg, 1=direct child, + 2 and above=further indicrect siblings). +*/ +static +void +dk_ls_process_non_directory(const dkChar *fn, int level) +{ + dk4_file_info_t fili; + + dk4fileinfo_init(&fili); + if (0 != dk4fileinfo_app(&fili, fn, app)) { + dk_ls_process_item_information(fn, &fili, 0, (dk4_um_t)0UL, 0); + } else { + /* ERROR: Failed to obtain information about file, already reported */ + exval = EXIT_FAILURE; + } +} + + + +/** Process one directory item. + @param dirnode Node for the items parent directory. + @param filename Path name for item. +*/ +static +void +dk_ls_process_item_for_node( + dk_ls_node_t *dirnode, + const dkChar *filename +) +{ + dk4_file_info_t fili; + dk4_er_t er; + dk4_um_t fs; + int ch = DK4_FILE_INFO_CONTENTS_DATA_TARGET; + $? "+ dk_ls_process_item_for_node PTR=%d \"%!ds\"", TR_IPTR(dirnode), filename + if ((0 >= dirnode->level) || (0 != recursive) || (0 != size_wanted)) + { + dk4error_init(&er); + dk4fileinfo_init(&fili); + if (0 != dk4fileinfo_app(&fili, filename, app)) { + if (0 != dk4fileinfo_is_symlink(&fili)) { + ch = DK4_FILE_INFO_CONTENTS_DATA_LINK ; + } + if (0 != dk4fileinfo_size(&fs, &fili, ch, &er)) { + dirnode->size = dk4ma_um_add(dirnode->size, fs, &er); + if (DK4_E_MATH_OVERFLOW == er.ec) { + dirnode->ovsize = 1; + } + } else { + /* ERROR: Failed to retrieve size */ + $? "! file size" + dk_ls_report_fileinfo_size_error( + app, filename, ch, dk_ls_msg, dk_ls_sz_msg + ); + fs = (dk4_um_t)0UL; + exval = EXIT_FAILURE; + } + if ((0 >= dirnode->level ) || (0 != recursive)) { + /* Show file information */ + dk_ls_process_item_information( + filename, &fili, 0, (dk4_um_t)0UL, 0 + ); + } + } else { + /* ERROR: Failed to obtain file information, already reported */ + exval = EXIT_FAILURE; + } + } + $? "- dk_ls_process_item_for_node" +} + + + +/** Process directory. Unless required otherwise by a non-zero + value for recursive, show contents and directory for level=0, + directory itself for level=1. + @param dn Directory name. + @param level Processing level (0=cmd line arg, 1=direct child, + 2 and above=further siblings). +*/ +static +void +dk_ls_process_directory(const dkChar *dn, int level) +{ + dk4_ufi_t pdufi; /* UFI for parent directory */ + dk4_ufi_t sdufi; /* UFI for sub directory */ + dk4_er_t er; /* Error report for size addition */ + dkChar *mybu; /* Buffer for path name construction */ +#if VERSION_BEFORE_20150821 + dk_ls_node_t *rn; /* Root node */ +#endif + dk_ls_node_t *cn; /* Current node */ + dk_ls_node_t *on; /* Other node */ + const dkChar *pa; /* Directory path */ + const dkChar *ndn; /* Next directory name */ + size_t szmb; /* Size of mybu (number of dkChar) */ + int gosub; /* Flag: Go into sub directory */ + int ufich; /* Channel to retrieve UFI */ + $? "+ dk_ls_process_directory \"%!ds\" %d", dn, level + /* + Allocate path name construction buffer. + */ + ufich = DK4_FILE_INFO_CONTENTS_DATA_TARGET; + szmb = DK4_MAX_PATH; + mybu = dk4mem_new_app(dkChar,szmb,app); + /* + If path name construction buffer available, run normally. + */ + if (NULL != mybu) { +#if VERSION_BEFORE_20150821 + rn = cn = dk_ls_new_node(dn, NULL, level); +#else + cn = dk_ls_new_node(dn, NULL, level); +#endif + while (NULL != cn) { $? ". still dir to process" + if (0 != dk_ls_can_continue()) { $? ". can continue" + ndn = dk4dir_next_dir(cn->dirptr); + if (NULL != ndn) { + /* + Handle sub directory. + */ + pa = dk4dir_get_path(cn->dirptr); + if (0 != dk_ls_construct_path(&mybu, &szmb, pa, ndn)) { + /* + Decide whether or not to go into subdirectory + */ + gosub = 0; +#if 0 + /* 2015-04-14 + There is no reason to open a node for the subdirectory + unless recursive output or size calculation is wanted. + */ + if (0 == cn->level) { /* Processing cmd line argument */ + gosub = 1; + } +#endif + if (0 != recursive) { /* Recursive output wanted */ + gosub = 1; + } + if (0 != size_wanted) { /* Size calculation required */ + if (0 != show_dirs) { /* ... and directory information wanted */ + gosub = 1; + } + } + if (0 != gosub) { + if (0 != dk4ufi_get(&sdufi, mybu, NULL)) { + if (0 != stay_on_fs) { /* Check for same filesystem */ + if (0 != dk4fileinfo_ufi(&pdufi, &(cn->fi), ufich, NULL)) { +#if DK4_ON_WINDOWS + if (pdufi.ser != sdufi.ser) { + gosub = 0; + } +#else + if (pdufi.dev != sdufi.dev) { + gosub = 0; + } +#endif + } else { + /* ERROR: Failed to obtain file identifier */ + dk4app_log_3( + app, dk_ls_msg, dk_ls_sz_msg, DK4_LL_ERROR, 14, 15, + dk4dir_get_path(cn->dirptr) + ); + gosub = 0; + exval = EXIT_FAILURE; + } + } + if (0 != gosub) { /* Check for symlink loop */ + on = cn; + while ((0 != gosub) && (NULL != on)) { + if (0 != dk4fileinfo_ufi(&pdufi, &(on->fi), ufich, NULL)) { +#if DK4_ON_WINDOWS + if (pdufi.ser == sdufi.ser) { + if (pdufi.inh == sdufi.inh) { + if (pdufi.inl == sdufi.inl) { + gosub = 0; + } + } + } +#else + if (pdufi.dev == sdufi.dev) { + if (pdufi.ino == sdufi.ino) { + gosub = 0; + } + } +#endif + } else { + /* ERROR: Failed to retrieve UFI for directory */ + dk4app_log_3( + app, dk_ls_msg, dk_ls_sz_msg, DK4_LL_ERROR, 14, 15, + dk4dir_get_path(on->dirptr) + ); + exval = EXIT_FAILURE; + gosub = 0; + } + on = on->parent; + } + } + } else { + /* ERROR: Failed to retrieve unique file identifier */ + dk4app_log_3( + app, dk_ls_msg, dk_ls_sz_msg, DK4_LL_ERROR, 14, 15, + mybu + ); + exval = EXIT_FAILURE; + gosub = 0; + } + } + if (0 != gosub) { + /* + Go into subdirectory. + */ + on = dk_ls_new_node( + mybu, cn, ((3 >= cn->level) ? (1 + cn->level) : 3) + ); + if (NULL != on) { + cn->child = on; + cn = on; + } else { + /* ERROR: Failed to create node, already reported */ + exval = EXIT_FAILURE; + } + } else { + /* + Do not go into subdirectory, probably show directory details. + */ + dk_ls_process_item_for_node(cn, mybu); + } + } else { + /* ERROR: Failed to construct path, already reported */ + exval = EXIT_FAILURE; + } + } else { + /* + Finalize node, report non-directory entries and the + directories, finally move to parent node. + */ + if ((0 != size_wanted) || (0 != show_files)) { + if (0 != dk_ls_can_continue()) { + do { + ndn = dk4dir_next_file(cn->dirptr); + if (NULL != ndn) { $? ". file \"%!ds\"", ndn + pa = dk4dir_get_path(cn->dirptr); + if (0 != dk_ls_construct_path(&mybu, &szmb, pa, ndn)) { + dk_ls_process_item_for_node(cn, mybu); + } else { + /* ERROR: Failed to construct path, already reported */ + exval = EXIT_FAILURE; + } + } + } while((0 != dk_ls_can_continue()) && (NULL != ndn)) ; + } + } + if (0 != dk_ls_can_continue()) { $? ". can continue" + if ((0 != size_wanted) || (0 != show_dirs)) { + if ((1 >= cn->level) || (0 != recursive)) { + dk_ls_process_item_information( + dk4dir_get_path(cn->dirptr), &(cn->fi), + 1, cn->size, cn->ovsize + ); + } + } + } + on = cn->parent; + if (NULL != on) { + on->child = NULL; + dk4error_init(&er); + on->size = dk4ma_size_t_add(on->size, cn->size, &er); + if (DK4_E_NONE != er.ec) { + on->ovsize = 1; + } + if (0 != cn->ovsize) { + on->ovsize = 1; + } + } + dk_ls_delete_node(cn); + cn = on; + } + } else { + /* + Abort: Close current node and move to parent. No output. + */ + $? ". abort processing" + on = cn->parent; + if (NULL != on) { on->child = NULL; } + dk_ls_delete_node(cn); + cn = on; + } + } + } else { $? "! mybu" + /* ERROR: Allocation failed, already reported */ + exval = EXIT_FAILURE; + } + /* + Release path name construction buffer. + */ + if (NULL != mybu) { + dk4mem_release(mybu); + } + $? "- dk_ls_process_directory" +} + + + +/** Check whether the specified file name is a directory. + @param fn File name. + @return 1 for directories, 0 for non-directory entries, + -1 on errors. +*/ +static +int +dk_ls_is_directory(const dkChar *fn) +{ +#if DK4_ON_WINDOWS + DWORD dwattr; + HANDLE ha; + LONG lasterror; +#if DK4_CHAR_SIZE > 1 + WIN32_FIND_DATAW finddata; +#else + WIN32_FIND_DATAA finddata; +#endif +#else + dk4_stat_t stb; + dk4_er_t er; +#endif + int back = -1; + $? "+ dk_ls_is_directory \"%!ds\"", fn + if (NULL != fn) { +#if DK4_ON_WINDOWS +#if DK4_CHAR_SIZE > 1 + dwattr = GetFileAttributesW(fn); +#else + dwattr = GetFileAttributesA(fn); +#endif + if (INVALID_FILE_ATTRIBUTES != dwattr) { + if (0 != (FILE_ATTRIBUTE_DIRECTORY & dwattr)) { + back = 1; + } else { + back = 0; + } + } else { + lasterror = GetLastError(); +#if DK4_CHAR_SIZE > 1 + ha = FindFirstFileW(fn, &finddata); +#else + ha = FindFirstFileA(fn, &finddata); +#endif + if (INVALID_HANDLE_VALUE != ha) { + if (0 != (FILE_ATTRIBUTE_DIRECTORY & (finddata.dwFileAttributes))) { + back = 1; + } else { + back = 0; + } + FindClose(ha); + } else { + /* ERROR: Failed to retrieve file attributes */ + dk4fileinfo_report_win_failed(app, fn, lasterror); + exval = EXIT_FAILURE; + } + } +#else + dk4error_init(&er); + if (0 != dk4stat(&stb, fn, &er)) { + if (0 != dk4stat_is_directory(&stb, &er)) { + back = 1; + } else { + back = 0; + } + } else { + /* ERROR: Failed to retrieve file information */ + dk4fileinfo_report_stat_failed(app, fn, er.dt.iDetails1); + exval = EXIT_FAILURE; + } +#endif + } $? "- dk_ls_is_directory %d", back + return back; +} + + + +/* !!!!! + For files explicitly mentioned on the command line + processing starts here, probably after name expansion. +*/ + +/** Run for one file or directory directly named on the command line. + @param arg Path name. +*/ +static +void +run_for_one_name(const dkChar *arg) +{ + $? "+ run_for_one_name \"%!ds\"", arg + switch (dk_ls_is_directory(arg)) { + case 1 : { $? ". directory" + dk_ls_process_directory(arg, 0); + } break; + case 0 : { $? ". not a directory" + if (0 != show_files) { + dk_ls_process_non_directory(arg, 0); + } + } break; + default : { $? "! no information" + /* ERROR: Failed to obtain information about file, already reported */ + exval = EXIT_FAILURE; + } break; + } + $? "- run_for_one_name" +} + + + +/** Process command line arguments. + @param xargc Number of command line arguments. +*/ +static +void +run_for_command_line_arguments(int xargc) +{ +#if DK4_ON_WINDOWS + dkChar buf[DK4_MAX_PATH]; + dk4_dir_t *fne; + const dkChar *pth; + const dkChar *fn; + int cc2; +#endif + const dkChar *xargv; + int i; + int cc = 1; + $? "+ run_for_command_line_arguments %d", xargc + for (i = 0; ((i < xargc) && (1 == cc)); i++) { $? ". loop start" + if (0 != dk_ls_can_continue()) { $? ". can continue" + xargv = dk4app_get_argv(app, i); $? ". xargv \"%!ds\"", xargv +#if DK4_ON_WINDOWS + if (0 != dk4path_must_expand(xargv)) { + /* !!!!! + For file names we need to expand + processing starts here. + */ + fne = dk4app_fne_open(xargv, app); + if (NULL != fne) { + cc2 = 1; + while (1 == cc2) { + if (0 != dk_ls_can_continue()) { + fn = dk4dir_next_dir(fne); + if (NULL != fn) { + pth = dk4dir_get_path(fne); + if (NULL != pth) { + if (0 != dk4str_cpy_s(buf,DK4_SIZEOF(buf,dkChar),pth,NULL)) { + if (0!=dk4str_cat_s(buf,DK4_SIZEOF(buf,dkChar),dk_ls_kwnl[5],NULL)) + { + if (0 != dk4str_cat_s(buf,DK4_SIZEOF(buf,dkChar),fn,NULL)) { + dk_ls_process_directory(buf, 0); + } else { + /* ERROR: File name too long! */ + dk4app_log_5( + app, dk_ls_msg, dk_ls_sz_msg, DK4_LL_ERROR, 16, 17, 18, + pth, fn + ); + exval = EXIT_FAILURE; + } + } else { + /* ERROR: File name too long! */ + dk4app_log_base3(app, DK4_LL_ERROR, 98, 99, pth); + exval = EXIT_FAILURE; + } + } else { + /* ERROR: File name too long! */ + dk4app_log_base3(app, DK4_LL_ERROR, 98, 99, pth); + exval = EXIT_FAILURE; + } + } else { + run_for_one_name(fn); + } + } else { + cc2 = 0; + } + } else { + cc2 = 0; + } + } + cc2 = 1; + while (1 == cc2) { + if (0 != dk_ls_can_continue()) { + fn = dk4dir_next_file(fne); + if (NULL != fn) { + pth = dk4dir_get_path(fne); + if (NULL != pth) { + if (0 != dk4str_cpy_s(buf,DK4_SIZEOF(buf,dkChar),pth,NULL)) { + if (0!=dk4str_cat_s(buf,DK4_SIZEOF(buf,dkChar),dk_ls_kwnl[5],NULL)) + { + if (0 != dk4str_cat_s(buf,DK4_SIZEOF(buf,dkChar),fn,NULL)) { + dk_ls_process_non_directory(buf, 0); + } else { + /* ERROR: File name too long! */ + dk4app_log_5( + app, dk_ls_msg, dk_ls_sz_msg, DK4_LL_ERROR, 16, 17, 18, + pth, fn + ); + exval = EXIT_FAILURE; + } + } else { + /* ERROR: File name too long! */ + dk4app_log_base3(app, DK4_LL_ERROR, 98, 99, pth); + exval = EXIT_FAILURE; + } + } else { + /* ERROR: File name too long! */ + dk4app_log_base3(app, DK4_LL_ERROR, 98, 99, pth); + exval = EXIT_FAILURE; + } + } else { + run_for_one_name(fn); + } + } else { + cc2 = 0; + } + } else { + cc2 = 0; + } + } + dk4dir_close(fne); + } else { + /* ERROR: Failed to expand file name, already reported */ + exval = EXIT_FAILURE; + } + } else { +#endif + $? ". UNIX/Linux" + run_for_one_name(xargv); +#if DK4_ON_WINDOWS + } +#endif + } else { + cc = 0; + } + } + $? "- run_for_command_line_arguments" +} + + + +/* !!!!! + If no file names was given on the command line processing + starts here. +*/ + +/** Show contents of current directory. +*/ +static +void +run_for_current_dir_contents(void) +{ + dk4_er_t er; + dk4_dir_t *dirptr; + const dkChar *fn; + int cc; + int om; + $? "+ run_for_current_dir_contents" + dk4error_init(&er); + om = DK4_DIR_OPEN_SORTED | DK4_DIR_SYMLINK_DIR_AS_FILE; + dirptr = dk4dir_open_app(dk_ls_kwnl[4], om, app); + if (NULL != dirptr) { + if ((0 != recursive) || (0 != show_dirs)) { + cc = 1; + while(1 == cc) { + if (0 != dk_ls_can_continue()) { + fn = dk4dir_next_dir(dirptr); + if (NULL != fn) { + if ((0 != recursive) || (0 != size_wanted)) { + dk_ls_process_directory(fn, 1); + } else { + dk_ls_process_non_directory(fn, 1); + } + } else { + cc = 0; + } + } else { + cc = 0; + } + } + } + if (0 != show_files) { + cc = 1; + while (1 == cc) { + if (0 != dk_ls_can_continue()) { + fn = dk4dir_next_file(dirptr); + if (NULL != fn) { + dk_ls_process_non_directory(fn, 1); + } else { + cc = 0; + } + } else { + cc = 0; + } + } + } + dk4dir_close(dirptr); + } else { + /* ERROR: Failed to open current directory, already reported */ + exval = EXIT_FAILURE; + } + $? "- run_for_current_dir_contents" +} + + + +/** Process command line arguments (if any). +*/ +static +void +dk_ls_normal_run(void) +{ + dkChar mdbuf[32]; + dkChar *bptr; + int res; + int xargc; + int mdset; + $? "+ dk_ls_normal_run" + exval = EXIT_SUCCESS; + + /* Process options. + */ + if (0 != dk4app_opt_is_set_short(app, dkT('p'), NULL)) { + res = dk4app_opt_get_string_short( + po_buf, DK4_SIZEOF(po_buf,dkChar), app, dkT('p'), NULL + ); + if (0 != res) { + print_order = po_buf; + } + } + if (NULL == print_order) { + if (0 == dk4app_opt_is_set_short(app, dkT('R'), NULL)) { + res = dk4app_pref_get( + po_buf, DK4_SIZEOF(po_buf,dkChar), app, dk_ls_kwnl[10], 0 + ); + if (0 != res) { + dk4str_rtwh(po_buf, NULL); + print_order = dk4str_start(po_buf, NULL); + } + } + } + if (NULL == print_order) { +#if DK4_ON_WINDOWS + print_order = dk_ls_kwnl[8]; +#else + print_order = dk_ls_kwnl[3]; +#endif + } + if (NULL != dk4str_chr(print_order, dkT('s'))) { + size_wanted = 1; + } + if (NULL != dk4str_chr(print_order, dkT('n'))) { + name_wanted = 1; + } + if (0 != dk4app_opt_is_set_short(app, dkT('r'), NULL)) { + recursive = 1; + } + if (0 != dk4app_opt_is_set_short(app, dkT('f'), NULL)) { + stay_on_fs = 1; + } + if (0 != dk4app_opt_is_set_short(app, dkT('t'), NULL)) { + res = dk4app_opt_get_string_short( + mdbuf, DK4_SIZEOF(mdbuf,dkChar), app, dkT('t'), NULL + ); + if (0 != res) { + bptr = mdbuf; + show_files = 0; show_dirs = 0; + while (dkT('\0') != *bptr) { + if (dkT('d') == *bptr) { show_dirs = 1; } + if (dkT('f') == *bptr) { show_files = 1; } + bptr++; + } + } + } + mdset = 0; + if (0 != dk4app_opt_is_set_short(app, dkT('m'), NULL)) { + res = dk4app_opt_get_string_short( + mdbuf, DK4_SIZEOF(mdbuf,dkChar), app, dkT('m'), NULL + ); + if (0 != res) { + /* Process string, find digest and encoding */ + mdset = 1; + dk_ls_set_md( + &digest_type, &digest_enco, mdbuf, app, dk_ls_msg, dk_ls_sz_msg + ); + } + } + if (0 != dk4app_opt_is_set_short(app, dkT('s'), NULL)) { + show_summary = 1; + } + if ((0 == mdset) && (0 == dk4app_opt_is_set_short(app, dkT('R'), NULL))) { + res = dk4app_pref_get( + mdbuf, DK4_SIZEOF(mdbuf,dkChar), app, dk_ls_kwnl[9], 0 + ); + if (0 != res) { + dk_ls_set_md( + &digest_type, &digest_enco, mdbuf, app, dk_ls_msg, dk_ls_sz_msg + ); + } + } + + /* Process command line arguments or current directory contents. + */ + xargc = dk4app_get_argc(app); + if (0 < xargc) { $? ". process command line arguments" + run_for_command_line_arguments(xargc); + } else { $? ". no command line args, use current dir" + run_for_current_dir_contents(); + } + if (0 != show_summary) { + if (((dk4_um_t)0UL != num_dirs) && (DK4_E_NONE == er_dirs.ec)) { + if (0 == dk4fputs(dk_ls_msg[30], stdout, NULL)) { + write_error = 1; exval = EXIT_FAILURE; + } + dk_ls_write_decimal_number(num_dirs,dk4numlength(sizeof(dk4_um_t),0)); + if (0 == dk4fputc(dkT('\n'), stdout, NULL)) { + write_error = 1; exval = EXIT_FAILURE; + } + } + if (((dk4_um_t)0UL != num_files) && (DK4_E_NONE == er_files.ec)) { + if (0 == dk4fputs(dk_ls_msg[31], stdout, NULL)) { + write_error = 1; exval = EXIT_FAILURE; + } + dk_ls_write_decimal_number(num_files,dk4numlength(sizeof(dk4_um_t),0)); + if (0 == dk4fputc(dkT('\n'), stdout, NULL)) { + write_error = 1; exval = EXIT_FAILURE; + } + } + if (((dk4_um_t)0UL != size_bytes) && (DK4_E_NONE == er_bytes.ec)) { + if (0 == dk4fputs(dk_ls_msg[32], stdout, NULL)) { + write_error = 1; exval = EXIT_FAILURE; + } + dk_ls_write_decimal_number(size_bytes,dk4numlength(sizeof(dk4_um_t),0)); + if (0 == dk4fputc(dkT('\n'), stdout, NULL)) { + write_error = 1; exval = EXIT_FAILURE; + } + } + } + $? "- dk_ls_normal_run" +} + + + + +#if DK4_HAVE_SIGACTION +/** Set signal handlers and run. +*/ +static +void +dk_ls_run_with_signal_handlers(void) +{ +#ifdef SIGPIPE + struct sigaction opipe; +#endif + struct sigaction oint; +#ifdef SIGPIPE + struct sigaction npipe; +#endif + struct sigaction nint; + struct sigaction oterm; + struct sigaction nterm; + int success = 0; + +#ifdef SIGPIPE + /* Set up signal handling for SIGPIPE. + */ + DK4_MEMRES(&npipe, sizeof(npipe)); + npipe.sa_handler = sig_handler_pipe; + npipe.sa_flags = 0; + if (0 != sigemptyset(&npipe.sa_mask)) { + /* ERROR: Failed to set up masked signal set for SIGPIPE */ + dk4app_log_1(app, dk_ls_msg, dk_ls_sz_msg, DK4_LL_ERROR, 0); + goto finished; + } + if (0 != sigaddset(&npipe.sa_mask, SIGPIPE)) { + /* ERROR: Failed to set up masked signal set for SIGPIPE */ + dk4app_log_1(app, dk_ls_msg, dk_ls_sz_msg, DK4_LL_ERROR, 0); + goto finished; + } + if (0 != sigaction(SIGPIPE, &npipe, &opipe)) { + /* ERROR: Failed to set up signal handler for SIGPIPE */ + dk4app_log_1(app, dk_ls_msg, dk_ls_sz_msg, DK4_LL_ERROR, 0); + goto finished; + } +#endif + + /* Set up signal handling for SIGINT. + */ + DK4_MEMRES(&nint, sizeof(nint)); + nint.sa_handler = sig_handler_int; + nint.sa_flags = 0; + if (0 != sigemptyset(&nint.sa_mask)) { + /* ERROR: Failed to set up masked signal set for SIGINT */ + dk4app_log_1(app, dk_ls_msg, dk_ls_sz_msg, DK4_LL_ERROR, 0); + goto restore_old_pipe; + } + if (0 != sigaddset(&nint.sa_mask, SIGINT)) { + /* ERROR: Failed to set up masked signal set for SIGINT */ + dk4app_log_1(app, dk_ls_msg, dk_ls_sz_msg, DK4_LL_ERROR, 0); + goto restore_old_pipe; + } + if (0 != sigaction(SIGINT, &nint, &oint)) { + /* ERROR: Failed to set up signal handler for SIGINT */ + dk4app_log_1(app, dk_ls_msg, dk_ls_sz_msg, DK4_LL_ERROR, 0); + goto restore_old_pipe; + } + + /* Set up signal handling for SIGTERM + */ + DK4_MEMRES(&nterm, sizeof(nterm)); + nterm.sa_handler = sig_handler_term; + nterm.sa_flags = 0; + if (0 != sigemptyset(&nterm.sa_mask)) { + /* ERROR: Failed to set up masked signal set for SIGTERM */ + dk4app_log_1(app, dk_ls_msg, dk_ls_sz_msg, DK4_LL_ERROR, 0); + goto restore_old_int; + } + if (0 != sigaddset(&nterm.sa_mask, SIGTERM)) { + /* ERROR: Failed to set up masked signal set for SIGTERM */ + dk4app_log_1(app, dk_ls_msg, dk_ls_sz_msg, DK4_LL_ERROR, 0); + goto restore_old_int; + } + if (0 != sigaction(SIGTERM, &nterm, &oterm)) { + /* ERROR: Failed to set up signal handler for SIGTERM */ + dk4app_log_1(app, dk_ls_msg, dk_ls_sz_msg, DK4_LL_ERROR, 0); + goto restore_old_int; + } + + success = 1; + dk_ls_normal_run(); + + /* Restore signal handling for SIGTERM. + */ + if (0 != sigaction(SIGTERM, &oterm, NULL)) { + /* ERROR: Failed to restore old SIGTERM settings */ + dk4app_log_1(app, dk_ls_msg, dk_ls_sz_msg, DK4_LL_ERROR, 1); + success = 0; + } + + /* Restore signal handling for SIGINT. + */ + restore_old_int: + if (0 != sigaction(SIGINT, &oint, NULL)) { + /* ERROR: Failed to restore old SIGPIPE settings */ + dk4app_log_1(app, dk_ls_msg, dk_ls_sz_msg, DK4_LL_ERROR, 1); + success = 0; + } + +#ifdef SIGPIPE + /* Restore signal handling for SIGPIPE. + */ + restore_old_pipe: + if (0 != sigaction(SIGPIPE, &opipe, NULL)) { + /* ERROR: Failed to restore old SIGPIPE settings */ + dk4app_log_1(app, dk_ls_msg, dk_ls_sz_msg, DK4_LL_ERROR, 1); + success = 0; + } +#endif + + /* Set exit status code if error occured. + */ + finished: + if (0 == success) { exval = EXIT_FAILURE; } +} +#else +#if DK4_HAVE_SIGSET +/** Set signal handlers and run. +*/ +static +void +dk_ls_run_with_signal_handlers(void) +{ +#ifdef SIGPIPE + dk4_sig_handler_t *oldpipe = NULL; +#endif + dk4_sig_handler_t *oldint = NULL; + dk4_sig_handler_t *oldterm = NULL; + +#ifdef SIGPIPE + oldpipe = sigset(SIGPIPE, sig_handler_pipe); +#endif + oldint = sigset(SIGINT, sig_handler_int); + oldterm = sigset(SIGTERM, sig_handler_term); + dk_ls_normal_run(); + sigset(SIGTERM, oldterm); + sigset(SIGINT, oldint); +#ifdef SIGPIPE + sigset(SIGPIPE, oldpipe); +#endif +} +#else +#if DK4_HAVE_SIGNAL +/** Set signal handlers and run. +*/ +static +void +dk_ls_run_with_signal_handlers(void) +{ +#ifdef SIGPIPE + dk4_sig_handler_t *oldpipe = NULL; +#endif + dk4_sig_handler_t *oldint = NULL; + dk4_sig_handler_t *oldterm = NULL; + +#ifdef SIGPIPE + oldpipe = signal(SIGPIPE, sig_handler_pipe); +#endif + oldint = signal(SIGINT, sig_handler_int); + oldterm = signal(SIGTERM, sig_handler_term); + dk_ls_normal_run(); + signal(SIGTERM, oldterm); + signal(SIGINT, oldint); +#ifdef SIGPIPE + signal(SIGPIPE, oldpipe); +#endif +} +#else +/** Set signal handlers and run. +*/ +static +void +dk_ls_run_with_signal_handlers(void) +{ + dk_ls_normal_run(); +} +#endif +#endif +#endif + + + +/** Main function. + @param argc Number of command line arguments. + @param argv Command line arguments array. + @return 0 on success, all other values indicate errors. +*/ +#if DK4_CHAR_SIZE > 1 +int wmain(int argc, wchar_t *argv[]) +#else +int main(int argc, char *argv[]) +#endif +{ + $!trace-init /tmp/dk-ls.deb + $? "+ main" + dk4fput_initialize_stdout(); + dk4fput_initialize_stderr(); + dk4error_init(&er_dirs); + dk4error_init(&er_files); + dk4error_init(&er_bytes); + app = dk4app_open_cmd( + argc, argv, dk_ls_options, dk_ls_sz_options, + dk_ls_kwnl[0], DKT_VERSION_DK, + dk_ls_kwnl[1], dk_ls_help_text, dk_ls_license_text + ); + if (NULL != app) { $? ". app" + dk_ls_sz_msg = dk4app_string_table_size(dk_ls_kw_def); + dk_ls_msg = dk4app_string_table(app, dk_ls_kwnl[2], dk_ls_kw_def); + if (0 != dk4app_can_run_normally(app)) { $? ". normal" + dk_ls_run_with_signal_handlers(); + } else { + if (0 != dk4app_help_version_license(app)) { $? ". help/vers/lic" + exval = EXIT_SUCCESS; + } + } + dk4app_close(app); + } else { $? "! app" + dk4fputs(dk_ls_kwnl[11], stdout, NULL); + fflush(stdout); + } + fflush(stdout); + fflush(stderr); + dk4fput_cleanup_stderr(); + dk4fput_cleanup_stdout(); + $? "- main %d", exval + $!trace-end + exit(exval); return exval; +} + |