C++ wininet fetching data in 513 byte chunks - c++

I am trying to fetch my server html text data using wininet, but it seems to be reading it and breaking it into 513 byte size chunks. However I would prefer the data to be fetched as a whole. Is there a way I can go around this?
Here is a full code for references:
#include <windows.h>
#include <wininet.h>
#include <stdio.h>
#include <iostream>
using namespace std;
#pragma comment (lib, "Wininet.lib")
int main(int argc, char** argv) {
HINTERNET hSession = InternetOpen(L"Mozilla/5.0", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
HINTERNET hConnect = InternetConnect(hSession, L"www.google.com", 0, L"", L"", INTERNET_SERVICE_HTTP, 0, 0);
HINTERNET hHttpFile = HttpOpenRequest(hConnect, L"GET", L"/", NULL, NULL, NULL, 0, 0);
while (!HttpSendRequest(hHttpFile, NULL, 0, 0, 0)) {
printf("Server Down.. (%lu)\n", GetLastError());
InternetErrorDlg(GetDesktopWindow(), hHttpFile, ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED, FLAGS_ERROR_UI_FILTER_FOR_ERRORS | FLAGS_ERROR_UI_FLAGS_GENERATE_DATA | FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS, NULL);
}
DWORD dwFileSize;
dwFileSize = BUFSIZ;
char* buffer;
buffer = new char[dwFileSize + 1];
while (true) {
DWORD dwBytesRead;
BOOL bRead;
bRead = InternetReadFile(hHttpFile, buffer, dwFileSize + 1, &dwBytesRead);
if (dwBytesRead == 0) break;
if (!bRead) {
printf("InternetReadFile error : <%lu>\n", GetLastError());
}
else {
buffer[dwBytesRead] = 0;
std::string newbuff = buffer;
std::wcout << "\n\nSize: " << newbuff.size() << std::endl;
std::cout << newbuff;
}
}
InternetCloseHandle(hHttpFile);
InternetCloseHandle(hConnect);
InternetCloseHandle(hSession);
}

dwFileSize = BUFSIZ;
If you look at your header files you will discover that BUFSIZ is #defined as 512.
buffer = new char[dwFileSize + 1];
// ...
Read = InternetReadFile(hHttpFile, buffer, dwFileSize + 1, &dwBytesRead);
Your program then proceeds to allocate a buffer of 513 bytes, and then read the input, 513 bytes at a time. And that's exactly the result you're observing. This is the only thing that the shown code knows how to do.
If you want to use a larger buffer size, you can easily change that (and there is no reason to new the buffer anyway, all that does is create an opportunity for memory leaks, just use std::vector, or a plain array for smaller buffers of this size).
Unless you have advance knowledge of the size of the file to retrieve you have no alternative but to read the file, in pieces, like that. Even though it's being retrieved in pieces it looks like the file is getting retrieved in a single request, and it's just that the shown code retrieve it one chunk at a time, which is perfectly fine. Switching to a large buffer size might improve the performance, but not dramatically.

Related

Why are these 2 sectors different?

i tried to read ntfs partition.
main function:
int main(int argc, char** argv)
{
BYTE sector[512];
ReadSector(L"\\\\.\\E:", 0, sector);
PrintBPB(ReadBPB(sector));
BYTE sector2[512];
ReadSector(L"\\\\.\\E:", 0, sector2);
PrintBPB(ReadBPB(sector2));
return 0;
}
ReadSector function:
int ReadSector(LPCWSTR drive, long readPoint, BYTE sector[Sector_Size])
{
int retCode = 0;
DWORD bytesRead;
HANDLE device = NULL;
device = CreateFile(drive, // Drive to open
GENERIC_READ, // Access mode
FILE_SHARE_READ | FILE_SHARE_WRITE, // Share Mode
NULL, // Security Descriptor
OPEN_EXISTING, // How to create
0, // File attributes
NULL); // Handle to template
if (device == INVALID_HANDLE_VALUE) // Open Error
{
printf("CreateFile: %u\n", GetLastError());
return 1;
}
SetFilePointer(device, readPoint, NULL, FILE_BEGIN);//Set a Point to Read
if (!ReadFile(device, sector, 512, &bytesRead, NULL))
{
printf("ReadFile: %u\n", GetLastError());
}
else
{
printf("Success!\n");
}
CloseHandle(device);
}
I think the way I copy those bytes into my BPB bpb is fine.
So what happend? Why they are different?
I can figure out that its relate to winapi, readfile, createfile but I still dont understand it :(
sorry for my bad english.
The bug is in the code we cannot see: PrintBPB. Apparently it switches to hexadecimal output (for the "Volume serial number") and then fails to switch back to decimal until later.
When the code calls PrintBPB a second time the output mode is still in hexadecimal format, and printing "Bytes per Sector" now displays 200 (0x200 is the same value as 512).
If you need to know whether two chunks of memory hold identical values, just memcmp them. This avoids introducing a bug in a transformation (such as console output).

How to use OVERLAPPED to write data at specific offset (win32 programming)

(I'm not native English speaker so sorry for potential mistake :p)
I want to write a Windows tool that can accelerate big files copying just like FastCopy. But get stuck at the very first step: Write data to specific offset of a file via OVERLAPPED (with WriteFile).
Here is my code:
#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <Windows.h>
#include <fileapi.h>
LPOVERLAPPED SetupOvl(DWORD OffsetHigh, DWORD Offset) {
printf("Ovl??: Got Offset %d\n", Offset);
LPOVERLAPPED Ovl = (LPOVERLAPPED)malloc(sizeof(OVERLAPPED));
Ovl->Internal = 0;
Ovl->InternalHigh = 0;
Ovl->OffsetHigh = OffsetHigh;
Ovl->Offset = Offset;
Ovl->Pointer = NULL;
Ovl->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
return Ovl;
}
int main()
{
HANDLE hf,hf2;
void* buffer2 = (void*)malloc(2 << 16);
void* buffer = (void*)malloc(2 << 16);
int readed_number = 0, writed_number = 0;
DWORD written_number = 0;
DWORD wn1 = 0, wn2 = 0;
// OpenThread
DeleteFileW(L"C:\\Users\\Lev\\Downloads\\dst.txt");
hf = CreateFileW(
L"C:\\Users\\Lev\\Downloads\\src.txt",
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
0);
hf2 = CreateFileW(
L"C:\\Users\\Lev\\Downloads\\dst.txt",
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
CREATE_NEW,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
NULL);
// ReadThread
BOOL ret = ReadFile(
hf,
buffer,
2 << 15,
(LPDWORD)&readed_number,
NULL
);
SetFilePointer(hf2, 16, 0, FILE_BEGIN);
SetEndOfFile(hf2);
LPOVERLAPPED Ovl1 = SetupOvl(0, 2);
WriteFile(hf2, buffer, 6, NULL, Ovl1);
LPOVERLAPPED Ovl2 = SetupOvl(0, 12);
buffer = (void*)((char*)buffer + (unsigned int)(10));
WriteFile(hf2, buffer, 4, NULL, Ovl2);
ret = GetOverlappedResult(hf2, Ovl1, &wn1, TRUE);
ret = GetOverlappedResult(hf2, Ovl2, &wn2, TRUE);
printf("Write_A: Write %d Bytes!\n", wn1);
printf("Write_B: Write %d Bytes!\n", wn2);
free(Ovl1);
free(Ovl2);
CloseHandle(hf);
CloseHandle(hf2);
return 0;
}
Output from console:
Ovl??: Got Offset 2
Ovl??: Got Offset 8
Write_A: Write 4 Bytes!
Write_B: Write 5 Bytes!
Content of src.txt: 1234567890abcdefghijklmn
Content of dst.txt: abcd56 (6 charactors and lots of 0x00)
In the code I try to write "123456" at 3rd byte and "abcd" at 13th byte. But it didn't work. I have look up MSDN and some books but found not code examples I need.
By the way, which is the best way to make a multi-thread acceleration? Multi-thread reading or multi-thread writing? Is it possible to use OVERLAPPED I/O to implement multiple threads writing to the same file in parallel? Or does it just write sequentially?
Any helpful suggestion is appreciated!

Getting Directory Size by reading through the MFT in C++ (like TreeSize)

Please read before quoting “repost” - I am aware similar questions have been asked, but I am yet to find a satisfactory answer
My goal is to provide a tree-like directory structure of disk space usage allowing the user to drill down the hierarchy in order to locate sizable folders.
The program TreeSize is an excellent example of this, and I am looking to get the same response times as this program.
My current code can iterate through my 480GB of files in aprx 25 seconds using the MFT. I am looking from this point to start building directory sizes by getting the file information (MFT contains only fileName and parentId, not full file path)
To get file information from MFT journal entry my current code calls
TCHAR filePath[MAX_PATH];
HANDLE hh = OpenFileById(hDevice, &(getFileIdDescriptor(pRecord->FileReferenceNumber)), 0, 0, 0, 0);
GetFinalPathNameByHandle(hh, filePath, MAX_PATH, 0);
Unfortunately this code increases the overall execution time of the program from 25 seconds to 5 minutes.
Is there a better way to get the file information?
Many thanks if you suggest FindFirstFile and FindNextFile but for processing large directories these options are too slow
Code as below (I’m not a C programmer as you might notice!)
#include <iostream>
#include <string>
#include <fstream>
#include <windows.h>
#include <fstream>
#include <atlbase.h>
#include <windows.h>
#include <stdio.h>
using namespace std;
typedef std::basic_string<TCHAR> tstring;
FILE_ID_DESCRIPTOR getFileIdDescriptor(const DWORDLONG fileId)
{
FILE_ID_DESCRIPTOR fileDescriptor;
fileDescriptor.Type = FileIdType;
fileDescriptor.FileId.QuadPart = fileId;
fileDescriptor.dwSize = sizeof(fileDescriptor);
return fileDescriptor;
}
bool ReadMFT()
{
HANDLE hDevice = CreateFile(TEXT("\\\\.\\C:"),
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
0,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
0);
if (hDevice == INVALID_HANDLE_VALUE) // cannot open the drive
{
printf("Error %d", GetLastError());
return (FALSE);
}
USN_JOURNAL_DATA ujd = { 0 };
DWORD cb = 0;
BYTE pData[sizeof(DWORDLONG) + 0x10000] = { 0 };
if (!DeviceIoControl(hDevice, FSCTL_QUERY_USN_JOURNAL, NULL, 0, &ujd, sizeof(USN_JOURNAL_DATA), &cb, NULL))
{
printf("Error %d", GetLastError());
return (FALSE);
}
MFT_ENUM_DATA med = { 0 };
med.StartFileReferenceNumber = 0;
med.LowUsn = 0;
med.HighUsn = ujd.NextUsn;
while (TRUE)
{
if (!DeviceIoControl(hDevice, FSCTL_ENUM_USN_DATA, &med, sizeof(med), pData, sizeof(pData), &cb, NULL))
{
printf("Error %d", GetLastError());
break;
}
PUSN_RECORD pRecord = (PUSN_RECORD)&pData[sizeof(USN)];
//Inner Loop
while ((PBYTE)pRecord < (pData + cb))
{
tstring sz((LPCWSTR)
((PBYTE)pRecord + pRecord->FileNameOffset),
pRecord->FileNameLength / sizeof(WCHAR));
pRecord = (PUSN_RECORD)((PBYTE)pRecord + pRecord->RecordLength);
// *******************************************************************************
// APPROACH 1
// Adding these lines of code increases the time from 25 seconds to 340 seconds
// Although it may be possible to push this onto a queue and run these in parrallel
// I still think it's an expensive option
/*TCHAR filePath[MAX_PATH];
HANDLE hh = OpenFileById(hDevice, &(getFileIdDescriptor(pRecord->FileReferenceNumber)), 0, 0, 0, 0);
GetFinalPathNameByHandle(hh, filePath, MAX_PATH, 0);*/
}
med.StartFileReferenceNumber = *(DWORDLONG *)pData;
}
}
int main()
{
ReadMFT();
}
Many thanks
After a few trials and errors, running the
FILE_ID_DESCRIPTOR f = getFileIdDescriptor(pRecord->FileReferenceNumber);
q.Dispatch(f, [f]
{
TCHAR filePath[MAX_PATH];
HANDLE hh = OpenFileById(hDevice, (LPFILE_ID_DESCRIPTOR)&(f), 0, 0, 0, 0);
GetFinalPathNameByHandle(hh, filePath, MAX_PATH, 0);
});
in parrallel brings the time down to 1:30
Check out this guys dispatch queue implementation
https://github.com/embeddedartistry/embedded-resources/blob/master/examples/cpp/dispatch.cpp
You might want to iterate the $INDEX_ALLOCATION attribute to get a list of the child nodes.

Incorrect Function Call "IOCTL_DISK_GET_DRIVE_LAYOUT_EX"

I am currently trying to write a C++ program to automate retrieving information about the partitions of a sample hard-drive image, the information in question being the number of partitions on the disk and for each partition its start sector, size and and file system type.
I'm pretty sure at this point the best way to achieve this is through MSDN functions, microsofts inbuilt commands. I am trying to use the "IOCTL_DISK_GET_DRIVE_LAYOUT_EX" function, but according to my get error call my function is incorrect. When I debug the program is appears that the bool value is also unchanged after the "IOCTL_DISK_GET_DRIVE_LAYOUT_EX" call, meaning it is not returning the bResult value.
I am using Microsoft Visual C++ Express Edition. If people could take a look at my code and tell me what they think I did wrong it would be much appreciated.
#define UNICODE 1
#define _UNICODE 1
#include <windows.h>
#include <winioctl.h>
#include <stdio.h>
#define wszDrive L"\\\\.\\PhysicalDrive6"
BOOL GetDriveParition(LPWSTR wszPath, DRIVE_LAYOUT_INFORMATION_EX *pdg)
{
HANDLE hDevice = INVALID_HANDLE_VALUE; // handle to the drive to be examined
BOOL bResult = FALSE; // results flag
DWORD junk = 0; // discard results
hDevice = CreateFileW(wszPath, // drive to open
0, // no access to the drive
FILE_SHARE_READ | // share mode
FILE_SHARE_WRITE,
NULL, // default security attributes
OPEN_EXISTING, // disposition
0, // file attributes
NULL); // do not copy file attributes
if (hDevice == INVALID_HANDLE_VALUE) // cannot open the drive
{
return (FALSE);
}
bResult = DeviceIoControl(
hDevice, // handle to device
IOCTL_DISK_GET_DRIVE_LAYOUT_EX, // dwIoControlCode
NULL, // lpInBuffer
0, // nInBufferSize
pdg, // lpOutBuffer
sizeof(*pdg), // nOutBufferSize
&junk, // lpBytesReturned
NULL); // lpOverlapped
CloseHandle(hDevice);
return (bResult);
}
int wmain(int argc, wchar_t *argv[])
{
DRIVE_LAYOUT_INFORMATION_EX pdg; // disk drive partition structure
BOOL bResult = FALSE; // generic results flag
bResult = GetDriveParition (wszDrive, &pdg);
if (bResult)
{
wprintf(L"Drive path = %ws\n", wszDrive);
wprintf(L"Partition Style = %I64d\n", pdg.PartitionStyle);
wprintf(L"Partition Count = %ld\n", pdg.PartitionCount);
system("Pause");
}
else
{
wprintf (L"GetDrivePartition failed. Error %ld.\n", GetLastError ());
system("Pause");
}
return ((int)bResult);
}
DRIVE_LAYOUT_INFORMATION_EX is a weird structure. It's defined as
struct {
DWORD PartitionStyle;
DWORD PartitionCount;
union {
DRIVE_LAYOUT_INFORMATION_MBR Mbr;
DRIVE_LAYOUT_INFORMATION_GPT Gpt;
};
PARTITION_INFORMATION_EX PartitionEntry[ 1 ];
}
but usually PartitionEntry is treated as a much larger array, with PartitionCount entries. This is similar to the C99 VLA mechanism. Since you'va allocated just sizeof(*pdg) bytes, there's no room for even a second PartitionEntry.
C++ hack:
struct ExtraEntries : DRIVE_LAYOUT_INFORMATION_EX
{
PARTITION_INFORMATION_EX PartitionEntry[ 9 ]; // Or some other reasonable value
};
Even if this post is a bit old, I found another way to get a fully populated PartitionEntry without creating a tricky struct. This is how I did it:
Inspired of an answer from this post: How-to-call-deviceiocontrol-to-retrieve-the-amount-of-memory-it-needs
DRIVE_LAYOUT_INFORMATION_EX dli;
DWORD bytesReturned = 0;
if (!DeviceIoControl(hDevice, IOCTL_DISK_GET_DRIVE_LAYOUT_EX, NULL, 0, (void*)&dli, sizeof(dli), &bytesReturned, NULL))
{
// Check last error if not ERROR_INSUFFICIENT_BUFFER then return
int nError = GetLastError();
if (nError != ERROR_INSUFFICIENT_BUFFER)
{
// std::cout << "DeviceIoControl() Failed: " << nError << std::endl;
CloseHandle(hDevice);
return false;
}
// Allocate enough buffer space based of the value of Partition Count:
size_t size = offsetof(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry[dli.PartitionCount]);
std::vector<BYTE> buffer(size);
if (!DeviceIoControl(hDevice, IOCTL_DISK_GET_DRIVE_LAYOUT_EX, NULL, 0, (void*)buffer.data(), size, &bytesReturned, NULL))
{
nError = GetLastError();
// std::cout << "DeviceIoControl() Failed: " << nError << std::endl;
CloseHandle(hDevice);
return false;
}
const DRIVE_LAYOUT_INFORMATION_EX& result = *reinterpret_cast<const DRIVE_LAYOUT_INFORMATION_EX*>(buffer.data());
// Here all parition entry are populated ...
// TO DO... Do your stuff with result
}
else
{
// Call succeeded; dli is populated with a signle partition entry
// TO DO... Do your stuff with dli
}

POST form data using WinInet c++

I'm trying to make this program connect to a website and submit form data in order to login, but I don't know what I'm doing wrong. I have heard of others like curl and Winsock but I chose the WinINet library. So just for the testing of this program I've been using the website Pastebin to post to. So far, I haven't seen any results from this. If this program succeeds in posting the form data it will give me the header to the location of the post on their site.
Am I writing the form data char* correctly? I have seen on other stackoverflow posts where they had a large amount of dashes before some number then the put their form data.
Do I need to add something to it make it simulate clicking the submit button?
Do I need to write out values for each elements on the form?
I have tried HttpAddRequestHeaders and that didn't help me.
Also, I get the ERROR_INSUFFICIENT_BUFFER error on HttpOpenRequest but it still returns a valid HINTERNET.
#include <Windows.h>
#include <WinInet.h>
#include <iostream>
#pragma comment( lib,"Wininet.lib")
using namespace std;
char* getheaders(HINTERNET hRequest){
DWORD dwInfoLevel=HTTP_QUERY_RAW_HEADERS_CRLF;
DWORD dwInfoBufferLength=10;
char* pInfoBuffer=(char*)malloc(dwInfoBufferLength+1);
while(!HttpQueryInfo(hRequest,dwInfoLevel,pInfoBuffer,&dwInfoBufferLength,NULL)){
if (GetLastError()==ERROR_INSUFFICIENT_BUFFER){
free(pInfoBuffer);
pInfoBuffer=(char*)malloc(dwInfoBufferLength+1);
}else{
fprintf(stderr,"HttpQueryInfo failed, error = %d (0x%x)\n",GetLastError(),GetLastError());
break;
}
}
pInfoBuffer[dwInfoBufferLength] = '\0';
return pInfoBuffer;
}
void readfile(HINTERNET hRequest,char** buffs,int size){
DWORD dwBytesAvailable;
DWORD dwBytesRead;
for(int i=0;i<size;i++){
if(!InternetQueryDataAvailable(hRequest,&dwBytesAvailable,0,0)) break;
buffs[i]=(char*)malloc(dwBytesAvailable+1);
bool bResult=InternetReadFile(hRequest,buffs[i],dwBytesAvailable,&dwBytesRead);
if(!bResult | dwBytesRead==0) break;
}
}
int main(int argc,char** argv){
char* hdrs="Content-Type: application/x-www-form-urlencoded";
char* frmdata="paste_code=test";
LPCSTR accept[2]={"*/*", NULL};
HINTERNET hSession = InternetOpen("http generic",INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
HINTERNET hConnect = InternetConnect(hSession, "www.pastebin.com",INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 1);
HINTERNET hRequest = HttpOpenRequest(hConnect, "GET","/", NULL, NULL, accept, 0, 0);
//ERROR_INSUFFICIENT_BUFFER (122) with "accept".
bool send=HttpSendRequest(hRequest, hdrs, strlen(hdrs), NULL,NULL);
if(!send){
printf("HttpSendRequest failed, code=%d",GetLastError());
system("pause>nul");
return 0;
}
char* heads=getheaders(hRequest);
printf("%s\n\n\n\n",heads);
HINTERNET hRequest2 = HttpOpenRequest(hConnect, "POST","/", NULL, NULL, accept, 0, 0);
//ERROR_INSUFFICIENT_BUFFER (122) with "accept".
send=HttpSendRequest(hRequest2, hdrs, strlen(hdrs), frmdata,strlen(frmdata));
if(!send){
printf("HttpSendRequest failed, code=%d",GetLastError());
system("pause>nul");
return 0;
}
heads=getheaders(hRequest);
printf("%s\n\n\n\n",heads);
InternetCloseHandle(hRequest);
InternetCloseHandle(hRequest2);
InternetCloseHandle(hConnect);
InternetCloseHandle(hSession);
system("pause>nul");
return 0;
}
Your code is nearly correct, you must make sure of the following points:
char* hdrs="Content-Type: application/x-www-form-urlencoded";
you must make sure that your return object from POST message will be of type x-www-form-urlencoded or JSON . if it's JSON you
need to define char* hdrs="Content-Type: application/json\r\n";
Note: you must append \r\n to the hdrs.
try to call readFile method with buffer of size 10000 for example
and print buffer , it will print the output of the response to the
connection
In HINTERNET hRequest2 = HttpOpenRequest(hConnect, "POST","/", NULL, NULL, accept, 0, 0); instead of "/" you must call the path of
the requested API for example: .
In HINTERNET hRequest2 = HttpOpenRequest(hConnect, "POST", "/users/jsonlogin", NULL, NULL, accept, 0, 0);