What tar standard are you aiming to adhere to?


On 2024-02-26 15:14, Rafał Miłecki wrote:
From: Jo-Philipp Wich <j...@mein.io>

This allows building uncompressed tar archives from shell scripts (and
compressing them later if needed)

Signed-off-by: Rafał Miłecki <ra...@milecki.pl>
---
  package/base-files/files/lib/upgrade/tar.sh | 84 +++++++++++++++++++++
  1 file changed, 84 insertions(+)
  create mode 100644 package/base-files/files/lib/upgrade/tar.sh

diff --git a/package/base-files/files/lib/upgrade/tar.sh 
b/package/base-files/files/lib/upgrade/tar.sh
new file mode 100644
index 0000000000..00057dd760
--- /dev/null
+++ b/package/base-files/files/lib/upgrade/tar.sh
@@ -0,0 +1,84 @@

No shebang?

+# SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+
+__tar_print_padding() {
+       [ $1 -eq 0 ] || dd if=/dev/zero bs=$1 count=1 2>/dev/null
+}
+
+__tar_make_member() {
+       local name="$1"
+       local content="$2"
+       local username="$3"
+       local groupname="$4"
+       local mtime="$5"
+       local mode=644
+       local uid=0
+       local gid=0
+       local size=${#content}
+       local type=0
+       local link=""
+

recommend that they're ordered here same as struct order:

struct posix_header
{                              /* byte offset */
  char name[100];               /*   0 */
  char mode[8];                 /* 100 */
  char uid[8];                  /* 108 */
  char gid[8];                  /* 116 */
  char size[12];                /* 124 */
  char mtime[12];               /* 136 */
  char chksum[8];               /* 148 */
  char typeflag;                /* 156 */
  char linkname[100];           /* 157 */
  char magic[6];                /* 257 */
  char version[2];              /* 263 */
  char uname[32];               /* 265 */
  char gname[32];               /* 297 */
  char devmajor[8];             /* 329 */
  char devminor[8];             /* 337 */
  char prefix[155];             /* 345 */
                                /* 500 */
};


+       # 100 byte of padding bytes, using 0x01 since the shell does not tolate 
null bytes in strings

tolerate?


+       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'
+

maybe try:

local pad=$(printf '\1%.0s' $(seq 100))

+       # validate name
+       if [ "${name:0:1}" = "/" ]; then
+               name="${name:1}"
+       fi

One liner:

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_make_member_from_file() {
+       local name="$1"
+       local username="$(ls -l "$1" | tr -s ' ' | cut -d ' ' -f 3)"
+       local groupname="$(ls -l "$1" | tr -s ' ' | cut -d ' ' -f 4)"
+
+       __tar_make_member "$name" "$(cat $name)" "$username" "$groupname" "$(date +%s -r 
"$1")"
+}
+
+tar_make_member_inline() {
+       local name="$1"
+       local content="$2"
+       local username="${3:-root}"
+       local groupname="${4:-root}"
+       local mtime="${5:-$(date +%s)}"
+
+       __tar_make_member "$name" "$content" "$username" "$groupname" "$mtime"
+}
+
+tar_close() {
+       __tar_print_padding 1024
+}


_______________________________________________
openwrt-devel mailing list
openwrt-devel@lists.openwrt.org
https://lists.openwrt.org/mailman/listinfo/openwrt-devel

Reply via email to