#include "StdAfx.h"
#include "BKDAndos.h"

CBKDAndos::CBKDAndos(const PARSE_RESULT &image) : CBKDImage(image),
	m_nSectorSize(0),
	m_nClusterSectors(0),
	m_nClusterSize(0),
	m_nBootSectors(0),
	m_nRootFilesNum(0),
	m_nRootSize(0),
	m_nFatSectors(0),
	m_nFatSize(0),
	m_pFatTbl(NULL),
	m_pCatTbl(NULL)
{
}

CBKDAndos::~CBKDAndos(void)
{
	if (m_pFatTbl)
	{
		delete [] m_pFatTbl;
	}

	if (m_pCatTbl)
	{
		delete [] m_pCatTbl;
	}
}

BOOL CBKDAndos::ReadCatalog()
{
	if (!CBKDImage::ReadCatalog())
	{
		return FALSE;
	}

	//читаем нулевой сектор
	ULONGLONG ulls = m_sPImg.nBaseOffset + 0;

	if (ulls != m_ImgFile.Seek(ulls, CFile::begin))
	{
		m_nLastErrorNumber = IMAGE_ERROR_CANNOT_SEEK_FILE;
		return FALSE;
	}

	if (m_ImgFile.Read(m_mSector, sizeof(m_mSector)) != sizeof(m_mSector))
	{
		m_nLastErrorNumber = IMAGE_ERROR_CANNOT_READ_FILE;
		return FALSE;
	}

	//прочитаем данные BPB
	m_nSectorSize = *(WORD *)&m_mSector[013];
	m_nClusterSectors = m_mSector[015];
	m_nClusterSize = m_nClusterSectors * m_nSectorSize;
	m_nBootSectors = *(WORD *)&m_mSector[016];
	m_nRootFilesNum = *(WORD *)&m_mSector[021];
	m_nRootSize = m_nRootFilesNum * 32;
	m_nFatSectors = *(WORD *)&m_mSector[026];
	m_nFatSize = m_nFatSectors * m_nSectorSize;
	m_nRootSectorOffset = (m_nBootSectors + m_nFatSectors * 2) * m_nSectorSize;
	m_nDataSectorOffset = m_nRootSectorOffset + m_nRootSize;

	//единственное место, где размеры массивов заранее неизвестны, и их надо выделять тут
	//и на всякий случай сделана проверка, вдруг уже было выделено раньше
	if (m_pFatTbl == NULL)
	{
		m_pFatTbl = new BYTE[m_nFatSize]; //место под ФАТ
	}

	if (m_pCatTbl == NULL)
	{
		m_pCatTbl = new BYTE[m_nRootSize]; //место под каталог
	}

	if ((m_pFatTbl == NULL) || (m_pCatTbl == NULL))
	{
		m_nLastErrorNumber = IMAGE_ERROR_NOT_ENOUGHT_MEMORY;
		//ShowMessageBox(IDS_ERR_NOTENOUGHT_MEMORY);
		return FALSE;
	}

	ulls = m_sPImg.nBaseOffset + m_nBootSectors * m_nSectorSize;

	//перемещаемся к началу фат и прочтем фат
	if (ulls != m_ImgFile.Seek(ulls, CFile::begin))
	{
		m_nLastErrorNumber = IMAGE_ERROR_CANNOT_SEEK_FILE;
		return FALSE;
	}

	if ((int)m_ImgFile.Read(m_pFatTbl, m_nFatSize) != m_nFatSize)
	{
		m_nLastErrorNumber = IMAGE_ERROR_CANNOT_READ_FILE;
		return FALSE;
	}

	//Перемещаемся к началу каталога и читаем каталог
	ulls = m_sPImg.nBaseOffset + m_nRootSectorOffset;

	if (ulls != m_ImgFile.Seek(ulls, CFile::begin))
	{
		m_nLastErrorNumber = IMAGE_ERROR_CANNOT_SEEK_FILE;
		return FALSE;
	}

	if ((int)m_ImgFile.Read(m_pCatTbl, m_nRootSize) != m_nRootSize)
	{
		m_nLastErrorNumber = IMAGE_ERROR_CANNOT_READ_FILE;
		return FALSE;
	}
	//теперь наш каталог представим в виде записей
	AndosFileRecord *pCat = reinterpret_cast<AndosFileRecord *>(m_pCatTbl);
	FileRecord curr_fr;
	CString ext;
	//каталог занимает m_nRootFilesNum/16 секторов, длина записи 32. байта, макс кол-во записей m_nRootFilesNum
	int free_recs = m_nRootFilesNum;
	int used_size = 0;

	for (int rec_count = 0; rec_count < m_nRootFilesNum; rec_count++)
	{
		if (pCat[rec_count].name[0] == 0)
		{
			break; //теоретически это вообще конец каталога
		}

		//опять же выяснилось, 0 - не гарантия конца каталога, возможно где-то есть счётчик файлов в каталоге,
		//а возможно мне попался просто образ с ошибками в фс.
		//потому что если в области каталога будет мусор, то он будет выводиться в каталог.
		curr_fr.clear();

		if (pCat[rec_count].name[0] == 0345)
		{
			curr_fr.nAttr |= FR_ATTR_DELETED;
			free_recs++;
		}

		free_recs--;

		if (pCat[rec_count].dir_num)
		{
			//если каталог
			curr_fr.nAttr |= FR_ATTR_DIR;
			curr_fr.nRecType = RECORD_TYPE_DIR;
			curr_fr.strName = BKToUNICODE((BYTE *)pCat[rec_count].name, 8).Trim() + BKToUNICODE((BYTE *)pCat[rec_count].ext, 3).Trim();
			curr_fr.nDirDir = pCat[rec_count].dir_num;
			curr_fr.nDirNum = pCat[rec_count].parent_dir_num;
			curr_fr.nBlkSize = 0;
		}
		else
		{
			//если файл
			curr_fr.nRecType = RECORD_TYPE_FILE;
			curr_fr.strName = BKToUNICODE((BYTE *)pCat[rec_count].name, 8).Trim();
			ext = BKToUNICODE((BYTE *)pCat[rec_count].ext, 3).Trim();

			if (!ext.IsEmpty())
			{
				curr_fr.strName += _T(".") + ext;
			}

			curr_fr.nDirDir = 0;
			curr_fr.nDirNum = pCat[rec_count].parent_dir_num;
			//посчитаем занятое пространство в кластерах.
			curr_fr.nBlkSize = (pCat[rec_count].length) ? ((((pCat[rec_count].length - 1) | (m_nClusterSize - 1)) + 1) / m_nClusterSize) : 0;

			if (curr_fr.nAttr & FR_ATTR_DELETED)
			{
				curr_fr.strName.SetAt(0, _T('x'));
			}
			else
			{
				used_size += curr_fr.nBlkSize;
			}
		}

		curr_fr.nAddress = pCat[rec_count].address;
		curr_fr.nSize = pCat[rec_count].length;
		curr_fr.nStartSector = pCat[rec_count].first_cluster;
		curr_fr.nSpecificData = pCat[rec_count].date;
		m_sDiskCat.vecFC.push_back(curr_fr);
	}

	m_sDiskCat.nTotalRecs = m_nRootFilesNum;
	m_sDiskCat.nFreeRecs = free_recs; //сколько свободных записей в каталоге
	m_sDiskCat.nTotalBlocks = (*(WORD *)&m_mSector[023] - m_nDataSectorOffset / m_nSectorSize) / m_nClusterSectors;
	m_sDiskCat.nFreeBlocks = m_sDiskCat.nTotalBlocks - used_size;
	return TRUE;
}

CString CBKDAndos::GetInfo()
{
	CString str, strf;
	strf.LoadString(IDS_INFO_FREE_CLUS);
	unsigned int bytes = (unsigned int)m_sDiskCat.nFreeBlocks * m_nClusterSize;
	unsigned int totalbytes = (unsigned int)m_sDiskCat.nTotalBlocks * m_nClusterSize;
	str.Format(strf, (unsigned int)m_sDiskCat.nFreeRecs, tblStrRec[GetWordEndIdx((unsigned int)m_sDiskCat.nFreeRecs)],
	           (unsigned int)m_sDiskCat.nTotalRecs,
	           (unsigned int)m_sDiskCat.nFreeBlocks, tblStrBlk[GetWordEndIdx((unsigned int)m_sDiskCat.nFreeBlocks)],
	           bytes, tblStrBlk[GetWordEndIdx(bytes)],
	           (unsigned int)m_sDiskCat.nTotalBlocks, totalbytes);
	return str;
}

int CBKDAndos::GetNextFat(int fat)
{
	/*
	0  1  2  3  4  5  6  7  8  9
	xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
	0 1 2 3 4 5 6 7 8 9 0 1 2 3 4
	0                   1
	fat*3/2
	0 1 2 3 4 5 6 7  8
	0 1 3 4 6 7 9 10 12
	*/
	int num = fat * 3 / 2;
	int val = *(WORD *)&m_pFatTbl[num];

	if (fat & 1)
	{
		//если номер нечётный, взять старшие 12 бит
		val >>= 4;
	}

	//если номер чётный, взять мл 12 бит
	return (val & 0xfff);
}

//ищем свободную ячейку от текущей (которая в качестве параметра)
int CBKDAndos::FindFreeFat(int fat)
{
	WORD val;
	int num = fat * 3 / 2;

	while (num < (m_nFatSize - 1))
	{
		val = *(WORD *)&m_pFatTbl[num];

		if (fat & 1)
		{
			//если номер нечётный, взять старшие 12 бит
			val >>= 4;
		}

		val &= 0xfff;

		if (val == 0)
		{
			//нашли пустую ячейку
			return fat;
		}

		fat++;
		num = fat * 3 / 2;
	}

	return -1;
}
//устанавливаем значение ячейки фат, возвращаем прошлое значение
WORD CBKDAndos::SetFat(int fat, WORD val)
{
	int num = fat * 3 / 2;
	WORD cval = *(WORD *)&m_pFatTbl[num];
	val &= 0xfff;

	if (fat & 1)
	{
		*(WORD *)&m_pFatTbl[num] = (cval & 0x000f) | (val << 4);
		cval >>= 4;
	}
	else
	{
		*(WORD *)&m_pFatTbl[num] = (cval & 0xf000) | val;
	}

	return (cval & 0xfff);
}

BOOL CBKDAndos::ExtractFile(FileRecord *sFile, BOOL bExtractAsBin, BOOL bExtractLog)
{
	m_nLastErrorNumber = IMAGE_ERROR_OK;
	BOOL bRet = TRUE;

	//если плохой или удалённый или директория - ничего не делаем
	if (sFile->nAttr & (FR_ATTR_BAD | FR_ATTR_DIR))
	{
		return bRet;
	}

	AnalyseFileStr sAFS;
	sAFS.bUseAsBin = bExtractAsBin;
	sAFS.nAddr = sFile->nAddress;
	sAFS.nLen = sFile->nSize;
	sAFS.strName = sFile->strName;
	SetSafeName(sAFS.strName);
	sAFS.strName += ((bExtractAsBin) ? _T(".bin") : _T(""));

	if (sAFS.file.Open(m_strStorePath + sAFS.strName, CFile::modeCreate | CFile::modeReadWrite))
	{
		m_currFat = sFile->nStartSector;
		int len = sFile->nSize;
		int out_len;

		if (bExtractAsBin)
		{
			m_mBinHeader[0] = (WORD)sFile->nAddress;
			m_mBinHeader[1] = (WORD)sFile->nSize; //и размер файла, если было больше 64кб, тут усекается.
			sAFS.file.Write(m_mBinHeader, sizeof(m_mBinHeader));
		}

		while ((len > 0) && ((1 < m_currFat) && (m_currFat < 07760)))
		{
			bRet = SeekToCluster(&m_ImgFile);

			if (!bRet)
			{
				break;
			}

			//читаем всегда покластерно
			m_ImgFile.Read(&m_mBlock, m_nClusterSize);  //если m_nClusterSize будет больше COPY_BLOCK_SIZE, то будет облом
			//но если в конце кластер неполон, нужно взять только нужную часть
			out_len = (len >= m_nClusterSize) ? m_nClusterSize : len;
			len -= out_len;
			sAFS.file.Write(&m_mBlock, out_len);
			m_currFat = GetNextFat(m_currFat);
		}

		if (bRet)
		{
			if (bExtractLog)
			{
				bRet = AnalyseExportFile(&sAFS);
			}
		}

		sAFS.file.Close();
	}
	else
	{
		m_nLastErrorNumber = IMAGE_ERROR_FILE_CANNOT_CREATE;
		bRet = FALSE;
	}

	return bRet;
}

/*
 *выход: TRUE - успешно
 *      FALSE - ошибка
*/
BOOL CBKDAndos::SeekToCluster(CFile *f)
{
	BOOL bRet = TRUE;
	m_nLenClust = m_nClusterSize;

	if ((1 < m_currFat) && (m_currFat < 07760))
	{
		int sector = m_nDataSectorOffset + (m_currFat - 2) * m_nClusterSize;
		m_tPos = f->Seek(m_sPImg.nBaseOffset + sector, CFile::begin);

		if (m_tPos != m_sPImg.nBaseOffset + sector)
		{
			m_nLastErrorNumber = IMAGE_ERROR_CANNOT_SEEK_FILE;
			bRet = FALSE;
		}
	}
	else
	{
		m_tPos = -1;
	}

	return bRet;
}

int CBKDAndos::SeekToPos(CFile *f, int pos)
{
	//если позиция больше чем размер кластера, сперва перемещаемся по кластерам
	while (pos > m_nClusterSize)
	{
		pos -= m_nClusterSize;
		m_currFat = GetNextFat(m_currFat);
		m_tLen -= m_nClusterSize;
	}

	SeekToCluster(f);

	//теперь переместимся в пределах кластера
	if (m_tPos + pos != m_ImgFile.Seek(m_tPos + pos, CFile::begin))
	{
		m_nLastErrorNumber = IMAGE_ERROR_CANNOT_SEEK_FILE;
	}

	m_nLenClust -= pos;
	return m_tLen - pos;
}

/*
 *выход: TRUE - успешно
 *      FALSE - ошибка
*/
BOOL CBKDAndos::SeekToBeginFile(CFile *f, FileRecord *fr)
{
	m_currFat = fr->nStartSector;
	return SeekToCluster(f);
}

BYTE CBKDAndos::GetByte(CFile *f, int *len)
{
	BYTE b = CBKDImage::GetByte(f, len);
	m_nLenClust -= sizeof(b); //уменьшаем счётчик байтов в кластере

	if (m_nLenClust <= 0)
	{
		//пора переходить к следующему кластеру
		m_currFat = GetNextFat(m_currFat);
		SeekToCluster(f);
	}

	return b;
}

WORD CBKDAndos::GetWord(CFile *f, int *len)
{
	WORD w = CBKDImage::GetWord(f, len);
	m_nLenClust -= sizeof(w); //уменьшаем счётчик байтов в кластере

	if (m_nLenClust <= 0)
	{
		//пора переходить к следующему кластеру
		m_currFat = GetNextFat(m_currFat);
		SeekToCluster(f);
	}

	return w;
}

FILESAVE_STATUS CBKDAndos::AddFile(const CString &str, int nDirNum, BOOL bAddAsBin)
{
	m_nLastErrorNumber = IMAGE_ERROR_OK;

	if (m_bFileROMode)
	{
		//Если образ открылся только для чтения,
		return FS_IMAGE_RO; //то записать в него мы ничего не сможем.
	}

	FILESAVE_STATUS bRet = FS_IO_ERROR;
	AnalyseFileStr sAFS;
	sAFS.bUseAsBin = bAddAsBin;
	int CatOffs = 0; //смещение в массиве каталога, до первой найденной свободной записи.
	AndosFileRecord aFR;

	if (sAFS.file.Open(str, CFile::modeRead | CFile::shareDenyWrite))
	{
		if (!AnalyseImportFile(&sAFS))
		{
			return FS_FILE_OPENERR;
		}

		UNICODEtoBK(sAFS.strName, aFR.name, 8, TRUE);
		UNICODEtoBK(sAFS.strExt, aFR.ext, 3, TRUE);
		aFR.parent_dir_num = nDirNum; //номер текущего открытого подкаталога
		aFR.address = sAFS.nAddr; //возможно, если мы сохраняем бин файл, адрес будет браться оттуда
		/*  формат даты. биты 0-4 - день месяца 1-31;
		биты 5-8 – месяц года, допускаются значения 1-12;
		биты 9-15 – год, считая от 1980 г. («эпоха MS-DOS»), возможны значения от 0 до 127 включительно, т.е. 1980-2107 гг.
		*/
		CFileStatus status;
		sAFS.file.GetStatus(status);
		aFR.date = (status.m_ctime.GetDay() & 037) | ((status.m_ctime.GetMonth() & 017) << 5) | ((status.m_ctime.GetYear() - 1980) << 9);
		aFR.length = sAFS.nLen;

		if (m_sDiskCat.nFreeBlocks * m_nClusterSize < ((sAFS.nLen) ? (((sAFS.nLen - 1) | (m_nClusterSize - 1)) + 1) : 0))
		{
			sAFS.file.Close();
			return FS_DISK_FULL;
		}
	}
	else
	{
		m_nLastErrorNumber = IMAGE_ERROR_FILE_CANNOT_OPEN;
		return FS_FILE_OPENERR;
	}

	AndosFileRecord *pCat = reinterpret_cast<AndosFileRecord *>(m_pCatTbl);
	/*
	1. прочитать фат и каталог.
	2. найти в каталоге свободное место
	3. если нашлось, убедиться, что на диске достаточно свободного места
	4. если всё нормально, покластерно сохранить файл
	5. создать запись о файле, в текущей директории
	6. сохранить фат и каталог.
	*/
	//Перемещаемся к 1му сектору
	ULONGLONG ulls = m_sPImg.nBaseOffset + m_nBootSectors * m_nSectorSize;

	if (ulls == m_ImgFile.Seek(ulls, CFile::begin))
	{
		//прочтем фат
		if (m_nFatSize == m_ImgFile.Read(m_pFatTbl, m_nFatSize))
		{
			//Перемещаемся к 5му сектору
			ulls = m_sPImg.nBaseOffset + m_nRootSectorOffset;

			if (ulls == m_ImgFile.Seek(ulls, CFile::begin))
			{
				//прочтем каталог
				if (m_nRootSize == m_ImgFile.Read(m_pCatTbl, m_nRootSize))
				{
					//поищем, вдруг такое имя файла уже существует.
					int tc = 0;
					BOOL bFound = FindRecord(pCat, aFR, FALSE, tc);

					if (bFound)
					{
						bRet = FS_FILE_EXIST;
					}
					else
					{
						//найдём свободное место в каталоге.
						bFound = FALSE;

						for (CatOffs = 0; CatOffs < m_nRootFilesNum; CatOffs++)
						{
							if ((pCat[CatOffs].name[0] == 0345) || (pCat[CatOffs].name[0] == 0))
							{
								bFound = TRUE;
								break;
							}
						}

						if (bFound)
						{
							//можно сохранять
							m_currFat = 1;
							BOOL bErr = FALSE;
							int nPrevFat = 0;

							do
							{
								m_currFat = FindFreeFat(m_currFat + 1); //если искать от текущего, то мы дважды будем считать

								// один и тот же кластер, т.к. он заполнится только после того как будет найден следующий
								if (m_currFat == -1)
								{
									bErr = TRUE;
									break;
								}

								if (nPrevFat == 0)
								{
									aFR.first_cluster = m_currFat;
								}
								else
								{
									SetFat(nPrevFat, m_currFat);
								}

								nPrevFat = m_currFat;
								bErr = !SeekToCluster(&m_ImgFile);
								memset(m_mBlock, 0, m_nClusterSize); //сделано чтобы хвост последнего кластера не заполнялся мусором от предыдущего, если размер данных меньше размера кластера
								sAFS.file.Read(m_mBlock, m_nClusterSize); //прочесть можем и меньше чем кластер
								m_ImgFile.Write(m_mBlock, m_nClusterSize); //пишем по любому покластерно.
								sAFS.nLen -= m_nClusterSize;
							}
							while (sAFS.nLen > 0);

							if (bErr)
							{
								bRet = FS_STRUCT_ERR;
							}
							else
							{
								SetFat(nPrevFat, 07777);
								bRet = FS_NO_ERROR;
							}
						}
						else
						{
							bRet = FS_CAT_FULL;
						}
					}
				}
				else
				{
					m_nLastErrorNumber = IMAGE_ERROR_CANNOT_READ_FILE;
				}
			}
			else
			{
				m_nLastErrorNumber = IMAGE_ERROR_CANNOT_SEEK_FILE;
			}
		}
		else
		{
			m_nLastErrorNumber = IMAGE_ERROR_CANNOT_READ_FILE;
		}
	}
	else
	{
		m_nLastErrorNumber = IMAGE_ERROR_CANNOT_SEEK_FILE;
	}

	sAFS.file.Close();

	if (bRet == FS_NO_ERROR)
	{
		//если ошибок не произошло, сохраним результаты
		m_ImgFile.Seek(m_sPImg.nBaseOffset + m_nBootSectors * m_nSectorSize, CFile::begin); //перейдём к началу фат
		m_ImgFile.Write(m_pFatTbl, m_nFatSize); //сохраним первую копию фат
		m_ImgFile.Write(m_pFatTbl, m_nFatSize); //сохраним вторую копию фат
		pCat[CatOffs] = aFR;
		m_ImgFile.Write(m_pCatTbl, m_nRootSize); //сохраним каталог
	}

	return bRet;
}

CString CBKDAndos::GetSpecificData(DWORD dd)
{
	CString str;

	if (dd == 0)
	{
		str = _T("");
	}
	else
	{
		int nDay = dd & 0x1f;
		int nMon = (dd >> 5) & 0xf;
		int nYear = ((dd >> 9) & 0x7f) + 1980;
		str.Format(_T("%02d.%02d.%04d"), nDay, nMon, nYear);
	}

	return str;
}

/*
поиск записи в каталоге.
вход:   pCat - указатель на массив каталога
aFR - искомая запись
bFull - FALSE - сравнивать только по имени, TRUE - ещё и по кластеру/адресу/длине/каталогу

выход:  TRUE - нашлось, FALSE - не нашлось
tc - индекс в массиве pCat
*/
BOOL CBKDAndos::FindRecord(AndosFileRecord *pCat, AndosFileRecord &aFR, BOOL bFull, int &tc)
{
	BOOL bFound = FALSE;

	for (tc = 0; tc < m_nRootFilesNum; tc++)
	{
		if (pCat[tc].name[0] == 0)
		{
			break;    //конец каталога
		}

		if (!memcmp((char *)aFR.name, (char *)pCat[tc].name, 11))
		{
			if (bFull) //если полная проверка
			{
				//кроме имени проверим и остальные записи
				if ((pCat[tc].address == aFR.address) &&
				        (pCat[tc].first_cluster == aFR.first_cluster) &&
				        (pCat[tc].length == aFR.length) &&
				        (pCat[tc].parent_dir_num = aFR.parent_dir_num)
				   )
				{
					bFound = TRUE;
					break;
				}
			}
			else
			{
				bFound = TRUE;
				break;
			}
		}
	}

	return bFound;
}

BOOL CBKDAndos::DeleteFile(FileRecord *sFile)
{
	m_nLastErrorNumber = IMAGE_ERROR_OK;
	BOOL bRet = FALSE;

	if (m_bFileROMode)
	{
		//Если образ открылся только для чтения,
		m_nLastErrorNumber = IMAGE_ERROR_CANNOT_WRITE_FILE;
		return bRet; //то записать в него мы ничего не сможем.
	}

	AndosFileRecord aFR;
	//преобразование FileRecord в AndosFileRecord
	CString name = sFile->strName;
	CString ext = _T("");
	int l = name.GetLength();
	int t = name.ReverseFind(_T('.'));

	if (t >= 0) //если расширение есть
	{
		ext = name.Right(l - t - 1);
		name = name.Left(t);
	}

	UNICODEtoBK(name, aFR.name, 8, TRUE);
	UNICODEtoBK(ext, aFR.ext, 3, TRUE);
	aFR.dir_num = sFile->nDirDir;
	aFR.parent_dir_num = sFile->nDirNum;
	aFR.address = sFile->nAddress;
	aFR.date = LOWORD(sFile->nSpecificData);
	aFR.first_cluster = sFile->nStartSector;
	aFR.length = sFile->nSize;
	/*
	Для удаления файла надо:
	1. Прочитать каталог
	2. Прочитать ФАТ
	3. Найти запись в каталоге
	4. Удалить цепочку ФАТ
	5. Пометить запись как удалённую
	6. Сохранить ФАТ
	7. Сохранить каталог.
	*/
	AndosFileRecord *pCat = reinterpret_cast<AndosFileRecord *>(m_pCatTbl);
	//Перемещаемся к 1му сектору
	ULONGLONG ulls = m_sPImg.nBaseOffset + m_nBootSectors * m_nSectorSize;

	if (ulls == m_ImgFile.Seek(ulls, CFile::begin))
	{
		//прочтем фат
		if (m_nFatSize == m_ImgFile.Read(m_pFatTbl, m_nFatSize))
		{
			//Перемещаемся к 5му сектору
			ULONGLONG ulls1 = m_sPImg.nBaseOffset + m_nRootSectorOffset;

			if (ulls1 == m_ImgFile.Seek(ulls1, CFile::begin))
			{
				//прочтем каталог
				if (m_nRootSize == m_ImgFile.Read(m_pCatTbl, m_nRootSize))
				{
					int tc = 0;
					BOOL bFound = FindRecord(pCat, aFR, TRUE, tc);

					if (bFound)
					{
						WORD vfat = aFR.first_cluster; //удаляем цепочку ФАТ

						do
						{
							vfat = SetFat(vfat, 0);
						}
						while (vfat < 07760);

						pCat[tc].name[0] = 0345; //пометим запись как удалённую
						m_ImgFile.Seek(ulls, CFile::begin); //перейдём к началу фат
						m_ImgFile.Write(m_pFatTbl, m_nFatSize); //сохраним первую копию фат
						m_ImgFile.Write(m_pFatTbl, m_nFatSize); //сохраним вторую копию фат
						m_ImgFile.Write(m_pCatTbl, m_nRootSize); //сохраним каталог
						bRet = TRUE;
					}
				}
				else
				{
					m_nLastErrorNumber = IMAGE_ERROR_CANNOT_READ_FILE;
				}
			}
			else
			{
				m_nLastErrorNumber = IMAGE_ERROR_CANNOT_SEEK_FILE;
			}
		}
		else
		{
			m_nLastErrorNumber = IMAGE_ERROR_CANNOT_READ_FILE;
		}
	}
	else
	{
		m_nLastErrorNumber = IMAGE_ERROR_CANNOT_SEEK_FILE;
	}

	return bRet;
}
