Created
April 16, 2025 12:10
-
-
Save SeanPesce/ef4aaa7ecf9d21240ae30d0ae620da70 to your computer and use it in GitHub Desktop.
Shell script to repack a SquashFS filesystem in-place, preserving the filesystem properties and individual file ownership/permissions
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# Check if squashfs-tools is installed | |
if ! command -v unsquashfs &> /dev/null || ! command -v mksquashfs &> /dev/null; then | |
echo "squashfs-tools not found. Please install squashfs-tools (e.g., sudo apt install squashfs-tools)." | |
exit 1 | |
fi | |
# Check if an argument (the SquashFS file) was provided | |
if [ "$#" -ne 1 ]; then | |
echo "Usage: $0 <squashfs_file>" | |
exit 1 | |
fi | |
SQUASHFS_FILE="$1" | |
# Check if the provided file exists | |
if [ ! -f "$SQUASHFS_FILE" ]; then | |
echo "File '$SQUASHFS_FILE' not found!" | |
exit 1 | |
fi | |
# Create directories for mounting and working | |
MOUNT_DIR="mounted_fs" | |
WORK_DIR="working_files" | |
if [ -d "$MOUNT_DIR" ] || [ -d "$WORK_DIR" ]; then | |
echo "Directories '$MOUNT_DIR' or '$WORK_DIR' already exist. Please remove or rename them and try again." | |
exit 1 | |
fi | |
mkdir "$MOUNT_DIR" "$WORK_DIR" | |
# Mount the SquashFS filesystem | |
echo "Mounting SquashFS filesystem..." | |
sudo mount -o loop "$SQUASHFS_FILE" "$MOUNT_DIR" | |
if [ $? -ne 0 ]; then | |
echo "Failed to mount the SquashFS filesystem! (You might need to run this script as root)" | |
rmdir "$MOUNT_DIR" | |
exit 1 | |
fi | |
echo "Filesystem mounted at '$MOUNT_DIR'." | |
# Copy files from the mounted filesystem to the working directory, preserving metadata | |
echo "Copying files to working directory while preserving ownership and permissions..." | |
sudo cp -a "$MOUNT_DIR/." "$WORK_DIR" | |
if [ $? -ne 0 ]; then | |
echo "Failed to copy files to working directory!" | |
sudo umount "$MOUNT_DIR" | |
rmdir "$MOUNT_DIR" | |
rm -rf "$WORK_DIR" | |
exit 1 | |
fi | |
# Unmount the filesystem | |
echo "Unmounting SquashFS filesystem..." | |
sudo umount "$MOUNT_DIR" | |
rmdir "$MOUNT_DIR" | |
echo "Filesystem copied to '$WORK_DIR'." | |
echo "Make your edits in the '$WORK_DIR' directory." | |
read -p "Press Enter when you've finished making edits..." | |
# Inspect the original SquashFS file for properties | |
echo "Inspecting the original SquashFS file for properties..." | |
ORIGINAL_FILE_SIZE=$(stat -c%s "$SQUASHFS_FILE") | |
SQUASHFS_INFO=$(unsquashfs -s "$SQUASHFS_FILE") | |
COMPRESSION_TYPE=$(echo "$SQUASHFS_INFO" | grep -oP "Compression[:\s]+\K\w+") | |
BLOCK_SIZE=$(echo "$SQUASHFS_INFO" | grep -oP "Block size[:\s]+\K\d+") | |
echo "Original filesystem properties:" | |
echo " Compression: $COMPRESSION_TYPE" | |
echo " Block size: $BLOCK_SIZE" | |
# Repack the filesystem | |
NEW_SQUASHFS_FILE="new_${SQUASHFS_FILE}" | |
echo "Repacking the filesystem into '$NEW_SQUASHFS_FILE'..." | |
sudo mksquashfs "$WORK_DIR" "$NEW_SQUASHFS_FILE" -comp "$COMPRESSION_TYPE" -b "$BLOCK_SIZE" | |
if [ $? -ne 0 ]; then | |
echo "Failed to repack the SquashFS filesystem!" | |
exit 1 | |
fi | |
echo "Filesystem successfully repacked into '$NEW_SQUASHFS_FILE'." | |
# Fix the ownership/permissions of the new file. | |
# Get ownership and permissions from the original file | |
REFERENCE_OWNER=$(stat -c "%U" "$SQUASHFS_FILE") | |
REFERENCE_GROUP=$(stat -c "%G" "$SQUASHFS_FILE") | |
REFERENCE_PERMISSIONS=$(stat -c "%a" "$SQUASHFS_FILE") | |
# Change ownership of the new file to match the original file | |
sudo chown "$REFERENCE_OWNER:$REFERENCE_GROUP" "$NEW_SQUASHFS_FILE" | |
if [ $? -ne 0 ]; then | |
echo "Failed to change ownership of '$NEW_SQUASHFS_FILE'!" | |
exit 1 | |
fi | |
# Change permissions of the new file to match the original file | |
chmod "$REFERENCE_PERMISSIONS" "$NEW_SQUASHFS_FILE" | |
if [ $? -ne 0 ]; then | |
echo "Failed to change permissions of '$NEW_SQUASHFS_FILE'!" | |
exit 1 | |
fi | |
# Get the size of the newly repacked file | |
NEW_FILE_SIZE=$(stat -c%s "$NEW_SQUASHFS_FILE") | |
echo "Original file size: $ORIGINAL_FILE_SIZE bytes" | |
echo "New file size: $NEW_FILE_SIZE bytes" | |
# Check if padding is needed | |
if [ "$NEW_FILE_SIZE" -lt "$ORIGINAL_FILE_SIZE" ]; then | |
DIFFERENCE=$((ORIGINAL_FILE_SIZE - NEW_FILE_SIZE)) | |
echo "New file is smaller than the original by $DIFFERENCE bytes. Appending padding..." | |
# Append 00 bytes to the new file | |
dd if=/dev/zero bs=1 count="$DIFFERENCE" >> "$NEW_SQUASHFS_FILE" 2>/dev/null | |
if [ $? -ne 0 ]; then | |
echo "Failed to append padding to '$NEW_SQUASHFS_FILE'." | |
exit 1 | |
fi | |
echo "Padding appended successfully. New file size matches the original." | |
else | |
echo "New file size is equal to or larger than the original. No padding needed." | |
fi | |
# Clean up extracted files (optional) | |
read -p "Do you want to remove the extracted files ([y]/n)? " CLEAN_UP | |
if [ "$CLEAN_UP" == "y" -o "$CLEAN_UP" == "Y" -o "$CLEAN_UP" == "" ]; then | |
sudo rm -rf "$WORK_DIR" | |
echo "Extracted files removed." | |
else | |
echo "Extracted files retained in '$WORK_DIR'." | |
fi | |
echo "Done!" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment