1 1.6 gavan #!/bin/sh -e 2 1.9 christos # $NetBSD: mksparkive.sh,v 1.9 2024/02/09 15:34:34 christos Exp $ 3 1.1 gavan # 4 1.1 gavan # Copyright (c) 2004 The NetBSD Foundation, Inc. 5 1.1 gavan # All rights reserved. 6 1.1 gavan # 7 1.1 gavan # This code is derived from software contributed to The NetBSD Foundation 8 1.1 gavan # by Gavan Fantom 9 1.1 gavan # 10 1.1 gavan # Redistribution and use in source and binary forms, with or without 11 1.1 gavan # modification, are permitted provided that the following conditions 12 1.1 gavan # are met: 13 1.1 gavan # 1. Redistributions of source code must retain the above copyright 14 1.1 gavan # notice, this list of conditions and the following disclaimer. 15 1.1 gavan # 2. Redistributions in binary form must reproduce the above copyright 16 1.1 gavan # notice, this list of conditions and the following disclaimer in the 17 1.1 gavan # documentation and/or other materials provided with the distribution. 18 1.1 gavan # 19 1.1 gavan # THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 gavan # ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 gavan # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 gavan # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 gavan # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 gavan # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 gavan # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 gavan # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 gavan # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 gavan # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 gavan # POSSIBILITY OF SUCH DAMAGE. 30 1.1 gavan # 31 1.1 gavan 32 1.1 gavan # 33 1.3 gavan # Creates a spark format archive. Some metadata is included, notably 34 1.4 gavan # filetypes, but permissions are not. Filename translation is performed 35 1.4 gavan # according to RISC OS conventions. 36 1.1 gavan # 37 1.1 gavan # This script is intended to provide sufficient functionality to create 38 1.1 gavan # an archive for distribution of the NetBSD/acorn32 bootloader which can be 39 1.1 gavan # used directly in RISC OS. 40 1.1 gavan # 41 1.1 gavan 42 1.4 gavan if [ -z "${TOOL_SPARKCRC}" ] 43 1.4 gavan then 44 1.4 gavan TOOL_SPARKCRC=sparkcrc 45 1.4 gavan fi 46 1.4 gavan 47 1.6 gavan if [ -z "${TOOL_STAT}" ] 48 1.6 gavan then 49 1.6 gavan TOOL_STAT=stat 50 1.6 gavan fi 51 1.6 gavan 52 1.7 jmc if [ -z "${TOOL_MKTEMP}" ] 53 1.7 jmc then 54 1.7 jmc TOOL_MKTEMP=mktemp 55 1.7 jmc fi 56 1.7 jmc 57 1.7 jmc 58 1.1 gavan # Target byte order is little endian. 59 1.1 gavan 60 1.1 gavan print2() 61 1.1 gavan { 62 1.6 gavan if [ -z "$1" ] 63 1.6 gavan then 64 1.6 gavan exit 1 65 1.6 gavan fi 66 1.9 christos lowbyte=$(expr $1 % 256 | xargs printf %02x) 67 1.9 christos highbyte=$(expr $1 / 256 | xargs printf %02x) 68 1.1 gavan printf "\x$lowbyte\x$highbyte" 69 1.1 gavan } 70 1.1 gavan 71 1.1 gavan print4() 72 1.1 gavan { 73 1.6 gavan if [ -z "$1" ] 74 1.6 gavan then 75 1.6 gavan exit 1 76 1.6 gavan fi 77 1.9 christos print2 $(expr $1 % 65536) 78 1.9 christos print2 $(expr $1 / 65536) 79 1.1 gavan } 80 1.1 gavan 81 1.1 gavan makeheader() 82 1.1 gavan { 83 1.1 gavan filename="$1" 84 1.1 gavan statfilename="$2" 85 1.1 gavan realfilename="$3" 86 1.9 christos filetype=$(printf %03s "$4") 87 1.3 gavan compressed="$5" 88 1.3 gavan # length is only passed to length4, so we don't need to worry about 89 1.3 gavan # extracting only the length here. 90 1.9 christos length=$(wc -c "$filename") 91 1.9 christos eval $(${TOOL_STAT} -s "$statfilename") 92 1.9 christos [ -n "${MKREPRO_TIMESTAMP}" ] && st_mtime=${MKREPRO_TIMESTAMP} 93 1.1 gavan # centiseconds since 1st Jan 1900 94 1.9 christos timestamp=$(expr $st_mtime \* 100 + 220898880000) 95 1.9 christos lowtype=$(echo "$filetype" | sed s/.//) 96 1.9 christos hightype=$(echo "$filetype" | sed s/..\$//) 97 1.9 christos highdate=$(expr $timestamp / 4294967296 | xargs printf %02x) 98 1.9 christos lowdate=$(expr $timestamp % 4294967296) 99 1.1 gavan 100 1.1 gavan # Header version number 101 1.3 gavan if [ "$compressed" -ne 0 ] 102 1.3 gavan then 103 1.3 gavan printf \\xff 104 1.3 gavan else 105 1.3 gavan printf \\x82 106 1.3 gavan fi 107 1.1 gavan # Filename 108 1.1 gavan printf %-13.13s "$realfilename" | tr " ." \\0/ 109 1.1 gavan # Compressed file length 110 1.1 gavan print4 $length 111 1.1 gavan # File date stamp 112 1.1 gavan print2 0 113 1.1 gavan # File time stamp 114 1.1 gavan print2 0 115 1.1 gavan # CRC 116 1.4 gavan if [ "$compressed" -ne 0 ] 117 1.4 gavan then 118 1.9 christos print2 $(${TOOL_SPARKCRC} "$statfilename") 119 1.4 gavan else 120 1.9 christos print2 $(${TOOL_SPARKCRC} "$filename") 121 1.4 gavan fi 122 1.1 gavan # Original file length 123 1.3 gavan if [ "$compressed" -ne 0 ] 124 1.3 gavan then 125 1.3 gavan print4 $st_size 126 1.3 gavan else 127 1.3 gavan print4 $length 128 1.3 gavan fi 129 1.1 gavan # Load address (FFFtttdd) 130 1.1 gavan printf \\x$highdate 131 1.1 gavan printf \\x$lowtype 132 1.1 gavan printf \\xf$hightype 133 1.1 gavan printf \\xff 134 1.1 gavan # Exec address (dddddddd) 135 1.1 gavan print4 $lowdate 136 1.1 gavan # Attributes 137 1.1 gavan # Public read, owner read/write 138 1.1 gavan print4 19 139 1.1 gavan } 140 1.1 gavan 141 1.1 gavan makearchive() 142 1.1 gavan { 143 1.1 gavan for file in "$@" 144 1.1 gavan do 145 1.9 christos temp=$(${TOOL_MKTEMP} -t $progname) || exit 1 146 1.3 gavan trap "rm -f $temp" 0 147 1.1 gavan # Archive marker 148 1.1 gavan printf \\x1a 149 1.1 gavan if [ -f "$file" ] 150 1.1 gavan then 151 1.1 gavan case "$file" in 152 1.3 gavan -*) echo "Invalid filename" >&2 153 1.3 gavan exit 1 154 1.3 gavan ;; 155 1.9 christos *,???) type=$(echo "$file" | \ 156 1.9 christos sed "s/.*,\(...\)$/\1/") 157 1.9 christos filename=$(echo "$file" | \ 158 1.9 christos sed "s/,...$//") 159 1.1 gavan ;; 160 1.1 gavan *) type=fff 161 1.1 gavan filename="$file" 162 1.1 gavan ;; 163 1.1 gavan esac 164 1.3 gavan # The compressed data in a sparkive is the output from 165 1.3 gavan # compress, minus the two bytes of magic at the start. 166 1.3 gavan # Compress also uses the top bit of the first byte 167 1.3 gavan # to indicate its choice of algorithm. Spark doesn't 168 1.3 gavan # understand that, so it must be stripped. 169 1.3 gavan compress -c "$file" | tail -c +3 >"$temp" 170 1.9 christos size1=$(wc -c "$file" | awk '{print $1}') 171 1.9 christos size2=$(wc -c "$temp" | awk '{print $1}') 172 1.3 gavan if [ $size1 -ge $size2 ] 173 1.3 gavan then 174 1.3 gavan makeheader "$temp" "$file" "$filename" "$type" 1 175 1.9 christos nbits=$(dd if="$temp" bs=1 count=1 \ 176 1.9 christos 2>/dev/null | od -t d1 | awk '{print $2}') 177 1.3 gavan if [ $nbits -ge 128 ] 178 1.3 gavan then 179 1.9 christos nbits=$(expr $nbits - 128) 180 1.3 gavan fi 181 1.9 christos printf \\x$(printf %02x $nbits) 182 1.3 gavan tail -c +2 "$temp" 183 1.3 gavan else 184 1.3 gavan makeheader "$file" "$file" "$filename" "$type" 0 185 1.3 gavan cat "$file" 186 1.3 gavan fi 187 1.1 gavan fi 188 1.1 gavan if [ -d "$file" ] 189 1.1 gavan then 190 1.1 gavan ( 191 1.1 gavan cd "$file" 192 1.9 christos makearchive $(ls -A) >$temp 193 1.1 gavan ) 194 1.3 gavan if [ $? -ne 0 ] 195 1.3 gavan then 196 1.3 gavan exit 1 197 1.3 gavan fi 198 1.3 gavan makeheader "$temp" "$file" "$file" ddc 0 199 1.1 gavan cat "$temp" 200 1.1 gavan fi 201 1.3 gavan rm -f "$temp" 202 1.1 gavan done 203 1.1 gavan 204 1.1 gavan # Archive marker 205 1.1 gavan printf \\x1a 206 1.1 gavan # Archive terminator 207 1.1 gavan printf \\x00 208 1.1 gavan } 209 1.1 gavan 210 1.9 christos progname=$(basename $0) 211 1.6 gavan 212 1.1 gavan if [ $# -eq 0 ] 213 1.1 gavan then 214 1.2 gavan echo "Usage: $progname filename" 215 1.6 gavan echo "$progname: Outputs an uncompressed sparkive to stdout." 216 1.1 gavan fi 217 1.1 gavan 218 1.1 gavan makearchive "$@" 219