Пример #1
0
void DirectoryRead(Directory* dir) {
    char* buffer = new char[bpb->bytesPerSector];

    FatEntry fatEntry;
    fatEntry.buffer = new char[bpb->bytesPerSector];
    fatEntry.cluster = dir->cluster;
    fatEntry.sector = GetFATSector(fatEntry.cluster);
    ReadSector(fatEntry.buffer, fatEntry.sector);

    Sector* sector;
    while (ReadCluster(&fatEntry, buffer)) {
        // Allocate a new sector
        sector = new Sector;
        sector->buffer = new char[512];
        sector->sector = ClusterToSector(fatEntry.cluster);
        memcpy(sector->buffer, buffer, 512);

        // Add to list
        directory.sectors[directory.count] = sector;
        directory.count++;
    }

    // Allocate a new sector
    sector = new Sector;
    sector->buffer = new char[512];
    sector->sector = ClusterToSector(fatEntry.cluster);
    memcpy(sector->buffer, buffer, 512);

    // Add to list
    directory.sectors[directory.count] = sector;
    directory.count++;

    delete[] buffer;
    delete[] fatEntry.buffer;
}
Пример #2
0
bool ReadCluster(FatEntry* entry, char* buffer) {
    // Load FAT sector if needed - Update FatEntry sector
    if (entry->sector != GetFATSector(entry->cluster)) {
        entry->sector = GetFATSector(entry->cluster);
        ReadSector(entry->buffer, entry->sector);
    }

    // Check if we're done
    if (*(uint32_t*)(entry->buffer + GetFATOffset(entry->cluster)) >= FAT_EOF) {
        ReadSector(buffer, ClusterToSector(entry->cluster));
        return false;
    }

    // Read sector 
    ReadSector(buffer, ClusterToSector(entry->cluster));

    // Update cluster
    entry->cluster = *(uint32_t*)(entry->buffer + GetFATOffset(entry->cluster));

    return true;
}
Пример #3
0
exp bool Open(const char* fname, unsigned int pO, unsigned int pLen) {
    partitionOffset = pO;
    partitionLength = pLen;

    // Open the image
    f.open(fname, std::ios::in | std::ios::out | std::ios::binary);

    if (!f.is_open()) {
        LastError("Open", "Failed to open disk");
        return false;
    }

    f.seekg(0, std::ios::end);
    fsize = (size_t)f.tellg();
    f.seekg(0);

    // Allocate a buffer
    sectorBuffer = new char[SECTOR_SIZE];

    // Read the BPB
    if (!ReadBPB()) {
        LastError("Open", "Failed to read the BPB");
        return false;
    }

    // Read filesystem info
    fsInfo = new FileSystemInfo;
    ReadSector((char*)fsInfo, bpb->clusterFSInfo);

    // Load the root directory
    if (!DirOpenRoot()) {
        LastError("Open", "Failed to load the root directory");
        return false;
    }

    volumeId = new char[DOS83_MAX_LEN + 1];
    ReadSector(sectorBuffer, ClusterToSector(bpb->clusterRoot));
    DirectoryEntry* entry = FindEntryAttribute(ATTRIB_VOLUME_ID, &directory);
    if (entry) {
        memcpy(volumeId, entry->name, DOS83_MAX_LEN);
        volumeId[11] = 0;
    }

    return true;
}
Пример #4
0
bool WriteCluster(FatEntry* fatEntry, char* buffer) {
    // Load FAT sector if needed - Update FatEntry sector
    if (fatEntry->sector != GetFATSector(fatEntry->cluster)) {
        fatEntry->sector = GetFATSector(fatEntry->cluster);
        ReadSector(fatEntry->buffer, fatEntry->sector);
    }

    // Write that sector
    WriteSector(buffer, ClusterToSector(fatEntry->cluster));

    // Find a new cluster
    uint32_t tmpCluster = FindFreeCluster();

    UpdateFAT(fatEntry, tmpCluster);
    fatEntry->cluster = tmpCluster;

    fsInfo->nextFreeCluster = tmpCluster;
    fsInfo->freeClusterCount--;

    return true;
}
Пример #5
0
static
NTSTATUS
VfatWriteFileData(
    PVFAT_IRP_CONTEXT IrpContext,
    ULONG Length,
    LARGE_INTEGER WriteOffset)
{
    PDEVICE_EXTENSION DeviceExt;
    PVFATFCB Fcb;
    ULONG Count;
    ULONG FirstCluster;
    ULONG CurrentCluster;
    ULONG BytesDone;
    ULONG StartCluster;
    ULONG ClusterCount;
    NTSTATUS Status = STATUS_SUCCESS;
    BOOLEAN First = TRUE;
    ULONG BytesPerSector;
    ULONG BytesPerCluster;
    LARGE_INTEGER StartOffset;
    ULONG BufferOffset;
    ULONG LastCluster;
    ULONG LastOffset;

    /* PRECONDITION */
    ASSERT(IrpContext);
    DeviceExt = IrpContext->DeviceExt;
    ASSERT(DeviceExt);
    ASSERT(DeviceExt->FatInfo.BytesPerCluster);
    ASSERT(IrpContext->FileObject);
    ASSERT(IrpContext->FileObject->FsContext2 != NULL);

    Fcb = IrpContext->FileObject->FsContext;
    BytesPerCluster = DeviceExt->FatInfo.BytesPerCluster;
    BytesPerSector = DeviceExt->FatInfo.BytesPerSector;

    DPRINT("VfatWriteFileData(DeviceExt %p, FileObject %p, "
           "Length %u, WriteOffset 0x%I64x), '%wZ'\n", DeviceExt,
           IrpContext->FileObject, Length, WriteOffset.QuadPart,
           &Fcb->PathNameU);

    ASSERT(WriteOffset.QuadPart + Length <= Fcb->RFCB.AllocationSize.QuadPart);
    ASSERT(WriteOffset.u.LowPart % BytesPerSector == 0);
    ASSERT(Length % BytesPerSector == 0);

    /* Is this a write of the volume? */
    if (Fcb->Flags & FCB_IS_VOLUME)
    {
        Status = VfatWriteDiskPartial(IrpContext, &WriteOffset, Length, 0, TRUE);
        if (!NT_SUCCESS(Status))
        {
            DPRINT1("Volume writing failed, Status %x\n", Status);
        }
        return Status;
    }

    /* Is this a write to the FAT? */
    if (Fcb->Flags & FCB_IS_FAT)
    {
        WriteOffset.u.LowPart += DeviceExt->FatInfo.FATStart * BytesPerSector;
        IrpContext->RefCount = 1;
        for (Count = 0; Count < DeviceExt->FatInfo.FATCount; Count++)
        {
            Status = VfatWriteDiskPartial(IrpContext, &WriteOffset, Length, 0, FALSE);
            if (!NT_SUCCESS(Status) && Status != STATUS_PENDING)
            {
                DPRINT1("FAT writing failed, Status %x\n", Status);
                break;
            }
            WriteOffset.u.LowPart += Fcb->RFCB.FileSize.u.LowPart;
        }

        if (InterlockedDecrement((PLONG)&IrpContext->RefCount) != 0)
        {
            KeWaitForSingleObject(&IrpContext->Event, Executive, KernelMode, FALSE, NULL);
        }

        if (NT_SUCCESS(Status) || Status == STATUS_PENDING)
        {
            Status = IrpContext->Irp->IoStatus.Status;
        }
        return Status;
    }

    /*
     * Find the first cluster
     */
    FirstCluster =
    CurrentCluster = vfatDirEntryGetFirstCluster (DeviceExt, &Fcb->entry);

    if (FirstCluster == 1)
    {
        ASSERT(WriteOffset.u.LowPart + Length <= DeviceExt->FatInfo.rootDirectorySectors * BytesPerSector);
        // Directory of FAT12/16 needs a special handling
        WriteOffset.u.LowPart += DeviceExt->FatInfo.rootStart * BytesPerSector;
        // Fire up the write command
        Status = VfatWriteDiskPartial (IrpContext, &WriteOffset, Length, 0, TRUE);
        return Status;
    }

    ExAcquireFastMutex(&Fcb->LastMutex);
    LastCluster = Fcb->LastCluster;
    LastOffset = Fcb->LastOffset;
    ExReleaseFastMutex(&Fcb->LastMutex);

    /*
     * Find the cluster to start the write from
     */
    if (LastCluster > 0 && WriteOffset.u.LowPart >= LastOffset)
    {
        Status = OffsetToCluster(DeviceExt, LastCluster,
                                 ROUND_DOWN(WriteOffset.u.LowPart, BytesPerCluster) -
                                 LastOffset,
                                 &CurrentCluster, FALSE);
#ifdef DEBUG_VERIFY_OFFSET_CACHING
        /* DEBUG VERIFICATION */
        {
            ULONG CorrectCluster;
            OffsetToCluster(DeviceExt, FirstCluster,
                            ROUND_DOWN(WriteOffset.u.LowPart, BytesPerCluster),
                            &CorrectCluster, FALSE);
            if (CorrectCluster != CurrentCluster)
                KeBugCheck(FAT_FILE_SYSTEM);
        }
#endif
    }
    else
    {
        Status = OffsetToCluster(DeviceExt, FirstCluster,
                                 ROUND_DOWN(WriteOffset.u.LowPart, BytesPerCluster),
                                 &CurrentCluster, FALSE);
    }

    if (!NT_SUCCESS(Status))
    {
        return Status;
    }

    ExAcquireFastMutex(&Fcb->LastMutex);
    Fcb->LastCluster = CurrentCluster;
    Fcb->LastOffset = ROUND_DOWN (WriteOffset.u.LowPart, BytesPerCluster);
    ExReleaseFastMutex(&Fcb->LastMutex);

    IrpContext->RefCount = 1;
    BufferOffset = 0;

    while (Length > 0 && CurrentCluster != 0xffffffff)
    {
        StartCluster = CurrentCluster;
        StartOffset.QuadPart = ClusterToSector(DeviceExt, StartCluster) * BytesPerSector;
        BytesDone = 0;
        ClusterCount = 0;

        do
        {
            ClusterCount++;
            if (First)
            {
                BytesDone =  min (Length, BytesPerCluster - (WriteOffset.u.LowPart % BytesPerCluster));
                StartOffset.QuadPart += WriteOffset.u.LowPart % BytesPerCluster;
                First = FALSE;
            }
            else
            {
                if (Length - BytesDone > BytesPerCluster)
                {
                    BytesDone += BytesPerCluster;
                }
                else
                {
                    BytesDone = Length;
                }
            }
            Status = NextCluster(DeviceExt, FirstCluster, &CurrentCluster, FALSE);
        }
        while (StartCluster + ClusterCount == CurrentCluster && NT_SUCCESS(Status) && Length > BytesDone);
        DPRINT("start %08x, next %08x, count %u\n",
               StartCluster, CurrentCluster, ClusterCount);

        ExAcquireFastMutex(&Fcb->LastMutex);
        Fcb->LastCluster = StartCluster + (ClusterCount - 1);
        Fcb->LastOffset = ROUND_DOWN(WriteOffset.u.LowPart, BytesPerCluster) + (ClusterCount - 1) * BytesPerCluster;
        ExReleaseFastMutex(&Fcb->LastMutex);

        // Fire up the write command
        Status = VfatWriteDiskPartial (IrpContext, &StartOffset, BytesDone, BufferOffset, FALSE);
        if (!NT_SUCCESS(Status) && Status != STATUS_PENDING)
        {
            break;
        }
        BufferOffset += BytesDone;
        Length -= BytesDone;
        WriteOffset.u.LowPart += BytesDone;
    }

    if (InterlockedDecrement((PLONG)&IrpContext->RefCount) != 0)
    {
        KeWaitForSingleObject(&IrpContext->Event, Executive, KernelMode, FALSE, NULL);
    }

    if (NT_SUCCESS(Status) || Status == STATUS_PENDING)
    {
        if (Length > 0)
        {
            Status = STATUS_UNSUCCESSFUL;
        }
        else
        {
            Status = IrpContext->Irp->IoStatus.Status;
        }
    }
    return Status;
}
Пример #6
0
DualErr 
FatParser::MakeFatFrags()
{
	DualErr		derr;
	PGPUInt8	bitsClust, clustBias;
	PGPUInt16	blockSize, spc;
	PGPUInt32	bitOffset, clustSec, curClust, fatSize, firstSecFat;
	PGPUInt32	firstClustFile, firstSecFile, firstSecData, i, maxClust;
	PGPUInt32	minClust, totalClusts;

	pgpAssertAddrValid(mDataBuf, PGPUInt8);
	pgpAssert(mNumFragsInUse == 0);

	// First fill in some filesystem specific data.
	switch (mFsId)
	{
	case kFS_FAT12:
		bitsClust	= kBitsFat12Clust;
		clustBias	= kFat12ClustBias;
		maxClust	= kMaxFat12Clust;
		minClust	= kMinFat12Clust;
		break;

	case kFS_FAT16:
		bitsClust	= kBitsFat16Clust;
		clustBias	= kFat16ClustBias;
		maxClust	= kMaxFat16Clust;
		minClust	= kMinFat16Clust;
		break;

	case kFS_FAT32:
		bitsClust	= kBitsFat32Clust;
		clustBias	= kFat32ClustBias;
		maxClust	= kMaxFat32Clust;
		minClust	= kMinFat32Clust;
		break;

	default:
		pgpAssert(FALSE);
		break;
	}

	// Then fill in the data specific to this drive.
	blockSize		= mFat.fdBlockSize;
	fatSize			= mFat.fdFatSize;
	spc				= mFat.fdSpc;		
	firstSecData	= mFat.fdFirstSecData;
	firstClustFile	= mFat.fdFirstClustFile;
	firstSecFat		= mFat.fdFirstSecFat + mFat.fdActiveFat*fatSize;

	totalClusts = TotalClusters(fatSize, bitsClust, blockSize);

	DebugOut("PGPdisk: blockSize is %u", blockSize);
	DebugOut("PGPdisk: fatSize is %u", fatSize);
	DebugOut("PGPdisk: spc is %u", spc);
	DebugOut("PGPdisk: firstSecData is %u", firstSecData);
	DebugOut("PGPdisk: firstClustFile is %u", firstClustFile);
	DebugOut("PGPdisk: firstSecFat is %u", firstSecFat);

	pgpAssert(firstSecFat < firstSecData);
	pgpAssert(firstClustFile <= totalClusts);

	// Now we will calculate the index of the first sector on disk holding our
	// file's contents.

	firstSecFile = ClusterToSector(firstClustFile, firstSecData, spc, 
		clustBias);

	pgpAssert(firstSecFile >= firstSecData);

	// Init the first file fragment structure for the file.
	if (derr.IsntError())
	{
		i = 0;
		mNumFragsInUse = 1;

		InitFileFrag(&mFragArray[i], 0, (PGPUInt64) firstSecFile*blockSize);
	}

	// 'curClust' will keep track of the index of the current cluster we are
	// looking at. 'clustSec' and 'bitOffset' keep track of the sector in the
	// FAT table where this cluster is located, and the offset (in bits) into
	// that sector where the cluster begins.

	if (derr.IsntError())
	{
		curClust = firstClustFile;

		GetClusterInfo(firstSecFat, curClust, bitsClust, blockSize, &clustSec, 
			&bitOffset);

		// Before parsing the FAT table we read the current sector into a
		// buffer. WE MUST read in the extra sector because FAT12 clusters can
		// overrun the boundary.

		derr = mHost.Read(mDataBuf, clustSec, kFPDataBufSize + 1);
	}

	if (derr.IsntError())
	{
		ParseNextClusterInfo PNCI;

		PNCI.blockSize	= blockSize;
		PNCI.clustBias	= clustBias;
		PNCI.spc		= spc;

		PNCI.bitsClust		= bitsClust;
		PNCI.bitOffset		= bitOffset;
		PNCI.clustSec		= clustSec;
		PNCI.curClust		= curClust;
		PNCI.firstSecData	= firstSecData;
		PNCI.firstSecFat	= firstSecFat;
		PNCI.i				= i;
		PNCI.nextClust		= 
			ExtractCluster(mDataBuf, bitOffset, curClust, mFsId);
		PNCI.overFlow		= 0;
		PNCI.totalClusts	= totalClusts;

		// We now construct the file fragment list by parsing the FAT table.
		// Beginning with the first cluster of the file, we iterate over all
		// remaining clusters until finished.
		//
		// As long as the cluster two numbers, it refers to a valid cluster
		// index; else it means the file has ended.

		while (derr.IsntError() && (PNCI.nextClust >= minClust) && 
			(PNCI.nextClust <= maxClust))
		{
			derr = ParseNextCluster(&PNCI);
		}

		i = PNCI.i;
	}

	// The file has been completely parsed.
	if (derr.IsntError())
	{
		mFragArray[i].fileEnd	+= (spc*blockSize) - 1;
		mFragArray[i].diskEnd	+= (spc*blockSize) - 1;

		// Does combined size of the fragments agree with the actual file size?
		if ((mFragArray[i].fileEnd < (mBytesFile - spc*blockSize)) ||
			(mFragArray[i].fileEnd > (mBytesFile + spc*blockSize)))
		{
			derr = DualErr(kPGDMinorError_CorruptFat);
		}
	}

	if (derr.IsError())
	{
		mNumFragsInUse = 0;
	}

	return derr;
}
Пример #7
0
DualErr 
FatParser::ParseNextCluster(ParseNextClusterInfo *pPNCI)
{
	DualErr		derr;
	PGPUInt64	blockVolume;

	pgpAssertAddrValid(pPNCI, ParseNextClusterInfo);

	// Sanity checks.

	if ((pPNCI->curClust > pPNCI->totalClusts) || 
		((++pPNCI->overFlow) > kFPMaxLoops))
	{
		derr = DualErr(kPGDMinorError_CorruptFat);
	}

	// Check if we are still within the current fragment - that is, if the
	// next cluster is 1 greater than the current cluster. If not, create a
	// new file fragment.

	if (derr.IsntError())
	{
		if (pPNCI->nextClust == (pPNCI->curClust + 1))	// within fragment?
		{
			// We are not at the end of a fragment. First increment curClust
			// by 1, and expand our fragment by the size (in bytes) of 1
			// cluster.

			pPNCI->curClust++;
			mFragArray[pPNCI->i].fileEnd += pPNCI->spc * pPNCI->blockSize;
			mFragArray[pPNCI->i].diskEnd += pPNCI->spc * pPNCI->blockSize;

			// Next update the offset to point to the new current cluster's
			// data (which will hold the next cluster's index). If the offset
			// runs over our buffer size, we have to read in the next buffer.

			pPNCI->bitOffset += pPNCI->bitsClust;

			if (pPNCI->bitOffset >= 
				(PGPUInt32) kFPDataBufSize * pPNCI->blockSize * kBitsPerByte)
			{
				GetClusterInfo(pPNCI->firstSecFat, pPNCI->curClust, 
					pPNCI->bitsClust, pPNCI->blockSize, &pPNCI->clustSec, 
					&pPNCI->bitOffset);

				derr = mHost.Read(mDataBuf, pPNCI->clustSec, 
					kFPDataBufSize + 1);
			}
		}
		else
		{
			PGPUInt64 oldSector;

			// OK, we are at the end of a fragment. Set curClust to the index
			// of the new cluster (which can be any valid cluster index), and
			// expand the current fragment.

			pPNCI->curClust = pPNCI->nextClust;

			mFragArray[pPNCI->i].fileEnd += 
				(pPNCI->spc * pPNCI->blockSize) - 1;

			mFragArray[pPNCI->i].diskEnd += 
				(pPNCI->spc * pPNCI->blockSize) - 1;

			oldSector = pPNCI->clustSec;

			// Find the new FAT sector.
			GetClusterInfo(pPNCI->firstSecFat, pPNCI->curClust, 
				pPNCI->bitsClust, pPNCI->blockSize, &pPNCI->clustSec, 
				&pPNCI->bitOffset);

			// If this lies in a different sector, read it in.
			if (pPNCI->clustSec != oldSector)
			{
				derr = mHost.Read(mDataBuf, pPNCI->clustSec, 
					kFPDataBufSize + 1);
			}

			// Finally we calculate which sector on disk the new curClust
			// refers to, and then we init a new fragment

			if (derr.IsntError())
			{
				blockVolume = ClusterToSector(pPNCI->curClust, 
					pPNCI->firstSecData, pPNCI->spc, pPNCI->clustBias);

				// See if we have to allocate a new frag.
				if (pPNCI->i + 1 == mSizeFragArray)
					derr = ExpandFragArray();
			}

			// Init a new file fragment.
			if (derr.IsntError())
			{
				pPNCI->i++;
				mNumFragsInUse++;

				InitFileFrag(&mFragArray[pPNCI->i], 
					mFragArray[pPNCI->i - 1].fileEnd + 1, 
					blockVolume * pPNCI->blockSize);
			}
		}
	}

	// Extract the next cluster.
	pPNCI->nextClust = ExtractCluster(mDataBuf, pPNCI->bitOffset, 
		pPNCI->curClust, mFsId);

	return derr;
}