Skip to content

Commit

Permalink
Tool documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
Helio Machado committed Aug 18, 2017
1 parent c1cbdae commit 72d04d6
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 0 deletions.
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# qdtar

A `qdtar` archive is a slightly modified `tar` archive, used to pack the root filesystem in the Qisda ES600 e-reader upgrades. The file name used for these archives is `rootfs.img`, even if it has nothing to do with a disk image.

***

The file format is simple: a header of 978 bytes whose contents are completely ignored, prepended to a normal `tar` archive.

The [executable found on the firmware](busybox) zero-fills the header when creating a new archive. However, the archives found in official firmware upgrade packages used a different approach:

* The first 970 bytes of the header were filled with a copy of the first 970 bytes of the `tar` file.
* The next 8 bytes were used to store the magic number (`QDTAR1.0`).

I suspect that the filling of the header with a copy of the first bytes of the `tar` file is a mistake made by the developer of the packer app. Probably the original code shifts the data on a buffer by copying it to the new offset without taking care of zeroing the contents of the header. The other possibility (more conspiranoid) is that copying the first bytes of the `tar` archive will fool a normal decompression utility.

70 changes: 70 additions & 0 deletions qdtar
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#!/bin/sh

magic="QDTAR1.0"


usage() {
echo "Usage: $0 <mode> <input> <output>"
echo
echo " -p, --pack pack the input file"
echo " -u, --unpack unpack the input file"
echo
echo "Example: $0 --unpack rootfs.img rootfs.tar"
exit 1
}


pack() {
# Function arguments.
input="$1"; output="$2";

# Offset 0, length 970: header fill.
dd if="$input" of="$output" bs=970 count=1
status=$((status + $?))

# Offset 970, length 8: magic number.
printf "$magic" | dd of="$output" bs=970 seek=1
status=$((status + $?))

# Offset 978, until EOF: tar file.
dd if="$input" of="$output" bs=978 seek=1
status=$((status + $?))

return $status
}


unpack() {
# Function arguments.
input="$1"; output="$2"

# Warn the user if the magic number is wrong.
if [[ "$(dd if="$input" bs=1 skip=970 count=8)" != "$magic" ]]; then
echo "warning: the magic number is not '$magic'"
fi

# Extract the tar file.
dd if="$input" of="$output" bs=978 skip=1
}


# Check the number of arguments.
[[ $# != 3 ]] && usage

# If the output file exists, ask before overwriting.
if test -f "$2"; then
read -p "Output file already exists. Overwrite? [y/N]: " answer
[[ "$answer" != "y" ]] && [[ "$answer" != "Y" ]] && exit 1
fi

# Operation mode selection.
case "$1" in
-u|--unpack) log="$(unpack "$1" "$2" 2>&1)";;
-p|--pack) log="$(pack "$1" "$2" 2>&1)";;
*) usage;;
esac

# Log dump in case of error.
if [[ $? > 0 ]]; then
echo "$log"
fi

0 comments on commit 72d04d6

Please sign in to comment.