⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ffs.c

📁 FSD file system driver
💻 C
📖 第 1 页 / 共 4 页
字号:


BOOLEAN
FFSExpandInode(
	PFFS_IRP_CONTEXT IrpContext,
	PFFS_VCB         Vcb,
	PFFS_FCB         Fcb,
	ULONG            *dwRet)
{
	ULONG    dwSizes[FFS_BLOCK_TYPES];
	ULONG    Index = 0;
	ULONG    dwTotal = 0;
	ULONG    dwBlk = 0, dwNewBlk = 0;
	ULONG    i;
	BOOLEAN  bRet = FALSE;
	BOOLEAN  bNewBlock = FALSE;

	PFFSv1_INODE dinode1 = Fcb->dinode1;

	Index = (ULONG)(Fcb->Header.AllocationSize.QuadPart >> BLOCK_BITS);

	for (i = 0; i < FFS_BLOCK_TYPES; i++)
	{
		dwSizes[i] = Vcb->dwData[i];
		dwTotal += dwSizes[i];
	}

	if (Index >= dwTotal)
	{
		FFSPrint((DBG_ERROR, "FFSExpandInode: beyond the maxinum size of an inode.\n"));
		return FALSE;
	}

	for (i = 0; i < FFS_BLOCK_TYPES; i++)
	{
		if (Index < dwSizes[i])
		{
			dwBlk = dinode1->di_db[i == 0 ? (Index) : (i + NDADDR - 1)];
			if (dwBlk == 0)
			{
				if (!FFSNewBlock(IrpContext,
							Vcb,
							Fcb->BlkHint ? 0 : ((Fcb->FFSMcb->Inode - 1) / INODES_PER_GROUP),
							Fcb->BlkHint,
							&dwBlk))
				{
					FFSPrint((DBG_ERROR, "FFSExpandInode: get new block error.\n"));
					break;
				}

				dinode1->di_ib[i == 0 ? (Index):(i + NDADDR - 1)] = dwBlk;

				dinode1->di_blocks += (Vcb->BlockSize / SECTOR_SIZE);

				bNewBlock = TRUE;
			}

			bRet = FFSExpandBlock(IrpContext,
					Vcb, Fcb,
					dwBlk, Index,
					i, bNewBlock,
					&dwNewBlk); 

			if (bRet)
			{
				Fcb->Header.AllocationSize.QuadPart += Vcb->BlockSize;
			}

			break;
		}

		Index -= dwSizes[i];
	}

	{
		ASSERT(FFSDataBlocks(Vcb, (ULONG)(dinode1->di_blocks / (BLOCK_SIZE / SECTOR_SIZE)))
				== (Fcb->Header.AllocationSize.QuadPart / BLOCK_SIZE));

		ASSERT(FFSTotalBlocks(Vcb, (ULONG)(Fcb->Header.AllocationSize.QuadPart / BLOCK_SIZE))
				== (dinode1->di_blocks / (BLOCK_SIZE / SECTOR_SIZE)));
	}


	FFSv1SaveInode(IrpContext, Vcb, Fcb->FFSMcb->Inode, dinode1);

	if (bRet && dwNewBlk)
	{
		if (dwRet)
		{
			Fcb->BlkHint = dwNewBlk+1;
			*dwRet = dwNewBlk;

			FFSPrint((DBG_INFO, "FFSExpandInode: %S (%xh) i=%2.2xh Index=%8.8xh New Block=%8.8xh\n", Fcb->FFSMcb->ShortName.Buffer, Fcb->FFSMcb->Inode, i, Index, dwNewBlk));
		}

		return TRUE;
	}

	return FALSE;
}


NTSTATUS
FFSNewInode(
	PFFS_IRP_CONTEXT IrpContext,
	PFFS_VCB         Vcb,
	ULONG            GroupHint,
	ULONG            Type,
	PULONG           Inode)
{
#if 0
	RTL_BITMAP      InodeBitmap;
	PVOID           BitmapCache;
	PBCB            BitmapBcb;

	ULONG           Group, i, j;
	ULONG           Average, Length;
	LARGE_INTEGER   Offset;

	ULONG           dwInode;

	*Inode = dwInode = 0XFFFFFFFF;

repeat:

	Group = i = 0;

	if (Type == DT_DIR)
	{
		Average = Vcb->ffs_super_block->s_free_inodes_count / Vcb->ffs_groups;

		for (j = 0; j < Vcb->ffs_groups; j++)
		{
			i = (j + GroupHint) % (Vcb->ffs_groups);

			if ((Vcb->ffs_group_desc[i].bg_used_dirs_count << 8) < 
					Vcb->ffs_group_desc[i].bg_free_inodes_count)
			{
				Group = i + 1;
				break;
			}
		}

		if (!Group)
		{
			for (j = 0; j < Vcb->ffs_groups; j++)
			{
				if (Vcb->ffs_group_desc[j].bg_free_inodes_count >= Average)
				{
					if (!Group || (Vcb->ffs_group_desc[j].bg_free_blocks_count > Vcb->ffs_group_desc[Group].bg_free_blocks_count))
						Group = j + 1;
				}
			}
		}
	}
	else 
	{
		/*
		 * Try to place the inode in its parent directory (GroupHint)
		 */
		if (Vcb->ffs_group_desc[GroupHint].bg_free_inodes_count)
		{
			Group = GroupHint + 1;
		}
		else
		{
			i = GroupHint;

			/*
			 * Use a quadratic hash to find a group with a
			 * free inode
			 */
			for (j = 1; j < Vcb->ffs_groups; j <<= 1)
			{

				i += j;
				if (i > Vcb->ffs_groups) 
					i -= Vcb->ffs_groups;

				if (Vcb->ffs_group_desc[i].bg_free_inodes_count)
				{
					Group = i + 1;
					break;
				}
			}
		}

		if (!Group) {
			/*
			 * That failed: try linear search for a free inode
			 */
			i = GroupHint + 1;
			for (j = 2; j < Vcb->ffs_groups; j++)
			{
				if (++i >= Vcb->ffs_groups) i = 0;

				if (Vcb->ffs_group_desc[i].bg_free_inodes_count)
				{
					Group = i + 1;
					break;
				}
			}
		}
	}

	// Could not find a proper group.
	if (!Group)
	{
		return STATUS_DISK_FULL;
	}
	else
	{
		Group--;

		Offset.QuadPart = (LONGLONG) Vcb->BlockSize;
		Offset.QuadPart = Offset.QuadPart * Vcb->ffs_group_desc[Group].bg_inode_bitmap;

		if (Vcb->ffs_groups == 1)
		{
			Length = INODES_COUNT;
		}
		else
		{
			if (Group == Vcb->ffs_groups - 1)
			{
				Length = INODES_COUNT % INODES_PER_GROUP;
				if (!Length) 
				{
					/* INODES_COUNT is integer multiple of INODES_PER_GROUP */
					Length = INODES_PER_GROUP;
				}
			}
			else
			{
				Length = INODES_PER_GROUP;
			}
		}

		if (!CcPinRead(Vcb->StreamObj,
					&Offset,
					Vcb->BlockSize,
					PIN_WAIT,
					&BitmapBcb,
					&BitmapCache))
		{
			FFSPrint((DBG_ERROR, "FFSNewInode: PinReading error ...\n"));

			return STATUS_UNSUCCESSFUL;
		}

		RtlInitializeBitMap(&InodeBitmap,
				BitmapCache,
				Length);

		dwInode = RtlFindClearBits(&InodeBitmap, 1, 0);

		if (dwInode == 0xFFFFFFFF)
		{
			CcUnpinData(BitmapBcb);
			BitmapBcb = NULL;
			BitmapCache = NULL;

			RtlZeroMemory(&InodeBitmap, sizeof(RTL_BITMAP));
		}
	}

	if (dwInode == 0xFFFFFFFF || dwInode >= Length)
	{
		if (Vcb->ffs_group_desc[Group].bg_free_inodes_count != 0)
		{
			Vcb->ffs_group_desc[Group].bg_free_inodes_count = 0;

			FFSSaveGroup(IrpContext, Vcb);            
		}

		goto repeat;
	}
	else
	{
		RtlSetBits(&InodeBitmap, dwInode, 1);

		CcSetDirtyPinnedData(BitmapBcb, NULL);

		FFSRepinBcb(IrpContext, BitmapBcb);

		CcUnpinData(BitmapBcb);

		FFSAddMcbEntry(Vcb, Offset.QuadPart, (LONGLONG)Vcb->BlockSize);

		*Inode = dwInode + 1 + Group * INODES_PER_GROUP;

		//Updating Group Desc / Superblock
		Vcb->ffs_group_desc[Group].bg_free_inodes_count--;
		if (Type == FFS_FT_DIR)
		{
			Vcb->ffs_group_desc[Group].bg_used_dirs_count++;
		}

		FFSSaveGroup(IrpContext, Vcb);

		Vcb->ffs_super_block->s_free_inodes_count--;
		FFSSaveSuper(IrpContext, Vcb);

		return STATUS_SUCCESS;        
	}

	return STATUS_DISK_FULL;
#endif
	return STATUS_UNSUCCESSFUL;
}


BOOLEAN
FFSFreeInode(
	PFFS_IRP_CONTEXT IrpContext,
	PFFS_VCB         Vcb,
	ULONG            Inode,
	ULONG            Type)
{
#if 0
	RTL_BITMAP      InodeBitmap;
	PVOID           BitmapCache;
	PBCB            BitmapBcb;

	ULONG           Group;
	ULONG           Length;
	LARGE_INTEGER   Offset;

	ULONG           dwIno;
	BOOLEAN         bModified = FALSE;


	Group = (Inode - 1) / INODES_PER_GROUP;
	dwIno = (Inode - 1) % INODES_PER_GROUP;

	FFSPrint((DBG_INFO, "FFSFreeInode: Inode: %xh (Group/Off = %xh/%xh)\n",
				Inode, Group, dwIno));

	{
		Offset.QuadPart = (LONGLONG) Vcb->BlockSize;
		Offset.QuadPart = Offset.QuadPart * Vcb->ffs_group_desc[Group].bg_inode_bitmap;
		if (Group == Vcb->ffs_groups - 1)
		{
			Length = INODES_COUNT % INODES_PER_GROUP;
			if (!Length)
			{ /* s_inodes_count is integer multiple of s_inodes_per_group */
				Length = INODES_PER_GROUP;
			}
		}
		else
		{
			Length = INODES_PER_GROUP;
		}

		if (!CcPinRead(Vcb->StreamObj,
					&Offset,
					Vcb->BlockSize,
					PIN_WAIT,
					&BitmapBcb,
					&BitmapCache))
		{
			FFSPrint((DBG_ERROR, "FFSFreeInode: PinReading error ...\n"));
			return FALSE;
		}

		RtlInitializeBitMap(&InodeBitmap,
				BitmapCache,
				Length);

		if (RtlCheckBit(&InodeBitmap, dwIno) == 0)
		{

		}
		else
		{
			RtlClearBits(&InodeBitmap, dwIno, 1);
			bModified = TRUE;
		}

		if (!bModified)
		{
			CcUnpinData(BitmapBcb);
			BitmapBcb = NULL;
			BitmapCache = NULL;

			RtlZeroMemory(&InodeBitmap, sizeof(RTL_BITMAP));
		}
	}

	if (bModified)
	{
		CcSetDirtyPinnedData(BitmapBcb, NULL);

		FFSRepinBcb(IrpContext, BitmapBcb);

		CcUnpinData(BitmapBcb);

		FFSAddMcbEntry(Vcb, Offset.QuadPart, (LONGLONG)Vcb->BlockSize);

		//Updating Group Desc / Superblock
		if (Type == DT_DIR)
		{
			Vcb->ffs_group_desc[Group].bg_used_dirs_count--;
		}

		Vcb->ffs_group_desc[Group].bg_free_inodes_count++;
		FFSSaveGroup(IrpContext, Vcb);

		Vcb->ffs_super_block->s_free_inodes_count++;
		FFSSaveSuper(IrpContext, Vcb);

		return TRUE;
	}
#endif
	return FALSE;
}


NTSTATUS
FFSAddEntry(
	IN PFFS_IRP_CONTEXT IrpContext,
	IN PFFS_VCB         Vcb,
	IN PFFS_FCB         Dcb,
	IN ULONG            FileType,
	IN ULONG            Inode,
	IN PUNICODE_STRING  FileName)
{
	NTSTATUS                Status = STATUS_UNSUCCESSFUL;

	PFFS_DIR_ENTRY          pDir = NULL;
	PFFS_DIR_ENTRY          pNewDir = NULL;
	PFFS_DIR_ENTRY          pTarget = NULL;

	ULONG                   Length = 0;
	ULONG                   dwBytes = 0;

	BOOLEAN                 bFound = FALSE;
	BOOLEAN                 bAdding = FALSE;

	BOOLEAN                 MainResourceAcquired = FALSE;

	ULONG                   dwRet;

	if (!IsDirectory(Dcb))
	{
		FFSBreakPoint();
		Status = STATUS_INVALID_PARAMETER;
		return Status;
	}

	MainResourceAcquired = ExAcquireResourceExclusiveLite(&Dcb->MainResource, TRUE);

	__try
	{
		Dcb->ReferenceCount++;

		pDir = (PFFS_DIR_ENTRY)ExAllocatePool(PagedPool,
				FFS_DIR_REC_LEN(FFS_NAME_LEN));
		if (!pDir)
		{
			Status = STATUS_INSUFFICIENT_RESOURCES;
			__leave;
		}

		pTarget = (PFFS_DIR_ENTRY)ExAllocatePool(PagedPool,
				2 * FFS_DIR_REC_LEN(FFS_NAME_LEN));
		if (!pTarget)
		{
			Status = STATUS_INSUFFICIENT_RESOURCES;
			__leave;
		}

#if 0
		if (IsFlagOn(SUPER_BLOCK->s_feature_incompat, 
					FFS_FEATURE_INCOMPAT_FILETYPE))
		{
			pDir->d_type = (UCHAR)FileType;
		}
		else
#endif
		{
			pDir->d_type = 0;
		}

		{
			OEM_STRING OemName;
			OemName.Buffer = pDir->d_name;
			OemName.MaximumLength = FFS_NAME_LEN;
			OemName.Length = 0;

			Status = FFSUnicodeToOEM(&OemName, FileName);

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

			pDir->d_namlen = (CCHAR)OemName.Length;
		}

		pDir->d_ino  = Inode;
		pDir->d_reclen = (USHORT)(FFS_DIR_REC_LEN(pDir->d_namlen));

		dwBytes = 0;

Repeat:

		while ((LONGLONG)dwBytes < Dcb->Header.AllocationSize.QuadPart)
		{
			RtlZeroMemory(pTarget, FFS_DIR_REC_LEN(FFS_NAME_LEN));

			// Reading the DCB contents
			Status = FFSv1ReadInode(
						NULL,
						Vcb,
						Dcb->dinode1,
						dwBytes,
						(PVOID)pTarget,
						FFS_DIR_REC_LEN(FFS_NAME_LEN),
						&dwRet);

			if (!NT_SUCCESS(Status))
			{
				FFSPrint((DBG_ERROR, "FFSAddDirectory: Reading Directory Content error.\n"));
				__leave;
			}

			if (((pTarget->d_ino == 0) && pTarget->d_reclen >= pDir->d_reclen) || 
					(pTarget->d_reclen >= FFS_DIR_REC_LEN(pTarget->d_namlen) + pDir->d_reclen))
			{
				if (pTarget->d_ino)
				{
					RtlZeroMemory(pTarget, 2 * FFS_DIR_REC_LEN(FFS_NAME_LEN));

					// Reading the DCB contents
					Status = FFSv1ReadInode(
							NULL,
							Vcb,
							Dcb->dinode1,
							dwBytes,
							(PVOID)pTarget,
							2 * FFS_DIR_REC_LEN(FFS_NAME_LEN),
							&dwRet);

					if (!NT_SUCCESS(Status))
					{
						FFSPrint((DBG_ERROR, "FFSAddDirectory: Reading Directory Content error.\n"));
						__leave;
					}

					Length = FFS_DIR_REC_LEN(pTarget->d_namlen);

					pNewDir = (PFFS_DIR_ENTRY) ((PUCHAR)pTarget + FFS_DIR_REC_LEN(pTarget->d_namlen));

					pNewDir->d_reclen = pTarget->d_reclen - FFS_DIR_REC_LEN(pTarget->d_namlen);

					pTarget->d_reclen = FFS_DIR_REC_LEN(pTarget->d_namlen);
				}
				else
				{
					pNewDir = pTarget;
					pNewDir->d_reclen = (USHORT)((ULONG)(Dcb->Header.AllocationSize.QuadPart) - dwBytes);
				}

				pNewDir->d_type = pDir->d_type;
				pNewDir->d_ino = pDir->d_ino;
				pNewDir->d_namlen = pDir->d_namlen;
				memcpy(pNewDir->d_name, pDir->d_name, pDir->d_namlen);
				Length += FFS_DIR_REC_LEN(pDir->d_namlen);

				bFound = TRUE;
				break;
			}

			dwBytes += pTarget->d_reclen;
		}

		if (bFound)
		{
			ULONG dwRet;

			if (FileType == DT_DIR)
			{
				if(((pDir->d_namlen == 1) && (pDir->d_name[0] == '.')) ||
						((pDir->d_namlen == 2) && (pDir->d_name[0] == '.') && (pDir->d_name[1] == '.')))
				{
				}
				else
				{
					Dcb->dinode1->di_nlink++;
				}
			}

			Status = FFSv1WriteInode(IrpContext, Vcb, Dcb->dinode1, dwBytes, pTarget, Length, FALSE, &dwRet);
		}
		else
		{
			// We should expand the size of the dir inode 
			if (!bAdding)
			{
				ULONG dwRet;

				bAdding = FFSExpandInode(IrpContext, Vcb, Dcb, &dwRet);

				if (bAdding)
				{

					Dcb->dinode1->di_size = Dcb->Header.AllocationSize.LowPart;

					FFSv1SaveInode(IrpContext, Vcb, Dcb->FFSMcb->Inode, Dcb->dinode1);

					Dcb->Header.FileSize = Dcb->Header.AllocationSize;

					goto Repeat;
				}

				__leave;

			}
			else  // Something must be error!
			{
				__leave;
			}
		}
	}

	__finally
	{

		Dcb->ReferenceCount--;

		if(MainResourceAcquired)
		{
			ExReleaseResourceForThreadLite(
					&Dcb->MainResource,
					ExGetCurrentResourceThread());
		}

		if (pTarget != NULL)
		{
			ExFreePool(pTarget);
		}

		if (pDir)
		{
			ExFreePool(pDir);
		}
	}

	return Status;
}


NTSTATUS
FFSRemoveEntry(
	IN PFFS_IRP_CONTEXT IrpContext,
	IN PFFS_VCB         Vcb,
	IN PFFS_FCB         Dcb,
	IN ULONG            FileType,
	IN ULONG            Inode)
{
	NTSTATUS                Status = STATUS_UNSUCCESSFUL;

	PFFS_DIR_ENTRY          pTarget = NULL;
	PFFS_DIR_ENTRY          pPrevDir = NULL;

	USHORT                  PrevRecLen = 0;

	ULONG                   Length = 0;
	ULONG                   dwBytes = 0;

	BOOLEAN                 bRet = FALSE;
	BOOLEAN                 MainResourceAcquired = FALSE;

	ULONG                   dwRet;

	if (!IsDirectory(Dcb))
	{
		return FALSE;
	}

	MainResourceAcquired = 
		ExAcquireResourceExclusiveLite(&Dcb->MainResource, TRUE);

	__try
	{

		Dcb->ReferenceCount++;

		pTarget = (PFFS_DIR_ENTRY)ExAllocatePool(PagedPool,
				FFS_DIR_REC_LEN(FFS_NAME_LEN));
		if (!pTarget)
		{
			Status = STATUS_INSUFFICIENT_RESOURCES;
			__leave;
		}

		pPrevDir = (PFFS_DIR_ENTRY)ExAllocatePool(PagedPool,
				FFS_DIR_REC_LEN(FFS_NAME_LEN));
		if (!pPrevDir)
		{
			Status = STATUS_INSUFFICIENT_RESOURCES;
			__leave;
		}

		dwBytes = 0;

		while ((LONGLONG)dwBytes < Dcb->Header.AllocationSize.QuadPart)
		{
			RtlZeroMemory(pTarget, FFS_DIR_REC_LEN(FFS_NAME_LEN));

			Status = FFSv1ReadInode(
						NULL,
						Vcb,
						Dcb->dinode1,
						dwBytes,
						(PVOID)pTarget,
						FFS_DIR_REC_LEN(FFS_NAME_LEN),
						&dwRet);

			if (!NT_SUCCESS(Status))
			{
				FFSPrint((DBG_ERROR, "FFSRemoveEntry: Reading Directory Content error.\n"));
				__leave;
			}

			if (pTarget->d_ino == Inode)
			{
				ULONG   dwRet;
				ULONG   RecLen;

				if ((PrevRecLen + pTarget->d_reclen) < MAXIMUM_RECORD_LENGTH)
				{
					pPrevDir->d_reclen += pTarget->d_reclen;
					RecLen = FFS_DIR_REC_LEN(pTarget->d_namlen);

					RtlZeroMemory(pTarget, RecLen);

					FFSv1WriteInode(IrpContext, Vcb, Dcb->dinode1, dwBytes - PrevRecLen, pPrevDir, 8, FALSE, &dwRet);
					FFSv1WriteInode(IrpContext, Vcb, Dcb->dinode1, dwBytes, pTarget, RecLen, FALSE, &dwRet);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -