How to use librsync functions to open remote files? - c++

I am using librsync library for maintaining file versions. I am not able to open files from a network.
Example (creating signature file):
int main(int argc, char** argv)//FILE *original, FILE *signature)
{
if(argc != 2)
{
cout<<"Enter the original file name."<<endl;
exit(1);
}
FILE *fpa;
fpa = fopen(argv[1],"r");
if(fpa==NULL)
{
cout<<"ERROR"<<endl;
exit(1);
}
FILE *fps;
fps = fopen("sig.sig","w+");
rs_result res = rs_sig_file(fpa, fps, 1,2,NULL);
fclose(fpa);
fclose(fps);
printf("Result code: %d\n", res);
return 0;
}
When I run the program with argument of a file over a network, e.g.
./a.out cs1130218#palasi.cse.iitd.ernet.in:games.txt
fpa is NULL.
I guess that fopen is not made for opening files over a network. I need a command which can do this. Any command in c/c++.
You can clearly see what I want to do with the programme.

"I need a command which can open files over a network" is a really, really high-level operation, and as such, it glosses over all kinds of details: What kind of network protocol should be used? How should authentication be handled? How should network errors be handled? What should be done once the file is opened: read / write / both, sequential or random?
librsync is relatively low-level and doesn't even try to answer these questions itself. Its README explains:
librsync does not implement the rsync wire protocol. If you want to talk to an rsync server to transfer files you'll need to shell out to rsync. librsync is for building other programs that transfer files as efficiently as rsync. You can use librsync to make backup tools, distribute binary patches to programs, or sync directories to a server or between peers.
To open files over a network, you'll need to implement your own server and wire protocol, or you'll need to shell out to commands like rsync that handle these details for you (and, if most of your logic is in shelling out to other commands, C++ may not be the best tool for the job).

Neither librsync nor fopen deal with remote files.
Look at using a virtual filesystem library like GVFS or KIO instead: these can open files over SFTP and you can then pass them to librsync.

Related

Looking for the correct way in Linux to write encrypted text from C++ application to encrypted gpg file

I have Linux C++ application ported from Solaris OS and the app needs to write some text data via gpg (or gpg2) into encrypted file. So the text data should be written directly to gpg (encrypted file).
I create pipes:
if(pipe(pipes) == -1)
throw Exception("Error creating pipes");
switch(fork())
{
case -1:
throw Exception("fork() failure");
case 0: // child process
close(pipes[PIPE_PARENT]);
close(READ);
close(ERR);
if(dup(pipes[PIPE_CHILD]) != READ)
throw Exception("dup() failure, READ descriptor unavailable");
execlp("gpg", "gpg", "--no-tty", "-r", "username", "-e", "-o", "home/username/out.pgp", NULL);
break;
}
...
Then I use write():
intWCount = write(intTextFD, strData.str().c_str(), strData.str().size());
Then I see errno == 9, intWCount = -1.
From STDOUT I get:
"gpg: WARNING: standard error reopened"
and the text data is not written to the file.
I use Ubuntu 16.04, gpg (GnuPG) 1.4.20, gcc 5.4.0.
The main question is - how to write my text data into encrypted gpg file securely?
Thank you!
https://wiki.gnupg.org/APIs states this:
A number of elder applications call GnuPG executables in a subprocess and interact with them via command line arguments and file-descriptors. This is less perferable to GPGME, because the command line arguments and text outputs are not an (official) API to GnuPG. While there is an effort made to keep them stable, using the official GPGME API can manage this more precisely and thus you end up with a more robust solution.
The correct way is using gpgme as an api, it has c++ bindings.
If you are absolutely sure you want to do that on your own you might want to consider popen()ening the binary without "--no-tty" and writing to the resulting file pointer. This is sub optimal, though, as GnuPG is wont to ask questions and you need to be ready to have your program answer them.
Using the API is much preferable.

copying binary files to remote location in C++

I'm in the process of trying to copy an hdf5 binary file on a local machine to a remote computing blade. I am using libssh to copy the desired directory or files out after they are generated by my Qt application. Using libssh I am able to open an ssh_session, authenticate it, open a channel and send remote commands.
for (QStringList::iterator it = ipList.begin(); it != ipList.end(); ++it)
{
ssh_session my_session = new ssh_new();
QString ip_address = *it;
ssh_options_set(my_session, SSH_OPTIONS_HOST, ip_address.toStdString().c_str());
// Connect...Authenticate using public key....
QString command = QString("rm -r %2; cp -r %1 %1; cp /local/file.txt /remote/file.txt").arg(local_dir, remote_dir);
execute_remote_command(my_session, command.toStdString().c_str());
// Open channel and execute command
ssh_disconnect(my_session);
ssh_free(my_session);
}
This command is being executed for each individual computing blade. In between each of the calls I am closing and opening an ssh session to the next blade. The files make it out the blades but they appear to be corrupt. They are the exact same file size. I haven't figured out a way to compare the individual bytes to see just how corrupt they are, any tips there would be appreciated as well.
When I run my ssh copy commands in a separate test terminal program the files appear to make it intact and are readable on the blades. The issue only seems to occur when the files are moved from within the Qt GUI program.
EDIT: So delving a little bit deeper into what is wrong, it appears that the file on the remote server is not the same size. It appears to be missing a large portion of the bytes. On top of that when I examine what is there byte by byte with the local version of the file, almost all of the bytes differ.
Turns out the answer was that the HDF5 writer wasn't being closed properly before the SSH commands were being called. I fixed the problem by dynamically allocating the custom H5 class that someone else wrote and made sure to delete it before the SSH commands were called. Turns out whoever wrote the HDF5 read and write class didn't handle file opening and closing properly and didn't provide functions to do so.
Below is an example of what I am talking about.
HDF5writer_class *hdf5_writer = new HDF5writer_class();
hdf5_writer->create_file("/local/machine/hdf5_file.h5");
// ... add the data to the file
delete hdf5_writer;
// Open SSH Session and run the copy commands
Long story short, make sure the file you are writing is closed and released for use before you try to copy it.

Close shared files programmatically

The company I'm working with has a program written in ye olde vb6, which is updated pretty frequently, and most clients run the executable from a mapped network drive. This actually has surprisingly few issues, the biggest of which is automatic updates. Currently the updater program (written in c++) renames the existing exe, then downloads and places the new version into the old version's place. This generally works fine, but in some environments it simply fails.
The solution is running this command from microsoft:
for /f "skip=4 tokens=1" %a in ('net files') do net files %a /close
This command closes all network files that are shared (well... most) and then the updater can replace the exe.
In C++ I can use the System(""); function to run that command, or I could redirect the output of net files, and iterate through the results looking for the particular file in question and run net file /close command to close them. But it would be much much nicer if there were winapi functions that have similar capabilities for better reliability and future safety.
Is there any way for me to programmatically find all network shared files and close relevant ones?
You can programmatically do what net file /close does. Just include lmshare.h and link to Netapi32.dll. You have two functions to use: NetFileEnum to enumerate all open network files (on a given computer) and NetFileClose to close them.
Quick (it assumes program is running on same server and there are not too many open connections, see last paragraph) and dirty (no error checking) example:
FILE_INFO_2* pFiles = NULL;
DWORD nRead = 0, nTotal = 0;
NetFileEnum(
NULL, // servername, NULL means localhost
"c:\\directory\\path", // basepath, directory where VB6 program is
NULL, // username, searches for all users
2, // level, we just need resource ID
(LPBYTE*)&pFiles, // bufptr, need to use a double pointer to get the buffer
MAX_PREFERRED_LENGTH, // prefmaxlen, collect as much as possible
&nRead, // entriesread, number of entries stored in pFiles
&nTotal, // totalentries, ignore this
NULL //resume_handle, ignore this
);
for (int i=0; i < nRead; ++i)
NetFileClose(NULL, pFiles[i].fi2_id);
NetApiBufferFree(pFiles);
Refer to MSDN for details about NetFileEnum and NetFileClose. Note that NetFileEnum may return ERROR_MORE_DATA if more data is available.

Recovering Files on Windows and C

Well this time I'm trying to write a program in C which recover deleted files from a disk, it could be an external disk, I have an idea than i had used before on linux, it is to open the disk as a kind of file and scaning the Headers and file footers of everything within the disk, the point is I'm not sure if there's allow on windows to open a disk as an File, basiclly I have the logic how to develope this program, but I'm not sure how to implement it on windows, anybody can give me a hand with this?.
The code I used on linux to open a disk as a file was:
Edit: That was a sample of what I was using guys, it's just to give you an idea of what I was doing, the correct syntax I used was the next:
direccion = ui->linea->text().toLatin1().constData();
f = fopen(direccion,"rb");
I used QT creator on linux, and direccion variable was a TextField value which contained the file path of the disk through a button function that open a QFileDialog...
could I use it in windows as well?
Thank you before hand..
"The code I used on linux to open a disk as a file was:"
File *f = fopen("E:\", "rb");
I seriously doubt you ever got this code working on any linux system (or windows either).
You'll need to escape the backslash path delimiter, if it's presented in any string literal:
FILE* f = fopen("E:\\", "rb");
// ^
Also all that filesystem path style you are presenting to access a particular disk, is about accessing a windows file path/disk.
No linux file system has notion about drive characters, and the file path delimiter value used is '/', not '\\'.
To recover deleted files, you can't use fopen or fstream::open because the file was deleted. Check the return value from the function or test the stream state.
The way to recover deleted files is:
Get the Master File Table as raw data.
Search for the record containing a string similar to the deleted
filename.
Change the entry in the Master File Table to "undeleted".
Write the Master File Table back to the drive.
The above usually requires platform specific API, which is different on Linux and Windows platforms.

printing to a network printer using fstream c++ in mac

I wish to print some text directly to a network printer from my c++ code (I am coding with xcode 4). I do know that everything on unix is a file and believe that it would not be impossible to redirect the text using fstream method in c++ to the printer device file. The only problem is I don't know the device file in /dev associated with my network printer.
Is it possible to achieve printing using fstream method? Something like
std::fstream printFile;
printFile.open("//PATH/TO/PRINTER/DEV", std::ios::out);
printFile << "This must go to printer" << std::endl;
printFile.close();
And, if so
How to obtain the file in /dev corresponding to a particular printer?
Thanks in advance,
Nikhil
Opening and writing directly to a file used to be possible back in the days of serial printers; however, this is not the approach available today.
The CUPS daemon provides print queuing, scheduling, and administrative interfaces on OS X and many other Unix systems. You can use the lp(1) or lpr(1) commands to print files. (The different commands come from different versions of print spoolers available in Unix systems over the years; one was derived from the BSD-sources and the other derived from the AT&T sources. For compatibility, CUPS provides both programs.)
You can probably achieve something like you were after with popen(3). In shell, it'd be something like:
echo hello | lp -
The - says to print from standard input.
I haven't tested this, but the popen(3) equivalent would probably look like this:
FILE *f = popen("lp -", "w");
if (!f)
exit(1);
fprintf(f, "output to the printer");
I recommend testing some inputs at the shell first to make sure that CUPS is prepared to handle the formatting of the content you intend to send. You might need to terminate lines with CRLF rather than just \n, otherwise the printer may "stair-step" the output. Or, if you're sending PDF or PS or PCL data, it'd be worthwhile testing that in the cheapest possible manner to make sure the print system works as you expect.