#!/bin/bash
#
#    STEPS TO RECREATE FILESYSTEM RESIZING PROBLEM
#    ---------------------------------------------
# 
#
#echo 1)  Check for proper command line arguments and set variables

if [ $# -ne 1 ]; then
    echo "Usage:  $0 dev-path"
    echo "        where: dev-path is the device path to a hard disk device"
    echo "                        that will be erased for this test."
    echo "  ***   WARNING!   ***"
    echo "        Only choose a device that has no important"
    echo "        data on it.  The data will be lost!"
    exit 1
fi

DEV=$1
echo "=== Using device ${DEV} for this test."
PARTNUM=1
SECTSTART=63
SECTEND=96389
SECTNEWSIZE=48132
SECTNEWEND=48194
PROGNAME=test-fs-part-resize

#2)  Start with a blank drive with no partition table.
#
#    If a partition table exists then remove it, reboot, and start
#    these steps over again.  You can remove the partition table with:

echo === dd if=/dev/zero of=${DEV} bs=512 count=1
dd if=/dev/zero of=${DEV} bs=512 count=${SECTEND}
echo === partprobe ${DEV}
partprobe ${DEV}
echo === sleep 9
sleep 9

#3)  Check if kernel sees partition.
#    This test will not work properly if the kernel can see an old partition.

echo === grep `echo ${DEV}${PARTNUM} | sed -e "s!/dev/!!"` /proc/partitions
grep `echo ${DEV}${PARTNUM} | sed -e "s!/dev/!!"` /proc/partitions

#4)  Create an MSDOS disk label using parted.

echo === parted -s ${DEV} mklabel msdos
parted -s ${DEV} mklabel msdos

#5)  Create a ~50 MB primary partition for an NTFS file system.

echo === parted -s ${DEV} mkpart primary ntfs ${SECTSTART}s 96389s
parted -s ${DEV} mkpart primary ntfs ${SECTSTART}s 96389s
echo === sleep 9
sleep 9
echo === blkid -c /dev/null ${DEV}${PARTNUM}
blkid -c /dev/null ${DEV}${PARTNUM}

#6)  Format the partition with an NTFS file system.

echo === mkntfs -Q ${DEV}${PARTNUM}
mkntfs -Q ${DEV}${PARTNUM}

#7)  Display the partition table.

echo === parted -s ${DEV} unit s print
parted -s ${DEV} unit s print

#    Sample Output
#    -------------
#    Model: ATA VMware Virtual I (scsi)
#    Disk /dev/sdb: 2097152s
#    Sector size (logical/physical): 512B/512B
#    Partition Table: msdos
#
#    Number  Start  End     Size    Type     File system  Flags
#     1      63s    96389s  96327s  primary  ntfs

#8)  Grow the NTFS file system to fill the partition.  This will require
#    reading the partition size from the kernel.
#    NOTE:  The partition should already be the same size as the
#           partition.

echo === ntfsresize -P --force ${DEV}${PARTNUM}
ntfsresize -P --force ${DEV}${PARTNUM}

#    Sample output
#    -------------
#    ntfsresize v2.0.0 (libntfs 10:0:0)
#    Device name        : /dev/sdb1
#    NTFS volume version: 3.1
#    Cluster size       : 4096 bytes
#    Current volume size: 49316352 bytes (50 MB)
#    Current device size: 49319424 bytes (50 MB)
#    New volume size    : 49312256 bytes (50 MB)
#    Nothing to do: NTFS volume size is already OK.

#9)  Shrink the NTFS file system down to ~25 MB.

echo === ntfsresize -P --force -s 24643583 ${DEV}${PARTNUM}
ntfsresize -P --force -s 24643583 ${DEV}${PARTNUM}

#    Sample output
#    -------------
#    ntfsresize v2.0.0 (libntfs 10:0:0)
#    Device name        : /dev/sdb1
#    NTFS volume version: 3.1
#    Cluster size       : 4096 bytes
#    Current volume size: 49316352 bytes (50 MB)
#    Current device size: 49319424 bytes (50 MB)
#    New volume size    : 24637952 bytes (25 MB)
#    Checking filesystem consistency ...
#    Accounting clusters ...
#    Space in use       : 3 MB (5.2%)
#    Collecting resizing constraints ...
#    Needed relocations : 513 (3 MB)
#    Schedule chkdsk for NTFS consistency check at Windows boot time ...
#    Resetting $LogFile ... (this might take a while)
#    Relocating needed data ...
#    Updating $BadClust file ...
#    Updating $Bitmap file ...
#    Updating Boot record ...
#    Syncing device ...
#    Successfully resized NTFS on device '/dev/sdb1'.
#    You can go on to shrink the device for example with Linux fdisk.
#    IMPORTANT: When recreating the partition, make sure that you
#      1)  create it at the same disk sector (use sector as the unit!)
#      2)  create it with the same partition type (usually 7, HPFS/NTFS)
#      3)  do not make it smaller than the new NTFS filesystem size
#      4)  set the bootable flag for the partition if it existed before
#    Otherwise you won't be able to access NTFS or can't boot from the disk!
#    If you make a mistake and don't have a partition table backup then you
#    can recover the partition table by TestDisk or Parted's rescue mode.

#10)  Shrink the partition down to ~25 MB.
#    The only way I know to do this with command line parted is to
#    remove and then recreate the partition.
#
#    $ parted -s ${DEV} rm 1
#    $ parted -s ${DEV} mkpart primary ntfs {SECTSTART}s 48194s
#
cat > ${PROGNAME}.c <<EOF
/* Program to test resizing a partition from ~50 MB to ~25MB */

#include <stdio.h>
#include <parted/parted.h>

int main ()
{
    PedDevice     *lp_device    = NULL;
    PedDisk       *lp_disk      = NULL;
    PedPartition  *lp_partition = NULL;
    PedConstraint *constraint   = NULL ;

    /* WARNING - Ensure DEV set to be a device with no important data */
    char * dev_name = "${DEV}";

    printf( "Using libparted %s\n", ped_get_version() );

    /* Retrieve device, disk, and partition */
    lp_device = ped_device_get( dev_name );
    if ( lp_device )
        lp_disk = ped_disk_new( lp_device );
    if ( lp_disk )
        lp_partition = ped_disk_get_partition (lp_disk, ${PARTNUM} );

    if ( lp_partition )
    {
        PedGeometry *geom = NULL;
        geom = ped_geometry_new( lp_device
                               , ${SECTSTART}
                               , ${SECTNEWSIZE}
                               );
        constraint = ped_constraint_exact( geom ) ;

        if ( constraint )
        {
            /* Actually resize the partition */
            if ( ped_disk_set_partition_geom( lp_disk
                                            , lp_partition
                                            , constraint
                                            , geom ->start
                                            , geom ->end
                                            )
               )
            {
                printf( "Partition resizing succeeded.\n" );
                printf( "  New Start: %lld sectors\n", geom ->start );
                printf( "  New End  : %lld sectors\n", geom ->end );

                /* Commit to device and os */
                if ( ped_disk_commit_to_dev( lp_disk ) )
                    printf( "ped_disk_commit_to_dev() succeeded.\n");
                else
                    printf( "ped_disk_commit_to_dev() failed.\n");
                if ( ped_disk_commit_to_os( lp_disk ) )
                    printf( "ped_disk_commit_to_os() succeeded.\n");
                else
                    printf( "ped_disk_commit_to_os() failed.\n");
            }

            //Clean up constraint
            ped_constraint_destroy( constraint );
        }
        else
        {
            printf( "Failed to find constraint for resizing partition.\n" );
        }
        
        //Close device and disk
        if ( lp_disk )
            ped_disk_destroy( lp_disk );
        if ( lp_device )
            ped_device_destroy( lp_device ) ;
    }
    else
    {
        printf( "Failed to locate partition and hence resize partition.\n" );
    }
}
EOF

#11a) Compile and execute code

echo === gcc -lparted -luuid -ldl -o ${PROGNAME} ${PROGNAME}.c
gcc -lparted -luuid -ldl -o ${PROGNAME} ${PROGNAME}.c

#11b) Execute program to shring partition down to ~25 MB

echo === ./${PROGNAME}
./${PROGNAME}
echo === sleep 9
sleep 9

#12) Check if kernel sees partition.
#
#    Sample Output - Correct
#    -----------------------
#     8       17      24066 sdb1
#
#    Sample Output - Wrong
#    ---------------------
#     8       17      48163 sdb1

echo === grep `echo ${DEV}${PARTNUM} | sed -e "s!/dev/!!"` /proc/partitions
grep `echo ${DEV}${PARTNUM} | sed -e "s!/dev/!!"` /proc/partitions

#13) Display the partition table.

echo === parted -s ${DEV} unit s print
parted -s ${DEV} unit s print

#    Sample output is:
#    Model: ATA VMware Virtual I (scsi)
#    Disk /dev/sdb: 2097152s
#    Sector size (logical/physical): 512B/512B
#    Partition Table: msdos
#
#    Number  Start  End     Size    Type     File system  Flags
#     1      63s    48194s  48132s  primary  ntfs

#14) Grow the NTFS file system to fill the partition.
#
#    NOTE:  The partition should already be the right size (~24 MB),
#           but the ntfsresize command will see the old 47 MB partition
#           size instead.

echo === ntfsresize -P --force ${DEV}${PARTNUM}
ntfsresize -P --force ${DEV}${PARTNUM}

#    *************************************************************
#    Note:  Following is the output that should happen when the OS
#           recognizes the changes to the partition table.
#    *************************************************************
#
#    Sample Output
#    -------------
#    ntfsresize v2.0.0 (libntfs 10:0:0)
#    Device name        : /dev/sdb1
#    NTFS volume version: 3.1
#    Cluster size       : 4096 bytes
#    Current volume size: 24637952 bytes (25 MB)
#    Current device size: 24643584 bytes (25 MB)
#    New volume size    : 24637952 bytes (25 MB)
#    Nothing to do: NTFS volume size is already OK.
#
#
#    ***************************************************************
#    Note:  Following is what happens when the OS does not recognize
#           the partition changes
#    ***************************************************************
#
#    Sample Output
#    -------------
#    ntfsresize v2.0.0 (libntfs 10:0:0)
#    Device name        : /dev/sdb1
#    NTFS volume version: 3.1
#    Cluster size       : 4096 bytes
#    Current volume size: 24637952 bytes (25 MB)
#    Current device size: 49319424 bytes (50 MB)
#    New volume size    : 49312256 bytes (50 MB)
#    Checking filesystem consistency ...
#    Accounting clusters ...
#    Space in use       : 3 MB (10.4%)
#    Collecting resizing constraints ...
#    WARNING: Every sanity check passed and only the dangerous operations left.
#    Make sure that important data has been backed up! Power outage or computer
#    crash may result major data loss!
#    Are you sure you want to proceed (y/[n])? y
#    Schedule chkdsk for NTFS consistency check at Windows boot time ...
#    Resetting $LogFile ... (this might take a while)
#    Updating $BadClust file ...
#    Updating $Bitmap file ...
#    Updating Boot record ...
#    Syncing device ...
#    Successfully resized NTFS on device '/dev/sdb1'.
