I want to match a group recursively using PCRE C library.
e.g.
pattern = "(\d,)"
subject = "5,6,3,2,"
OVECCOUNT = 30
pcrePtr = pcre_compile(pattern, 0, &error, &erroffset, NULL);
rc = pcre_exec(pcrePtr, NULL, subject, (int)strlen(subject),
0, 0, ovector, OVECCOUNT);
rc is -1..
How to match all groups so that matches are "5,", "6,", "3,", "2,"
For analogy, PHP's preg_match_all parses entire string until the end of subject...
Any way I used strtok since "," was repeating after each group..
Solution using pcre is welcomed....
Try this :
pcre *myregexp;
const char *error;
int erroroffset;
int offsetcount;
int offsets[(0+1)*3]; // (max_capturing_groups+1)*3
myregexp = pcre_compile("\\d,", 0, &error, &erroroffset, NULL);
if (myregexp != NULL) {
offsetcount = pcre_exec(myregexp, NULL, subject, strlen(subject), 0, 0, offsets, (0+1)*3);
while (offsetcount > 0) {
// match offset = offsets[0];
// match length = offsets[1] - offsets[0];
if (pcre_get_substring(subject, &offsets, offsetcount, 0, &result) >= 0) {
// Do something with match we just stored into result
}
offsetcount = pcre_exec(myregexp, NULL, subject, strlen(subject), 0, offsets[1], offsets, (0+1)*3);
}
} else {
// Syntax error in the regular expression at erroroffset
}
I believe the comments are self explanatory?
Related
I replace the first occurrence of the match with pcre2_substitute,
#define PCRE2_CODE_UNIT_WIDTH 8
#include <stdio.h>
#include <string.h>
#include <pcre2.h>
int main(int argc, char **argv)
{
PCRE2_SPTR pattern = "(\\d+)";
PCRE2_SPTR subject = "1 something 849 for 993";
PCRE2_SPTR replacement = "XXX";
pcre2_code *re;
int errornumber;
int i;
int rc;
PCRE2_SIZE erroroffset;
PCRE2_SIZE *ovector;
size_t subject_length;
size_t replacement_length = strlen((char *)replacement);
pcre2_match_data *match_data;
subject_length = strlen((char *)subject);
PCRE2_UCHAR output[1024] = "";
PCRE2_SIZE outlen = sizeof(output) / sizeof(PCRE2_UCHAR);
re = pcre2_compile(pattern, PCRE2_ZERO_TERMINATED, 0, &errornumber, &erroroffset, NULL);
if (re == NULL)
{
PCRE2_UCHAR buffer[256];
pcre2_get_error_message(errornumber, buffer, sizeof(buffer));
printf("PCRE2 compilation failed at offset %d: %s\n", (int)erroroffset, buffer);
}
match_data = pcre2_match_data_create_from_pattern(re, NULL);
rc = pcre2_substitute(re, subject, subject_length, 0, 0, match_data, NULL, replacement,
replacement_length, output, &outlen);
printf("Output: %s", output);
return 0;
}
I know that I should repeat pcre2_substitute in a loop for replacing the next match, but I am not sure about the safest way to feed output as the subject of the next step.
You can replace all with a single call to pcre2_substitute using extended option PCRE2_SUBSTITUTE_GLOBAL:
rc = pcre2_substitute(re, subject, subject_length, 0,
PCRE2_SUBSTITUTE_GLOBAL | PCRE2_SUBSTITUTE_EXTENDED,
match_data, NULL, replacement, replacement_length, output, &outlen);
Am trying to verify a message using RSA public key with help of WolfCrypt library. The message signing and verification is done using Openssl is successful with below commands.
openssl dgst -sha256 -sign private.pem -out Message.sign.rsa1024-sha-256 Message.txt
openssl dgst -sha256 -verify public.der -signture Message.sign.rsa1024-sha-256 Message.txt
Now, while trying to write a program using WolfCrypt library to verify the message(the program is not complete, Am stuck at parse public key part), the program is raising segmentation fault while parsing the public key itself. However, while trying to debug the program using GDB, the parse key section of code executes does not raise any segmentation fault and going to next step and exiting normally.
To avoid segfault, I tried malloc instead, still getting alloc(): memory corruption error.
It looks like the problem lies in wc_RsaPublicKeyDecode parameters. on GDB, while step-in to this function, the parameters looks empty. Any suggestion is welcome.
#include <stdio.h>
#include <stdlib.h>
/* Import APIs for Signing and Verification */
#include "wolfssl/wolfcrypt/rsa.h"
#include "wolfssl/wolfcrypt/hash.h"
#include "wolfssl/wolfcrypt/signature.h"
/* Import WolfSSL Types */
#include "wolfssl/wolfcrypt/types.h"
typedef struct wrap_Key
{
word32 _KeyIndex;
RsaKey _RsaKey;
}Key_t;
typedef struct wrap_Signature
{
/* Signature Algorithms */
enum wc_SignatureType _TYPE;
enum wc_HashType _DIGEST;
/* Message & Signature */
byte *_Message;
word32 _MessageLength;
byte *_Signature;
word32 _SignatureLength;
byte *_KeyBuffer;
word32 _KeyBufferLength;
/* RSA Key Structure */
Key_t _PKCS;
}Signature_t;
static int wrap_ReadFileToBuffer( byte **BufferData, word32* BufferLength, byte* URI )
{
int ret = EXIT_SUCCESS;
FILE *file = NULL;
file = fopen(URI, "r");
if( NULL == file )
{
printf( "Error! Unable to stat file.\r\n" );
return EXIT_FAILURE;
}
/* Get content length & Reset Cursor */
fseek( file, 0, SEEK_END );
*BufferLength = (word32) ftell(file);
fseek( file, 0, SEEK_SET );
/* Allocate Enough Buffer */
*BufferData = (byte*)(malloc( *BufferLength ));
if( NULL == *BufferData )
{
fclose(file);
printf("Error! Memory Allocation Failed.\r\n");
return EXIT_FAILURE;
}
/* Read File Content */
if( ( ret = fread( *BufferData, 1, *BufferLength, file ) )
!= *BufferLength )
{
fclose(file);
printf("Error! Unable to read file.\r\n");
return EXIT_FAILURE;
}
fclose(file);
return ret;
}
Signature_t *RSA1;
int main()
{
int ret = EXIT_SUCCESS;
RSA1 = malloc(sizeof(Signature_t));
/* Define Signagure & Type */
RSA1->_TYPE = WC_SIGNATURE_TYPE_RSA;
RSA1->_DIGEST = WC_HASH_TYPE_SHA256;
/* Initialize Message & Signature */
RSA1->_Message = NULL;
RSA1->_Signature = NULL;
/* Verify does the Hash given above is supproted? */
if( wc_HashGetDigestSize( RSA1->_DIGEST ) <= 0 )
{
printf("Hash type %d not supported!\n", RSA1->_DIGEST);
return EXIT_FAILURE;
}
if( wrap_ReadFileToBuffer( &(RSA1->_Message),
&(RSA1->_MessageLength), "Message.txt" ) <= 0 )
{
printf("Error! Reading Message Failed.\r\n");
return EXIT_FAILURE;
}
if( wrap_ReadFileToBuffer( &(RSA1->_Signature),
&(RSA1->_SignatureLength),
"Message.sign.rsa1024-sha-256" ) <= 0 )
{
printf("Error! Reading Signature Failed.\r\n");
return EXIT_FAILURE;
}
if( wrap_ReadFileToBuffer( &(RSA1->_KeyBuffer), &(RSA1->_KeyBufferLength),
"public.der" ) <= 0 )
{
printf("Error! Reading Key Failed.\r\n");
return EXIT_FAILURE;
}
if( ( ret = wc_InitRsaKey( &(RSA1->_PKCS._RsaKey), NULL ) ) )
{
printf("Error! Initialize Key Failed: -%d.\r\n", -ret);
return EXIT_FAILURE;
}
RSA1->_PKCS._KeyIndex = 0;
if( ( ret = wc_RsaPublicKeyDecode( RSA1->_KeyBuffer,
&RSA1->_PKCS._KeyIndex,
&RSA1->_PKCS._RsaKey,
RSA1->_KeyBufferLength ) ) )
{
printf("Error! Reading Key Failed: -%d.\r\n", -ret);
return EXIT_FAILURE;
}
free(RSA1);
printf("WolfCrypt - Sample program!\r\n");
return ret;
}
While trying to debug using GDB, found that after wc_InitRsaKey function, the entire structure *RSA1 is getting char array(byte here) is missing it's data.
(gdb) p *RSA1
$43 = {_TYPE = WC_SIGNATURE_TYPE_RSA, _DIGEST = WC_HASH_TYPE_SHA256,
_Message = 0x5555557585d0 "This is sample message to be signed!\n", _MessageLength = 37,
_Signature = 0x555555758600 "$\372\324#\340M\353\"\216\226\302V\372\265\210\242\377\362\343ɮ\032\021\206K\016/\f2\002\020!\274\234\024\212,\034\276\276,31\217\277\274sP\341c\024=u\236\233l\207\330\320>Ė\300K\211]\325\322x\307_9\251\017#\021'\225Oƞ\276\311\a\177\063`\016\271G8\r;\201\036,7x\246\251Wd\246j\273\272\220\304\354\244\305\370\027\321\312\017\250n\336'\375v{\251\267\270\237M", _SignatureLength = 128,
_KeyBuffer = 0x555555758690 "0\201\237\060\r\006\t*\206H\206\367\r\001\001\001\005",
_KeyBufferLength = 162, _PKCS = {_KeyIndex = 0, _RsaKey = {n = {used = 0, alloc = 0,
sign = 0, dp = 0x0}, e = {used = 0, alloc = 0, sign = 0, dp = 0x0}, d = {used = 0,
alloc = 0, sign = 0, dp = 0x0}, p = {used = 0, alloc = 0, sign = 0, dp = 0x0}, q = {
used = 0, alloc = 0, sign = 0, dp = 0x0}, dP = {used = 0, alloc = 0, sign = 0,
dp = 0x0}, dQ = {used = 0, alloc = 0, sign = 0, dp = 0x0}, u = {used = 0, alloc = 0,
sign = 0, dp = 0x0}, heap = 0x0, data = 0x0, type = 0, state = 0, dataLen = 0,
dataIsAlloc = 0 '\000'}}}
(gdb) n
133 RSA1->_PKCS._KeyIndex = 0;
(gdb) p *RSA1
$44 = {_TYPE = WC_SIGNATURE_TYPE_RSA, _DIGEST = WC_HASH_TYPE_SHA256,
_Message = 0x5555557585d0 "", _MessageLength = 37, _Signature = 0x555555758600 "",
_SignatureLength = 128, _KeyBuffer = 0x555555758690 "", _KeyBufferLength = 162, _PKCS = {
_KeyIndex = 0, _RsaKey = {n = {used = 0, alloc = 0, sign = 0, dp = 0x0}, e = {used = 0,
alloc = 0, sign = 0, dp = 0x0}, d = {used = 0, alloc = 0, sign = 0, dp = 0x0}, p = {
used = 0, alloc = 0, sign = 0, dp = 0x0}, q = {used = 0, alloc = 0, sign = 0,
dp = 0x0}, dP = {used = 0, alloc = 0, sign = 0, dp = 0x0}, dQ = {used = 0, alloc = 0,
sign = 0, dp = 0x0}, u = {used = 0, alloc = 0, sign = 0, dp = 0x0}, heap = 0x0,
data = 0x0, type = 0, state = 0, dataLen = 0, dataIsAlloc = 0 '\000'}}}
#Gopi,
The most common cause of such a segmentation fault is a misconfiguration of application and library. The first thing to check is the headers included.
/* Import APIs for Signing and Verification */
#include "wolfssl/wolfcrypt/rsa.h"
#include "wolfssl/wolfcrypt/hash.h"
#include "wolfssl/wolfcrypt/signature.h"
/* Import WolfSSL Types */
#include "wolfssl/wolfcrypt/types.h"
Notice that neither "wolfssl/options.h" or "wolfssl/wolfcrypt/settings.h" was included. If you built the wolfSSL library with ./configure && make please include "wolfssl/options.h" before all other wolfSSL headers. If you are only using "wolfssl/wolfcrypt/settings.h" to control the build and options.h is not found then at least include "wolfssl/wolfcrypt/settings.h" before all other wolfSSL headers:
/* Import APIs for Signing and Verification */
#include <wolfssl/options.h> // If not found or not available then include <wolfssl/wolfcrypt/settings.h>
#include "wolfssl/wolfcrypt/rsa.h"
#include "wolfssl/wolfcrypt/hash.h"
#include "wolfssl/wolfcrypt/signature.h"
/* Import WolfSSL Types */
#include "wolfssl/wolfcrypt/types.h"
Cheers,
K
My requirement is to extend drive volume through program. When I used IOCTL_DISK_GROW_PARTITION in DeviceIO to extend it, the disk management shows the new modified size while the size of the drive in This PC (My Computer) remains unchanged.
BOOL DeviceIoControl(
(HANDLE) hDevice, // handle to device
IOCTL_DISK_GROW_PARTITION, // dwIoControlCode
(LPVOID) lpInBuffer, // input buffer
(DWORD) nInBufferSize, // size of the input buffer
NULL, // lpOutBuffer
0, // nOutBufferSize
(LPDWORD) lpBytesReturned, // number of bytes returned
(LPOVERLAPPED) lpOverlapped // OVERLAPPED structure
);
Through some analysis I found that while using this API the MBR of the disk is modified but the cluster bitmap of drive is not changed. I want to know the correct way of using this DeviceIO to expand a volume or some other API to do the same process.
need understand different between disk driver, which maintain info about disk layout and partitions (it size, offset from disk begin, style (gpt or mbr) ) and file system, which mount this partition.
IOCTL_DISK_GROW_PARTITION - this ioctl is handled by disk driver and extend partition, but this can not have effect for file system, which not handle this ioctl and have no knowledge at all that partition was extended. so you need additional ioctl use FSCTL_EXTEND_VOLUME - this ioctl already send and handle to file-system.
so if we have to do next steps
send IOCTL_DISK_GROW_PARTITION with
DISK_GROW_PARTITION as input buffer
send IOCTL_DISK_UPDATE_DRIVE_SIZE with DISK_GEOMETRY
as output buffer
send IOCTL_DISK_GET_PARTITION_INFO_EX with
PARTITION_INFORMATION_EX as output for get actual size of
partition now.
calculate new size of the volume, in sectors
LONGLONG SectorsPerPartition = PartitionEntry->PartitionLength.QuadPart / dg.BytesPerSector;
(dg we got at step 2 and PartitionEntry at step 3)
finally use FSCTL_EXTEND_VOLUME
full code can be like next
int __cdecl SortPartitions(PPARTITION_INFORMATION_EX PartitionEntry1, PPARTITION_INFORMATION_EX PartitionEntry2)
{
if (!PartitionEntry1->PartitionNumber) return PartitionEntry2->PartitionNumber ? -1 : 0;
if (!PartitionEntry2->PartitionNumber) return +1;
if (PartitionEntry1->StartingOffset.QuadPart < PartitionEntry2->StartingOffset.QuadPart) return -1;
if (PartitionEntry1->StartingOffset.QuadPart > PartitionEntry2->StartingOffset.QuadPart) return +1;
return 0;
}
DWORD ExtendTest(HANDLE hDisk)
{
STORAGE_DEVICE_NUMBER sdn;
ULONG dwBytesRet;
if (!DeviceIoControl(hDisk, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, &sdn, sizeof(sdn), &dwBytesRet, NULL))
{
return GetLastError();
}
if (sdn.DeviceType != FILE_DEVICE_DISK || sdn.PartitionNumber != 0)
{
return ERROR_GEN_FAILURE;
}
GET_LENGTH_INFORMATION gli;
if (!DeviceIoControl(hDisk, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, &gli, sizeof(gli), &dwBytesRet, NULL))
{
return GetLastError();
}
DbgPrint("Disk Length %I64x (%I64u)\n", gli.Length.QuadPart, gli.Length.QuadPart);
PVOID stack = alloca(guz);
union {
PVOID buf;
PDRIVE_LAYOUT_INFORMATION_EX pdli;
};
ULONG cb = 0, rcb, PartitionCount = 4;
for (;;)
{
if (cb < (rcb = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry[PartitionCount])))
{
cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
}
if (DeviceIoControl(hDisk, IOCTL_DISK_GET_DRIVE_LAYOUT_EX, NULL, 0, buf, cb, &dwBytesRet, NULL))
{
if (PartitionCount = pdli->PartitionCount)
{
PPARTITION_INFORMATION_EX PartitionEntry = pdli->PartitionEntry;
qsort(PartitionEntry, PartitionCount, sizeof(PARTITION_INFORMATION_EX),
(int (__cdecl *)(const void *, const void *))SortPartitions );
do
{
if (!PartitionEntry->PartitionNumber)
{
continue;
}
LARGE_INTEGER EndOffset;
LARGE_INTEGER MaximumOffset = PartitionCount != 1 ? (PartitionEntry + 1)->StartingOffset : gli.Length;
EndOffset.QuadPart = PartitionEntry->StartingOffset.QuadPart + PartitionEntry->PartitionLength.QuadPart;
if (EndOffset.QuadPart > MaximumOffset.QuadPart)
{
//??
__debugbreak();
}
else if (EndOffset.QuadPart < MaximumOffset.QuadPart)
{
DISK_GROW_PARTITION dgp;
dgp.PartitionNumber = PartitionEntry->PartitionNumber;
dgp.BytesToGrow.QuadPart = MaximumOffset.QuadPart - EndOffset.QuadPart;
WCHAR sz[128];
swprintf(sz, L"\\\\?\\GLOBALROOT\\Device\\Harddisk%d\\Partition%u", sdn.DeviceNumber, dgp.PartitionNumber);
HANDLE hPartition = CreateFile(sz, FILE_READ_ACCESS|FILE_WRITE_ACCESS, FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, 0, 0);
if (hPartition != INVALID_HANDLE_VALUE)
{
// +++ begin extend
BOOL fOk = FALSE;
DISK_GEOMETRY dg;
if (DeviceIoControl(hPartition, IOCTL_DISK_GROW_PARTITION, &dgp, sizeof(dgp), 0, 0, &dwBytesRet, 0) &&
DeviceIoControl(hPartition, IOCTL_DISK_UPDATE_DRIVE_SIZE, 0, 0, &dg, sizeof(dg), &dwBytesRet, 0) &&
DeviceIoControl(hPartition, IOCTL_DISK_GET_PARTITION_INFO_EX, 0, 0, PartitionEntry, sizeof(*PartitionEntry), &dwBytesRet, 0)
)
{
LONGLONG SectorsPerPartition = PartitionEntry->PartitionLength.QuadPart / dg.BytesPerSector;
fOk = DeviceIoControl(hPartition, FSCTL_EXTEND_VOLUME, &SectorsPerPartition,
sizeof(SectorsPerPartition), 0, 0, &dwBytesRet, 0);
}
if (!fOk)
{
GetLastError();
}
//--- end extend
CloseHandle(hPartition);
}
}
// else EndOffset.QuadPart == MaximumOffset.QuadPart - partition can not be extended
} while (PartitionEntry++, --PartitionCount);
}
return NOERROR;
}
switch (ULONG err = GetLastError())
{
case ERROR_MORE_DATA:
PartitionCount = pdli->PartitionCount;
continue;
case ERROR_BAD_LENGTH:
case ERROR_INSUFFICIENT_BUFFER:
PartitionCount <<= 1;
continue;
default:
return err;
}
}
}
DWORD ExtendTest()
{
HANDLE hDisk = CreateFileW(L"\\\\?\\PhysicalDrive0", FILE_GENERIC_READ|FILE_GENERIC_WRITE,
FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, 0, 0);
if (hDisk != INVALID_HANDLE_VALUE)
{
DWORD err = ExtendTest(hDisk);
CloseHandle(hDisk);
return err;
}
return GetLastError();
}
I've tested the following regular expression at http://www.regexpal.com/
([A-Z]{1}[a-z]+)+([_]{1}([A-Z]{1}[a-z]+)+)+[.][a-z]+
Which successfully matches the following file names:
Butter_Butter.jpg
JavaPiebald_Java_Piebald.jpg
LowWhitePied_Pied.jpg
Piebald_Piebald.jpg
SpinnerBlast_Spider_Pinstripe_Pastel.jpg
Caramel_Caramel.jpg
LightningPied_Pied_Axanthic.jpg
Pastel_Pastel.jpg
Spider_Spider.jpg
Spinner_Spider_Pinstripe.jpg
When I implement the regular expression in the following C code, I receive no matches:
#define COLLECTION_REGEX "([A-Z]{1}[a-z]+)+([_]{1}([A-Z]{1}[a-z]+)+)+[.][a-z]+"
int is_valid_filename(char *filename)
{
regex_t regex;
int i, match;
char msgbuf[100];
match = 1;
i = regcomp(®ex, COLLECTION_REGEX, 0);
if (i)
{
perror("Could not compile regex");
}
else
{
match = regexec(®ex, filename, 0, NULL, 0);
if (!match)
{
puts("Match");
}
else if (match == REG_NOMATCH)
{
puts("No match");
}
else
{
regerror(match, ®ex, msgbuf, sizeof(msgbuf));
puts(msgbuf);
}
}
regfree(®ex);
return match;
}
Subsequent execution:
./a.out
No match
No match
No match
No match
No match
No match
No match
No match
No match
No match
The regular expression appears correct, I am uncertain as to why I am obtaining these results.
Output from GDB:
Breakpoint 1, is_valid_filename (filename=0x609050 "Piebald_Piebald.jpg") at crp-web-builder.c:76
76 match = regexec(®ex, filename, 0, NULL, 0);
(gdb) continue
Continuing.
No match
Breakpoint 1, is_valid_filename (filename=0x609460 "LightningPied_Pied_Axanthic.jpg") at crp-web-builder.c:76
76 match = regexec(®ex, filename, 0, NULL, 0);
(gdb) continue
Continuing.
No match
Breakpoint 1, is_valid_filename (filename=0x609870 "SpinnerBlast_Spider_Pinstripe_Pastel.jpg") at crp-web-builder.c:76
76 match = regexec(®ex, filename, 0, NULL, 0);
(gdb) continue
Continuing.
No match
Thanks to Jonathan Leffler. The line:
i = regcomp(®ex, COLLECTION_REGEX, 0);
Should be:
i = regcomp(®ex, COLLECTION_REGEX, REG_EXTENDED);
I tried issuing a SCSI Read(10) command to a physical drive on a Windows 7 machine. Below is the code snippet that I am using. It is failing with error code 87.
void scsi_read()
{
const UCHAR cdb[10] = { 0x28, 0, 0, 0, 0, 0, 0, 0, 512, 0 };
UCHAR buf[512];
BYTE senseBuf[196];
const int SENSE_LENGTH = 196;
LPCSTR fname = "\\\\.\\E:";
HANDLE fh;
DWORD ioctl_bytes;
DWORD err = 0;
SCSI_PASS_THROUGH s = {0};
memcpy(s.Cdb, cdb, sizeof(cdb));
s.CdbLength = 10;
s.DataIn = SCSI_IOCTL_DATA_IN;
s.TimeOutValue = 30;
s.Length = sizeof(SCSI_PASS_THROUGH);
s.ScsiStatus = 0x00;
s.SenseInfoOffset = senseBuf;
s.SenseInfoLength = SENSE_LENGTH;
s.DataBufferOffset = buf;
s.DataTransferLength = 512;
fh = CreateFile("\\\\.\\E:", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if(fh == INVALID_HANDLE_VALUE) {
printf("Could not open %s file, error %d\n", fname, GetLastError());
return (FALSE);
}
int ret = DeviceIoControl(fh,IOCTL_SCSI_PASS_THROUGH, &s,sizeof(s), //scsiPassThrough.sizeof,
&s,
sizeof(s),
&ioctl_bytes,
NULL);
printf("ret %d",(int)ret);
if (ret==1) {
printf("OK");
}
else {
err = GetLastError();
printf("Last error code %u\n", err);
printf("Return size %d\n", ioctl_bytes);
printf("Sense data\n");
int i=0;
for (i = 0; i < 20; i++) {
printf("\t%x", senseBuf[i]);
}
printf("\n");
}
CloseHandle(fh);
}
Error: Hex dumps are printed in the output
you got error code 87 - ERROR_INVALID_PARAMETER because code totally wrong.
for example:
const UCHAR cdb[10] = { 0x28, 0, 0, 0, 0, 0, 0, 0, 512, 0 };
but 512 is > 255 (MAXUCHAR) are you not got compiler warning here ?
warning C4305: 'initializing': truncation from 'int' to 'const UCHAR'
look at this line !
s.DataBufferOffset = buf;
from SCSI_PASS_THROUGH structure:
DataBufferOffset
Contains an offset from the beginning of this structure to the data
buffer. The offset must respect the data alignment requirements of the
device.
so offset to buffer, not pointer to buffer
for use this correct you code need be like this:
struct MY_DATA : SCSI_PASS_THROUGH
{
UCHAR buf[512];
} s;
s.DataBufferOffset = FIELD_OFFSET(MY_DATA, buf);
but better use SCSI_PASS_THROUGH_DIRECT with IOCTL_SCSI_PASS_THROUGH_DIRECT
you hardcode sector size (512), when need get it at runtime. and how you initialize CDB ?!? at all unclear what you try todo.
working code example (sorry but on c++ instead c)
#define _NTSCSI_USER_MODE_
#include <scsi.h>
#include <ntddscsi.h>
BOOL scsi_read(HANDLE fh, PVOID buf, DWORD cb, ULONGLONG LogicalBlock, ULONG TransferBlocks)
{
SCSI_PASS_THROUGH_DIRECT s = {
sizeof(SCSI_PASS_THROUGH_DIRECT), 0, 0, 0, 0, 0, 0, SCSI_IOCTL_DATA_IN, cb, 30, buf
};
union {
PUCHAR Cdb;
CDB::_CDB10* Cdb10;
CDB::_CDB16* Cdb16;
};
Cdb = s.Cdb;
if (MAXULONG < LogicalBlock || MAXUSHORT < TransferBlocks)
{
s.CdbLength = sizeof(CDB::_CDB16);
Cdb16->OperationCode = SCSIOP_READ16;
*(ULONGLONG*)Cdb16->LogicalBlock = _byteswap_uint64(LogicalBlock);
*(ULONG*)Cdb16->TransferLength = _byteswap_ulong(TransferBlocks);
}
else
{
s.CdbLength = sizeof(CDB::_CDB10);
Cdb10->OperationCode = SCSIOP_READ;
*(ULONG*)&Cdb10->LogicalBlockByte0 = _byteswap_ulong((ULONG)LogicalBlock);
*(USHORT*)&Cdb10->TransferBlocksMsb = _byteswap_ushort((USHORT)TransferBlocks);
}
DWORD ioctl_bytes;
return DeviceIoControl(fh, IOCTL_SCSI_PASS_THROUGH_DIRECT, &s, sizeof(s), &s, sizeof(s), &ioctl_bytes, NULL);
}
BOOL test_scsi_read(PCWSTR fname)
{
BOOL fOk = FALSE;
HANDLE fh = CreateFileW(fname, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if (fh != INVALID_HANDLE_VALUE)
{
DWORD ioctl_bytes;
DISK_GEOMETRY_EX dg;
if (DeviceIoControl(fh, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, NULL, 0, &dg, sizeof(dg), &ioctl_bytes, 0))
{
// 16 sectors for example
ULONG cb = 16 * dg.Geometry.BytesPerSector;
if (PVOID buf = new CHAR[cb])
{
// read first 16 sectors
fOk = scsi_read(fh, buf, cb, 0, 16);
if (ULONGLONG LogicalBlock = dg.DiskSize.QuadPart / dg.Geometry.BytesPerSector)
{
// read last sector
fOk = scsi_read(fh, buf, dg.Geometry.BytesPerSector, LogicalBlock - 1, 1);
}
delete buf;
}
}
CloseHandle(fh);
}
return fOk;
}
test_scsi_read(L"\\\\?\\e:");