1*906afcb8SAndy Fiddaman#!/usr/bin/ksh93 2*906afcb8SAndy Fiddaman 3*906afcb8SAndy Fiddaman# 4*906afcb8SAndy Fiddaman# CDDL HEADER START 5*906afcb8SAndy Fiddaman# 6*906afcb8SAndy Fiddaman# The contents of this file are subject to the terms of the 7*906afcb8SAndy Fiddaman# Common Development and Distribution License (the "License"). 8*906afcb8SAndy Fiddaman# You may not use this file except in compliance with the License. 9*906afcb8SAndy Fiddaman# 10*906afcb8SAndy Fiddaman# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 11*906afcb8SAndy Fiddaman# or http://www.opensolaris.org/os/licensing. 12*906afcb8SAndy Fiddaman# See the License for the specific language governing permissions 13*906afcb8SAndy Fiddaman# and limitations under the License. 14*906afcb8SAndy Fiddaman# 15*906afcb8SAndy Fiddaman# When distributing Covered Code, include this CDDL HEADER in each 16*906afcb8SAndy Fiddaman# file and include the License file at usr/src/OPENSOLARIS.LICENSE. 17*906afcb8SAndy Fiddaman# If applicable, add the following below this CDDL HEADER, with the 18*906afcb8SAndy Fiddaman# fields enclosed by brackets "[]" replaced with your own identifying 19*906afcb8SAndy Fiddaman# information: Portions Copyright [yyyy] [name of copyright owner] 20*906afcb8SAndy Fiddaman# 21*906afcb8SAndy Fiddaman# CDDL HEADER END 22*906afcb8SAndy Fiddaman# 23*906afcb8SAndy Fiddaman 24*906afcb8SAndy Fiddaman# 25*906afcb8SAndy Fiddaman# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. 26*906afcb8SAndy Fiddaman# 27*906afcb8SAndy Fiddaman 28*906afcb8SAndy Fiddaman# 29*906afcb8SAndy Fiddaman# simplefileattributetree1 - build a simple file tree (including file attributes) 30*906afcb8SAndy Fiddaman# 31*906afcb8SAndy Fiddaman 32*906afcb8SAndy Fiddaman# Solaris needs /usr/xpg6/bin:/usr/xpg4/bin because the tools in /usr/bin are not POSIX-conformant 33*906afcb8SAndy Fiddamanexport PATH=/usr/xpg6/bin:/usr/xpg4/bin:/bin:/usr/bin 34*906afcb8SAndy Fiddaman 35*906afcb8SAndy Fiddaman# Make sure all math stuff runs in the "C" locale to avoid problems 36*906afcb8SAndy Fiddaman# with alternative # radix point representations (e.g. ',' instead of 37*906afcb8SAndy Fiddaman# '.' in de_DE.*-locales). This needs to be set _before_ any 38*906afcb8SAndy Fiddaman# floating-point constants are defined in this script). 39*906afcb8SAndy Fiddamanif [[ "${LC_ALL}" != "" ]] ; then 40*906afcb8SAndy Fiddaman export \ 41*906afcb8SAndy Fiddaman LC_MONETARY="${LC_ALL}" \ 42*906afcb8SAndy Fiddaman LC_MESSAGES="${LC_ALL}" \ 43*906afcb8SAndy Fiddaman LC_COLLATE="${LC_ALL}" \ 44*906afcb8SAndy Fiddaman LC_CTYPE="${LC_ALL}" 45*906afcb8SAndy Fiddaman unset LC_ALL 46*906afcb8SAndy Fiddamanfi 47*906afcb8SAndy Fiddamanexport LC_NUMERIC=C 48*906afcb8SAndy Fiddaman 49*906afcb8SAndy Fiddaman 50*906afcb8SAndy Fiddamanfunction add_file_to_tree 51*906afcb8SAndy Fiddaman{ 52*906afcb8SAndy Fiddaman typeset treename=$1 53*906afcb8SAndy Fiddaman typeset filename=$2 54*906afcb8SAndy Fiddaman nameref destnodename=$3 55*906afcb8SAndy Fiddaman integer i 56*906afcb8SAndy Fiddaman typeset nodepath # full name of compound variable 57*906afcb8SAndy Fiddaman typeset -a pe # path elements 58*906afcb8SAndy Fiddaman 59*906afcb8SAndy Fiddaman # first built an array containing the names of each path element 60*906afcb8SAndy Fiddaman # (e.g. "foo/var/baz"" results in an array containing "( 'foo' 'bar' 'baz' )") 61*906afcb8SAndy Fiddaman typeset IFS='/' 62*906afcb8SAndy Fiddaman pe+=( ${filename} ) 63*906afcb8SAndy Fiddaman 64*906afcb8SAndy Fiddaman [[ ${pe[0]} == '' ]] && pe[0]='/' 65*906afcb8SAndy Fiddaman 66*906afcb8SAndy Fiddaman # walk path described via the "pe" array and build nodes if 67*906afcb8SAndy Fiddaman # there aren't any nodes yet 68*906afcb8SAndy Fiddaman nodepath="${treename}" 69*906afcb8SAndy Fiddaman for (( i=0 ; i < (${#pe[@]}-1) ; i++ )) ; do 70*906afcb8SAndy Fiddaman nameref x="${nodepath}" 71*906afcb8SAndy Fiddaman 72*906afcb8SAndy Fiddaman # [[ -v ]] does not work for arrays because [[ -v ar ]] 73*906afcb8SAndy Fiddaman # is equal to [[ -v ar[0] ]]. In this case we can 74*906afcb8SAndy Fiddaman # use the output of typeset +p x.nodes 75*906afcb8SAndy Fiddaman [[ "${ typeset +p x.nodes ; }" == "" ]] && compound -A x.nodes 76*906afcb8SAndy Fiddaman 77*906afcb8SAndy Fiddaman nodepath+=".nodes[${pe[i]}]" 78*906afcb8SAndy Fiddaman done 79*906afcb8SAndy Fiddaman 80*906afcb8SAndy Fiddaman # insert element 81*906afcb8SAndy Fiddaman nameref node="${nodepath}" 82*906afcb8SAndy Fiddaman [[ "${ typeset +p node.elements ; }" == "" ]] && compound -A node.elements 83*906afcb8SAndy Fiddaman node.elements[${pe[i]}]=( 84*906afcb8SAndy Fiddaman filepath="${filename}" 85*906afcb8SAndy Fiddaman ) 86*906afcb8SAndy Fiddaman 87*906afcb8SAndy Fiddaman destnodename="${!node}.elements[${pe[i]}]" 88*906afcb8SAndy Fiddaman 89*906afcb8SAndy Fiddaman return 0 90*906afcb8SAndy Fiddaman} 91*906afcb8SAndy Fiddaman 92*906afcb8SAndy Fiddamanfunction parse_findls 93*906afcb8SAndy Fiddaman{ 94*906afcb8SAndy Fiddaman nameref out=$1 95*906afcb8SAndy Fiddaman typeset str="$2" 96*906afcb8SAndy Fiddaman 97*906afcb8SAndy Fiddaman # find -ls on Solaris uses the following output format by default: 98*906afcb8SAndy Fiddaman #604302 3 -rw-r--r-- 1 test001 users 2678 May 9 00:46 ./httpsresdump 99*906afcb8SAndy Fiddaman 100*906afcb8SAndy Fiddaman integer out.inodenum="${str/~(Elr)[[:space:]]*([[:digit:]]+)[[:space:]]+([[:digit:]]+)[[:space:]]+([[:alpha:]-]+)[[:space:]]+([[:digit:]]+)[[:space:]]+([[:alnum:]]+)[[:space:]]+([[:alnum:]]+)[[:space:]]+([[:digit:]]+)[[:space:]]+([[:alpha:]]*[[:space:]]+[[:digit:]]*[[:space:]]+[[:digit:]:]+)[[:space:]]+(.+)/\1}" 101*906afcb8SAndy Fiddaman integer out.kbblocks="${str/~(Elr)[[:space:]]*([[:digit:]]+)[[:space:]]+([[:digit:]]+)[[:space:]]+([[:alpha:]-]+)[[:space:]]+([[:digit:]]+)[[:space:]]+([[:alnum:]]+)[[:space:]]+([[:alnum:]]+)[[:space:]]+([[:digit:]]+)[[:space:]]+([[:alpha:]]*[[:space:]]+[[:digit:]]*[[:space:]]+[[:digit:]:]+)[[:space:]]+(.+)/\2}" 102*906afcb8SAndy Fiddaman typeset out.mode="${str/~(Elr)[[:space:]]*([[:digit:]]+)[[:space:]]+([[:digit:]]+)[[:space:]]+([[:alpha:]-]+)[[:space:]]+([[:digit:]]+)[[:space:]]+([[:alnum:]]+)[[:space:]]+([[:alnum:]]+)[[:space:]]+([[:digit:]]+)[[:space:]]+([[:alpha:]]*[[:space:]]+[[:digit:]]*[[:space:]]+[[:digit:]:]+)[[:space:]]+(.+)/\3}" 103*906afcb8SAndy Fiddaman integer out.numlinks="${str/~(Elr)[[:space:]]*([[:digit:]]+)[[:space:]]+([[:digit:]]+)[[:space:]]+([[:alpha:]-]+)[[:space:]]+([[:digit:]]+)[[:space:]]+([[:alnum:]]+)[[:space:]]+([[:alnum:]]+)[[:space:]]+([[:digit:]]+)[[:space:]]+([[:alpha:]]*[[:space:]]+[[:digit:]]*[[:space:]]+[[:digit:]:]+)[[:space:]]+(.+)/\4}" 104*906afcb8SAndy Fiddaman compound out.owner=( 105*906afcb8SAndy Fiddaman typeset user="${str/~(Elr)[[:space:]]*([[:digit:]]+)[[:space:]]+([[:digit:]]+)[[:space:]]+([[:alpha:]-]+)[[:space:]]+([[:digit:]]+)[[:space:]]+([[:alnum:]]+)[[:space:]]+([[:alnum:]]+)[[:space:]]+([[:digit:]]+)[[:space:]]+([[:alpha:]]*[[:space:]]+[[:digit:]]*[[:space:]]+[[:digit:]:]+)[[:space:]]+(.+)/\5}" 106*906afcb8SAndy Fiddaman typeset group="${str/~(Elr)[[:space:]]*([[:digit:]]+)[[:space:]]+([[:digit:]]+)[[:space:]]+([[:alpha:]-]+)[[:space:]]+([[:digit:]]+)[[:space:]]+([[:alnum:]]+)[[:space:]]+([[:alnum:]]+)[[:space:]]+([[:digit:]]+)[[:space:]]+([[:alpha:]]*[[:space:]]+[[:digit:]]*[[:space:]]+[[:digit:]:]+)[[:space:]]+(.+)/\6}" 107*906afcb8SAndy Fiddaman ) 108*906afcb8SAndy Fiddaman integer out.filesize="${str/~(Elr)[[:space:]]*([[:digit:]]+)[[:space:]]+([[:digit:]]+)[[:space:]]+([[:alpha:]-]+)[[:space:]]+([[:digit:]]+)[[:space:]]+([[:alnum:]]+)[[:space:]]+([[:alnum:]]+)[[:space:]]+([[:digit:]]+)[[:space:]]+([[:alpha:]]*[[:space:]]+[[:digit:]]*[[:space:]]+[[:digit:]:]+)[[:space:]]+(.+)/\7}" 109*906afcb8SAndy Fiddaman typeset out.date="${str/~(Elr)[[:space:]]*([[:digit:]]+)[[:space:]]+([[:digit:]]+)[[:space:]]+([[:alpha:]-]+)[[:space:]]+([[:digit:]]+)[[:space:]]+([[:alnum:]]+)[[:space:]]+([[:alnum:]]+)[[:space:]]+([[:digit:]]+)[[:space:]]+([[:alpha:]]*[[:space:]]+[[:digit:]]*[[:space:]]+[[:digit:]:]+)[[:space:]]+(.+)/\8}" 110*906afcb8SAndy Fiddaman typeset out.filepath="${str/~(Elr)[[:space:]]*([[:digit:]]+)[[:space:]]+([[:digit:]]+)[[:space:]]+([[:alpha:]-]+)[[:space:]]+([[:digit:]]+)[[:space:]]+([[:alnum:]]+)[[:space:]]+([[:alnum:]]+)[[:space:]]+([[:digit:]]+)[[:space:]]+([[:alpha:]]*[[:space:]]+[[:digit:]]*[[:space:]]+[[:digit:]:]+)[[:space:]]+(.+)/\9}" 111*906afcb8SAndy Fiddaman 112*906afcb8SAndy Fiddaman return 0 113*906afcb8SAndy Fiddaman} 114*906afcb8SAndy Fiddaman 115*906afcb8SAndy Fiddamanfunction usage 116*906afcb8SAndy Fiddaman{ 117*906afcb8SAndy Fiddaman OPTIND=0 118*906afcb8SAndy Fiddaman getopts -a "${progname}" "${simplefileattributetree1_usage}" OPT '-?' 119*906afcb8SAndy Fiddaman exit 2 120*906afcb8SAndy Fiddaman} 121*906afcb8SAndy Fiddaman 122*906afcb8SAndy Fiddaman# main 123*906afcb8SAndy Fiddamanbuiltin basename 124*906afcb8SAndy Fiddamanbuiltin dirname 125*906afcb8SAndy Fiddaman 126*906afcb8SAndy Fiddamanset -o noglob 127*906afcb8SAndy Fiddamanset -o nounset 128*906afcb8SAndy Fiddaman 129*906afcb8SAndy Fiddaman# tree base 130*906afcb8SAndy Fiddamancompound filetree 131*906afcb8SAndy Fiddaman 132*906afcb8SAndy Fiddaman# benchmark data 133*906afcb8SAndy Fiddamancompound bench=( 134*906afcb8SAndy Fiddaman float start 135*906afcb8SAndy Fiddaman float stop 136*906afcb8SAndy Fiddaman) 137*906afcb8SAndy Fiddaman 138*906afcb8SAndy Fiddamancompound appconfig=( 139*906afcb8SAndy Fiddaman typeset do_benchmarking=false 140*906afcb8SAndy Fiddaman compound do_record=( 141*906afcb8SAndy Fiddaman typeset content=false 142*906afcb8SAndy Fiddaman typeset filetype=false 143*906afcb8SAndy Fiddaman ) 144*906afcb8SAndy Fiddaman) 145*906afcb8SAndy Fiddaman 146*906afcb8SAndy Fiddaman 147*906afcb8SAndy Fiddamaninteger i 148*906afcb8SAndy Fiddaman 149*906afcb8SAndy Fiddamantypeset progname="${ basename "${0}" ; }" 150*906afcb8SAndy Fiddaman 151*906afcb8SAndy Fiddamantypeset -r simplefileattributetree1_usage=$'+ 152*906afcb8SAndy Fiddaman[-?\n@(#)\$Id: simplefileattributetree1 (Roland Mainz) 2010-03-27 \$\n] 153*906afcb8SAndy Fiddaman[-author?Roland Mainz <roland.mainz@nrubsig.org>] 154*906afcb8SAndy Fiddaman[+NAME?simplefileattributetree1 - generate compound variable tree which contains file names and their attributes] 155*906afcb8SAndy Fiddaman[+DESCRIPTION?\bsimplefileattributetree1\b is a simple variable tree 156*906afcb8SAndy Fiddaman demo which builds a compound variable tree based on the output 157*906afcb8SAndy Fiddaman of /usr/xpg4/bin/file which contains the file name, the file attributes 158*906afcb8SAndy Fiddaman and optionally file type and content] 159*906afcb8SAndy Fiddaman[b:benchmark?Print time needed to generate the tree.] 160*906afcb8SAndy Fiddaman[c:includecontent?Include the file\'s content in the tree, split into 1kb blocks.] 161*906afcb8SAndy Fiddaman[t:includefiletype?Include the file type (output of /usr/xpg4/bin/file).] 162*906afcb8SAndy Fiddaman 163*906afcb8SAndy Fiddamanpath 164*906afcb8SAndy Fiddaman 165*906afcb8SAndy Fiddaman[+SEE ALSO?\bksh93\b(1), \bfile\b(1), \bfind\b(1)] 166*906afcb8SAndy Fiddaman' 167*906afcb8SAndy Fiddaman 168*906afcb8SAndy Fiddamanwhile getopts -a "${progname}" "${simplefileattributetree1_usage}" OPT ; do 169*906afcb8SAndy Fiddaman# printmsg "## OPT=|${OPT}|, OPTARG=|${OPTARG}|" 170*906afcb8SAndy Fiddaman case ${OPT} in 171*906afcb8SAndy Fiddaman b) appconfig.do_benchmarking="true" ;; 172*906afcb8SAndy Fiddaman +b) appconfig.do_benchmarking="false" ;; 173*906afcb8SAndy Fiddaman c) appconfig.do_record.content="true" ;; 174*906afcb8SAndy Fiddaman +c) appconfig.do_record.content="false" ;; 175*906afcb8SAndy Fiddaman t) appconfig.do_record.filetype="true" ;; 176*906afcb8SAndy Fiddaman +t) appconfig.do_record.filetype="false" ;; 177*906afcb8SAndy Fiddaman *) usage ;; 178*906afcb8SAndy Fiddaman esac 179*906afcb8SAndy Fiddamandone 180*906afcb8SAndy Fiddamanshift $((OPTIND-1)) 181*906afcb8SAndy Fiddaman 182*906afcb8SAndy Fiddaman 183*906afcb8SAndy Fiddaman# argument prechecks 184*906afcb8SAndy Fiddamanif (( $# == 0 )) ; then 185*906afcb8SAndy Fiddaman print -u2 -f "%s: Missing <path> argument.\n" "${progname}" 186*906afcb8SAndy Fiddaman exit 1 187*906afcb8SAndy Fiddamanfi 188*906afcb8SAndy Fiddaman 189*906afcb8SAndy Fiddaman 190*906afcb8SAndy Fiddamanprint -u2 -f "# reading file names...\n" 191*906afcb8SAndy Fiddamanwhile (( $# > 0 )) ; do 192*906afcb8SAndy Fiddaman # "ulimit -c 0" use used to force ksh93 to use a seperate process for subshells, 193*906afcb8SAndy Fiddaman # this is used to work around a bug with LC_ALL changes bleeding through subshells 194*906afcb8SAndy Fiddaman IFS=$'\n' ; typeset -a findls_lines=( $(ulimit -c 0 ; LC_ALL=C find "$1" -type f -ls) ) ; IFS=$' \t\n' 195*906afcb8SAndy Fiddaman shift 196*906afcb8SAndy Fiddamandone 197*906afcb8SAndy Fiddaman 198*906afcb8SAndy Fiddaman 199*906afcb8SAndy Fiddamanprint -u2 -f "# building tree...\n" 200*906afcb8SAndy Fiddaman 201*906afcb8SAndy Fiddaman${appconfig.do_benchmarking} && (( bench.start=SECONDS )) 202*906afcb8SAndy Fiddaman 203*906afcb8SAndy Fiddamanfor (( i=0 ; i < ${#findls_lines[@]} ; i++ )) ; do 204*906afcb8SAndy Fiddaman compound parseddata 205*906afcb8SAndy Fiddaman typeset treenodename 206*906afcb8SAndy Fiddaman 207*906afcb8SAndy Fiddaman # parse "find -ls" output 208*906afcb8SAndy Fiddaman parse_findls parseddata "${findls_lines[i]}" 209*906afcb8SAndy Fiddaman 210*906afcb8SAndy Fiddaman # add node to tree and return it's absolute name in "treenodename" 211*906afcb8SAndy Fiddaman add_file_to_tree filetree "${parseddata.filepath}" treenodename 212*906afcb8SAndy Fiddaman 213*906afcb8SAndy Fiddaman # merge parsed "find -ls" output into tree node 214*906afcb8SAndy Fiddaman nameref treenode="${treenodename}" 215*906afcb8SAndy Fiddaman treenode+=parseddata 216*906afcb8SAndy Fiddaman 217*906afcb8SAndy Fiddaman # extras (calculated from the existing values in "parseddata") 218*906afcb8SAndy Fiddaman typeset treenode.dirname="${ dirname "${treenode.filepath}" ; }" 219*906afcb8SAndy Fiddaman typeset treenode.basename="${ basename "${treenode.filepath}" ; }" 220*906afcb8SAndy Fiddaman 221*906afcb8SAndy Fiddaman if ${appconfig.do_record.filetype} ; then 222*906afcb8SAndy Fiddaman # Using /usr/(xpg4/)*/bin/file requires a |fork()|+|exec()| which makes the script a few hundred times slower... ;-( 223*906afcb8SAndy Fiddaman typeset treenode.filetype="$(file "${treenode.filepath}")" 224*906afcb8SAndy Fiddaman fi 225*906afcb8SAndy Fiddaman 226*906afcb8SAndy Fiddaman if ${appconfig.do_record.content} ; then 227*906afcb8SAndy Fiddaman if [[ -r "${treenode.filepath}" ]] ; then 228*906afcb8SAndy Fiddaman # We use an array of compound variables here to support 229*906afcb8SAndy Fiddaman # files with holes (and later alternative streams, too) 230*906afcb8SAndy Fiddaman compound -a treenode.content 231*906afcb8SAndy Fiddaman integer cl=0 232*906afcb8SAndy Fiddaman while \ 233*906afcb8SAndy Fiddaman { 234*906afcb8SAndy Fiddaman treenode.content[${cl}]=( 235*906afcb8SAndy Fiddaman typeset type="data" # (todo: "add support for "holes" (sparse files)) 236*906afcb8SAndy Fiddaman typeset -b bin 237*906afcb8SAndy Fiddaman ) 238*906afcb8SAndy Fiddaman read -n1024 treenode.content[${cl}].bin 239*906afcb8SAndy Fiddaman } ; do 240*906afcb8SAndy Fiddaman (( cl++ )) 241*906afcb8SAndy Fiddaman done < "${treenode.filepath}" 242*906afcb8SAndy Fiddaman unset treenode.content[${cl}] 243*906afcb8SAndy Fiddaman 244*906afcb8SAndy Fiddaman typeset -A treenode.hashsum=( 245*906afcb8SAndy Fiddaman [md5]="$(sum -x md5 < "${treenode.filepath}")" 246*906afcb8SAndy Fiddaman [sha512]="$(sum -x sha512 < "${treenode.filepath}")" 247*906afcb8SAndy Fiddaman ) 248*906afcb8SAndy Fiddaman 249*906afcb8SAndy Fiddaman # we do this for internal debugging only 250*906afcb8SAndy Fiddaman if [[ "${ { 251*906afcb8SAndy Fiddaman integer j 252*906afcb8SAndy Fiddaman for (( j=0 ; j < ${#treenode.content[@]} ; j++ )) ; do 253*906afcb8SAndy Fiddaman printf "%B" treenode.content[$j].bin 254*906afcb8SAndy Fiddaman done 255*906afcb8SAndy Fiddaman } | sum -x sha512 ; }" != "${treenode.hashsum[sha512]}" ]] ; then 256*906afcb8SAndy Fiddaman # this should never happen... 257*906afcb8SAndy Fiddaman print -u2 -f "fatal hash mismatch for %s\n" "${treenode.filepath}" 258*906afcb8SAndy Fiddaman unset treenode.content treenode.hashsum 259*906afcb8SAndy Fiddaman fi 260*906afcb8SAndy Fiddaman fi 261*906afcb8SAndy Fiddaman fi 262*906afcb8SAndy Fiddamandone 263*906afcb8SAndy Fiddaman 264*906afcb8SAndy Fiddaman${appconfig.do_benchmarking} && (( bench.stop=SECONDS )) 265*906afcb8SAndy Fiddaman 266*906afcb8SAndy Fiddaman 267*906afcb8SAndy Fiddamanif ${appconfig.do_benchmarking} ; then 268*906afcb8SAndy Fiddaman # print benchmark data 269*906afcb8SAndy Fiddaman print -u2 -f "# time used: %f\n" $((bench.stop - bench.start)) 270*906afcb8SAndy Fiddamanfi 271*906afcb8SAndy Fiddaman 272*906afcb8SAndy Fiddaman# print variable tree 273*906afcb8SAndy Fiddamanprint -v filetree 274*906afcb8SAndy Fiddaman 275*906afcb8SAndy Fiddamanexit 0 276*906afcb8SAndy Fiddaman# EOF. 277