diff options
Diffstat (limited to 'subr.rtl/rtl_filepath.subr')
-rw-r--r-- | subr.rtl/rtl_filepath.subr | 286 |
1 files changed, 248 insertions, 38 deletions
diff --git a/subr.rtl/rtl_filepath.subr b/subr.rtl/rtl_filepath.subr index 671f8534..a2f0f5c4 100644 --- a/subr.rtl/rtl_filepath.subr +++ b/subr.rtl/rtl_filepath.subr @@ -1,18 +1,52 @@ # +# Copyright (c) 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023 LucĂa Andrea Illanes Albornoz <lucia@luciaillanes.de> # set +o errexit -o noglob -o nounset is assumed. # +# +# rtl_basename() - obtain base name from filename +# @_rfname: inout reference to filename +# +# Returns: zero (0) on success, non-zero (>0) on failure +# rtl_basename() { - local _fname="${1##*/}"; printf "%s" "${_fname}"; + rtl_basename2 "${1}" "${1}"; +}; + +# +# rtl_basename2() - obtain base name from filename +# @_rfname: in reference to filename +# @_rfname_out: out reference to new filename +# +# Returns: zero (0) on success, non-zero (>0) on failure +# +rtl_basename2() { + local _rb2_rfname="${1#\$}" _rb2_rfname_out="${2#\$}" \ + _rb2_fname=""; + + eval _rb2_fname="\${${_rb2_rfname}}"; + eval ${_rb2_rfname_out}='${_rb2_fname##*/}'; + return 0; }; +# +# rtl_check_digest() - check digest of single file +# @_rdigest: out reference to digest of file +# @_fname: name of file to check +# @_digest_check: digest to check against +# +# Returns: zero (0) on success, non-zero (>0) on failure +# rtl_check_digest() { - local _fname="${1}" _digest_check="${2}" _digest=""; RTL_CHECK_DIGEST_DIGEST=""; - if ! [ -e "${_fname}" ]; then + local _rcd_rdigest="${1#\$}" _rcd_fname="${2}" _rcd_digest_check="${3}" \ + _rcd_digest=""; + + if ! [ -e "${_rcd_fname}" ]; then return 1; - else set -- $(sha256sum "${_fname}"); - RTL_CHECK_DIGEST_DIGEST="${1}"; - if [ "${RTL_CHECK_DIGEST_DIGEST}" = "${_digest_check}" ]; then + else set -- $(sha256sum "${_rcd_fname}"); + _rcd_digest="${1}"; + eval ${_rcd_rdigest}='${_rcd_digest}'; + if [ "${_rcd_digest}" = "${_rcd_digest_check}" ]; then return 0; else return 1; @@ -20,58 +54,132 @@ rtl_check_digest() { fi; }; +# +# rtl_check_digest_file() - check digest of single file w/ digest file +# @_fname: name of file to check +# @_digest_check: digest to check against +# @_digest_fname: name of file containing digest +# +# Returns: zero (0) on success, non-zero (>0) on failure +# rtl_check_digest_file() { - local _fname="${1}" _digest_check="${2}" _digest_fname="${3}" _digest="" RTL_CHECK_DIGEST_DIGEST=""; - if ! [ -e "${_digest_fname}" ]; then + local _rcdf_fname="${1}" _rcdf_digest_check="${2}" _rcdf_digest_fname="${3}" \ + _rcdf_digest="" _rcdf_digest_file=""; + + if ! [ -e "${_rcdf_digest_fname}" ]; then return 1; - else _digest="$(cat "${_digest_fname}")"; - if [ "${_digest}" != "${_digest_check}" ]\ - || ! rtl_check_digest "${_fname}" "${_digest_check}"; then + else _rcdf_digest_file="$(cat "${_rcdf_digest_fname}")"; + if [ "${_rcdf_digest_file}" != "${_rcdf_digest_check}" ]\ + || ! rtl_check_digest \$_rcdf_digest "${_rcdf_fname}" \ + "${_rcdf_digest_check}"; + then return 1; + else + return 0; fi; fi; }; +# +# rtl_check_path_vars() - check pathname variables for validity +# @_rstatus: out reference to status string +# @_vnames: list of variable names +# +# Returns: zero (0) on success, non-zero (>0) on empty or unset pathname variable or pathname variable containing whitespace characters +# rtl_check_path_vars() { - local _vnames="${1}" _rc=0 _vname="" _vname_val=""; _status=""; - for _vname in ${_vnames}; do - _vname_val="$(rtl_get_var_unsafe "${_vname}")"; - if [ -z "${_vname_val}" ]; then - _rc=1; _status="Error: variable \`${_vname}' is empty or unset."; break; - elif [ "${_vname_val#* *}" != "${_vname_val}" ]; then - _rc=2; _status="Error: variable \`${_vname}' contains one or more whitespace characters."; break; + local _rcpv_rstatus="${1#\$}" _rcpv_vnames="${2}" \ + _rcpv_rc=0 _rcpv_vname="" _rcpv_vname_val=""; + + for _rcpv_vname in ${_rcpv_vnames}; do + rtl_get_var_unsafe \$_rcpv_vname_val "${_rcpv_vname}"; + if [ "${_rcpv_vname_val:+1}" != 1 ]; then + _rcpv_rc=1; + rtl_setrstatus "${_rcpv_rstatus}" 'Error: variable \`'"${_rcpv_vname}'"' is empty or unset.'; + break; + elif [ "${_rcpv_vname_val#* *}" != "${_rcpv_vname_val}" ]; then + _rcpv_rc=2; + rtl_setrstatus "${_rcpv_rstatus}" 'Error: variable \`'"${_rcpv_vname}'"' contains one or more whitespace characters.'; + break; fi; done; - return "${_rc}"; + return "${_rcpv_rc}"; }; +# +# rtl_dirname() - obtain directory name from filename +# @_rfname: inout reference to {file,directory} name +# +# Returns: zero (0) on success, non-zero (>0) on failure +# rtl_dirname() { - local _dname="${1%/*}"; - case "${_dname}" in - "") _dname="."; ;; - *) while rtl_matchr "${_dname}" "*/"; do - _dname="${_dname%/}"; + rtl_dirname2 "${1}" "${1}"; +}; + +# +# rtl_dirname2() - obtain directory name from filename +# @_rfname: in reference to filename +# @_rfname_out: out reference to directory name +# +# Returns: zero (0) on success, non-zero (>0) on failure +# +rtl_dirname2() { + local _rfname="${1#\$}" _rdname_out="${2#\$}" \ + _rd2_dname=""; + + eval _rd2_dname="\${${_rfname}}"; + _rd2_dname="${_rd2_dname%/*}"; + + case "${_rd2_dname}" in + "") _rd2_dname="."; ;; + *) while rtl_matchr "${_rd2_dname}" "*/"; do + _rd2_dname="${_rd2_dname%/}"; done; ;; - esac; printf "%s" "${_dname:-/}"; + esac; + + eval ${_rdname_out}='${_rd2_dname}'; + return 0; }; +# +# rtl_exists_any() - check for existence of pathnames beneath directory +# @_subdir: single directory name +# @...: list of pathnames to check +# +# Returns: zero (0) on success, non-zero (>0) on failure +# rtl_exists_any() { - local _subdir="${1}"; shift; + local _rea_subdir="${1}"; shift; + while [ "${#}" -gt 0 ]; do - if [ -e "${_subdir}/${1}" ]; then + if [ -e "${_rea_subdir}/${1}" ]; then return 0; else shift; fi; - done; return 1; + done; + return 1; }; +# +# rtl_flock_acquire() - acquire file lock +# @_fd: single file descriptor +# @_conflict_exit_code: exit code on conflict +# @_wait: wait period in seconds +# +# Returns: zero (0) on success, non-zero (>0) on failure +# rtl_flock_acquire() { - local _fd="${1}" _conflict_exit_code="${2:-253}" _wait="${3:-3600}" + local _rfa_fd="${1}" _rfa_conflict_exit_code="${2:-253}" _rfa_wait="${3:-3600}"; + while true; do - if flock -E "${_conflict_exit_code}" -w "${_wait}" "${_fd}"; then - break; - elif [ "${?}" -eq "${_conflict_exit_code}" ]; then + if flock \ + -E "${_rfa_conflict_exit_code}" \ + -w "${_rfa_wait}" \ + "${_rfa_fd}"; + then + return 0; + elif [ "${?}" -eq "${_rfa_conflict_exit_code}" ]; then continue; else return "${?}"; @@ -79,13 +187,24 @@ rtl_flock_acquire() { done; }; +# +# rtl_is_newer() - check if single file is newer than other single file +# @_new_fname: single name of newer file +# @_old_fname: single name of older file +# +# Returns: zero (0) if @_new_fname is newer, non-zero (>0) if @_old_fname is newer +# rtl_is_newer() { - local _new_fname="${1}" _old_fname="${2}" _new_ts="" _old_ts=""; - if ! [ -e "${_old_fname}" ]; then + local _ris_new_fname="${1}" _ris_old_fname="${2}" \ + _ris_new_ts="" _ris_old_ts=""; + + if ! [ -e "${_ris_old_fname}" ]; then return 0; - else _new_ts="$(stat -c %Y "${_new_fname}" 2>/dev/null)"; - _old_ts="$(stat -c %Y "${_old_fname}" 2>/dev/null)"; - if [ "${_new_ts:-0}" -gt "${_old_ts:-0}" ]; then + else + _ris_new_ts="$(stat -c %Y "${_ris_new_fname}" 2>/dev/null)"; + _ris_old_ts="$(stat -c %Y "${_ris_old_fname}" 2>/dev/null)"; + + if [ "${_ris_new_ts:-0}" -gt "${_ris_old_ts:-0}" ]; then return 0; else return 1; @@ -93,4 +212,95 @@ rtl_is_newer() { fi; }; -# vim:filetype=sh +# +# rtl_patch_files() - patch files +# @_patch_cwd: patch(1) -d directory +# @_strip_count: patch(1) strip count +# @_fn: name of function that produces patch filenames and takes the arguments @_rpatch_fname @_patch_idx @... +# @... optional arguments to pass to @_fn +# +# Returns: zero (0) on success, non-zero (>0) on failure +# +rtl_patch_files() { + local _rpf_patch_cwd="${1}" _rpf_strip_count="${2}" _rpf_fn="${3}" \ + _rpf_patch_fname="" _rpf_patch_idx=0; + shift $((3 + 2)); + + _rpf_patch_idx=1; + while "${_rpf_fn}" \ + \$_rpf_patch_fname "${_rpf_patch_idx}" \ + "${@}" \ + && [ "${_rpf_patch_fname:+1}" = 1 ]; + do + : $((_rpf_patch_idx += 1)); + if [ -r "${_rpf_patch_fname}" ]\ + && ! patch \ + -b \ + -d "${_rpf_patch_cwd}" \ + "-p${_rpf_strip_count}" \ + < "${_rpf_patch_fname}"; + then + return 1; + fi; + done; + return 0; +}; + +# +# rtl_set_perms_treeV() - set mode bits of directories and files +# @_mode_dir: mode bits for directories +# @_mode_file_exec: mode bits for executable files +# @_mode_file_nonexec: mode bits for non-executable files +# @...: list of base directory pathnames as positional parameters; empty strings are ignored +# +# Returns: zero (0) on success, non-zero (>0) on failure +# +rtl_set_perms_treeV() { + local _rspt_mode_dir="${1}" _rspt_mode_file_exec="${2}" _rspt_mode_file_nonexec="${3}" \ + _rspt_destdir="" _rspt_fname="" \ + IFS IFS0="${IFS}"; + shift 3; + + for _rspt_destdir in "${@}"; do + if [ -e "${_rspt_destdir}" ]; then + rtl_set_IFS_nl; + + for _rspt_fname in $(find "${_rspt_destdir}" -type d); do + if ! rtl_fileop chmod "${_rspt_mode_dir}" \ + "${_rspt_fname}"; + then + return 1; + fi; + done; + + for _rspt_fname in $(find \ + "${_rspt_destdir}" \ + \( -not -perm /0111 \) \ + -type f); + do + if ! rtl_fileop chmod "${_rspt_mode_file_nonexec}" \ + "${_rspt_fname}"; + then + return 1; + fi; + done; + + for _rspt_fname in $(find \ + "${_rspt_destdir}" \ + -perm /0111 \ + -type f); + do + if ! rtl_fileop chmod "${_rspt_mode_file_exec}" \ + "${_rspt_fname}"; + then + return 1; + fi; + done; + + IFS="${IFS0}"; + fi; + done; + return 0; +}; + +# vim:filetype=sh textwidth=0 |