forked from Openwrt/openwrt
08495b7f24
This allows building uncompressed tar archives from shell scripts (and compressing them later if needed) Signed-off-by: Jo-Philipp Wich <jo@mein.io> [rmilecki: adapt to sysupgrade needs] Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
72 lines
2.1 KiB
Bash
72 lines
2.1 KiB
Bash
# SPDX-License-Identifier: GPL-2.0-or-later OR MIT
|
|
|
|
# Example usage:
|
|
#
|
|
# {
|
|
# tar_print_member "date.txt" "It's $(date +"%Y")"
|
|
# tar_print_trailer
|
|
# } > test.tar
|
|
|
|
__tar_print_padding() {
|
|
dd if=/dev/zero bs=1 count=$1 2>/dev/null
|
|
}
|
|
|
|
tar_print_member() {
|
|
local name="$1"
|
|
local content="$2"
|
|
local mtime="${3:-$(date +%s)}"
|
|
local mode=644
|
|
local uid=0
|
|
local gid=0
|
|
local size=${#content}
|
|
local type=0
|
|
local link=""
|
|
local username="root"
|
|
local groupname="root"
|
|
|
|
# 100 byte of padding bytes, using 0x01 since the shell does not tolerate null bytes in strings
|
|
local pad=$'\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1'
|
|
|
|
# validate name (strip leading slash if present)
|
|
name=${name#/}
|
|
|
|
# truncate string header values to their maximum length
|
|
name=${name:0:100}
|
|
link=${link:0:100}
|
|
username=${username:0:32}
|
|
groupname=${groupname:0:32}
|
|
|
|
# construct header part before checksum field
|
|
local header1="${name}${pad:0:$((100 - ${#name}))}"
|
|
header1="${header1}$(printf '%07d\1' $mode)"
|
|
header1="${header1}$(printf '%07o\1' $uid)"
|
|
header1="${header1}$(printf '%07o\1' $gid)"
|
|
header1="${header1}$(printf '%011o\1' $size)"
|
|
header1="${header1}$(printf '%011o\1' $mtime)"
|
|
|
|
# construct header part after checksum field
|
|
local header2="$(printf '%d' $type)"
|
|
header2="${header2}${link}${pad:0:$((100 - ${#link}))}"
|
|
header2="${header2}ustar ${pad:0:1}"
|
|
header2="${header2}${username}${pad:0:$((32 - ${#username}))}"
|
|
header2="${header2}${groupname}${pad:0:$((32 - ${#groupname}))}"
|
|
|
|
# calculate checksum over header fields
|
|
local checksum=0
|
|
for byte in $(printf '%s%8s%s' "$header1" "" "$header2" | tr '\1' '\0' | hexdump -ve '1/1 "%u "'); do
|
|
checksum=$((checksum + byte))
|
|
done
|
|
|
|
# print member header, padded to 512 byte
|
|
printf '%s%06o\0 %s' "$header1" $checksum "$header2" | tr '\1' '\0'
|
|
__tar_print_padding 183
|
|
|
|
# print content data, padded to multiple of 512 byte
|
|
printf "%s" "$content"
|
|
__tar_print_padding $((512 - (size % 512)))
|
|
}
|
|
|
|
tar_print_trailer() {
|
|
__tar_print_padding 1024
|
|
}
|