Skip to content

Instantly share code, notes, and snippets.

@SeanPesce
Created April 16, 2025 12:10
Show Gist options
  • Save SeanPesce/ef4aaa7ecf9d21240ae30d0ae620da70 to your computer and use it in GitHub Desktop.
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
#!/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