/
tffs_add_file
executable file
·264 lines (264 loc) · 14.9 KB
/
tffs_add_file
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
#! /bin/sh
# SPDX-License-Identifier: GPL-2.0-or-later
# vi: set tabstop=4 syntax=sh : # colorize it in 'vi' and use shorter tabstops
#######################################################################################
# #
# extract newest TFFS image from support data, add one or more files to it and output #
# the resulting TFFS image #
# #
#######################################################################################
# #
# include shell library #
# #
#######################################################################################
. ${YF_SCRIPT_DIR:-.}/yf_helpers
#######################################################################################
# #
# constants #
# #
#######################################################################################
FIRST_SUPPORTDATA_LINE="##### TITLE Version"
FIRST_TFFS_LINE="##### BEGIN SECTION TFFS_DUMP TFFS Dump"
LAST_TFFS_LINE="##### END SECTION TFFS_DUMP"
TFFS_DIR_NAME="var/tmp/tffs-dump/"
DEFAULT_SEGMENTID_OFFSET=16
#######################################################################################
# #
# functions #
# #
#######################################################################################
# #
# display usage info #
# #
#######################################################################################
usage()
(
printf "Extract TFFS image from an extended support data file and (optional) add file(s)\n"
printf "to the end of the already contained data.\n\n"
printf "Usage: $0 support_data [ -o offset ] [ node file [ ... ] ]\n\n"
printf "'support_data' is the name of your input file, which may be created, after you've\n"
printf "checked the 'extended support data' selector and applied your changes.\n"
printf "'offset' is an optional value to be substracted from the TFFS segment ID to ensure,\n"
printf "that the created image has the lowest value there - the default offset value is 16.\n"
printf "For each file to add to the TFFS image (remember, that the overall length of the\n"
printf "image is limited and that this script will not do a cleanup of obsolete entries),\n"
printf "you've to specify the TFFS node number (in decimal) and the name of a file contain-\n"
printf "ing the uncompressed data to add.\n\n"
printf "The final result is written to STDOUT and it's the responsibility of the caller to\n"
printf "redirect it to a proper location. Execution will be stopped immediately, if STDOUT\n"
printf "is a terminal device.\n\n"
printf "Example:\n"
printf "$0 \$HOME/support_data.txt 29 provideradditive.tar\n\n"
printf "Remark:\n"
printf "You should change the original name of the support data file to a more handy one,\n"
printf "but this script should be able to handle even a name containing spaces.\n"
)
#######################################################################################
# #
# emulate zlib deflate using gzip utility #
# #
#######################################################################################
zlib_deflate()
(
deflated="$(yf_mktemp -p "$tmp")"
gzip -c >"$deflated"
size=$(stat -c %s "$deflated")
start=10 # header size, if no filename is present (RFC 1952)
end=8 # CRC32 and original size at the end of a member
count=$(( size - end - start ))
printf "%b" "\0170\234" # CMF/FLG (RFC 1950)
dd if="$deflated" bs=1 skip=$start count=$count 2>/dev/null
)
#######################################################################################
# #
# initialize default values #
# #
#######################################################################################
segmentid_offset=$DEFAULT_SEGMENTID_OFFSET
add_files_count=0
#######################################################################################
# #
# check parameters #
# #
#######################################################################################
[ -t 1 ] && usage 1>&2 && printf "\n\n%bSTDOUT isn't redirected - would you really like to see binary data on your terminal?\nDo you prefer the output in binary, octal or hexadecimal presentation?\n\nPLEASE READ THE USAGE INFORMATION ABOVE THIS TEXT CAREFULLY AGAIN AND AGAIN, UNTIL YOU'VE FOUND YOUR MISTAKE!%b\n\n" "\033[91m\033[1m" "\033[21m\033[0m" 1>&2 && exit 1
[ -z "$1" ] && usage 1>&2 && exit 1
support_data_file="$1"
first_line="$(sed -n -e 1p "$support_data_file" | sed -e "s|^\($FIRST_SUPPORTDATA_LINE\).*|\1|p" | sed -n -e 1p)"
if ! [ "$first_line" = "$FIRST_SUPPORTDATA_LINE" ]; then
printf "Input file '%s' doesn't look like a file with extended support data.\n" $support_data_file 1>&2
exit 1
fi
shift
remove_nodes=""
while ! [ -z "$1" ]; do
if [ $add_files_count -eq 0 ]; then # maybe offset value
if [ "$1" = "-o" ]; then
if [ -z "$2" ]; then
printf "Missing offset value after '-o'.\n" 1>&2
exit 1
else
if yf_is_decimal "$2"; then
segmentid_offset="$2"
shift 2
continue
else
printf "Invalid offset value '%s' after '-o', it has to be a decimal number.\n" "$2" 1>&2
exit 1
fi
fi
fi
fi
if yf_is_decimal "$1"; then
if [ -z "$2" ]; then
printf "Missing file name for node number '%d'.\n" $1 1>&2
exit 1
fi
if ! [ -f "$2" ]; then
printf "The specified file '%s' for node number '%d' does not exist.\n" $1 "$2" 1>&2
exit 1
fi
add_files_count=$(( add_files_count + 1 ))
eval add_file_node_${add_files_count}=$1
eval add_file_name_${add_files_count}='$2'
remove_nodes="$remove_nodes $1"
shift 2
else
printf "Invalid TFFS node number '%s'.\n" "$1" 1>&2
exit 1
fi
done
#######################################################################################
# #
# check, that the support file contains a TFFS dump #
# #
#######################################################################################
if [ -z "$(sed -n -e "/^$FIRST_TFFS_LINE/=" "$support_data_file")" ]; then
printf "The specified support data file '%s' doesn't contain a TFFS dump.\n" "$support_data_file" 1>&2
exit 1
fi
if [ -z "$(sed -n -e "/^$LAST_TFFS_LINE/=" "$support_data_file")" ]; then
printf "The specified support data file '%s' doesn't contain a valid TFFS dump.\n" "$support_data_file" 1>&2
exit 1
fi
lines="$(sed -e "1,/^$FIRST_TFFS_LINE/d" "$support_data_file" | sed -e "/^$LAST_TFFS_LINE/,\$d" | sed -n -e '$=')"
if [ -z "$lines" ]; then
printf "The TFFS dump section in the specified support data file '%s' is empty.\n" "$support_data_file" 1>&2
exit 1
fi
#######################################################################################
# #
# set up working directory and prepare cleanup on exit #
# #
#######################################################################################
tmp="$(yf_mktemp -d)"
trap "rm -r \"$tmp\";exit 127" EXIT HUP INT
#######################################################################################
# #
# extract and decode the tarball with the TFFS dumps #
# #
#######################################################################################
tarball=$(yf_mktemp -p "$tmp")
sed -e "1,/^$FIRST_TFFS_LINE/d" "$support_data_file" | sed -e "/^$LAST_TFFS_LINE/,\$d" | \
sed -e "s|\r||g" | yf_base64_decode >"$tarball"
if ! [ -s "$tarball" ]; then
printf "Error while decoding the TFFS dump content from base64 presentation.\n" 1>&2
exit 1
fi
#######################################################################################
# #
# extract TFFS images from tarball and get their segment id values #
# #
#######################################################################################
segmentid=$(( 0xFFFFFFFF ))
use_file=""
for file in $(tar -t -f "$tarball"); do
[ -z "${file##$TFFS_DIR_NAME}" ] && continue
id=$(tar -x -f "$tarball" -O "$file" | gunzip -c | dd bs=4 count=1 skip=1 2>/dev/null | yf_bin2dec B)
if [ $id -lt $segmentid ]; then
use_file="$file"
segmentid=$id
fi
done
if [ -z "$use_file" ]; then
printf "Unable to detect the newer image file.\n" 1>&2
exit 1
fi
image="$(yf_mktemp -p "$tmp")"
tar -x -f "$tarball" -O "$use_file" | gunzip -c >"$image"
#######################################################################################
# #
# change segment id value #
# #
#######################################################################################
segmentid=$(dd if="$image" bs=4 skip=1 count=1 2>/dev/null | yf_bin2dec B)
new_segmentid="$(yf_mktemp -p "$tmp")"
yf_pack B32 $(( segmentid - segmentid_offset )) >"$new_segmentid"
dd if="$new_segmentid" of="$image" bs=4 seek=1 count=1 conv=notrunc 2>/dev/null
#######################################################################################
# #
# output image and exit, if there're no files to add - there's no reason to look for #
# the first free entry #
# #
#######################################################################################
[ $add_files_count -eq 0 ] && cat "$image" && exit 0
#######################################################################################
# #
# locate first free entry and compute remaining space available #
# #
#######################################################################################
image_size=$(stat -c %s "$image")
offset=0
printf "%b" "\033[s" 1>&2
while [ $offset -lt $image_size ]; do
hdr=$(dd if="$image" bs=4 skip=$(( offset / 4 )) count=1 2>/dev/null | yf_bin2hex)
id=$(yf_hex2dec $(yf_substring $hdr 0 4))
len=$(yf_hex2dec $(yf_substring $hdr 4 4))
[ $id -eq 65535 ] && break
! [ -z "$remove_nodes" ] && \
for r_id in $remove_nodes; do
[ $r_id -eq $id ] || continue
dd if=/dev/zero of="$image" bs=2 seek=$(( offset / 2 )) count=1 conv=notrunc 2>/dev/null
done
printf "." 1>&2
offset=$(( ( offset + 4 + len + 3 ) & ~3 ))
done
printf "%b" "\033[u\033[K" 1>&2
rem_size=$(( image_size - 4 - offset ))
#######################################################################################
# #
# add specified files #
# #
#######################################################################################
i=0
payload="$(yf_mktemp -p "$tmp")"
header="$(yf_mktemp -p "$tmp")"
while [ $i -lt $add_files_count ]; do
i=$(( i + 1 ))
eval fn=\"\${add_file_name_$i}\"
eval id=\${add_file_node_$i}
zlib_deflate <"$fn" >"$payload"
packed_size=$(stat -c %s "$payload")
needed_size=$(( ( packed_size + 4 + 3 ) & ~3 ))
if [ $needed_size -gt $rem_size ]; then
printf "Not enough free space to add file '%s' as node '%d'.\n" $fn $id
exit 1
fi
yf_pack B16 $id B16 $packed_size >"$header"
cat "$header" "$payload" | dd bs=4 conv=sync 2>/dev/null | dd bs=4 of="$image" seek=$(( offset / 4 )) count=$(( needed_size / 4 )) conv=notrunc 2>/dev/null
offset=$(( offset + needed_size ))
rem_size=$(( rem_size - needed_size ))
done
#######################################################################################
# #
# output image and exit #
# #
#######################################################################################
offset=$(( offset + 4 )) # add header for first free entry and limit output image size to the next 4K boundary (SPI erase size)
dd if="$image" bs=4096 count=$(( ( offset / 4096 ) + 1 )) 2>/dev/null
exit 0
#######################################################################################
# #
# end of script #
# #
#######################################################################################