fileset

git mirror of https://ccx.te2000.cz/bzr/fileset
git clone https://ccx.te2000.cz/git/fileset
Log | Files | Refs | README

fslist (3214B)


      1 #!/bin/zsh
      2 # there is no posix stat(1) and the implementations are riddled with locale-speciffic stuff
      3 # better use sane version from zsh
      4 
      5 setopt extendedglob globdots
      6 zmodload zsh/stat
      7 
      8 typeset -A ftypes hardlinks s
      9 ftypes=(  # convert hex type to mnemonic character
     10 	C  s  # socket
     11 	c  s
     12 	A  l  # symbolic link
     13 	a  l
     14 	8  f  # regular file
     15 	6  b  # block device
     16 	4  d  # directory
     17 	2  u  # character device
     18 	1  p  # FIFO
     19 )
     20 
     21 delim=''
     22 
     23 statement() {
     24 	# start on new line for multiline statements - more readable
     25 	if [[ -n delim && $1 == *$'\n'* ]]; then
     26 		delim=$'\n'
     27 	fi
     28 	printf '%s%s' $delim ${1//$'\n'/$'\n\t'}
     29 	delim=${2:-$'\t'}
     30 }
     31 
     32 statement_end() {
     33 	printf '\n'
     34 	delim=''
     35 }
     36 
     37 ROOT=${${${ROOT:-$PWD}:A}%/}
     38 : ${compact:=1}
     39 : ${print_m:=1}
     40 : ${print_o:=1}
     41 : ${print_c:=1}
     42 if (($+commands[file])) && (($+commands[base64])); then
     43 	: ${print_b:=1}
     44 else
     45 	: ${print_b:=0}
     46 	if (($+commands[file])) && (($+commands[xxd])); then
     47 		: ${print_x:=1}
     48 	fi
     49 fi
     50 : ${print_x:=0}
     51 : ${max_bin_size:=}
     52 
     53 fnames=( )
     54 for arg in "${@:-$ROOT}"; do
     55 	fnames+=( $arg:a )
     56 	[[ -d $arg ]] && fnames+=( $arg:a/**/* )
     57 done
     58 
     59 for fname in $fnames; do
     60 	if ! [[ $fname == $ROOT || $fname == $ROOT/* ]]; then
     61 		printf "skipping out-of-root file: %s\n" "$fname" >&2
     62 		continue
     63 	fi
     64 	relname=${${fname#$ROOT}#/}
     65 	zstat -LH s $fname || continue
     66 	ftype=$(( [##16] $s[mode] >> 12 ))
     67 	fmode=$(( [##8] $s[mode] & 8#7777 ))
     68 	t=$ftypes[$ftype]
     69 
     70 	(($compact)) || printf '\n'
     71 
     72 	if [[ $relname == *$'\t'* || $relname == *$'\n'* ]]; then
     73 		statement $'P\t'$relname $'\t'
     74 	else
     75 		if (($compact)); then
     76 			statement /$relname
     77 		else
     78 			statement /$relname $'\n'
     79 		fi
     80 	fi
     81 
     82 	if [[ $t != d && $s[nlink] -gt 1 ]]; then
     83 		id=$s[device]:$s[inode]
     84 		if (($+hardlinks[$id])); then
     85 			statement $'H\t'$hardlinks[$id] $'\n'
     86 			continue
     87 		else
     88 			hardlinks[$id]=./$relname
     89 		fi
     90 	fi
     91 
     92 	if [[ $t == [bu] ]]; then
     93 		statement $t$(( $s[rdev] >> 8 )):$(( $s[rdev] & 255 ))
     94 	elif [[ $t == l ]]; then
     95 		statement $'l\t'$s[link] $'\t'
     96 	elif [[ $t == f ]]; then
     97 		if (($print_c)); then
     98 			if (($s[size])) && (($print_b + $print_x)) && \
     99 					[[ $(file -bi $fname) != text/* ]]; then
    100 				if [[ -n $max_bin_size && $s[size] -gt $max_bin_size ]]; then
    101 					statement s$'\tSHA512:'${"$(sha512sum < $fname)"%% *}
    102 				elif (($print_x)); then
    103 					statement X$'\t'"$(xxd $fname)" $'\n'
    104 				else
    105 					statement B$'\t'"$(base64 <$fname)" $'\n'
    106 				fi
    107 			else
    108 				IFS= read -r -d '' content <$fname
    109 				flags=''
    110 				if [[ $content == *$'\n' ]]; then
    111 					content=${content%$'\n'}
    112 					if [[ $content == *$'\n' ]]; then
    113 						# force appending newline
    114 						flags+=n
    115 					fi
    116 				else
    117 					flags+=N
    118 				fi
    119 				if ! (($compact)) || [[ $content == *$'\t'* || $content == *$'\n'* ]]; then
    120 					statement C$flags$'\t'$content $'\n'
    121 				else
    122 					statement c$flags$'\t'$content
    123 				fi
    124 			fi
    125 		else
    126 			statement f
    127 		fi
    128 	else
    129 		statement $t
    130 	fi
    131 	(($print_o)) && statement o$s[uid]:$s[gid]
    132 	(($print_m)) && statement m$fmode
    133 	statement_end
    134 done
    135 
    136 # while getopts omcaOMC o
    137 # do	case "$o" in
    138 # 	([?])
    139 # 		print >&2 "Usage: $(basename "$0") [-omcaOMC] [dir [...]]"
    140 # 		exit 1;;
    141 # 	esac
    142 # done
    143 
    144 # find "${@:-$PWD}" -exec stat -c '%F	%U:%G	%a	%h:%i:%d	%t:%T	%n' '{}' + | awk '
    145 # BEGIN {
    146 # 	FS="\t"
    147 # }
    148 
    149 # /\t/
    150 # '