/** * @public * @brief Mounts and Image with FullFAT. * * **/ DLL_EXPORT int FFC_MountImage(char *szFilename, unsigned long ulBlockSize, unsigned long ulPartitionNumber) { FF_ERROR Error = FF_ERR_NONE; if(g_pIoman || g_hDisk) { return FFD_ERR_IMAGE_ALREADY_MOUNTED; } g_hDisk = fnOpen(szFilename, ulBlockSize); if(!g_hDisk) { return FFD_ERR_COULD_NOT_OPEN_IMAGE; } g_pIoman = FF_CreateIOMAN(NULL, 8192, GetBlockSize(g_hDisk), &Error); // Using the BlockSize from the Device Driver (see blkdev_win32.c) if(!g_pIoman) { return FFD_ERR_COULD_NOT_INITIALISE_FULLFAT; } else { Error = FF_RegisterBlkDevice(g_pIoman, GetBlockSize(g_hDisk), (FF_WRITE_BLOCKS) fnWrite, (FF_READ_BLOCKS) fnRead, g_hDisk); if(Error) { printError(Error); FF_DestroyIOMAN(g_pIoman); fnClose(g_hDisk); return -1; } // Attempt to mount! Error = FF_MountPartition(g_pIoman, (FF_T_UINT8) ulPartitionNumber); if(Error) { if(g_hDisk) { fnClose(g_hDisk); } FF_DestroyIOMAN(g_pIoman); g_pIoman = NULL; return -1; } g_Env.pIoman = g_pIoman; strcpy(g_Env.WorkingDir, "\\"); // Reset working dir! } return FFD_ERR_NONE; }
/** * @public * @brief Creates an FF_IOMAN object, to initialise FullFAT * * @param pCacheMem Pointer to a buffer for the cache. (NULL if ok to Malloc). * @param Size The size of the provided buffer, or size of the cache to be created. (Must be atleast 2 * BlkSize). Always a multiple of BlkSize. * @param BlkSize The block size of devices to be attached. If in doubt use 512. * @param pError Pointer to a signed byte for error checking. Can be NULL if not required. * @param pError To be checked when a NULL pointer is returned. * * @return Returns a pointer to an FF_IOMAN type object. NULL on Error, check the contents of * @return pError **/ FF_IOMAN *FF_CreateIOMAN(FF_T_UINT8 *pCacheMem, FF_T_UINT32 Size, FF_T_UINT16 BlkSize, FF_ERROR *pError) { FF_IOMAN *pIoman = NULL; FF_T_UINT32 *pLong = NULL; // Force malloc to malloc memory on a 32-bit boundary. #ifdef FF_PATH_CACHE FF_T_UINT32 i; #endif if(pError) { *pError = FF_ERR_NONE; } if((BlkSize % 512) != 0 || BlkSize == 0) { if(pError) { *pError = FF_ERR_IOMAN_BAD_BLKSIZE | FF_CREATEIOMAN; } return NULL; // BlkSize Size not a multiple of 512 > 0 } if((Size % BlkSize) != 0 || Size == 0 || Size == BlkSize) { // Size must now be atleast 2 * BlkSize (or a deadlock will occur). if(pError) { *pError = FF_ERR_IOMAN_BAD_MEMSIZE | FF_CREATEIOMAN; } return NULL; // Memory Size not a multiple of BlkSize > 0 } pIoman = (FF_IOMAN *) FF_MALLOC(sizeof(FF_IOMAN)); if(!pIoman) { // Ensure malloc() succeeded. if(pError) { *pError = FF_ERR_NOT_ENOUGH_MEMORY | FF_CREATEIOMAN; } return NULL; } memset (pIoman, '\0', sizeof(FF_IOMAN)); // This is just a bit-mask, to use a byte to keep track of memory. // pIoman->MemAllocation = 0x00; // Unset all allocation identifiers. pIoman->pPartition = (FF_PARTITION *) FF_MALLOC(sizeof(FF_PARTITION)); if(!pIoman->pPartition) { if(pError) { *pError = FF_ERR_NOT_ENOUGH_MEMORY | FF_CREATEIOMAN; } FF_DestroyIOMAN(pIoman); return NULL; } memset (pIoman->pPartition, '\0', sizeof(FF_PARTITION)); pIoman->MemAllocation |= FF_IOMAN_ALLOC_PART; // If succeeded, flag that allocation. pIoman->pPartition->LastFreeCluster = 0; pIoman->pPartition->PartitionMounted = FF_FALSE; // This should be checked by FF_Open(); #ifdef FF_PATH_CACHE pIoman->pPartition->PCIndex = 0; for(i = 0; i < FF_PATH_CACHE_DEPTH; i++) { pIoman->pPartition->PathCache[i].DirCluster = 0; pIoman->pPartition->PathCache[i].Path[0] = '\0'; /*#ifdef FF_HASH_TABLE_SUPPORT pIoman->pPartition->PathCache[i].pHashTable = FF_CreateHashTable(); pIoman->pPartition->PathCache[i].bHashed = FF_FALSE; #endif*/ } #endif #ifdef FF_HASH_CACHE for(i = 0; i < FF_HASH_CACHE_DEPTH; i++) { pIoman->HashCache[i].pHashTable = FF_CreateHashTable(); pIoman->HashCache[i].ulDirCluster = 0; pIoman->HashCache[i].ulMisses = 100; } #endif pIoman->pBlkDevice = (FF_BLK_DEVICE *) FF_MALLOC(sizeof(FF_BLK_DEVICE)); if(!pIoman->pBlkDevice) { // If succeeded, flag that allocation. if(pError) { *pError = FF_ERR_NOT_ENOUGH_MEMORY | FF_CREATEIOMAN; } FF_DestroyIOMAN(pIoman); return NULL; } memset (pIoman->pBlkDevice, '\0', sizeof(FF_BLK_DEVICE)); pIoman->MemAllocation |= FF_IOMAN_ALLOC_BLKDEV; // Make sure all pointers are NULL pIoman->pBlkDevice->fnpReadBlocks = NULL; pIoman->pBlkDevice->fnpWriteBlocks = NULL; pIoman->pBlkDevice->pParam = NULL; // Organise the memory provided, or create our own! if(pCacheMem) { pIoman->pCacheMem = pCacheMem; }else { // No-Cache buffer provided (malloc) pLong = (FF_T_UINT32 *) FF_MALLOC(Size); pIoman->pCacheMem = (FF_T_UINT8 *) pLong; if(!pIoman->pCacheMem) { if(pError) { *pError = FF_ERR_NOT_ENOUGH_MEMORY | FF_CREATEIOMAN; } FF_DestroyIOMAN(pIoman); return NULL; } pIoman->MemAllocation |= FF_IOMAN_ALLOC_BUFFERS; } memset (pIoman->pCacheMem, '\0', Size); pIoman->BlkSize = BlkSize; pIoman->CacheSize = (FF_T_UINT16) (Size / BlkSize); pIoman->FirstFile = NULL; pIoman->Locks = 0; /* Malloc() memory for buffer objects. (FullFAT never refers to a buffer directly but uses buffer objects instead. Allows us to provide thread safety. */ pIoman->pBuffers = (FF_BUFFER *) FF_MALLOC(sizeof(FF_BUFFER) * pIoman->CacheSize); if(!pIoman->pBuffers) { if(pError) { *pError = FF_ERR_NOT_ENOUGH_MEMORY | FF_CREATEIOMAN; } FF_DestroyIOMAN(pIoman); return NULL; // HT added } memset (pIoman->pBuffers, '\0', sizeof(FF_BUFFER) * pIoman->CacheSize); pIoman->MemAllocation |= FF_IOMAN_ALLOC_BUFDESCR; FF_IOMAN_InitBufferDescriptors(pIoman); // Finally create a Semaphore for Buffer Description modifications. pIoman->pSemaphore = FF_CreateSemaphore(); #ifdef FF_BLKDEV_USES_SEM pIoman->pBlkDevSemaphore = FF_CreateSemaphore(); #endif return pIoman; // Sucess, return the created object. }
NTSTATUS NTAPI FatMountVolume(PFAT_IRP_CONTEXT IrpContext, PDEVICE_OBJECT TargetDeviceObject, PVPB Vpb, PDEVICE_OBJECT FsDeviceObject) { NTSTATUS Status; DISK_GEOMETRY DiskGeometry; ULONG MediaChangeCount = 0; PVOLUME_DEVICE_OBJECT VolumeDevice; VCB *Vcb; FF_ERROR Error; PBCB BootBcb; PPACKED_BOOT_SECTOR BootSector; DPRINT1("FatMountVolume()\n"); /* Make sure this IRP is waitable */ ASSERT(IrpContext->Flags & IRPCONTEXT_CANWAIT); /* Request media changes count, mostly useful for removable devices */ Status = FatPerformDevIoCtrl(TargetDeviceObject, IOCTL_STORAGE_CHECK_VERIFY, NULL, 0, &MediaChangeCount, sizeof(ULONG), TRUE); if (!NT_SUCCESS(Status)) return Status; /* TODO: Check if data-track present in case of a CD drive */ /* TODO: IOCTL_DISK_GET_PARTITION_INFO_EX */ /* Remove unmounted VCBs */ FatiCleanVcbs(IrpContext); /* Acquire the global exclusive lock */ FatAcquireExclusiveGlobal(IrpContext); /* Create a new volume device object */ Status = IoCreateDevice(FatGlobalData.DriverObject, sizeof(VOLUME_DEVICE_OBJECT) - sizeof(DEVICE_OBJECT), NULL, FILE_DEVICE_DISK_FILE_SYSTEM, 0, FALSE, (PDEVICE_OBJECT *)&VolumeDevice); if (!NT_SUCCESS(Status)) { /* Release the global lock */ FatReleaseGlobal(IrpContext); return Status; } /* Match alignment requirements */ if (TargetDeviceObject->AlignmentRequirement > VolumeDevice->DeviceObject.AlignmentRequirement) { VolumeDevice->DeviceObject.AlignmentRequirement = TargetDeviceObject->AlignmentRequirement; } /* Init stack size */ VolumeDevice->DeviceObject.StackSize = TargetDeviceObject->StackSize + 1; /* Get sector size */ Status = FatPerformDevIoCtrl(TargetDeviceObject, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &DiskGeometry, sizeof(DISK_GEOMETRY), TRUE); if (!NT_SUCCESS(Status)) goto FatMountVolumeCleanup; VolumeDevice->DeviceObject.SectorSize = (USHORT) DiskGeometry.BytesPerSector; /* Signal we're done with initializing */ VolumeDevice->DeviceObject.Flags &= ~DO_DEVICE_INITIALIZING; /* Save device object in a VPB */ Vpb->DeviceObject = (PDEVICE_OBJECT)VolumeDevice; /* Initialize VCB for this volume */ Status = FatInitializeVcb(IrpContext, &VolumeDevice->Vcb, TargetDeviceObject, Vpb); if (!NT_SUCCESS(Status)) goto FatMountVolumeCleanup; Vcb = &VolumeDevice->Vcb; /* Initialize FullFAT library */ Vcb->Ioman = FF_CreateIOMAN(NULL, 8192, VolumeDevice->DeviceObject.SectorSize, &Error); ASSERT(Vcb->Ioman); /* Register block device read/write functions */ Error = FF_RegisterBlkDevice(Vcb->Ioman, VolumeDevice->DeviceObject.SectorSize, (FF_WRITE_BLOCKS)FatWriteBlocks, (FF_READ_BLOCKS)FatReadBlocks, Vcb); if (Error) { DPRINT1("Registering block device with FullFAT failed with error %d\n", Error); FF_DestroyIOMAN(Vcb->Ioman); goto FatMountVolumeCleanup; } /* Mount the volume using FullFAT */ if(FF_MountPartition(Vcb->Ioman, 0)) { DPRINT1("Partition mounting failed\n"); FF_DestroyIOMAN(Vcb->Ioman); goto FatMountVolumeCleanup; } /* Read the boot sector */ FatReadStreamFile(Vcb, 0, sizeof(PACKED_BOOT_SECTOR), &BootBcb, (PVOID)&BootSector); /* Check if it's successful */ if (!BootBcb) { Status = STATUS_UNRECOGNIZED_VOLUME; goto FatMountVolumeCleanup; } /* Unpack data */ FatiUnpackBpb(&Vcb->Bpb, &BootSector->PackedBpb); /* Verify if sector size matches */ if (DiskGeometry.BytesPerSector != Vcb->Bpb.BytesPerSector) { DPRINT1("Disk geometry BPS %d and bios BPS %d don't match!\n", DiskGeometry.BytesPerSector, Vcb->Bpb.BytesPerSector); /* Fail */ Status = STATUS_UNRECOGNIZED_VOLUME; goto FatMountVolumeCleanup; } /* If Sectors value is set, discard the LargeSectors value */ if (Vcb->Bpb.Sectors) Vcb->Bpb.LargeSectors = 0; /* Copy serial number */ if (FatiBpbFat32(&BootSector->PackedBpb)) { CopyUchar4(&Vpb->SerialNumber, ((PPACKED_BOOT_SECTOR_EX)BootSector)->Id); } else { /* This is FAT12/16 */ CopyUchar4(&Vpb->SerialNumber, BootSector->Id); } /* Unpin the BCB */ CcUnpinData(BootBcb); /* Create root DCB for it */ FatCreateRootDcb(IrpContext, &VolumeDevice->Vcb); /* Keep trace of media changes */ VolumeDevice->Vcb.MediaChangeCount = MediaChangeCount; //ObDereferenceObject(TargetDeviceObject); /* Release the global lock */ FatReleaseGlobal(IrpContext); /* Notify about volume mount */ //FsRtlNotifyVolumeEvent(VolumeDevice->Vcb.StreamFileObject, FSRTL_VOLUME_MOUNT); /* Return success */ return STATUS_SUCCESS; FatMountVolumeCleanup: /* Unwind the routine actions */ IoDeleteDevice((PDEVICE_OBJECT)VolumeDevice); /* Release the global lock */ FatReleaseGlobal(IrpContext); return Status; }