WindowsXP/base/fs/utils/dfrg/fraggedfilelist.cpp
2025-04-27 07:49:33 -04:00

489 lines
15 KiB
C++

//=============================================================================*
// COPYRIGHT© 2001 Microsoft Corporation and Executive Software International, Inc.
//=============================================================================*
// File: FraggedFileList.cpp
//=============================================================================*
#include "stdafx.h"
#include <windows.h>
#include "ErrMacro.h"
#include "alloc.h"
#include "GetDfrgRes.h" // to use the GetDfrgResHandle()
#include "TextBlock.h" // to use the FormatNumber function
#include "FraggedFileList.h"
//-------------------------------------------------------------------*
// function: CFraggedFile::CFraggedFile
//
// returns: None
//-------------------------------------------------------------------*
CFraggedFile::CFraggedFile(
PTCHAR cFileName,
LONGLONG fileSize,
LONGLONG extentCount)
{
// check for null pointer
require(cFileName);
require(fileSize);
require(extentCount);
// allocate memory for the name string (it could be really long!)
m_cFileName = (PTCHAR) new TCHAR[wcslen(cFileName) + 1];
//fix put in for 55985 prefix bug to prevent dereferencing NULL pointer
if(m_cFileName == NULL) //memory allocation failed
{
m_FileSize = 0;
// m_cFileSize = NULL;
m_ExtentCount = 0;
// m_cExtentCount = NULL;
return;
}
// now grab a copy of the name string
wcscpy(m_cFileName, cFileName);
m_FileSize = fileSize;
m_ExtentCount = extentCount;
// formats the number in Bytes, KB, MB or GB and puts in commas
FormatNumber(GetDfrgResHandle(), m_FileSize, m_cFileSize);
CommafyNumber(m_ExtentCount, m_cExtentCount, sizeof(m_cExtentCount) / sizeof(TCHAR));
}
//-------------------------------------------------------------------*
// function: CFraggedFile::CFraggedFile
//
// desc: Version used to create an empty object
// returns: None
//-------------------------------------------------------------------*
CFraggedFile::CFraggedFile(void)
{
m_cFileName = NULL;
m_FileSize = 0;
m_ExtentCount = 0;
}
//-------------------------------------------------------------------*
// function: CFraggedFile::~CFraggedFile
//
// returns: None
//-------------------------------------------------------------------*
CFraggedFile::~CFraggedFile(void)
{
// deallocate memory for the name string
if (m_cFileName){
delete m_cFileName;
}
}
//-------------------------------------------------------------------*
// function: CFraggedFile::FileNameLen
//
// returns: length of FileName
//-------------------------------------------------------------------*
UINT CFraggedFile::FileNameLen()
{
if (m_cFileName == NULL) {
return 0;
}
else {
return wcslen(m_cFileName);
}
}
//-------------------------------------------------------------------*
// function: CFraggedFile::FileNameTruncated
//
// returns: FileName truncated to MaxLen
//-------------------------------------------------------------------*
PTCHAR CFraggedFile::FileNameTruncated(UINT MaxLen)
{
PTCHAR cStart = m_cFileName;
PTCHAR cPtr = m_cFileName;
// nothing to do if no filename or already within length limit
if (m_cFileName != NULL && wcslen(m_cFileName) > MaxLen) {
// find the starting point that gives a MaxLen string
UINT len = wcslen(m_cFileName);
cStart += len - MaxLen;
// jump ahead to the next path separator
cPtr = wcschr(cStart, TEXT('\\'));
// make sure we got one
if (cPtr == NULL) {
cPtr = cStart;
}
}
return cPtr;
}
LONGLONG CFraggedFile::FileSize(void)
{
return m_FileSize;
}
LONGLONG CFraggedFile::ExtentCount(void)
{
return m_ExtentCount;
}
//-------------------------------------------------------------------*
// function: CFraggedFileList::CFraggedFileList
//
// returns: None
//-------------------------------------------------------------------*
CFraggedFileList::CFraggedFileList(PTCHAR cVolumeName)
{
// check for null pointer
require(cVolumeName);
wcscpy(m_cVolumeName, cVolumeName);
m_FraggedFileList.RemoveAll();
m_hTransferBuffer = NULL;
m_pTransferBuffer = NULL;
m_TransferBufferSize = 0;
m_MinExtentCount = -1;
m_MinIndex = 0;
}
//-------------------------------------------------------------------*
// function: CFraggedFileList::CFraggedFileList
//
// desc: Version when the volume name is not known yet
// returns: None
//-------------------------------------------------------------------*
CFraggedFileList::CFraggedFileList(void)
{
m_FraggedFileList.RemoveAll();
m_hTransferBuffer = NULL;
m_pTransferBuffer = NULL;
m_TransferBufferSize = 0;
m_MinExtentCount = -1;
m_MinIndex = 0;
}
//-------------------------------------------------------------------*
// function: CFraggedFileList::~CFraggedFileList
//
// returns: None
//-------------------------------------------------------------------*
CFraggedFileList::~CFraggedFileList(void)
{
// Clear out the list
CFraggedFile *pFraggedFile;
for (int i=0; i<m_FraggedFileList.Size(); i++){
pFraggedFile = (CFraggedFile *) m_FraggedFileList[i];
if (pFraggedFile)
delete pFraggedFile;
}
m_FraggedFileList.RemoveAll();
DeleteTransferBuffer();
}
//-------------------------------------------------------------------*
// function: CFraggedFileList::GetAt(based on index)
//
// returns: Address of object at an index (used for looping)
// note:
//-------------------------------------------------------------------*
CFraggedFile * CFraggedFileList::GetAt(UINT i)
{
if (i >= (UINT) m_FraggedFileList.Size())
return (CFraggedFile *) NULL;
if (m_FraggedFileList.Size() > -1){
return (CFraggedFile *) m_FraggedFileList[i];
}
return (CFraggedFile *) NULL;
}
//-------------------------------------------------------------------*
// function: CFraggedFileList::RemoveAt(based on index)
//
// returns: TRUE if this worked, otherwise FALSE
// note:
//-------------------------------------------------------------------*
BOOL CFraggedFileList::RemoveAt(UINT i)
{
if (i >= (UINT) m_FraggedFileList.Size())
return FALSE;
if (m_FraggedFileList.Size() > -1){
CFraggedFile *pFraggedFile = (CFraggedFile *) m_FraggedFileList[i];
if (pFraggedFile){
delete pFraggedFile;
}
return m_FraggedFileList.RemoveAt(i);
}
return FALSE;
}
//-------------------------------------------------------------------*
// function: CFraggedFileList::Add(...)
//
// returns: Index of new element, -1 if it failed
// note:
//-------------------------------------------------------------------*
int CFraggedFileList::Add(PTCHAR cFileName, LONGLONG fileSize, LONGLONG extentCount)
{
// if it's not fragged, don't bother
if (extentCount < 2){
return -1;
}
// filter out the meta-files - they confuse the users!
if (_tcsstr(cFileName, TEXT("\\$Extend")) != (PTCHAR) NULL){
return -1;
}
CFraggedFile *pFraggedFile;
// if the list is full, delete the smallest guy
if (m_FraggedFileList.Size() >= MAX_MOST_FRAGGED_FILES){
// dont bother if this is as small as the smallest extent count
if (extentCount <= m_MinExtentCount){
return -1;
}
// delete the current min to make room for the new entry
RemoveAt(m_MinIndex);
// calculate who the new minimum is and where he is located
pFraggedFile = (CFraggedFile *) m_FraggedFileList[0];
m_MinExtentCount = pFraggedFile->ExtentCount();
m_MinIndex = 0;
// find the file with the min extent count
for (UINT i=1; i<(UINT)m_FraggedFileList.Size(); i++){
// get a pointer to the object
pFraggedFile = (CFraggedFile *) m_FraggedFileList[i];
if (pFraggedFile->ExtentCount() < m_MinExtentCount){
m_MinExtentCount = pFraggedFile->ExtentCount();
m_MinIndex = i;
}
}
}
// strip the volume name (guid) off the prefix of the file name
PTCHAR pTmp = cFileName;
// only if the first 2 character are a double whack
if (wcslen(cFileName) > wcslen(m_cVolumeName) && wcsncmp(cFileName, L"\\\\", 2) == 0){
pTmp += wcslen(m_cVolumeName);
}
// if we are below the limit, then just add the file
pFraggedFile = (CFraggedFile *) new CFraggedFile(
pTmp,
fileSize,
extentCount);
if (pFraggedFile == (CFraggedFile *) NULL)
{
return -1;
}
// add the new object to the list
int newIndex = m_FraggedFileList.Add(pFraggedFile);
// if this guy has the new min, save the min and his location in the list
if ((-1 == m_MinExtentCount) || (extentCount <= m_MinExtentCount)){
m_MinExtentCount = extentCount;
m_MinIndex = newIndex;
}
return newIndex;
}
//-------------------------------------------------------------------*
// function: CFraggedFileList::CreateTransferBuffer(void)
//
// returns: pointer to the transfer buffer
// note:
//-------------------------------------------------------------------*
BOOL CFraggedFileList::CreateTransferBuffer(void)
{
// the number of files in the list goes first
m_TransferBufferSize = sizeof(UINT);
// this get the Byte count, not the char count
m_TransferBufferSize += sizeof(m_cVolumeName);
CFraggedFile *pFraggedFile;
for (int i=0; i<m_FraggedFileList.Size(); i++){
// get a pointer to the object
pFraggedFile = (CFraggedFile *) m_FraggedFileList[i];
// add the size of the object
m_TransferBufferSize += sizeof(CFraggedFile);
// add the length of the name string (+1 for the null)
m_TransferBufferSize += (1 + _tcslen(pFraggedFile->FileName())) * sizeof(TCHAR);
}
EF(AllocateMemory(m_TransferBufferSize, &m_hTransferBuffer, (PVOID *)&m_pTransferBuffer));
// use a temp pointer to walk thru the transfer buffer
PCHAR pTB = (PCHAR) m_pTransferBuffer;
// copy the frag file list count into the buffer
UINT fileListSize = m_FraggedFileList.Size();
CopyMemory(pTB, (PVOID)&fileListSize, sizeof(UINT));
pTB += sizeof(UINT);
// copy the volume name into the buffer.
// this is a fixed length buffer, so we can just slam it in
CopyMemory(pTB, m_cVolumeName, sizeof(m_cVolumeName));
pTB += sizeof(m_cVolumeName);
// now put the data into the buffer
for (i=0; i<m_FraggedFileList.Size(); i++){
// get a pointer to the object
pFraggedFile = (CFraggedFile *) m_FraggedFileList[i];
// copy the object into the buffer
CopyMemory(pTB, pFraggedFile, sizeof(CFraggedFile));
pTB += sizeof(CFraggedFile);
// copy the file name into the buffer (and a null)
_tcscpy((PTCHAR) pTB, pFraggedFile->FileName());
pTB += (1 + _tcslen(pFraggedFile->FileName())) * sizeof(TCHAR);
}
return TRUE;
}
//-------------------------------------------------------------------*
// function: CFraggedFileList::DeleteTransferBuffer(void)
//
// returns: TRUE if it worked, otherwise FALSE
// note:
//-------------------------------------------------------------------*
BOOL CFraggedFileList::DeleteTransferBuffer(void)
{
if (m_hTransferBuffer){
EH_ASSERT(GlobalUnlock(m_hTransferBuffer) == FALSE)
EH_ASSERT(GlobalFree(m_hTransferBuffer) == NULL);
}
m_hTransferBuffer = NULL;
m_pTransferBuffer = NULL;
return TRUE;
}
//-------------------------------------------------------------------*
// function: CFraggedFileList::ParseTransferBuffer(PVOID pTransferBuffer)
//
// returns: TRUE if it worked, otherwise FALSE
// note: Builds the CFraggedFileList from scratch out of a buffer
//-------------------------------------------------------------------*
BOOL CFraggedFileList::ParseTransferBuffer(PTCHAR pTransferBuffer)
{
// EF_ASSERT(pTransferBuffer);
LONGLONG lFileSize = 0;
LONGLONG lExtentCount = 0;
PTCHAR tmpString;
PCHAR pTB;
UINT fileListSize;
RemoveAll();
m_TransferBufferSize = 0;
// use a temp pointer to walk thru the transfer buffer
pTB = (PCHAR) pTransferBuffer;
// first: get the number of fragged files in the list
CopyMemory(&fileListSize, pTB, sizeof(UINT));
pTB += sizeof(UINT);
m_TransferBufferSize = sizeof(UINT);
// then get the volume name
wcsncpy(m_cVolumeName, (PTCHAR)pTB, GUID_LENGTH);
pTB += GUID_LENGTH * sizeof(TCHAR);
m_TransferBufferSize += sizeof(m_cVolumeName);
// create a temp object to hold data as we parse the transfer buffer
// the rest of the transfer buffer is a stack of CFraggedFile objects/FileName pairs
// CFraggedFile objects
// File name (null terminated) that goes with the previous object
// CFraggedFile objects
// File name (null terminated) that goes with the previous object
// CFraggedFile objects
// File name (null terminated) that goes with the previous object
// CFraggedFile objects
// File name (null terminated) that goes with the previous object
// and so on...
for (UINT i=0; i<fileListSize; i++){
// the next CFraggedFile object is next in the buffer
memcpy(&lExtentCount, pTB, sizeof(LONGLONG));
memcpy(&lFileSize, pTB+sizeof(LONGLONG), sizeof(LONGLONG));
pTB += sizeof(CFraggedFile);
// the file name for that object is after that
tmpString = (PTCHAR) pTB;
Add(tmpString, lFileSize, lExtentCount);
// increment the counter
m_TransferBufferSize += sizeof(CFraggedFile) + (1 + wcslen(tmpString)) * sizeof(TCHAR);
// move the transfer buffer pointer to the next object-file name pair
pTB += (1 + wcslen(tmpString)) * sizeof(TCHAR);
}
return TRUE;
}
//-------------------------------------------------------------------*
// function: CFraggedFileList::GetTransferBuffer(void)
//
// returns: TRUE if it worked, otherwise FALSE
// note: returns pointer to transfer buffer, builds it if needed
//-------------------------------------------------------------------*
PTCHAR CFraggedFileList::GetTransferBuffer(void)
{
return m_pTransferBuffer;
}
//-------------------------------------------------------------------*
// function: CFraggedFileList::GetTransferBuffer(void)
//
// returns: TRUE if it worked, otherwise FALSE
// note: returns pointer to transfer buffer, builds it if needed
//-------------------------------------------------------------------*
void CFraggedFileList::RemoveAll(void)
{
// Clear out the list
CFraggedFile *pFraggedFile;
for (int i=0; i<m_FraggedFileList.Size(); i++){
pFraggedFile = (CFraggedFile *) m_FraggedFileList[i];
if (pFraggedFile)
delete pFraggedFile;
}
m_FraggedFileList.RemoveAll();
}