#!/bin/bash
#
PATH="/bin:/sbin:/usr/bin:/usr/sbin:$PATH"

help() {
if [ -x "`type -path less`" ]; then
    pager="less -M"
else
    pager=more    
fi

$pager << EOF

Press 'q' to Quit, Enter to scroll!

=============================================================================
Clone NTFS v1.5 (12-12-2007) Kent Robotti <krobotti@gmail.com>

You can use this script to clone and restore a Windows XP/Vista
NTFS partition. The clone can be put on the same hard drive as
the NTFS partition. This script can resize the NTFS partition
and then create a Linux partition to hold the gzip compressed
clone. The hard drive MBR is also copied.

For example, if the contents of the NTFS partition were 10GB, a 5GB
Linux Ext2 partition would be created to hold the clone etc.

Windows doesn't know anything about Linux or the Ext2 filesystem,
so the clone would be safe.

First you specify the NTFS partition you want to clone.
You can get a listing of the partitions on your hard drive(s)
this way \`fdisk -l'.

# clonentfs -c1 /dev/sda1

If you want lzma compression, do this. It will take longer (about 8 times,
2 times to restore) than the default gzip, but the Windows NTFS cloned
image will be smaller and require a smaller Linux partition to hold it.

# clonentfs -c1 -lzma /dev/sda1

If you don't want compression, do this. It will be faster, but the
Windows NTFS cloned image will be larger and require a larger Linux
partition to hold it.

# clonentfs -c1 -no-compression /dev/sda1

It will resize the NTFS partition and free enough space on the
hard drive to create a Linux partition that will hold the clone.
The next available partition will be used for Linux.

The next step is to reboot to Windows and let it run chkdsk.

*** If you use option \`-c1', this script won't run if you have
*** more than 2 partitions on the hard drive!

*** If you already have a Linux etc. partition or external USB/DVD drive etc.
*** you want to use, you can skip \`-c1' above and go to \`-c2'!	
*** It doesn't matter what it is or what filesystem is on it,
*** as long as Linux can mount and read-write it.
*** It can be /dev/dvd, /dev/sdb, or /dev/sdb3 etc.
*** Make sure it's big enough to hold the compressed or uncompressed
*** image of the Windows NTFS partition.

You then return to this system and run this script again, specify
the NTFS partition followed by the Linux partition.

*** It's optional, but before you continue you should run 'backup-mbr' 
*** and make a copy of the MBR somewhere other than the hard drive that
*** has Windows. 

# clonentfs -c2 /dev/sda1 /dev/sda2

If you want lzma compression, do this. It will take longer (about 8 times,
2 times to restore) than the default gzip, but the clone image will be smaller.

# clonentfs -c2 -lzma /dev/sda1 /dev/sda2

If you don't want compression, do this. It will be faster, but the
clone image will be larger.

# clonentfs -c2 -no-compression /dev/sda1 /dev/sda2

The restore is done by specifying the NTFS partition followed by
the Linux partition. The MBR is not restored.

# clonentfs -r /dev/sda1 /dev/sda2

If you made any changes to the hard drive layout since you last
ran this script, you may not want to restore the old MBR!

If you want the MBR restored, do this!

# clonentfs -r -mbr /dev/sda1 /dev/sda2

To just restore the MBR and nothing else, do this!

# clonentfs -just-mbr /dev/sda1 /dev/sda2

----------------------------------------------------------------
You can do this to calculate how much space you'll need.

This will tell you how much space you'll need (compressed and
uncompressed) to hold the NTFS filesystem that's on /dev/sda1. 

# clonentfs -s /dev/sda1

This will tell you how much space you'll need (compressed and
uncompressed) to hold the NTFS filesystem that's on /dev/sda1,
and if /dev/sda2 is big enough to hold it (compressed and
uncompressed).

# clonentfs -s /dev/sda1 /dev/sda2
----------------------------------------------------------------

=============================================================================
EOF
exit
}

if [ "$1" = "-c1" ]; then

if [ -z $2 ]; then
    help
elif [ "$2" = "-no-compression" ]; then
    shift
    no-compression=yes
elif [ "$2" = "-lzma" ]; then
    shift
    lzma=yes
fi

if [ -z $2 ]; then
    help
elif [ ! -b $2 ]; then
    echo "Can't find device \`$2'!"
    exit
fi

  dev=`echo $2 | cut -b 1-8`
  ntfs_pt="`echo $2 | cut -b 9-`"

if ! fdisk -l $dev | grep "^$2" | grep -q -E "NTFS|SFS" ; then
    echo "The partition \`$2' is not type 7 (NTFS)!"
    exit
elif [ "`fdisk -l $dev | grep "^/dev/" | wc -l`" -gt "2" ]; then
    echo "You have more than 2 partitions on $dev, I don't know how to handle that!"
    exit
elif mount 2>/dev/null | grep " on / " | grep -q "^$dev" ; then
    echo "Run this script from CD etc. in memory!"
    exit
elif mount 2>/dev/null | grep " on " | grep -q "^$dev" ; then
    echo "There's a partition on \`$dev' being used!"
    mount 2>/dev/null | grep " on " | grep "^$dev"
    echo "Unmount any mounted partitions on \`$dev'!"
    exit
fi

if [ ! -x "`type -path ntfsresize`" ]; then
    echo "Can't find \`ntfsresize'!"
    exit
elif [ ! -x "`type -path fdisk`" ]; then
    echo "Can't find \`fdisk'!"
    exit
elif [ ! -x "`type -path mke2fs`" ]; then
    echo "Can't find \`mke2fs'!"
    exit
fi

fdisk_error() {
echo
cat /tmp/fdisk_error
echo "
There was an fdisk ERROR!
"
      dd if=/tmp/mbr of=$dev bs=512 count=1 1>/dev/null 2>/dev/null
      partprobe $dev 2>/dev/null
      sleep 1
      echo y | ntfsresize -f $2 1>/dev/null 2>/dev/null
      echo "-------------------------------------------------------------------"
      echo "*** ERROR: There was a problem, so I restored the original layout!"
      echo "***        The next time you boot Windows, it will run chkdsk."
      echo "-------------------------------------------------------------------"
      exit
}

for p in 1 2 3 ; do
if ! fdisk -l $dev | grep -q "^$dev$p" ; then 
  pt=$p
  break
fi
done

    umount $2 2>/dev/null
    mkdir -p /tmp/mount-ntfs
    mount -o ro $2 /tmp/mount-ntfs || exit

    size1="`df -m | grep "^$2" | awk '{print $3}'`" 
    size2="`df -m | grep "^$2" | awk '{print $2}'`"

    if [ "$no-compression" = "yes" ]; then
      linux_size="`expr $size1 - 1000`"
    elif [ "$lzma" = "yes" ]; then
      linux_size="`expr $size1 / 2 - 2000`"
    else
      linux_size="`expr $size1 / 2 - 1000`"
    fi
    
    ntfs_size="`expr $size2 - $linux_size`"
    umount /tmp/mount-ntfs || exit

#    if grep -q "^$dev" /proc/mounts ; then 
#      for p in `grep "^$dev" /proc/mounts | awk '{print $1}'`
#      do
#        umount $p 2>/dev/null || exit
#      done 
#    fi

    rm -f /tmp/mbr
    dd if=$dev of=/tmp/mbr bs=512 count=1 1>/dev/null 2>/dev/null

    echo "-----------------------------------------------------------"
    echo "*** NTFSRESIZE: Resizing NTFS filesystem on $2 to $ntfs_size MB..."
    echo "*** If everything is all right, answer 'y' when asked to proceed."
    ntfsresize -s $ntfs_size"M" $2 || exit

    echo "-------------------------------------------------------------------"
    echo "*** FDISK: Resizing NTFS partition on $2 to $ntfs_size MB!"
    if [ "`fdisk -l $dev | grep "^/dev/" | wc -l`" -eq "1" ]; then
      echo -e "d\n$ntfs_pt\nn\np\n$ntfs_pt\n\n+$ntfs_size"M"\nt\n7\na\n$ntfs_pt\nw\n" | fdisk $dev 1>/tmp/fdisk_error 2>/dev/null || fdisk_error
    else
      echo -e "d\n$ntfs_pt\nn\np\n$ntfs_pt\n\n+$ntfs_size"M"\nt\n$ntfs_pt\n7\na\n$ntfs_pt\nw\n" | fdisk $dev 1>/tmp/fdisk_error 2>/dev/null || fdisk_error
    fi
  
      partprobe $dev 2>/dev/null
      sleep 1
      rm -f /tmp/pt
      dd if=$2 of=/tmp/pt bs=512 count=1 1>/dev/null 2>/dev/null

    if ! grep -q -E "BOOTMGR|NTLDR" /tmp/pt ; then
      dd if=/tmp/mbr of=$dev bs=512 count=1 1>/dev/null 2>/dev/null
      partprobe $dev 2>/dev/null
      sleep 1
      echo y | ntfsresize -f $2
      echo "-------------------------------------------------------------------"
      echo "*** ERROR: There was a problem, so I restored the original layout!"
      echo "***        The next time you boot Windows, it will run chkdsk."
      echo "-------------------------------------------------------------------"
      exit
    fi

    echo "*** FDISK: Creating $linux_size MB Linux partition on $dev$pt!"
    echo -e "n\np\n$pt\n\n+$linux_size"M"\nw\n" | fdisk $dev 1>/tmp/fdisk_error 2>/dev/null || fdisk_error
    partprobe $dev 2>/dev/null

    echo "*** MKE2FS: Creating Ext2 filesystem on $dev$pt..."
    echo "-----------------------------------------------------------"
    sleep 5
    mke2fs -q -m 0 $dev$pt || exit
    tune2fs -c 0 -i 0 $dev$pt 1>/dev/null 2>/dev/null

echo "*** DONE! The next step is to reboot to Windows and let it run chkdsk,"
echo "    then boot Windows once and shutdown/restart."
echo
echo "          You then return to this system and run this script again,"
echo "          specify the NTFS partition followed by the Linux partition."
echo
echo "          # clonentfs -c2 $2 $dev$pt"

elif [ "$1" = "-c2" ]; then

if [ -z $2 ]; then
    help
elif [ "$2" = "-no-compression" ]; then
    shift
    no-compression=yes
elif [ "$2" = "-lzma" ]; then
    shift
    lzma=yes
fi

if [ -z $2 ]; then
    help
elif [ ! -b $2 ]; then
    echo "Can't find device \`$2'!"
    exit
elif [ ! -b $3 ]; then
    echo "Can't find device \`$3'!"
    exit
fi

if [ ! -x "`type -path ntfsclone`" ]; then
    echo "Can't find \`ntfsclone'!"
    exit
fi

    dev=`echo $2 | cut -b 1-8`

if ! fdisk -l $dev | grep "^$2" | grep -q -E "NTFS|SFS" ; then
    echo "The partition \`$2' is not type 7 (NTFS)!"
    exit
fi
  
    umount $3 2>/dev/null
    mkdir -p /tmp/mount-linux
    mount -o rw $3 /tmp/mount-linux || exit
    mkdir -p /tmp/mount-linux/ntfs-backup || exit

  if [ "$no-compression" = "yes" ]; then
    if [ -f /tmp/mount-linux/ntfs-backup/ntfs-`echo $2 | cut -b6-`.backup.img ]; then
      echo "There's already a /ntfs-backup/ntfs-`echo $2 | cut -b6-`.backup.img on $3!"
      echo -n "I need to remove it. Should I remove it? (Y/n) "
      read ans
      if [ "$ans" = "n" -o "$ans" = "N" ]; then
        umount /tmp/mount-linux
        echo "*** Cancelled!"
        exit
      fi
        echo "*** Deleting /ntfs-backup/ntfs-`echo $2 | cut -b6-`.backup.img..."
        rm -f /tmp/mount-linux/ntfs-backup/ntfs-`echo $2 | cut -b6-`.backup.img
    fi
  else
  if [ "$lzma" = "yes" ]; then
    if [ -f /tmp/mount-linux/ntfs-backup/ntfs-`echo $2 | cut -b6-`.backup.img.lzma ]; then
      echo "There's already a /ntfs-backup/ntfs-`echo $2 | cut -b6-`.backup.img.lzma on $3!"
      echo -n "I need to remove it. Should I remove it? (Y/n) "
      read ans
      if [ "$ans" = "n" -o "$ans" = "N" ]; then
        umount /tmp/mount-linux
        echo "*** Cancelled!"
        exit
      fi
        echo "*** Deleting /ntfs-backup/ntfs-`echo $2 | cut -b6-`.backup.img.lzma..."
        rm -f /tmp/mount-linux/ntfs-backup/ntfs-`echo $2 | cut -b6-`.backup.img.lzma
    fi
  else
    if [ -f /tmp/mount-linux/ntfs-backup/ntfs-`echo $2 | cut -b6-`.backup.img.gz ]; then
      echo "There's already a /ntfs-backup/ntfs-`echo $2 | cut -b6-`.backup.img.gz on $3!"
      echo -n "I need to remove it. Should I remove it? (Y/n) "
      read ans
      if [ "$ans" = "n" -o "$ans" = "N" ]; then
        umount /tmp/mount-linux
        echo "*** Cancelled!"
        exit
      fi
        echo "*** Deleting /ntfs-backup/ntfs-`echo $2 | cut -b6-`.backup.img.gz..."
        rm -f /tmp/mount-linux/ntfs-backup/ntfs-`echo $2 | cut -b6-`.backup.img.gz
    fi
  fi
  fi
    
    echo "*** Copying MBR on $dev to /ntfs-backup/mbr.`echo $dev | cut -b6-` on $3!"
    dd if=$dev of=/tmp/mount-linux/ntfs-backup/mbr.`echo $dev | cut -b6-` bs=512 count=1 1>/dev/null 2>/dev/null
    fdisk -l $dev > /tmp/mount-linux/ntfs-backup/fdisk.`echo $dev | cut -b6-`.txt
    
    echo "*** Removing pagefile.sys and hiberfil.sys on $2, please wait..."
    echo "*** They will be recreated when you boot Windows!"
    mkdir -p /tmp/ntfs
    ntfsmount $2 /tmp/ntfs || exit
    rm -f /tmp/ntfs/hiberfil.sys
    rm -f /tmp/ntfs/pagefile.sys
    umount /tmp/ntfs || exit
    
    if [ "$no-compression" = "yes" ]; then
      echo "*** Cloning $2 to /ntfs-backup/ntfs-`echo $2 | cut -b6-`.backup.img on $3..."
      ntfsclone --save-image -o /tmp/mount-linux/ntfs-backup/ntfs-`echo $2 | cut -b6-`.backup.img $2 || exit
    else
    if [ "$lzma" = "yes" ]; then
      echo "*** Cloning $2 to /ntfs-backup/ntfs-`echo $2 | cut -b6-`.backup.img.lzma on $3..."
      ntfsclone --save-image -o - $2 | lzma -c > /tmp/mount-linux/ntfs-backup/ntfs-`echo $2 | cut -b6-`.backup.img.gz || exit
    else
      echo "*** Cloning $2 to /ntfs-backup/ntfs-`echo $2 | cut -b6-`.backup.img.gz on $3..."
      ntfsclone --save-image -o - $2 | gzip -c > /tmp/mount-linux/ntfs-backup/ntfs-`echo $2 | cut -b6-`.backup.img.gz || exit
    fi
    fi
        
    umount /tmp/mount-linux
    echo "*** DONE!"

elif [ "$1" = "-r" ]; then

if [ -z $2 ]; then
    help
elif [ "$2" = "-mbr" ]; then
    shift
    mbr=yes
fi

if [ -z $2 ]; then
    help
elif [ ! -b $2 ]; then
    echo "Can't find device \`$2'!"
    exit
elif [ ! -b $3 ]; then
    echo "Can't find device \`$3'!"
    exit
fi

if [ ! -x "`type -path ntfsclone`" ]; then
    echo "Can't find \`ntfsclone'!"
    exit
fi

    dev=`echo $2 | cut -b 1-8`

    umount $3 2>/dev/null
    mkdir -p /tmp/mount-linux
    mount -o ro $3 /tmp/mount-linux || exit

    if ! ls /tmp/mount-linux/ntfs-backup/ntfs-`echo $2 | cut -b6-`.backup.img* 1>/dev/null 2>/dev/null ; then
       umount /tmp/mount-linux
       echo "Can't find \`/ntfs-backup/ntfs-`echo $2 | cut -b6-`.backup.img*' on $3!"
       exit
    fi

    if [ -f /tmp/mount-linux/ntfs-backup/ntfs-`echo $2 | cut -b6-`.backup.img ]; then
       no-compression=yes    
    elif [ -f /tmp/mount-linux/ntfs-backup/ntfs-`echo $2 | cut -b6-`.backup.img.lzma ]; then
       lzma=yes    
    fi

   if [ "$mbr" = "yes" ]; then
     echo "*** Restoring MBR to $dev from backup on $3!"
     dd if=/tmp/mount-linux/ntfs-backup/mbr.`echo $dev | cut -b6-` of=$dev bs=512 count=1 1>/dev/null 2>/dev/null
     blockdev --rereadpt $dev 2>/dev/null || partprobe $dev 2>/dev/null
     sleep 5
   fi

    echo "*** Restoring $2 from backup on $3..."
    if [ "$no-compression" = "yes" ]; then
      ntfsclone -r --overwrite $2 /tmp/mount-linux/ntfs-backup/ntfs-`echo $2 | cut -b6-`.backup.img || exit
    elif [ "$lzma" = "yes" ]; then
      lzma -dc /tmp/mount-linux/ntfs-backup/ntfs-`echo $2 | cut -b6-`.backup.img.lzma | \
      ntfsclone -r --overwrite $2 - || exit
    else
      gzip -dc /tmp/mount-linux/ntfs-backup/ntfs-`echo $2 | cut -b6-`.backup.img.gz | \
      ntfsclone -r --overwrite $2 - || exit
    fi

    umount /tmp/mount-linux
    echo "*** DONE!"
    
elif [ "$1" = "-just-mbr" ]; then

if [ ! -b $2 ]; then
    echo "Can't find device \`$2'!"
    exit
elif [ ! -b $3 ]; then
    echo "Can't find device \`$3'!"
    exit
fi

    dev=`echo $2 | cut -b 1-8`

    umount $3 2>/dev/null
    mkdir -p /tmp/mount-linux
    mount -o ro $3 /tmp/mount-linux || exit

     if [ ! -f /tmp/mount-linux/ntfs-backup/mbr.`echo $dev | cut -b6-` ]; then
       umount /tmp/mount-linux
       echo "Can't find MBR backup on $3"
       exit
     fi

     echo "*** Restoring MBR to $dev from backup on $3!"
     dd if=/tmp/mount-linux/ntfs-backup/mbr.`echo $dev | cut -b6-` of=$dev bs=512 count=1 1>/dev/null 2>/dev/null
     blockdev --rereadpt $dev 2>/dev/null || partprobe $dev 2>/dev/null
     sleep 5
     
     fdisk -l $dev 2>/dev/null

    umount /tmp/mount-linux
    echo "*** DONE!"

elif [ "$1" = "-s" ]; then

if [ -z $2 ]; then
    help
elif [ ! -b $2 ]; then
    echo "Can't find device \`$2'!"
    exit
elif [ ! $3 = "" ]; then
if [ ! -b $3 ]; then
    echo "Can't find device \`$3'!"
    exit
fi
fi

    umount $2 2>/dev/null
    mkdir -p /tmp/mount1
    mount -o ro $2 /tmp/mount1 || exit
   if [ ! $3 = "" ]; then
      mkdir -p /tmp/mount2
      umount $3 2>/dev/null
      mount -o ro $3 /tmp/mount2 || exit
   fi

    size1="`df -m | grep "^$2" | awk '{print $3}'`" 

   if [ ! $3 = "" ]; then
      size2="`df -m | grep "^$3" | awk '{print $4}'`"
   fi

      lzma_compressed_size="`expr $size1 / 2 - 2500`"
      compressed_size="`expr $size1 / 2 - 1000`"
      uncompressed_size="`expr $size1 - 1000`"
   
        echo "-----------------------------------------------------------"
   if [ ! $3 = "" ]; then
      if [ "$compressed_size" -gt "$size2" ]; then
        echo "\`$2' = $compressed_size MB  \`$3' = $size2 MB"
        echo "\`$3' probably isn't big enough to hold \`$2' GZIP compressed!"
      else
        echo "You'll need at most \`$compressed_size MB' to hold \`$2' GZIP compressed!"
        echo "You seem to have enough space on \`$3'!"
      fi

      if [ "$lzma_compressed_size" -gt "$size2" ]; then
        echo "\`$2' = $compressed_size MB  \`$3' = $size2 MB"
        echo "\`$3' probably isn't big enough to hold \`$2' LZMA compressed!"
      else
        echo "You'll need at most \`$compressed_size MB' to hold \`$2' LZMA compressed!"
        echo "You seem to have enough space on \`$3'!"
      fi

      if [ "$uncompressed_size" -gt "$size2" ]; then
        echo "\`$2' = $uncompressed_size MB  \`$3' = $size2 MB"
        echo "\`$3' probably isn't big enough to hold \`$2' uncompressed!"
      else
        echo
        echo "You'll need at most \`$uncompressed_size MB' to hold \`$2' uncompressed!"
        echo "You seem to have enough space on \`$3'!"
      fi
   else
      echo "You'll need at most \`$lzma_compressed_size MB' to hold \`$2' LZMA compressed!"
      echo "You'll need at most \`$compressed_size MB' to hold \`$2' GZIP compressed!"
      echo "You'll need at most \`$uncompressed_size MB' to hold \`$2' uncompressed!"
   fi
      echo "-----------------------------------------------------------"
      echo "*** The compressed numbers are liberal estimates!"
      echo "*** There's no way to be exact!"
      echo "-----------------------------------------------------------"

    umount /tmp/mount1 2>/dev/null
    umount /tmp/mount2 2>/dev/null
    
else
    help
fi
