Member 13208896 Ответов: 1

В чем, по-видимому, заключается проблема с этим кодом/приложением


Моя проблема заключается в том, что я пытаюсь понять, почему эта программа не создает образы дисков, которые я попросил ее обработать.

Происходит следующее :

входные данные : C:\windd64>windd64.exe /если:\\.\PhysicalDrive0 /of:D:\image.raw /buffer:100
Выход : Полный

Это не проблема, проблема в том, что когда я пытаюсь переписать этот образ на другой диск или даже на тот же диск, это ошибка, которую он мне дает.

вход : C:\windd64>windd64.exe /если:д:\изображения.сырье /о:\\.\PhysicalDrive0 /буфер:100

вывод : ошибки назначения : 87



Что я должен изменить или что даже кажется здесь проблемой? Нет, я не хочу использовать что-то еще, я бы %100 предпочел остаться с этим кодом. Это кажется очень эффективным во многих отношениях, спасибо!


Ссылка На Github : https://github.com/luisgf/windd




Код для windd64.cpp

/*
	windd64 (c) Luis González Fernández 2015
	luisgf@luisgf.es
	https://www.luisgf.es/
*/

#include "windd64.h"

LPVOID xmalloc(size_t size) {
	LPVOID ptr = malloc(size);
	if (!ptr) {
		wprintf(L"xmalloc(%d): Memory allocation error\n", size);
		exit(-1);
	}
	return ptr;
}

VOID Usage(LPCTSTR ProgName) {
	wprintf(L"Usage: %s /if:INPUT /of:OUTPUT /buffer:200\n\n", ProgName);
	wprintf(L"Parameters:\n");
	wprintf(L"/?\t\t Show this help\n");
	wprintf(L"/if\t\t Input block device or file. Like \\\\.\\PhysicalDrive0\n");
	wprintf(L"/of\t\t Source block device or file. Like D:\\image.windd\n");
	wprintf(L"/buffer\t\t Amount of memory to use as buffer. In Mb, default=100\n");	
	wprintf(L"/ibs\t\t Input block size (in bytes)\n");
	wprintf(L"/obs\t\t Output block size (in bytes)\n");
	wprintf(L"/bs\t\t Block size (Input & Output), overwrite ibs and obs (in bytes)\n");
	wprintf(L"/skip\t\t Skip n bytes at input start\n");
	wprintf(L"/seek\t\t Seek n bytes at output\n");
	wprintf(L"/nd\t\t Hide the disclaimer banner.\n");
	wprintf(L"/v\t\t Verbose Output. Show more info about reader/writer parameters.\n");
	wprintf(L"\n\n");
	exit(0);
}

VOID Disclaimer() {	
	wprintf(L"WARNING: This program commes without warranty and can damage your computer\n");
	wprintf(L"if used incorrectly. Use with caution.\n\n");
}

DWORD WINAPI ReadSect(LPVOID lpParam)
{
	DWORD dwRead;								// bytes readed
	BOOL rs = FALSE;
	DWORD dwWaitResult;
	PDATA data = NULL;							// pointer to disk data readed
	PTPARAMS param = (PTPARAMS)lpParam;			// Thread parameters
	LONGLONG CurrentOffset = param->StartOffset;	
	DWORD BytesToRead = MB_TO_BYTES(20);		// read 20 mb at a time
	
	if (param->Verbose)
		wprintf(L"Reader(): StartOffset %lu, EndOffset: %lu, Size %lu, SectorSize: %lu\n", param->StartOffset, param->EndOffset, param->DiskSize, param->SectorSize);

	if (param->StartOffset) {
		LARGE_INTEGER liStart;
		liStart.QuadPart = param->StartOffset;
		SetFilePointerEx(param->hDev, liStart, NULL, FILE_BEGIN);
	}

	while (CurrentOffset != param->EndOffset) {		
		if (param->cola->size > param->MemBuff) {
			// Queue Full. Sleep...
			Sleep(100);
		}
		else {
			// estamos al final del dispositivo y no hay tantos bloques que leer.			
			if (param->EndOffset - CurrentOffset EndOffset - CurrentOffset);
			
			data = (PDATA)xmalloc(sizeof(DATA));
			data->size = BytesToRead;
			data->ptr = (LPVOID)xmalloc(data->size);
			rs = ReadFile(param->hDev, data->ptr, data->size, &dwRead, 0);  // read sector	

			if (dwRead != data->size) {
				wprintf(L"Error reading at offset: %lu\n", CurrentOffset);
				return -1;
			}

			dwWaitResult = WaitForSingleObject(param->Mutex, INFINITE); 

			switch (dwWaitResult)
			{
				// The thread got ownership of the mutex
				case WAIT_OBJECT_0:
					__try {
						param->cola->ptr->push(data);
						param->cola->size += BytesToRead;
						param->DataProcessed += BytesToRead;
					}
					__finally {
						ReleaseMutex(param->Mutex);
					}
				break;
			}
			CurrentOffset += BytesToRead;
			wprintf(L"\rCompleted: %.2f %%", (float)((float)(CurrentOffset * 100) / (float)param->DiskSize));
		}
	}
	if (param->Verbose)
		wprintf(L"\rData Readed: %lu bytes\n", param->DataProcessed);
	return rs;
}

DWORD WINAPI WriteSect(LPVOID lpParam)
{
	PTPARAMS param = (PTPARAMS)lpParam;	
	DWORD dwWaitResult;
	PDATA data = NULL;
	BOOL rs = FALSE;	
	ULONGLONG CurrentOffset = param->StartOffset;

	if (param->Verbose)
		wprintf(L"Writer(): StartOffset %lu, EndOffset: %lu, Size %lu, SectorSize: %lu\n", param->StartOffset, param->EndOffset, param->DiskSize, param->SectorSize);

	if (param->StartOffset) {
		LARGE_INTEGER liStart;
		liStart.QuadPart = param->StartOffset;
		SetFilePointerEx(param->hDev, liStart, NULL, FILE_BEGIN);
	}

	while (CurrentOffset != param->EndOffset) {
		dwWaitResult = WaitForSingleObject(param->Mutex, INFINITE);

		switch (dwWaitResult)
		{
			// The thread got ownership of the mutex
		case WAIT_OBJECT_0:
			__try {
				if (param->cola->size == 0) {
					// Queue depleted
					Sleep(100);
				}
				else {
					data = (PDATA)param->cola->ptr->front();

					DWORD written;					
					rs = WriteFile(param->hDev, data->ptr, data->size, &written, NULL);

					if (written > 0 && written size) {
						wprintf(L"\nError, Out of space at destination.\n");
						exit(-1);
					}
					
					if (!rs) {
						wprintf(L"\nError Writing to destination. %lu\n", GetLastError());
						exit(-1);
					}					
					
					param->cola->ptr->pop();
					param->cola->size -= data->size;
					param->DataProcessed += data->size;										
					CurrentOffset += data->size;

					free(data->ptr);
					free(data);
					data = NULL;
				}
			}
			__finally {				
				ReleaseMutex(param->Mutex);
			}
			break;
		}
	}
	if (param->Verbose)
		wprintf(L"Data Writed: %lu bytes\n", param->DataProcessed);

	return rs;
}

/*
** Get the disk geometry info
*/

BOOL GetDescriptorGeometry(HANDLE hDevice, PDWORD SectorSize, PLONGLONG DiskSize) {
	BOOL bResult = FALSE;                 // results flag
	DWORD junk = 0;                     // discard results
	DISK_GEOMETRY_EX pdg = { 0 };
	STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR pAlignmentDescriptor = { 0 };	
	STORAGE_PROPERTY_QUERY Query;

	ZeroMemory(&Query, sizeof(STORAGE_PROPERTY_QUERY));
	Query.PropertyId = StorageAccessAlignmentProperty;

	/*
	* First  try using STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR, if not supported we revert
	* to DISK_GEOMETRY_EX
	*/

	bResult = DeviceIoControl(hDevice, IOCTL_STORAGE_QUERY_PROPERTY,
		&Query, sizeof(STORAGE_PROPERTY_QUERY),
		&pAlignmentDescriptor, sizeof(STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR),
		&junk, NULL);
	
	if (bResult) {
		*SectorSize = pAlignmentDescriptor.BytesPerPhysicalSector;
	} 

	bResult = DeviceIoControl(hDevice,                       // device to be queried
			IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, // operation to perform
			NULL, 0,                       // no input buffer
			&pdg, sizeof(pdg),            // output buffer
			&junk,                         // # bytes returned
			(LPOVERLAPPED)NULL);          // synchronous I/O	

	if (bResult) {		
		if (!*SectorSize)
			*SectorSize = pdg.Geometry.BytesPerSector;

		*DiskSize = pdg.DiskSize.QuadPart;
	}
	else {
		// Ok, the descriptor must be a file rather than a block device
		LARGE_INTEGER FileSize;
		GetFileSizeEx(hDevice, &FileSize);
		*SectorSize = 4096;			// TODO: detect NTFS cluster Size
		*DiskSize = FileSize.QuadPart;
		bResult = TRUE;


		if (!FileSize.QuadPart) {
			wprintf(L"Unable to get descriptor Geometry\n");
			bResult = FALSE;
		}
	}

	return bResult;
}

/*
* Open the source and destination descriptors. Fail otherwhise.
*/
BOOL OpenDescriptors(LPTSTR InDev, LPTSTR OutDev, PHANDLE hInDev, PHANDLE hOutDev)
{
	DWORD desired_mask = (DWORD)(GENERIC_READ | GENERIC_WRITE);
	DWORD acces_mask = (DWORD)(FILE_SHARE_READ | FILE_SHARE_WRITE);

	*hInDev = CreateFileW(InDev, desired_mask, acces_mask, 0, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, 0);
	
	if (*hInDev == INVALID_HANDLE_VALUE)
	{
		wprintf(L"Open source descriptor error: %lu", GetLastError());
		CloseHandle(*hInDev);
		return FALSE;
	}
	
	SetFilePointer(*hInDev, 0, 0, FILE_BEGIN); // empezamos en el sector 0

	*hOutDev = CreateFile(OutDev, desired_mask, acces_mask, 0, CREATE_ALWAYS, FILE_FLAG_NO_BUFFERING, 0);
	
	if (*hOutDev == INVALID_HANDLE_VALUE)
	{
		wprintf(L"Out destination descriptor error: %lu", GetLastError());
		CloseHandle(*hOutDev);
		return FALSE;
	}
	
	SetFilePointer(*hOutDev, 0, 0, FILE_BEGIN); // empezamos en el sector 0

	return TRUE;
}

/*
	Parse de program arguments. Return TRUE all arguments are parsed correctly, FALSE otherwise.
	Valid parameters are:

	/if			Input device
	/of			Output device
	/bs			Block size for input and output (in bytes)
	    /ibs	Input block size (in bytes)
	    /obs	Output block size (in bytes)
	/buffer		Memory buffer (in Mb, default=100)
	/nd			No Disclaimer.

	Note: Block size are autodetected unless you force it with /ibs,/obs or /bs.
*/
BOOL ParseProgramArguments(PARGUMENTS pParams, DWORD args, _TCHAR **argv) {
	LPCTSTR param = NULL;	

	if (args Verbose = FALSE;
	pParams->NoDisclaimer = FALSE;
	pParams->dwBuff = MB_TO_BYTES(100);
	pParams->dwSkip = 0;
	pParams->dwSeek = 0;

	// Skip argv[0], that is the path to the program executable.
	for (DWORD i = 1; i sInDev = (LPTSTR)(param += 3);
		}
		if (!_wcsnicmp(param, L"of:", 3)) {
			pParams->sOutDev = (LPTSTR)(param += 3);
		}

		if (!_wcsnicmp(param, L"bs:", 3)) {
			LPCTSTR dwBs = (param += 3);
			pParams->dwOutBs = pParams->dwInBs = wcstol(dwBs, NULL, 10);
		} 
		if (!_wcsnicmp(param, L"ibs:", 4)) {
			LPCTSTR dwBs = (param += 4);
			// We set too, obs to the same value as ibs, unless /obs switch is used.
			pParams->dwOutBs = pParams->dwInBs = wcstol(dwBs, NULL, 10);
		}
		if (!_wcsnicmp(param, L"obs:", 4)) {
			LPCTSTR dwBs = (param += 4);
			pParams->dwOutBs = wcstol(dwBs, NULL, 10);
		}		
		if (!_wcsnicmp(param, L"buffer:", 7)) {
			LPCTSTR dwBuff = (param += 7);
			pParams->dwBuff = MB_TO_BYTES(wcstol(dwBuff, NULL, 10));
		}
		if (!_wcsnicmp(param, L"skip:", 5)) {
			LPCTSTR dwSkip = (param += 5);
			pParams->dwSkip = wcstol(dwSkip, NULL, 10);
		}
		if (!_wcsnicmp(param, L"seek:", 5)) {
			LPCTSTR dwSeek = (param += 5);
			pParams->dwSeek = wcstol(dwSeek, NULL, 10);
		}
		if (!_wcsnicmp(param, L"nd", 2)) {
			pParams->NoDisclaimer = TRUE;			
		}
		if (!_wcsnicmp(param, L"v", 1)) {
			pParams->Verbose = TRUE;
		}

		// Add next parameters parsing here...		
	}

	if (!pParams->sInDev) {
		wprintf(L"Input (/if) parameter missing.\n");
		return FALSE;
	}
	if (!pParams->sOutDev) {
		wprintf(L"Output (/of) parameter missing.\n");
		return FALSE;
	}
	if (!pParams->dwBuff) {
		pParams->dwBuff = MB_TO_BYTES(100);		
	}
	// Input block size checks
	if (pParams->dwInBs && (pParams->dwInBs dwInBs % 512) > 0)) {
		wprintf(L"Input block size must be multiple of 512.\n");
		return FALSE;
	}
	// Output block size checks
	if (pParams->dwOutBs && (pParams->dwOutBs dwOutBs % 512) > 0)) {
		wprintf(L"Output block size must be multiple of 512.\n");
		return FALSE;
	}

	return TRUE;
}


int _tmain(int argc, _TCHAR* argv[])
{
	ARGUMENTS params = { 0 };					// Parsed program arguments
	HANDLE hInDev = NULL;
	HANDLE hOutDev = NULL;

	// Disk Geometry
	LONGLONG DiskSize = { 0 };			// disk size in bytes	
	DWORD SectorSize;					// Physical sector size
	std::queue  cola;

	// Thread synchronization
	HANDLE hMutex;
	HANDLE hThread[2] = { 0 };
	DWORD ThreadID[2] = { 0 };

	if (!ParseProgramArguments(¶ms, argc, argv)) {
		return 1;
	}
	 
	BQUEUE data = { &cola, 0};					// data queue		 

#if (_WIN32_WINNT >= _WIN32_WINNT_VISTA)
	HANDLE hToken;
	OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &hToken);
	DWORD infoLen;

	TOKEN_ELEVATION elevation;
	GetTokenInformation(hToken, TokenElevation, &elevation, sizeof(elevation), &infoLen);
	if (!elevation.TokenIsElevated)
	{
		wprintf(L"This program must run in elevated mode\n");
		return -1;
	}
#else
#error you are using an old version of sdk or not supported operating system
#endif	

	if (!OpenDescriptors(params.sInDev, params.sOutDev, &hInDev, &hOutDev))
	{
		return -1;
	}
	
	if (!GetDescriptorGeometry(hInDev, &SectorSize, &DiskSize))
	{
		return -1;	
	} 

	/* Mutex Creation */
	hMutex = CreateMutex(NULL, FALSE, NULL);

	if (hMutex == NULL)
	{
		wprintf(L"CreateMutex() error: %d\n", GetLastError());
		return -1;
	}

	/* The party start now	*/
	wprintf(L">>> windd %s - By Luis Gonzalez Fernandez\n", VERSION);
	if (!params.NoDisclaimer)
		Disclaimer();
	wprintf(L"%s => %s\n", params.sInDev, params.sOutDev);

	/* Reader Thread */
	TPARAMS ReaderParams = { 0 };
	ReaderParams.hDev = hInDev;
	ReaderParams.cola = &data;
	ReaderParams.StartOffset = params.dwSkip;			// skip n bytes at input
	ReaderParams.EndOffset = DiskSize;

	if (params.dwInBs)
		ReaderParams.SectorSize = params.dwInBs;
	else 
		ReaderParams.SectorSize = SectorSize;	

	ReaderParams.MemBuff = params.dwBuff;
	ReaderParams.Mutex = hMutex;	
	ReaderParams.DiskSize = DiskSize;
	ReaderParams.DataProcessed = 0;
	ReaderParams.Verbose = params.Verbose;

	hThread[0] = CreateThread(NULL, 0, ReadSect, &ReaderParams, 0, &ThreadID[0]);

	/* Writer Thread */
	TPARAMS WriterParams = { 0 };
	WriterParams.hDev = hOutDev;
	WriterParams.cola = &data;
	WriterParams.StartOffset = params.dwSeek;				// seek until this offset at write.
	WriterParams.EndOffset = (DiskSize + params.dwSeek - params.dwSkip);

	if (params.dwOutBs)
		WriterParams.SectorSize = params.dwOutBs;
	else
		WriterParams.SectorSize = SectorSize;
	
	WriterParams.Mutex = hMutex;	
	WriterParams.DiskSize = DiskSize;
	WriterParams.DataProcessed = 0;
	WriterParams.Verbose = params.Verbose;

	hThread[1] = CreateThread(NULL, 0, WriteSect, &WriterParams, 0, &ThreadID[1]);

	WaitForMultipleObjects(2, hThread, TRUE, INFINITE);

	if (ReaderParams.DataProcessed == WriterParams.DataProcessed)
		wprintf(L"Done!\n");
	else
		wprintf(L"Error, %lu bytes are not copied.\n", (ReaderParams.DataProcessed - WriterParams.DataProcessed));

	CloseHandle(hInDev);
	CloseHandle(hOutDev);

	return 0;
}







Вот заголовочный файл соответственно :

/*
	windd64 (c) Luis González Fernández 2015
	luisgf@luisgf.es
	https://www.luisgf.es/
*/

#pragma once

#include "targetver.h"

#include 
#include 
#include 
#include 
#include 

#define VERSION L"v1.0.3"
#define MB_TO_BYTES(x) (x * 1024 * 1024)

typedef struct _bqueue {
	std::queue  *ptr;	// pointer to std::object	
	LONGLONG size;				// queue size, in bytes
} BQUEUE, *PBQUEUE;

/*
 Thread parameters structure
*/

typedef struct tParams {
	HANDLE hDev;				// device descriptor
	HANDLE Mutex;				// mutex to synchronize threads
	DWORD SectorSize;			// sector size	
	DWORD MemBuff;				// memory buffer in bytes
	LONGLONG StartOffset;		// start offset to read/write
	LONGLONG EndOffset;			// start offset to read/write
	LONGLONG DiskSize;			// disk size in bytes
	LONGLONG DataProcessed;		// amount of data processed by the thread
	PBQUEUE cola;				// pointer to queue of data
	BOOL Verbose;				// verbose
} TPARAMS, *PTPARAMS;

/*
Program Arguments structure
*/

typedef struct ProgArgumentss {
	LPTSTR sInDev;
	LPTSTR sOutDev;
	DWORD dwInBs;
	DWORD dwOutBs;
	DWORD dwBuff;
	DWORD dwSkip;
	DWORD dwSeek;
	BOOL NoDisclaimer;
	BOOL Verbose;
} ARGUMENTS, *PARGUMENTS;

/*
Data Structure. That holds de data readed from disk
*/
typedef struct _data {
	LPVOID ptr;						// pointer to data
	DWORD size;						// size of data stored	
} DATA, *PDATA;


Что я уже пробовал:

Я пробовал переформатировать целевой диск, я пробовал переходить с диска на диск много раз, я пробовал удалять разделы и создавать новые, я пробовал почти все, что я могу придумать, что я знаю, по крайней мере.

Richard MacCutchan

Вам нужно связаться с человеком, который написал исходный код.

Member 13208896

Я пытался в течение нескольких недель я просто задавался вопросом просто просматривая код чтобы увидеть пропустил ли я что то вроде исключения которое я пропустил

Richard MacCutchan

Использование вашего отладчика, вероятно, было бы лучшей идеей.

phil.o

Линия

if (param->EndOffset - CurrentOffset EndOffset - CurrentOffset);
отсутствует оператор сравнения.

Richard MacCutchan

Он также заканчивается точкой с запятой, поэтому полностью избыточен. Не знаю, почему компилятор пропустил его.

Peter_in_2780

Это совершенно справедливо, просто бессмысленно. Достойно предупреждения компилятора, но не ошибки.
*Упс* пропустил место посередине. Это действительно делает его ошибкой, даже если он будет оптимизирован до нуля,

1 Ответов

Рейтинг:
2

KarstenK

Вы должны использовать отладчик, чтобы выяснить это. Ошибка 87 звучит как какое-то несоответствие dll.

Мой совет заключается в том, что в коде есть какой-то дескриптор, который неправильно используется или закрыт, и поэтому второй запуск создает проблемы.

Теперь я вижу: мое первое предположение-это ручки резьбы :-O