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; }
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; }
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; }
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; }
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; }
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; }
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; }