在测试应用程序稳定性时,我试图删除/损坏应用程序使用的数据库。 OS是Windows,文件系统是NTFS,测试语言是C ++。
我需要的是将任何内容粘贴到数据库文件中或将其删除。但它在运行期间被测试的应用程序锁定。所以也许有人在此之前遇到过这种情况,你可以给我/我们一个关于绕过测试代码锁定的可能方法的例子吗?理论或来源 - 我感谢任何帮助。
答案 0 :(得分:2)
您必须关闭应用程序对文件的句柄。请记住,我相信你必须再次在你的应用程序上打开你的文件。
我发现了一个不同但相似的问题,示例代码可以解决您的问题:Force close file by its path on Windows
您只需复制所有内容并将删除该文件的部分替换为破坏该文件的内容。我希望它有所帮助:D
答案 1 :(得分:2)
一般来说,接管文件锁所有权不是操作系统提供或应该做的,而不是没有原锁拥有者的帮助。 (1)您无法轻易绕过操作系统安全保障,当然也不能绕过用户级别的测试代码。
有关如何通过原始所有者的主动帮助完成此操作的一些指示,请参阅 MSDN: Windows → Dev Center - Desktop → LockFileEx function和MSDN: Windows → Dev Center - Desktop → DuplicateHandle function,但这不太可能是你想去的方式。
在http://www.sqlite.org/lockingv3.html中描述了SqLite
数据库锁定方法(您的应用程序使用的)的一些描述,特别是“如何损坏您的数据库文件”一章
..显然,将错误数据引入数据库文件或日志中间的硬件或操作系统故障将导致问题。同样,如果恶意进程打开数据库文件或日志并将格式错误的数据写入其中间,则数据库将损坏。关于这些问题没有太多可以做的,所以没有给予进一步的关注。
如果你真的想模拟事情是如何变得非常错误的,那么一种方法就是(2)构建自定义测试版SqLite,其中pager module
(http://www.sqlite.org/src/finfo?name=src/pager.c)已被泄露,SqLite有源代码可用,因此可以自定义
(3)最常用的理论认为,对于您的测试场景,您应该使用配备Mock objects伪装您要测试的行为的特殊测试环境。在这样的测试环境中,您的应用程序将以特殊的“测试中”模式进行编译,其中应用程序会在被要求时自动临时释放SqLite
连接,以便环境可以模拟操作系统或硬件故障然后继续。
在应用程序中使用模拟对象更容易,例如在黑盒环境中伪造错误的文件系统驱动程序。
相关:http://en.wikipedia.org/wiki/Software_testing#Destructive_testing
答案 2 :(得分:2)
#include <Windows.h>
#include <stdio.h>
#include <string.h>
#include <tchar.h>
#include <iostream>
#include <FileAPI.h>
#include <WinBase.h>
#include <conio.h>
#include <ctype.h>
#define START_ALLOC 0x1000
#define STATUS_INFO_LENGTH_MISMATCH 0xC0000004
#define SystemHandleInformation 0x10
typedef long(__stdcall *NtQSI)(
ULONG SystemInformationClass,
PVOID SystemInformation,
ULONG SystemInformationLength,
PULONG ReturnLength
);
typedef struct _SYSTEM_HANDLE_ENTRY {
ULONG OwnerPid;
BYTE ObjectType;
BYTE HandleFlags;
USHORT HandleValue;
PVOID ObjectPointer;
ACCESS_MASK AccessMask;
} SYSTEM_HANDLE_ENTRY, *PSYSTEM_HANDLE_ENTRY;
int main(int argc, char *argv[])
{
HMODULE hNtDll = NULL;
NtQSI pNtQSI = NULL;
PVOID pMem = NULL;
ULONG allocSize = START_ALLOC;
ULONG retVal = 0;
// --------------------------------
ULONG hCount = 0;
PSYSTEM_HANDLE_ENTRY hFirstEntry = NULL;
// --------------------------------
ULONG i;
hNtDll = LoadLibraryA("NTDLL.dll");
if (!hNtDll)
return 1;
pNtQSI = (NtQSI)GetProcAddress(hNtDll, "NtQuerySystemInformation");
if (!pNtQSI) {
FreeLibrary(hNtDll);
return 2;
}
pMem = malloc(allocSize);
while (pNtQSI(SystemHandleInformation, pMem, allocSize, &retVal)
== STATUS_INFO_LENGTH_MISMATCH) {
pMem = realloc(pMem, allocSize *= 2);
}
hCount = *(ULONG*)pMem;
hFirstEntry = (PSYSTEM_HANDLE_ENTRY)((PBYTE)pMem + 4);
int pid = atoi(argv[1]);
for (i = 0; i < hCount; ++i)
if ((hFirstEntry[i].ObjectType == 30) && (hFirstEntry[i].OwnerPid == pid))
{
HANDLE TargetHandleValueTemp = (HANDLE)hFirstEntry[i].HandleValue;
HANDLE SourceProcHandleTemp = OpenProcess(PROCESS_DUP_HANDLE, FALSE, hFirstEntry[i].OwnerPid);
char confirm ='n';
DuplicateHandle(SourceProcHandleTemp, (HANDLE)hFirstEntry[i].HandleValue, GetCurrentProcess(), &TargetHandleValueTemp, 0, FALSE, DUPLICATE_SAME_ACCESS);
TCHAR Path[MAX_PATH];
DWORD dwret = GetFinalPathNameByHandle(TargetHandleValueTemp, Path, MAX_PATH, 0);
if (!argv[2])
{
_tprintf(TEXT("PID: %d\tFileHandle: %d\tThe final path is: %s\n"), hFirstEntry[i].HandleValue, TargetHandleValueTemp, Path);
}
else if (_tcsstr(Path, _T(argv[2])))
{
_tprintf(TEXT("PID: %d\tFileHandle: %d\tThe final path is: %s\n\t Remove it? (y/n): "), hFirstEntry[i].HandleValue, TargetHandleValueTemp, Path);
_flushall();
std::cin.get(confirm);
if (confirm == 'y')
DuplicateHandle(SourceProcHandleTemp, (HANDLE)hFirstEntry[i].HandleValue, GetCurrentProcess(), &TargetHandleValueTemp, 0, FALSE, DUPLICATE_CLOSE_SOURCE);
}
CloseHandle(SourceProcHandleTemp);
CloseHandle(TargetHandleValueTemp);
}
free(pMem);
FreeLibrary(hNtDll);
}