Defragmenting File Programatically On Windows - c

I am attempting to follow this tutorial: Defragmenting Files.
I call DeviceIoControl() with FSCTL_GET_VOLUME_BITMAP on a handle to the C: volume, and I get a proper response.
I then open a handle to another file (I tried files from 10KB to a few MB) successfully, then I call DeviceIoControl() with FSCTL_GET_RETRIEVAL_POINTERS, and it succeeds with no last error or failed result, but the RETRIEVAL_POINTERS_BUFFER is not filled.
I also tried calling it on the C: volume handle, but it keeps returning ERROR_HANDLE_EOF even after trying to set the OVERLAPPED offset to 0, and setting the file pointer with SetFilePointer() to 0 relative to the beginning of the file.
BOOL dic(HANDLE dev, DWORD code, LPVOID in, DWORD ins, LPVOID out, LPDWORD outs)
{
HANDLE h = GetProcessHeap();
DWORD s = 1000;
DWORD r = 0;
out = HeapAlloc(h,HEAP_ZERO_MEMORY,s);
while (!DeviceIoControl(dev, code, in, ins, out, s, &r, 0))
{
if (ERROR_INSUFFICIENT_BUFFER == GetLastError() || ERROR_MORE_DATA == GetLastError())
{
s *= 10;
LPVOID t = HeapReAlloc(h, HEAP_ZERO_MEMORY, out, s);
if(!t){
HeapFree(h, 0, out);
return 0;
}
out = t;
}
else
{
HeapFree(h, 0, out);
printf("dic unk: %d\n", GetLastError());
return 0;
}
}
*outs = s;
return 1;
}
BOOL getvolptr(HANDLE volh, PRETRIEVAL_POINTERS_BUFFER rpb, LPDWORD rpbs)
{
STARTING_VCN_INPUT_BUFFER vcn = { 0 };
return dic(volh, FSCTL_GET_RETRIEVAL_POINTERS, &vcn, sizeof(vcn), rpb, rpbs);
}
RETRIEVAL_POINTERS_BUFFER rpb = { 0 };
DWORD rpbs = 0;
ULONGLONG cluster_cnt=0;
HANDLE fi = openfile("C:\\Windows\\System32\\Kernel32.dll");
if (INVALID_HANDLE_VALUE == fi)
{
printf("failed to open file! (%d)\n", GetLastError());
getchar();
}
r = getvolptr(fi, &rpb, &rpbs);
if (!r)
{
printf("failed to get vol ptrs! (%d)\n", GetLastError());
getchar();
}
for (int i = 0; i < rpb.ExtentCount; ++i)
{
cluster_cnt = (ULONGLONG)(rpb.Extents[i].NextVcn.QuadPart) - (ULONGLONG)(rpb.StartingVcn.QuadPart);
printf("%d) size: %llu clusters (0x%016X)\n", i, cluster_cnt, rpb.Extents[i].Lcn.QuadPart);
}

You are not checking the first HeapAlloc() for failure. And HeapFree() can wipe the last error code from DeviceIoControl() before you print it.
But more importantly, you are not passing the out data back to the caller correctly, so you are leaking the allocated memory, and the caller ends up with garbage for output.
Since the caller is passing in their own RETRIEVAL_POINTERS_BUFFER to receive the data, you need to copy the contents of the allocate memory into that buffer, eg:
BOOL dic(HANDLE dev, DWORD code, LPVOID in, DWORD ins, LPVOID out, LPDWORD outs)
{
if (!in || !out || !outs)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
*outs = 0;
HANDLE h = GetProcessHeap();
DWORD s = 1000;
LPVOID buf = HeapAlloc(h, HEAP_ZERO_MEMORY, s);
if (!buf)
return FALSE;
DWORD r = 0;
while (!DeviceIoControl(dev, code, in, ins, buf, s, &r, 0))
{
if (ERROR_INSUFFICIENT_BUFFER == GetLastError() || ERROR_MORE_DATA == GetLastError())
{
s *= 10;
LPVOID t = HeapReAlloc(h, HEAP_ZERO_MEMORY, buf, s);
if (!t)
{
HeapFree(h, 0, buf);
return FALSE;
}
buf = t;
}
else
{
printf("dic unk: %u\n", GetLastError());
HeapFree(h, 0, buf);
return FALSE;
}
}
if (s > *outs)
{
HeapFree(h, 0, buf);
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
CopyMemory(out, buf, s);
*outs = s;
HeapFree(h, 0, buf);
return TRUE;
}
BOOL getvolptr(HANDLE volh, PRETRIEVAL_POINTERS_BUFFER rpb, LPDWORD rpbs)
{
STARTING_VCN_INPUT_BUFFER vcn = { 0 };
return dic(volh, FSCTL_GET_RETRIEVAL_POINTERS, &vcn, sizeof(vcn), rpb, rpbs);
}
HANDLE fi = openfile("C:\\Windows\\System32\\Kernel32.dll");
if (INVALID_HANDLE_VALUE == fi)
{
printf("failed to open file! (%u)\n", GetLastError());
getchar();
}
else
{
RETRIEVAL_POINTERS_BUFFER rpb = { 0 };
DWORD rpbs = sizeof(rpb);
if (!getvolptr(fi, &rpb, &rpbs))
{
printf("failed to get vol ptrs! (%u)\n", GetLastError());
getchar();
}
else
{
ULONGLONG cluster_cnt = 0;
for (int i = 0; i < rpb.ExtentCount; ++i)
{
cluster_cnt = (ULONGLONG)(rpb.Extents[i].NextVcn.QuadPart) - (ULONGLONG)(rpb.StartingVcn.QuadPart);
printf("%d) size: %llu clusters (0x%016X)\n", i, cluster_cnt, rpb.Extents[i].Lcn.QuadPart);
}
}
closefile(fi);
}
Alternatively, you can return the pointer to the allocated memory to the caller, and the caller will have to free the memory when done using it, eg:
BOOL dic(HANDLE dev, DWORD code, LPVOID in, DWORD ins, LPVOID* out, LPDWORD outs)
{
if (!in || !out || !outs)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
*out = NULL;
*outs = 0;
HANDLE h = GetProcessHeap();
DWORD s = 1000;
LPVOID buf = HeapAlloc(h, HEAP_ZERO_MEMORY, s);
if (!buf)
return FALSE;
DWORD r = 0;
while (!DeviceIoControl(dev, code, in, ins, buf, s, &r, 0))
{
if (ERROR_INSUFFICIENT_BUFFER == GetLastError() || ERROR_MORE_DATA == GetLastError())
{
s *= 10;
LPVOID t = HeapReAlloc(h, HEAP_ZERO_MEMORY, buf, s);
if (!t)
{
HeapFree(h, 0, buf);
return FALSE;
}
buf = t;
}
else
{
printf("dic unk: %u\n", GetLastError());
HeapFree(h, 0, buf);
return FALSE;
}
}
*out = buf;
*outs = s;
return TRUE;
}
BOOL getvolptr(HANDLE volh, PRETRIEVAL_POINTERS_BUFFER* rpb, LPDWORD rpbs)
{
STARTING_VCN_INPUT_BUFFER vcn = { 0 };
return dic(volh, FSCTL_GET_RETRIEVAL_POINTERS, &vcn, sizeof(vcn), (void**)rpb, rpbs);
}
HANDLE fi = openfile("C:\\Windows\\System32\\Kernel32.dll");
if (INVALID_HANDLE_VALUE == fi)
{
printf("failed to open file! (%u)\n", GetLastError());
getchar();
}
else
{
PRETRIEVAL_POINTERS_BUFFER rpb = NULL;
DWORD rpbs = 0;
if (!getvolptr(fi, &rpb, &rpbs))
{
printf("failed to get vol ptrs! (%u)\n", GetLastError());
getchar();
}
else
{
ULONGLONG cluster_cnt = 0;
for (int i = 0; i < rpb->ExtentCount; ++i)
{
cluster_cnt = (ULONGLONG)(rpb->Extents[i].NextVcn.QuadPart) - (ULONGLONG)(rpb->StartingVcn.QuadPart);
printf("%d) size: %llu clusters (0x%016X)\n", i, cluster_cnt, rpb->Extents[i].Lcn.QuadPart);
}
HeapFree(GetProcessHeap(), 0, rpb);
}
closefile(fi);
}

Related

Reading motion vectors of every 60th frame in video file

I have the following code which reads a video files and extracts motion vectors from each frame and outputs them to stdout:
#include <libavutil/motion_vector.h>
#include <libavformat/avformat.h>
static AVFormatContext *fmt_ctx = NULL;
static AVCodecContext *video_dec_ctx = NULL;
static AVStream *video_stream = NULL;
static const char *src_filename = NULL;
static int video_stream_idx = -1;
static AVFrame *frame = NULL;
static int video_frame_count = 0;
static int decode_packet(const AVPacket *pkt)
{
//fprintf(stderr, "%d\n", video_dec_ctx->width);
int ret = avcodec_send_packet(video_dec_ctx, pkt);
if (ret < 0) {
fprintf(stderr, "Error while sending a packet to the decoder: %s\n", av_err2str(ret));
return ret;
}
while (ret >= 0) {
ret = avcodec_receive_frame(video_dec_ctx, frame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
break;
} else if (ret < 0) {
fprintf(stderr, "Error while receiving a frame from the decoder: %s\n", av_err2str(ret));
return ret;
}
if (ret >= 0) {
int i;
AVFrameSideData *sd;
video_frame_count++;
sd = av_frame_get_side_data(frame, AV_FRAME_DATA_MOTION_VECTORS);
if (sd) {
const AVMotionVector *mvs = (const AVMotionVector *)sd->data;
for (i = 0; i < sd->size / sizeof(*mvs); i++) {
const AVMotionVector *mv = &mvs[i];
printf("%d,%4d,%4d,%4d\n",
video_frame_count,
abs(mv->src_x - mv->dst_x),
abs(mv->src_y - mv->dst_y));
}
}
av_frame_unref(frame);
}
}
return 0;
}
static int open_codec_context(AVFormatContext *fmt_ctx, enum AVMediaType type)
{
int ret;
AVStream *st;
AVCodecContext *dec_ctx = NULL;
AVCodec *dec = NULL;
AVDictionary *opts = NULL;
ret = av_find_best_stream(fmt_ctx, type, -1, -1, &dec, 0);
if (ret < 0) {
fprintf(stderr, "Could not find %s stream in input file '%s'\n",
av_get_media_type_string(type), src_filename);
return ret;
} else {
int stream_idx = ret;
st = fmt_ctx->streams[stream_idx];
dec_ctx = avcodec_alloc_context3(dec);
if (!dec_ctx) {
fprintf(stderr, "Failed to allocate codec\n");
return AVERROR(EINVAL);
}
ret = avcodec_parameters_to_context(dec_ctx, st->codecpar);
if (ret < 0) {
fprintf(stderr, "Failed to copy codec parameters to codec context\n");
return ret;
}
/* Init the video decoder */
av_dict_set(&opts, "flags2", "+export_mvs", 0);
if ((ret = avcodec_open2(dec_ctx, dec, &opts)) < 0) {
fprintf(stderr, "Failed to open %s codec\n",
av_get_media_type_string(type));
return ret;
}
video_stream_idx = stream_idx;
video_stream = fmt_ctx->streams[video_stream_idx];
video_dec_ctx = dec_ctx;
}
return 0;
}
int main(int argc, char **argv)
{
int ret = 0;
AVPacket pkt = { 0 };
if (argc != 2) {
fprintf(stderr, "Usage: %s <video>\n", argv[0]);
exit(1);
}
src_filename = argv[1];
if (avformat_open_input(&fmt_ctx, src_filename, NULL, NULL) < 0) {
fprintf(stderr, "Could not open source file %s\n", src_filename);
exit(1);
}
if (avformat_find_stream_info(fmt_ctx, NULL) < 0) {
fprintf(stderr, "Could not find stream information\n");
exit(1);
}
open_codec_context(fmt_ctx, AVMEDIA_TYPE_VIDEO);
av_dump_format(fmt_ctx, 0, src_filename, 0);
if (!video_stream) {
fprintf(stderr, "Could not find video stream in the input, aborting\n");
ret = 1;
goto end;
}
frame = av_frame_alloc();
if (!frame) {
fprintf(stderr, "Could not allocate frame\n");
ret = AVERROR(ENOMEM);
goto end;
}
printf("framenum,dx,dy\n");
/* read frames from the file */
while (av_read_frame(fmt_ctx, &pkt) >= 0) {
if (pkt.stream_index == video_stream_idx)
ret = decode_packet(&pkt);
av_packet_unref(&pkt);
if (ret < 0)
break;
}
/* flush cached frames */
decode_packet(NULL);
end:
avcodec_free_context(&video_dec_ctx);
avformat_close_input(&fmt_ctx);
av_frame_free(&frame);
return ret < 0;
}
Instead and outputting every frame, I only want to read one frame every 60 frames. The speed of the program is very important so I want to eliminate as much unnecessary code as possible. The problem is I'm having a hard time understanding how to advance the video stream without reading in new frames. I call av_read_frame(fmt_ctx, &pkt) to get packet info that is decoded by decode_packet and then goes on to read the next, but I can't find a way to only get packet info for one frame out of each 60.
Use av_seek_frame() to read every 60th frame.

strtok_s return incorrect data inside windbg

(Hello Everyone) I have some problem with strtok_s. I wrote this code(x64).
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
BOOL TestMD5(CONST WCHAR* MD5_DATABASE_FILE)
{
HANDLE hFile = INVALID_HANDLE_VALUE;
DWORD FileSize = 0;
DWORD dwReaded = 0;
PBYTE pData = NULL;
BOOL bRead = FALSE;
PCHAR token_string = NULL;
PCHAR context = NULL;
CONST PCHAR delimeter = "\r\n";
hFile = CreateFileW(
MD5_DATABASE_FILE,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if (hFile == INVALID_HANDLE_VALUE)
{
wprintf(L"Can't open md5 database file: ");
return FALSE;
}
FileSize = GetFileSize(hFile, NULL);
if (FileSize == 0 || FileSize == INVALID_FILE_SIZE)
{
CloseHandle(hFile);
return FALSE;
}
pData = (PBYTE)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (SIZE_T)FileSize);
if (pData == NULL)
{
CloseHandle(hFile);
return FALSE;
}
bRead = ReadFile(hFile, pData, FileSize, &dwReaded, NULL);
if (bRead != TRUE || dwReaded != FileSize)
{
HeapFree(GetProcessHeap(), 0, pData);
CloseHandle(hFile);
return FALSE;
}
token_string = (PCHAR)strtok_s(pData, delimeter, &context);
if (token_string == NULL)
{
HeapFree(GetProcessHeap(), 0, pData);
CloseHandle(hFile);
return FALSE;
}
do {
printf("%s\n", token_string);
} while (token_string = (PCHAR)strtok_s(NULL, delimeter, &context));
HeapFree(GetProcessHeap(), 0, pData);
CloseHandle(hFile);
return TRUE;
}
int main(void)
{
WCHAR* MD5_DATABASE_FILE = L"c:\\md5.txt";
TestMD5(MD5_DATABASE_FILE);
}
When I run exe this gives me a incorrect data. Content of md5.txt (DC288E0B39EA16B4E9455F82FF265A67:1213:TestDBG + (\r\n)
output:
D:\repos\TestWindbg\x64\Debug>TestWindbg.exe
DC288E0B39EA16B4E9455F82FF265A67:1213:TestDBG
áááááááááááááááá
I open exe in windbg and I saw while(token_string) is not NULL after first time. But is must?
WinDbg image : "https://i.ibb.co/60nHk5S/Untitled.png"
What is problem? Thanks for reading
Jeffrey Shao - MSFT :Thank you for reply but this is not solution(but I changed my code PBYTE TO PCHAR). The problem is that strtok_s is a string function for this reason you must add NULL byte after buff. Like HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,(SIZE_T)FileSize + 1) #1 for NULL character . HeapAlloc alloc buff size:FileSize and +1 For Null...
Thanks for blabb and Daniel Sęk:
I just change some types of pData and token_string.
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
BOOL TestMD5(CONST WCHAR* MD5_DATABASE_FILE)
{
HANDLE hFile = INVALID_HANDLE_VALUE;
DWORD FileSize = 0;
DWORD dwReaded = 0;
char* pData = NULL;
BOOL bRead = FALSE;
char* token_string = NULL;
PCHAR context = NULL;
CONST PCHAR delimeter = "\r\n";
hFile = CreateFileW(
MD5_DATABASE_FILE,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if (hFile == INVALID_HANDLE_VALUE)
{
wprintf(L"Can't open md5 database file: ");
return FALSE;
}
FileSize = GetFileSize(hFile, NULL);
if (FileSize == 0 || FileSize == INVALID_FILE_SIZE)
{
CloseHandle(hFile);
return FALSE;
}
pData = (char*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,(SIZE_T)FileSize + 1);
if (pData == NULL)
{
CloseHandle(hFile);
return FALSE;
}
bRead = ReadFile(hFile, pData, FileSize, &dwReaded, NULL);
if (bRead != TRUE || dwReaded != FileSize)
{
HeapFree(GetProcessHeap(), 0, pData);
CloseHandle(hFile);
return FALSE;
}
token_string = strtok_s(pData, delimeter, &context);
if (token_string == NULL)
{
HeapFree(GetProcessHeap(), 0, pData);
CloseHandle(hFile);
return FALSE;
}
do {
printf("%s\n", token_string);
} while (token_string = strtok_s(NULL, delimeter, &context));
HeapFree(GetProcessHeap(), 0, pData);
CloseHandle(hFile);
return TRUE;
}
int main(void)
{
WCHAR* MD5_DATABASE_FILE = L"c:\\md5.txt";
TestMD5(MD5_DATABASE_FILE);
}
Output:
DC288E0B39EA16B4E9455F82FF265A67:1213:TestDBG + (\r\n)

How to set l2tp preshared key?

I need to create RASENTRY for L2TP with pre-shared key set. So far, I can see that entry has somewhat correct flags, but no key is set, unfortunately.
Here is code:
int common_ras_manager_create_entry(const char* server_address, const char* username, const char* password, MY_VPN_CONNECTION_TYPE connection_type, const char* preshared_key)
{
DWORD EntryInfoSize = 0;
DWORD DeviceInfoSize = 0;
DWORD Ret;
LPRASENTRY lpRasEntry;
LPBYTE lpDeviceInfo;
// Get buffer sizing information for a default phonebook entry
if ((Ret = RasGetEntryProperties(NULL, "", NULL, &EntryInfoSize, lpDeviceInfo, &DeviceInfoSize)) != 0)
{
if (Ret != ERROR_BUFFER_TOO_SMALL)
{
printf("RasGetEntryProperties sizing failed with error %d\n", Ret);
return Ret;
}
}
lpRasEntry = (LPRASENTRY) GlobalAlloc(GPTR, EntryInfoSize);
if (DeviceInfoSize == 0)
lpDeviceInfo = NULL;
else
lpDeviceInfo = (LPBYTE) GlobalAlloc(GPTR, DeviceInfoSize);
// Get default phonebook entry
lpRasEntry->dwSize = sizeof(RASENTRY);
if ((Ret = RasGetEntryProperties(NULL, "", lpRasEntry, &EntryInfoSize, lpDeviceInfo, &DeviceInfoSize)) != 0)
{
printf("RasGetEntryProperties failed with error %d\n", Ret);
return Ret;
}
// Validate new phonebook name "Testentry"
if ((Ret = RasValidateEntryName(NULL, APP_NAME)) != ERROR_SUCCESS)
{
printf("RasValidateEntryName failed with error %d\n", Ret);
if (Ret != ERROR_ALREADY_EXISTS)
return Ret;
}
LPRASDEVINFO ras_devices;
DWORD cb =sizeof(RASDEVINFO);
DWORD cbDevices = 0;
ras_devices = (LPRASDEVINFO)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cb);
if (NULL == ras_devices)
{
printf("HeapAlloc failed.\n");
return ERROR_OUTOFMEMORY;
}
ras_devices->dwSize = sizeof(RASDEVINFO);
if ((Ret = RasEnumDevices(ras_devices, &cb, &cbDevices)) != ERROR_SUCCESS)
{
printf("RasEnumDevices failed with error %d\n", Ret);
switch(Ret)
{
case ERROR_BUFFER_TOO_SMALL:
printf("buffer too small");
HeapFree(GetProcessHeap(), 0, (LPVOID)ras_devices);
ras_devices = (LPRASDEVINFO)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cb);
if (NULL == ras_devices)
{
printf("HeapAlloc failed.\n");
return ERROR_OUTOFMEMORY;
}
ras_devices->dwSize = sizeof(RASDEVINFO);
Ret = RasEnumDevices(ras_devices, &cb, &cbDevices);
if (ERROR_SUCCESS == Ret)
{
//fSuccess = TRUE;
}
else
{
printf("RasEnumDevices failed again: Error = %d\n", Ret);
return Ret;
//goto done;
}
break;
case ERROR_NOT_ENOUGH_MEMORY:
printf("ERROR_NOT_ENOUGH_MEMORY");
return Ret;
break;
case ERROR_INVALID_PARAMETER:
printf("ERROR_INVALID_PARAMETER");
return Ret;
break;
case ERROR_INVALID_USER_BUFFER:
printf("ERROR_INVALID_USER_BUFFER");
return Ret;
break;
}
}
DWORD dwVpnStrategy = 0;
char device_name_mask[5];
strcpy(device_name_mask, "");
gboolean preshared_key_valid = 0;
switch(connection_type)
{
case PPTP:
strcpy(device_name_mask, "PPTP");
dwVpnStrategy = VS_PptpOnly;
break;
case L2TP:
if (preshared_key == 0 || strlen(preshared_key) == 0)
{
printf("CRITICAL: preshared key not set.");
return 1;
}
else
{
preshared_key_valid = TRUE;
}
strcpy(device_name_mask, "L2TP");
dwVpnStrategy = VS_L2tpOnly;
break;
}
int i =0;
for (i = 0; i < cbDevices; i++)
{
RASDEVINFO r = ras_devices[i];
if (strstr(r.szDeviceName, device_name_mask))
{
break;
}
}
//lpRasEntry->dwfOptions |= RASEO_SpecificIpAddr;
//lpRasEntry->szLocalPhoneNumber = RASDT_Vpn;
lpRasEntry->dwfNetProtocols |= RASNP_Ip;
lpRasEntry->dwFramingProtocol = RASFP_Ppp;
lstrcpy(lpRasEntry->szDeviceType, RASDT_Vpn);
lstrcpy(lpRasEntry->szDeviceName, ras_devices[i].szDeviceName);
lstrcpy(lpRasEntry->szLocalPhoneNumber, server_address);
lpRasEntry->dwVpnStrategy = dwVpnStrategy; // VS_PptpOnly; VS_SstpOnly
if (preshared_key_valid)
{
L2TP_CONFIG_DATA* data = GlobalAlloc(GPTR, sizeof(L2TP_CONFIG_DATA));
lpRasEntry->dwfOptions2 |= RASEO2_UsePreSharedKey;
data->dwOffsetKey = 16;
memcpy((PBYTE)data + data->dwOffsetKey, preshared_key, strlen(preshared_key));
data->dwAuthType =L2TP_IPSEC_AUTH_PRESHAREDKEY;
RasSetCustomAuthData(NULL, APP_NAME, data, sizeof(L2TP_CONFIG_DATA));
}
if ((Ret = RasSetEntryProperties(NULL, APP_NAME, lpRasEntry, EntryInfoSize, lpDeviceInfo, DeviceInfoSize)) != 0)
{
printf("RasSetEntryProperties failed with error %d\n", Ret);
return Ret;
}
//if ((Ret = RasSetCredentials(NULL, lpRasEntry.))
}
I cant find where is buffer to fill for pre-shared key.
Following code works fine.
// l2tp
if (preshared_key_valid)
{
RASCREDENTIALS ras_cre_psk = {0};
ras_cre_psk.dwSize = sizeof(ras_cre_psk);
ras_cre_psk.dwMask = 0x00000010; //RASCM_PreSharedKey;
wcscpy(ras_cre_psk.szPassword, preshared_key);
if ((Ret = RasSetCredentials(NULL, APP_NAME, &ras_cre_psk, FALSE)))
{
printf("RasSetCredentials failed with error %d\n", Ret);
return Ret;
}
}

Not able to decode mp4 file using latest ffmpeg library : av_decode_video2

I am writing a wrapper code around latest ffmpeg library. I am supplying MP4 files from local system. My problem is that I am unable to get any decoded frames when I use av_decode_video2(). The return value comes out to be negative. I have used av_read_frame() which returns 0. I googled about the problem I am facing but no where could I find the correct explanation. Please give me insight here. Pasting the pseudo code here.
av_init_packet(avpkt);
picture=av_frame_alloc();
pFrameRGB=av_frame_alloc();
codec = avcodec_find_decoder(CODEC_ID_H264);
c= avcodec_alloc_context3(codec)
avcodec_open2(decoderLibraryData->c, decoderLibraryData->codec, NULL)
FormatContext = avformat_alloc_context();
char *pUrl ="./1.MP4";
iRet = avformat_open_input(atContext, pUrl, pFmt, NULL);
if(FormatContext == NULL)
{
printf("could not assign any memory !!!!!!!!! \n");
}
avformat_find_stream_info(FormatContext, NULL);
while(av_read_frame(FormatContext,avpkt) >= 0)
{
len = avcodec_decode_video2(c, picture, &got_picture,avpkt);
printf("CODEC MANAGER len %d Frame decompressed %d \n",len,got_picture);
if (len <= 0)
{
return ERROR;
}
}
}
if(lastHeight != 0 && lastWidth != 0)
{
if(lastWidth != c->width || lastHeight != c->height )
{
av_free(buffer);
buffer = NULL;
lastWidth = c->width;
lastHeight = c->height;
}
}
else
{
lastWidth = c->width;
lastHeight = c->height;
}
decodeFlag = 1;
if(!buffer)
{
int numBytes;
v_mutex_lock(globalCodecLock);
switch(inPixFormat)
{
case RGB:
// Determine required buffer size and allocate buffer
numBytes=avpicture_get_size(PIX_FMT_RGB24, c->width, c->height);
buffer=(uint8_t *)av_malloc(numBytes*sizeof(uint8_t));
avpicture_fill((AVPicture *)pFrameRGB,buffer,PIX_FMT_RGB24,c->width, c->height);
if(cntxt)
sws_freeContext(cntxt);
cntxt = sws_getContext(c->width, c->height, c->pix_fmt,
c->width, c->height, PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL);
break;
}
v_mutex_unlock(globalCodecLock);
if(cntxt == NULL)
{
printf("sws_getContext error\n");
return ERROR;
}
}
{
sws_scale(cntxt, picture->data, picture->linesize, 0, c->height, pFrameRGB->data, pFrameRGB->linesize);
if(rgbBuff)
{
if(c->width <= *width && c->height <= *height)
{
saveFrame(pFrameRGB, c->width, c->height, rgbBuff,inPixFormat);
*width = c->width;
*height = c->height;
rs = SUCCESS;
break;
}
else
{
rs = VA_LOWBUFFERSIZE;
}
}
else
{
rs = VA_LOWBUFFERSIZE;
}
}
if(width)
{
*width = c->width;
}
if(height)
{
*height = c->height;
}
if(rs == VA_LOWBUFFERSIZE)
{
break;
}
I am getting the return value of av_read_frame as 0 but av_decode_video2 returns value in negative. I am not able to get any clue here.
Make sure you have called
av_register_all();
or
avcodec_register_all();
at the beginning of your app.
Also it seems the problem is from calling avformat_find_stream_info. Test with the following code:
AVPacket avpkt;
av_init_packet(&avpkt);
AVFrame* picture = av_frame_alloc();
AVFrame* pFrameRGB = av_frame_alloc();
AVFormatContext* c2 = avformat_alloc_context();
char *pUrl = "C:/Sample Videos/20-06-34.MP4";
int video_stream_index = 0;
AVInputFormat* pFmt;
int iRet = avformat_open_input(&c2, pUrl, pFmt, NULL);
AVStream* stream = c2->streams[video_stream_index];
AVCodec* codec = avcodec_find_decoder(stream->codec->codec_id);
avcodec_open2(stream->codec, codec, NULL);
if (c2 == NULL)
{
printf("could not assign any memory !!!!!!!!! \n");
}
while (av_read_frame(c2, &avpkt) >= 0)
{
int got_picture;
int len = avcodec_decode_video2(stream->codec, picture, &got_picture, &avpkt);
printf("CODEC MANAGER len %d Frame decompressed %d \n", len, got_picture);
if (len <= 0)
{
return ERROR;
}
}

How do I SCP a file programmatically using C?

What would be the best way to do an scp or sftp copy in a Unix environment using C?
I'm interested in knowing the best library to use and an example if at all possible. I'm working on a Solaris server with the Sun tools installed.
Try Libcurl
libcurl is a free and easy-to-use client-side URL transfer library, supporting DICT, FILE, > FTP, FTPS, Gopher, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, POP3, POP3S, RTMP, RTSP, SCP, SFTP, SMTP, SMTPS, Telnet and TFTP. libcurl supports SSL certificates, HTTP POST, HTTP PUT, FTP uploading, HTTP form based upload, proxies, cookies, user+password authentication (Basic, Digest, NTLM, Negotiate, Kerberos), file transfer resume, http proxy tunneling and more!
libcurl is highly portable, it builds and works identically on numerous platforms, including Solaris, NetBSD, FreeBSD, OpenBSD, Darwin, HPUX, IRIX, AIX, Tru64, Linux, UnixWare, HURD, Windows, Amiga, OS/2, BeOs, Mac OS X, Ultrix, QNX, OpenVMS, RISC OS, Novell NetWare, DOS and more...
I'm not really a C expert, but I think you can use system() to run OS commands. This would assume that you don't actually want to re-implement scp, just use it.
I've always just used the system() command. Of course doing this requires that you have SSH keys properly installed between the client and target machine so that it doesn't prompt for the password.
You can use libssh for sftp. I put some code here for you which has Pause/Resume and works on Windows. For Linux, you need to replace local file handling functions. I cannot copy the entire class because it will exceed this website limit. Change username and password and hostname to proper equivalents of your SFTP server:
int main(array<System::String ^> ^args)
{
//Console::WriteLine(L"Hello World");
pSFTPConnector sshc = new SFTPConnector(L".\\", L"127.0.0.1", 22, L"iman", L"iman"); // Change the hostname, port, username, password to your SFTP server, your credentials
//FILE *nullfile = fopen("null", "w");
//sshc->setLogFile(nullfile);
sshc->setVerbosity(SSH_LOG_RARE); // You can change the verbosity as appropriate for you
int i = sshc->InitSession();
i = sshc->ConnectSession();
i = sshc->InitSFTP();
//i = sshc->SFTPrename("renamed_myfile.txt", "myfile.txt"); // Change these file names
//i = sshc->Makedir("sftpdir");
//i = sshc->testUploadFile("myfile2.txt", "1234567890testfile");
// Change these file names to whatever appropriate
//i = sshc->SFTPget("c:\\testdir\\Got_CAR_HIRE_FINAL_test.jpg", "CAR_HIRE_FINAL_test.jpg", 64*1024);
i = sshc->SFTPget("c:\\testdir\\get_downloaded_CAR_HIRE_FINAL.jpg", "CAR_HIRE_FINAL.jpg", 64 *1024);
i = sshc->SFTPreget("c:\\testdir\\reget_downloaded_CAR_HIRE_FINAL.jpg", "CAR_HIRE_FINAL.jpg", 64 * 1024);
i = sshc->SFTPput("c:\\testdir\\CAR_HIRE_FINAL.jpg", "put_CAR_HIRE_FINAL.jpg", 64 * 1024);
i = sshc->SFTPreput("c:\\testdir\\CAR_HIRE_FINAL.jpg", "reput_CAR_HIRE_FINAL.jpg", 64 * 1024);
delete sshc;
return 0;
}
typedef enum sshconerr {
E_OK = 1, E_SESSION_ALOC = -1, E_SSH_CONNECT_ERR = -2, E_SFTP_ALLOC = -3, E_INIT_SFTP = -4, E_CREATE_DIR = -5, E_FILEOPEN_WRITE = -6, E_WRITE_ERR = -7,
E_FILE_CLOSE = -8, E_FILE_OPEN_READ = -9, E_INVALID_PARAMS = -10, E_SFTP_ERR = -11, E_SFTP_READ_ERR = -12, E_SFTP_READBYTES_ERR = -13, E_GET_FILEINF = -14,
E_LOCAL_FILE_NOTFOUND = -15, E_RENAME_ERR = -16, E_MEM_ALLOC = -17, E_LOCAL_FILE_READ = -18, E_LOCAL_FILE_RDWR = -19, E_REMOTEFILE_SEEK = -20,
E_REMOTE_FILE_OPEN = -21, E_DELETE_ERR = -22, E_RENAME_LOCAL_FILE = -23, E_LOCAL_DELETE_FILE = -24, E_FILEOPEN_RDONLY = -25, E_SFTP_READ_EOF = -26,
E_UNKNOWN = -999
} ESSHERR;
// Status of transfers;
typedef enum sftpstat{ES_DONE=0, ES_INPROGRESS, ES_FAILED, ES_STARTING, ES_PAUSED, ES_RESUMING, ES_CANCELLED, ES_NONE } ESFTPSTAT;
using namespace std;
// Statistics about the transfer;
typedef struct transferstatstruct {
string remote_file_name;
string local_file_name;
__int64 total_size;
__int64 transferred;
__int64 averagebps;
long long seconds_elapsed;
long long seconds_remained;
int percent;
ESFTPSTAT transferstate;
} TTransStat;
#define E_SESSION_NEW -1
// These libraries are required
#pragma comment(lib, "ssh.lib")
// This is the main class that does the majority of the work
typedef class CSFTPConnector {
private:
ssh_session session; // SSH session
sftp_session sftp; // SFTP session
sftp_file file; // Structure for a remote file
FILE *localfile; // Not used on Windows, but it could be local file pointer in Unix
FILE *logfile; // The file for writing logs, default is set to stderr
string filename; // File name of the transfer;
string localfilename; // File name of local file;
string tempfilename; // A temporary file name will be used during the transfer which is renamed when transfer is completed.
ESFTPSTAT transferstatus; // State of the transfer which has one of the above values (ESFTPSTAT)
time_t transferstarttime; // Time of start of the transfer
wchar_t username[SHORT_BUFF_LEN];
wchar_t password[SHORT_BUFF_LEN];
wchar_t hostname[SHORT_BUFF_LEN]; // Hostname of the SFTP server
wchar_t basedir[SHORT_BUFF_LEN]; // This base directory is the directory of the public and private key structure (NOT USED IN THIS VERSION)
int port; // Port of the server;
int verbosity; // Degree of verbosity of libssh
__int64 filesize; // Total number of bytes to be transferred;
DWORD local_file_size_hiDWORD; // Bill Gates cannot accept the file size
// without twisting the programmers, so
// he accepts them in two separate words
// like this
DWORD local_file_size_lowDWORD; // These two DWORDs when connected together comprise a 64 bit file size.
__int64 lfilesize; // Local file size
__int64 rfilesize; // Remote file size
__int64 transferred; // Number of bytes already transferred
bool pause; // Pause flag
TTransStat stats; // Statistics of the transfer
HANDLE localfilehandle; // Windows uses handles to manipulate files. this is the handle to local file.
ESSHERR CSFTPConnector::rwopen_existing_SFTPfile(char *fn); // Open a file on remote (server) read/write for upload
ESSHERR CSFTPConnector::rdopen_existing_SFTPfile(char *fn); // Open a file on remote (server) read only for download
ESSHERR createSFTPfile(char *fn); // Create a file on server;
ESSHERR writeSFTPfile(char *block, size_t blocksize); // Write a block of data to the open remote file
ESSHERR readSFTPfile(char *block, size_t len, size_t *bytesread); // Read a block of data from the open remote file
ESSHERR readSFTPfile(char *block, __int64 len, DWORD *bytesread);
ESSHERR closeSFTPfile(); // Closes the remote file;
ESSHERR openSFTPfile(char *fn); // Opens the remote file
ESSHERR getSFTPfileinfo(); // Gets information about the remote file
public:
wstring errstring; // The string describing last error
ESSHERR Err; // Error code of last error
CSFTPConnector(); // Default constructor;
CSFTPConnector(wchar_t *dir, wchar_t *hn, int hostport, wchar_t *un, wchar_t *pass); // Constructor
void setVerbosity(int v);
int getVerbosity();
ESSHERR InitSession(); // Must be called before doing any transfer
ESSHERR ConnectSession(); // Connects to the SSH server
ESSHERR InitSFTP(); // Must be called before doing any transfer
ESSHERR Makedir(char *newdir);
ESSHERR testUploadFile(char *fn, char *block); // Do not use this, only for test purposes for myself
ESSHERR SFTPput(char *lfn, char *rfn, size_t blocksize); // Upload a file from start
ESSHERR SFTPreput(char *lfn, char *rfn, size_t blocksize); // Checks for previouse interrupted transfer, then
// either continues the previous transfer (if
// there was any) or starts a new one (UPLOAD)
ESSHERR SFTPrename(char *newname, char *oldname); // Renames a remote file( must be closed)
ESSHERR CSFTPConnector::SFTPdelete(char *remfile); // Deletes a remote file
TTransStat getStatus(); // Gets statistics of the transfer
ESSHERR CSFTPConnector::SFTPget(char *lfn, char *rfn, size_t blocksize); // Downloads a file from the SFTP server
ESSHERR CSFTPConnector::SFTPreget(char *lfn, char *rfn, size_t blocksize); // Checks for a previous interrupted transfer,
// then either continues the previous transfer
// (if there was any) or starts a new one (DOWNLOAD).
void CancelTransfer();
void PauseTransfer();
void setLogFile(FILE *logf); // Sets the log file. If not set, standard
// error will be used. By default.
void CloseLocalFile();
void CloseRemoteFile();
~CSFTPConnector();
} SFTPConnector, *pSFTPConnector;
void CSFTPConnector::CloseLocalFile()
{
CloseHandle(localfilehandle);
}
void CSFTPConnector::CloseRemoteFile()
{
sftp_close(file);
}
void CSFTPConnector::setLogFile(FILE *logf)
{
logfile = logf;
}
void CSFTPConnector::CancelTransfer()
{
transferstatus = ES_CANCELLED;
}
void CSFTPConnector::PauseTransfer()
{
transferstatus = ES_PAUSED;
pause = true;
}
//----------------------------------------
ESSHERR CSFTPConnector::SFTPget(char *lfn, char *rfn, size_t blocksize)
{
DWORD result;
int rc;
BOOL bresult;
DWORD bytesread;
filesize = 0;
transferred = 0;
pause = false;
transferstatus = ES_NONE;
char *block;
struct stat st;
wchar_t temp[SHORT_BUFF_LEN];
size_t tempsize;
wstring wlfn;
int loopcounter = 0;
localfilename = lfn;
filename = rfn;
tempfilename = string(lfn) + ".sftp_temp";
mbstowcs_s(&tempsize, temp, tempfilename.c_str(), SHORT_BUFF_LEN);
localfilehandle = CreateFile(temp, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (localfilehandle == INVALID_HANDLE_VALUE)
{
transferstatus = ES_FAILED;
errstring = L"Could not open local file:" + wstring(temp) + L" for read and write";
Err = E_LOCAL_FILE_RDWR;
return E_LOCAL_FILE_RDWR;
}
lfilesize = 0;
transferred = 0;
block = (char*)malloc(blocksize + 1);
if (block == NULL) {
Err = E_MEM_ALLOC;
transferstatus = ES_FAILED;
errstring = L"Could not allocate memory for file block size";
CloseLocalFile();
return E_MEM_ALLOC;
}
result = rdopen_existing_SFTPfile((char *)rfn);
if (result == E_OK) {
getSFTPfileinfo();
filesize = rfilesize;
}
else
{
Err = E_REMOTE_FILE_OPEN;
transferstatus = ES_FAILED;
errstring = L"Could not open remote file";
CloseLocalFile();
delete block;
return E_REMOTEFILE_SEEK;
}
transferstatus = ES_STARTING;
sftp_file_set_blocking(file);
transferstarttime = time(NULL);
transferstatus = ES_INPROGRESS;
while (transferstatus != ES_FAILED &&
transferstatus != ES_PAUSED &&
transferstatus != ES_CANCELLED &&
transferstatus != ES_DONE)
{
loopcounter++;
result = readSFTPfile(block, blocksize, (size_t *)&bytesread);
if (result != E_OK && result!= E_SFTP_READ_EOF)
{
errstring = L"Error reading from remote SFTP server file.";
Err = (ESSHERR)result;
transferstatus = ES_FAILED;
CloseRemoteFile();
CloseLocalFile();
delete block;
return (ESSHERR)result;
}
if (result == E_SFTP_READ_EOF)
transferstatus = ES_DONE;
fprintf(logfile, "Read %d bytes from input file. Number of packets: %d, %llu from %llu bytes\n", bytesread, loopcounter, transferred, filesize);
bresult = WriteFile(localfilehandle, (LPVOID)block, bytesread, &bytesread, NULL);
if (bytesread < blocksize)
{
if (bresult == FALSE)
{
errstring = L"Error writing to local file.";
Err = E_LOCAL_FILE_RDWR;
transferstatus = ES_FAILED;
CloseRemoteFile();
CloseLocalFile();
delete block;
return E_LOCAL_FILE_RDWR;
}
else if (bytesread == 0)
{
errstring = L"Transfer done.";
Err = E_OK;
transferstatus = ES_DONE;
continue;
}
}
Err = E_OK;
if (pause == true)
transferstatus = ES_PAUSED;
if (bresult == TRUE && bytesread == 0)
{
// At the end of the file
transferstatus = ES_DONE;
}
Sleep(BLOCKTRANSDELAY);
if (loopcounter % 331 == 0)
Sleep(77 * BLOCKTRANSDELAY);
if (loopcounter % 3331 == 0)
Sleep(777 * BLOCKTRANSDELAY);
}
// Closing files
result = closeSFTPfile();
CloseHandle(localfilehandle);
Sleep(1000);
if (transferstatus == ES_DONE)
{
wchar_t temp2[SHORT_BUFF_LEN];
mbstowcs_s(&tempsize, temp2, lfn, SHORT_BUFF_LEN);
bresult = MoveFile(temp, temp2);
if (bresult != TRUE)
{
Err = E_RENAME_LOCAL_FILE;
errstring = L"Could not rename local file: " + wstring(temp);
transferstatus = ES_FAILED;
delete block;
return E_RENAME_LOCAL_FILE;
}
}
if (transferstatus == ES_CANCELLED)
{
wchar_t temp2[SHORT_BUFF_LEN];
mbstowcs_s(&tempsize, temp2, lfn, SHORT_BUFF_LEN);
bresult = DeleteFile(temp);
if (bresult != TRUE)
{
Err = E_LOCAL_DELETE_FILE;
errstring = L"Could not rename local file: " + wstring(temp);
transferstatus = ES_FAILED;
delete block;
return E_LOCAL_DELETE_FILE;
}
}
delete block;
return (ESSHERR) result;
}
TTransStat CSFTPConnector::getStatus()
{
stats.seconds_elapsed = time(NULL) - transferstarttime;
stats.averagebps = (transferred * 8) / stats.seconds_elapsed;
if (filesize > 0) {
stats.percent = (transferred *100)/ filesize;
stats.seconds_remained = ((filesize - transferred) * 8) / stats.averagebps;
}
else
{
stats.percent = -1;
stats.seconds_remained = -1;
}
stats.total_size = filesize;
stats.transferstate = transferstatus;
stats.remote_file_name = filename;
stats.local_file_name = localfilename;
return stats;
}
ESSHERR CSFTPConnector::SFTPrename(char *newname, char *oldname)
{
int rc = sftp_rename(sftp, oldname, newname);
if (rc != SSH_OK) {
return E_RENAME_ERR;
}
return E_OK;
}
ESSHERR CSFTPConnector::SFTPdelete(char *remfile)
{
int rc = sftp_unlink(sftp, remfile);
if (rc != SSH_OK) {
return E_DELETE_ERR;
}
return E_OK;
}
ESSHERR CSFTPConnector::SFTPreput(char *lfn, char *rfn, size_t blocksize)
{
ESSHERR result;
BOOL bresult;
DWORD bytesread;
filesize = 0;
transferred = 0;
pause = false;
transferstatus = ES_NONE;
char *block;
struct stat st;
wchar_t temp[SHORT_BUFF_LEN];
size_t tempsize;
wstring wlfn;
int loopcounter = 0;
localfilename = lfn;
//wlfn = wstring(lfn);
//localfile = fopen(lfn, L"r");
filename = rfn;
mbstowcs_s(&tempsize, temp, lfn, SHORT_BUFF_LEN);
//filesize = getFileSize(localfilename);
/*if (filesize < 0) {
transferstatus = ES_FAILED;
Err = E_LOCAL_FILE_NOTFOUND;
return E_LOCAL_FILE_NOTFOUND;
}*/
localfilehandle = CreateFile(temp, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (localfilehandle == INVALID_HANDLE_VALUE)
{
transferstatus = ES_FAILED;
Err = E_LOCAL_FILE_NOTFOUND;
return E_LOCAL_FILE_NOTFOUND;
}
local_file_size_lowDWORD = GetFileSize(localfilehandle, &local_file_size_hiDWORD);
filesize = (local_file_size_hiDWORD * 0x100000000) + local_file_size_lowDWORD;
if (filesize < 0) {
transferstatus = ES_FAILED;
Err = E_LOCAL_FILE_NOTFOUND;
CloseLocalFile();
return E_LOCAL_FILE_NOTFOUND;
}
block = (char*)malloc(blocksize + 1);
if (block == NULL) {
Err = E_MEM_ALLOC;
transferstatus = ES_FAILED;
errstring = L"Could not allocate memory for file block size";
CloseLocalFile();
return E_MEM_ALLOC;
}
tempfilename = string(rfn) + ".sftp_temp";
result = rwopen_existing_SFTPfile((char *)tempfilename.c_str());
if (result == E_OK) {
getSFTPfileinfo();
sftp_seek64(file, rfilesize);
__int64 tempi64 = rfilesize & 0x00000000FFFFFFFF;
DWORD dwlow = tempi64;
tempi64 = (rfilesize & 0x7FFFFFFF00000000);
tempi64 = tempi64 >> 32;
long dwhi = tempi64;
DWORD dwResult = SetFilePointer(localfilehandle, dwlow, &dwhi, FILE_BEGIN);
if (dwResult == INVALID_SET_FILE_POINTER)
{
transferstatus = ES_FAILED; Err = result; return result;
}
transferstatus = ES_RESUMING;
transferred = rfilesize;
}
else{
result = createSFTPfile((char *)tempfilename.c_str());
transferstatus = ES_STARTING;
if (result != E_OK) {
transferstatus = ES_FAILED;
Err = result;
CloseLocalFile();
return result;
}
}
sftp_file_set_blocking(file);
transferstarttime = time(NULL);
transferstatus = ES_INPROGRESS;
while (transferstatus != ES_FAILED &&
transferstatus != ES_PAUSED &&
transferstatus != ES_DONE)
{
loopcounter++;
bresult = ReadFile(localfilehandle, (LPVOID)block, blocksize, &bytesread, NULL);
fprintf(logfile, "Read %d bytes from input file. Number of packets: %d, %llu from %llu bytes\n", bytesread, loopcounter, transferred, filesize);
if (bytesread < blocksize)
{
if (bresult == FALSE)
{
errstring = L"Error reading from local file.";
Err = E_LOCAL_FILE_READ;
transferstatus = ES_FAILED;
CloseRemoteFile();
CloseLocalFile();
return E_LOCAL_FILE_READ;
}
else if (bytesread == 0)
{
errstring = L"Transfer done.";
Err = E_OK;
transferstatus = ES_DONE;
continue;
}
}
result = writeSFTPfile(block, bytesread);
if (result != E_OK && bytesread>0)
{
errstring = L"Error transmitting to remote SFTP server file.";
Err = result;
transferstatus = ES_FAILED;
CloseRemoteFile();
CloseLocalFile();
return result;
}
Err = E_OK;
//transferred = transferred + bytesread;
if (pause == true)
transferstatus = ES_PAUSED;
if (bresult == TRUE && bytesread == 0)
{
// At the end of the file
transferstatus = ES_DONE;
}
Sleep(BLOCKTRANSDELAY);
if (loopcounter % 331 == 0)
Sleep(77 * BLOCKTRANSDELAY);
if (loopcounter % 3331 == 0)
Sleep(777 * BLOCKTRANSDELAY);
}
CloseRemoteFile();
CloseLocalFile();
Sleep(1000);
if (transferstatus == ES_CANCELLED)
{
result = SFTPdelete((char *)tempfilename.c_str());
if (bresult != E_OK)
{
Err = E_DELETE_ERR;
errstring = L"Could not delete remote file.";
transferstatus = ES_FAILED;
return E_DELETE_ERR;
}
}
if (transferstatus == ES_DONE)
result = SFTPrename(rfn, (char *)tempfilename.c_str());
delete block;
return result;
}
ESSHERR CSFTPConnector::getSFTPfileinfo()
{
sftp_attributes fileinf = sftp_fstat(file);
if (fileinf == NULL) {
return E_GET_FILEINF;
}
rfilesize = fileinf->size;
sftp_attributes_free(fileinf);
return E_OK;
}
ESSHERR CSFTPConnector::closeSFTPfile()
{
int rc = sftp_close(file);
if (rc != SSH_OK)
{
fprintf(logfile, "Can't close the written file: %s\n",
ssh_get_error(session));
return E_FILE_CLOSE;
}
return E_OK;
}
ESSHERR CSFTPConnector::writeSFTPfile(char *block, size_t blocksize)
{
size_t nwritten = sftp_write(file, block, blocksize);
if (nwritten != blocksize)
{
fprintf(logfile, "Can't write data to file: %s\n",
ssh_get_error(session));
//sftp_close(file);
transferred = transferred + nwritten;
return E_WRITE_ERR;
}
transferred = transferred + nwritten;
return E_OK;
}
ESSHERR CSFTPConnector::readSFTPfile(char *block, size_t len, size_t *bytesread)
{
DWORD readbytes;
*bytesread = 0;
if (len <= 0)
return E_INVALID_PARAMS;
if (bytesread == NULL || block == NULL)
return E_INVALID_PARAMS;
readbytes = sftp_read(file, block, len);
if (readbytes < 0)
{
fprintf(logfile, "Can't read from remote file: %s %s\n", filename.c_str(), ssh_get_error(session));
*bytesread = 0;
return E_SFTP_READ_ERR;
}
if (readbytes < len)
{
*bytesread = readbytes;
transferred = transferred + readbytes;
return E_SFTP_READ_EOF;
}
*bytesread = readbytes;
transferred = transferred + readbytes;
return E_OK;
}
ESSHERR CSFTPConnector::readSFTPfile(char *block, __int64 len, DWORD *bytesread)
{
DWORD readbytes;
*bytesread = 0;
if (len <= 0)
return E_INVALID_PARAMS;
if (bytesread == NULL || block == NULL)
return E_INVALID_PARAMS;
readbytes = sftp_read(file, block, len);
if (readbytes < 0)
{
fprintf(logfile, "Can't read from remote file: %s %s\n", filename.c_str(), ssh_get_error(session));
*bytesread = 0;
return E_SFTP_READ_ERR;
}
if (readbytes < len)
{
*bytesread = readbytes;
return E_SFTP_READ_EOF;
}
*bytesread = readbytes;
transferred = transferred + readbytes;
return E_OK;
}
ESSHERR CSFTPConnector::createSFTPfile(char *fn)
{
int access_type = O_CREAT | O_RDWR;
int rc, nwritten;
filename = string(fn);
file = sftp_open(sftp, fn,
access_type, S_IWRITE);
if (file == NULL)
{
fprintf(logfile, "Can't open file for writing: %s\n",
ssh_get_error(session));
return E_FILEOPEN_WRITE;
}
return E_OK;
}
ESSHERR CSFTPConnector::rdopen_existing_SFTPfile(char *fn)
{
int access_type = O_RDONLY;
int rc, nwritten;
filename = string(fn);
file = sftp_open(sftp, fn,
access_type, S_IREAD);
if (file == NULL)
{
fprintf(logfile, "Can't open file for writing: %s\n",
ssh_get_error(session));
return E_FILEOPEN_RDONLY;
}
return E_OK;
}
ESSHERR CSFTPConnector::openSFTPfile(char *fn)
{
int access_type = O_RDONLY;
int rc, nwritten;
filename = string(fn);
file = sftp_open(sftp, fn,
access_type, S_IWRITE);
if (file == NULL)
{
fprintf(logfile, "Can't open file for writing: %s\n",
ssh_get_error(session));
return E_FILE_OPEN_READ;
}
return E_OK;
}
ESSHERR CSFTPConnector::Makedir(char *newdir)
{
int rc;
rc = sftp_mkdir(sftp, newdir, S_IFDIR);
if (rc != SSH_OK)
{
if (sftp_get_error(sftp) != SSH_FX_FILE_ALREADY_EXISTS)
{
fprintf(logfile, "Can't create directory: %s\n",
ssh_get_error(session));
return E_CREATE_DIR;
}
}
return E_OK;
}
SFTPConnector::CSFTPConnector()
{
//libssh2_init(0);
session = ssh_new();
if (session == NULL)
{
Err = E_SESSION_ALOC;
errstring = L"Could not allocate a session.";
}
wcscpy(hostname, L"localhost");
wcscpy(username, L"User");
wcscpy(password, L"Password");
wcscpy(basedir, L".\\");
port = 22;
verbosity = SSH_LOG_RARE;
filesize = 0;
transferred = 0;
pause = false;
transferstatus = ES_NONE;
logfile = stderr;
}
CSFTPConnector::CSFTPConnector(wchar_t *dir, wchar_t *hn, int hostport, wchar_t *un, wchar_t *pass)
{
session = ssh_new();
if (session == NULL)
{
Err = E_SESSION_ALOC;
errstring = L"Could not allocate a session.";
}
wcscpy(hostname, hn);
wcscpy(username, un);
wcscpy(password, pass);
wcscpy(basedir, dir);
port = hostport;
verbosity = SSH_LOG_RARE;
filesize = 0;
transferred = 0;
pause = false;
transferstatus = ES_NONE;
logfile = stderr;
}
ESSHERR CSFTPConnector::InitSFTP()
{
int rc;
sftp = sftp_new(session);
if (session == NULL)
{
Err = E_SFTP_ALLOC;
errstring = L"Could not allocate a sftp session.";
}
rc = sftp_init(sftp);
if (rc != SSH_OK)
{
fprintf(logfile, "Error initializing SFTP session: %s.\n",
sftp_get_error(sftp));
sftp_free(sftp);
return E_INIT_SFTP;
}
return E_OK;
}
ESSHERR CSFTPConnector::ConnectSession()
{
char temp[SHORT_BUFF_LEN];
size_t n_of_chars;
wcstombs_s(&n_of_chars, temp, SHORT_BUFF_LEN, (const wchar_t *)password, SHORT_BUFF_LEN);
int ir;
ir = ssh_connect(session);
if (ir != SSH_OK) {
errstring = L"Could not connect the ssh session.";
return E_SSH_CONNECT_ERR;
}
ir = ssh_userauth_password(session, NULL, temp);
if (ir != SSH_OK) {
errstring = L"Could not connect the ssh session.";
return E_SSH_CONNECT_ERR;
}
return E_OK;
}
ESSHERR CSFTPConnector::InitSession()
{
char temp[SHORT_BUFF_LEN];
size_t n_of_chars;
wcstombs_s(&n_of_chars, temp, SHORT_BUFF_LEN, (const wchar_t *) hostname, SHORT_BUFF_LEN);
ssh_options_set(session, SSH_OPTIONS_HOST, temp);
ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
ssh_options_set(session, SSH_OPTIONS_PORT, &port);
wcstombs_s(&n_of_chars, temp, SHORT_BUFF_LEN, (const wchar_t *)username, SHORT_BUFF_LEN);
ssh_options_set(session, SSH_OPTIONS_USER, temp);
wcstombs_s(&n_of_chars, temp, SHORT_BUFF_LEN, (const wchar_t *)basedir, SHORT_BUFF_LEN);
ssh_options_set(session, SSH_OPTIONS_SSH_DIR, temp);
return E_OK;
}
CSFTPConnector::~CSFTPConnector()
{
sftp_free(sftp);
ssh_disconnect(session);
ssh_free(session);
return;
}
In the past, I've simply called a shell script that contained the file transfer code.
int transferFile()
{
// Declare the transfer command
char transferCommand[50] = "/home/tyler/transferFile.shl";
// Execute the command
return system(transferCommand);
}
This will return 1 if the transfer command returns successfully.

Resources