tar compress inside android adb su root -c sub command produces empty tar file
3
votes
1
answer
121
views
I just stumbled upon a weird behavior on android:
echo test>/data/local/tmp/test.txt
su root -c "cat /data/local/tmp/test.txt && \
tar -cvzf /data/local/tmp/test.tar.gz /data/local/tmp/test.txt && \
echo $?"
ls -alh /data/local/tmp/test.txt
This will produce an empty test.tar.gz:
test
removing leading '/' from member names
data/local/tmp/test.txt
0
-rw-r--r-- 1 root root 0 2025-01-09 17:43 /data/local/tmp/test.tar.gz
Running without
su root -c
I will get a 120 byte tar.gz:
-rw-r--r-- 1 root root 120 2025-01-09 17:47 /data/local/tmp/test.tar.gz
Adding a sleep like this:
su root -c "tar -cvzf /data/local/tmp/test.tar.gz /data/local/tmp/test.txt && sleep 1"
Also produces a 120 byte tar.gz.
*Update:*
Doing this with a 50mb file, the tar subcommand blocks until it's finished and produces an invalid tar.gz which is short of 22031 bytes to a valid tar.gz produced without su -c
$ ls -alh /system/apex/com.android.art.release.apex
-rw-r--r-- 1 root root 54M 2009-01-01 00:00 /system/apex/com.android.art.release.apex
$ tar -cvzf /data/local/tmp/big.tar.gz /system/apex/com.android.art.release.apex
$ su root -c "tar -cvzf /data/local/tmp/bigsu.tar.gz /system/apex/com.android.art.release.apex"
removing leading '/' from member names
system/apex/com.android.art.release.apex
$ ls -al /data/local/tmp/b*
-rw-r--r-- 1 root root 22541839 2025-01-09 21:43 /data/local/tmp/big.tar.gz
-rw-r--r-- 1 root root 22519808 2025-01-09 21:33 /data/local/tmp/bigsu.tar.gz
$ tar -xvzf /data/local/tmp/bigsu.tar.gz /data/local/tmp/big.apex ; echo $?
zcat: gzclose: Inappropriate ioctl for device
tar: EOF: Illegal seek
1
$ tar -xvzf /data/local/tmp/big.tar.gz /data/local/tmp/big.apex ; echo $?
0
Same behavior when using another user besides root.
This problem occurs on an android 11 emulator. I wasn't able to reproduce this on my linux servers.
The only way I can explain it is that the write buffer from tar is not flushed to the emulated disk.
A stat to the file inside the subcommand makes it flush the data correctly:
$ su root -c "tar -cvzf /data/local/tmp/test.tar.gz /data/local/tmp/test.txt && stat /data/local/tmp/test.tar.gz"
removing leading '/' from member names
data/local/tmp/test.txt
File: /data/local/tmp/test.tar.gz
Size: 120 Blocks: 16 IO Blocks: 512 regular file
Device: fd05h/64773d Inode: 65546 Links: 1 Device
type: 0,0
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2025-01-09 17:43:44.964000000 +0000
Modify: 2025-01-09 22:00:28.496000000 +0000
Change: 2025-01-09 22:00:28.496000000 +0000
$ ls -alh /data/local/tmp/test.tar.gz
-rw-r--r-- 1 root root 120 2025-01-09 22:00 /data/local/tmp/test.tar.gz
But why on earth would ending the subshell prevent flushing of the output file? When tar exits with a success exit 0, that means the written data should already be handled and flushed by the kernel.
Simple copying does not have the flush problem. So it might be a tar bug.
su root -c "cp /system/apex/com.android.art.release.apex>/data/local/tmp/release.apex"
su root -c "cat /system/apex/com.android.art.release.apex>/data/local/tmp/releasecat.apex"
ls -al /data/local/tmp/release*
-rw-r--r-- 1 root root 56510850 2025-01-09 22:31 /data/local/tmp/release.apex
-rw-r--r-- 1 root root 56510850 2025-01-09 22:33 /data/local/tmp/releasecat.apex
The tar version of busybox does not have this problem!
$ su root -c "/data/adb/magisk/busybox tar --version"
tar (busybox) 1.36.1-Magisk
$ su root -c "/data/adb/magisk/busybox tar -cvzf /data/local/tmp/test.tar.gz /data/local/tmp/test.txt"
$ ls -alh /data/local/tmp/test.tar.gz
-rw-r--r-- 1 root root 120 2025-01-09 22:42 /data/local/tmp/test.tar.gz
*Notes:*
- tar version toybox 0.8.3-android
- same when using /sdcard/Download as a directory.
Asked by 5andr0
(113 rep)
Jan 9, 2025, 05:59 PM
Last activity: Jan 10, 2025, 01:52 PM
Last activity: Jan 10, 2025, 01:52 PM