При тестировании стабильности приложения я пытаюсь удалить / повредить базу данных, используемую приложением. ОС — Windows, файловая система — NTFS, язык тестов — C ++.
Что мне нужно, это вставить что-нибудь в файл базы данных или удалить его. Но он заблокирован тестируемым приложением во время запуска. Так, может, кто-то сталкивался с этим делом раньше, и вы можете дать мне / нам пример возможных способов обойти эту блокировку в тестовом коде? Теория или источник — я ценю любую помощь.
Вам придется закрыть дескриптор, который ваше приложение имеет к файлу. Имейте в виду, что вам придется снова открыть свой файл в приложении, я считаю.
Я нашел другой, но похожий вопрос с примером кода, который решает вашу проблему: Принудительно закрыть файл по его пути в Windows
Вам просто нужно скопировать все и заменить часть, которая удаляет файл, чем-то, что его портит. Надеюсь, это поможет: D
В общем, захват владения блокировкой файлов — это не то, что операционные системы предоставляют или должны делать, не без помощи первоначального владельца блокировки. (1) Вы не можете легко обойти гарантии безопасности ОС, конечно же, не из своего кода тестирования на уровне пользователя.
Некоторые советы о том, как это можно сделать при активной помощи первоначального владельца, см.
MSDN: Windows → Центр разработки — Рабочий стол → Функция LockFileEx а также MSDN: Windows → Центр разработки — Рабочий стол → Функция DuplicateHandle но это вряд ли так, как вы хотели бы пойти.
Некоторое описание SqLite
Подход к блокировке базы данных (который использует ваше приложение) описан в http://www.sqlite.org/lockingv3.html и особенно глава «Как испортить ваши файлы базы данных» говорит
..Очевидно, что сбой оборудования или операционной системы, который вводит неверные данные в середину файла базы данных или журнала, вызовет проблемы. Аналогичным образом, если мошеннический процесс открывает файл базы данных или журнал и записывает искаженные данные в его середину, база данных будет повреждена. С этими проблемами мало что можно сделать, поэтому им больше не уделяется внимания.
Если вы действительно хотите смоделировать, как дела идут совсем не так, то один из способов — (2) создать собственный тестовый SqLite только с pager module
(http://www.sqlite.org/src/finfo?name=src/pager.cСкомпрометировано, SqLite имеет доступный исходный код, так что возможна настройка
(3) Наиболее часто используемая теория говорит, что для ваших сценариев тестирования вы должны использовать специальные среды тестирования, оснащенные Макет объектов подделка поведения, которое вы хотите проверить. В такой среде тестирования ваше приложение будет скомпилировано в специальном «тестируемом» режиме, когда приложение добровольно временно освобождает SqLite
подключение по запросу, чтобы среда могла смоделировать сбой ОС или оборудования, а затем продолжить.
Использование макетов объектов в вашем приложении намного легче затем, например, подделка неисправного драйвера файловой системы в среде черного ящика.
Соответствующий: http://en.wikipedia.org/wiki/Software_testing#Destructive_testing
#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);
}