(bm, 3.LBN - (0.size + 1.size + 2.size), 0.size + 1.size + 2.size) && RtlAreBitsClear(bm, 3.LBN + 3.size, 4.size) then
      can be defragmented around 3
   else
      check next fragment

   if all fragments are checked and the file can't be defragmented 'in-place', then fall back
   to some other algorithm (partial or complete)
 */
class VolumeBitmap
{
public:
   DWORD Open( LPCWSTR VolumeName ) NO_THROW;
   void Close( ) NO_THROW;


private:
   HANDLE _hVolume;
};

class FileBitmap
{
public:
   DWORD Initialize( HANDLE File ) NO_THROW;
   void Uninitialize( ) NO_THROW;

   // _DetermineDefragmentationType()

   // _FileMapLoad() - build file bitmap
   // _FileMapMaskReserved() - mark clusters in the file bitmap that are in use by the volume
};


DWORD FpiBuildFileBitMap( HANDLE hFile, PRTL_BITMAP pBitMap )
{
   hFile;pBitMap;
   // need 1 bit for every cluster, from lowest to highest
   //    get fragdata, FpiGetFragmentInformation will sort by VCN
   //    resort by size (ClusterCount)
   //    allocate bitmap for ClusterCount
   //    for each fragment > LIMIT(64MB default)
   //       get volume bitmap for file with frag placed in middle
   //          set all frag bits in bitmap to 0
   //       if bitmap is clear, can be defragged in place
   //

   // how to use this to defrag a file?
   //    some function to build a list of records that say move x to y

   return ( ERROR_INVALID_FUNCTION );
}

DWORD FpiBuildFileDefragPlan2( LPCWSTR pwszFile, DWORD dwFlags, PDEFRAG_PLAN pDefragPlan )
{
   DWORD dwRet;

   dwRet = NO_ERROR;

   pwszFile;dwFlags;pDefragPlan;

   // this is going to be pretty confusing, no matter what

   // 1) FPIF_DEFRAGPLAN_COMPACT_FULL | FPIF_DEFRAGPLAN_PLACEMENT_OPTIMAL
   
   
   // based on the placement, try to determine the best hint for the cluster range

   // local will call some function to get the frags and find which one it can 
   //    hold the file
   // optimal will determine file type/use, and pick best place on disk to place
   //    the file
   //
   // both of these functions must return a plan. compact will determine the minimum
   //    required size of each file chunk after the plan is executed. full will be
   //    the full file size, partial will be a user configurable size, default is 64MB

   if ( FlagOn(dwFlags, FPIF_DEFRAGPLAN_PLACE_OPTIMAL) )
   {
      //dwRet = FpiBuildFileDefragPlanOptimal(hFile,
      //                                      dwFlags,
      //                                      ppDefragPlan);
   }
   else
   {
      //dwRet = FpiBuildFileDefragPlanLocal(hFile,
      //                                    dwFlags,
      //                                    ppDefragPlan);
   }

   //dwRet = FpiBuildFileDefragPlanLocal(hFile,                                       dwFlags,                                       pDefragPlan);

   /* Success / Failure */
   return ( dwRet );
}

int __cdecl FpiFragmentInfoSortByClusterCountRoutine( const void* pElem1, const void* pElem2 ) NO_THROW
{
   PFRAGMENT_INFORMATION pFrag1;
   PFRAGMENT_INFORMATION pFrag2;

   /* Initialize locals */
   pFrag1 = (PFRAGMENT_INFORMATION)(pElem1);
   pFrag2 = (PFRAGMENT_INFORMATION)(pElem2);

   if ( pFrag1->ClusterCount > pFrag2->ClusterCount )
   {
      return ( -1 );
   }
   else if ( pFrag1->ClusterCount < pFrag2->ClusterCount )
   {
      return ( 1 );
   }
   
   return ( 0 );
}

DWORD FpiBuildFileDefragPlanLocal( LPCWSTR pwszFile, DWORD dwFlags, PDEFRAG_PLAN pDefragPlan )
{
   DWORD         dwRet;   
   HANDLE        hFragCtx;
   //PFRAG_CONTEXT pFragCtx;

   dwRet    = NO_ERROR;
   hFragCtx = NULL;

   pwszFile;dwFlags;pDefragPlan;

   /* Load the fragment info for this file.. */
   dwRet = FpCreateContext(pwszFile,
                           0,
                           &hFragCtx);
   
   //DbgDumpFragmentInfo(pFragInfo, cFragCount);

   // 

   return ( NO_ERROR );
}

#pragma endregion TODO


/**********************************************************************

   FRAG_CONTEXT Management

 **********************************************************************/


/**********************************************************************

   Public - Exported functions

 **********************************************************************/
__declspec(deprecated)
DWORD FRAGAPI FpGetContextFilePath( HANDLE hFragCtx, LPWSTR FileName, ULONG FileNameLength ) NO_THROW
{
   PFRAG_CONTEXT pFragCtx;

   /* Validate parameters */
   if (!IsValidFragCtxHandle(hFragCtx) )
   {
      /* Failure */
      return ( ERROR_INVALID_HANDLE );
   }

   if (!FileName )
   {
      /* Failure */
      return ( ERROR_INVALID_PARAMETER );
   }

   /* Initialize locals */
   pFragCtx = HandleToFragCtx(hFragCtx);

   if ( FAILED(StringCchCopy(FileName,
                             static_cast<size_t>(FileNameLength),
                             pFragCtx->FilePath)) )
   {
      /* Failure */
      return ( ERROR_BUFFER_OVERFLOW );
   }

   /* Success */
   return ( NO_ERROR );
}


/**********************************************************************

   Private

 **********************************************************************/

DWORD 
FpiGetFullFilePath( 
   __in HANDLE hFile, 
   __out_ecount_z(cchFileName) LPWSTR pwszFilePath, 
   __in size_t cchFilePath
) NO_THROW
{
   /*****!!!!!!!!! this assumes SeChangeNotifyPrivilege  is granted!!!!!!!!!!!!!!!!******/

   DWORD                      dwRet;   
   PFILE_NAME_INFORMATION     pFileName;
   POBJECT_NAME_INFORMATION   pObjectName;
   ULONG                      cbFileDeviceName;
   PMOUNTMGR_MOUNT_POINT      pMountPoint;
   PMOUNTMGR_MOUNT_POINTS     pMountPoints;
   ULONG                      iIdx;
   UNICODE_STRING             VolumeName;
   UNICODE_STRING             DeviceName;
   
   /* Initialize locals */
   pFileName    = NULL;
   pObjectName  = NULL;
   pMountPoint  = NULL;
   pMountPoints = NULL;
                        
   /* Get the file's path. This won't include the volume name */
   dwRet = FpiQueryFileNameInformation(hFile,
                                       &pFileName);

   if ( NO_ERROR!= dwRet )
   {  
      /* Failure */
      goto __CLEANUP;
   }

   /* Get the object path. This will include the NT device name and the full file path */
   dwRet = FpiQueryObjectNameInformation(hFile,
                                         &pObjectName);

   if ( NO_ERROR!= dwRet )
   {
      /* Failure */
      goto __CLEANUP;
   }

   if ( pObjectName->Name.Length < pFileName->FileNameLength )
   {
      dwRet = ERROR_BAD_PATHNAME;
      /* Failure */
      goto __CLEANUP;
   }
   
   cbFileDeviceName = (pObjectName->Name.Length - pFileName->FileNameLength);

   /* Build a mount point to limit the mount points returned */
   pMountPoint = FpiBuildMountManagerMountPoint(NULL,
                                                0,
                                                NULL,
                                                0,
                                                pObjectName->Name.Buffer,
                                                static_cast<USHORT>(cb