Initial commit
This commit is contained in:
parent
f7b3598e0e
commit
9d995ee1cf
10 changed files with 848 additions and 2 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -16,8 +16,6 @@
|
||||||
|
|
||||||
# Shared objects (inc. Windows DLLs)
|
# Shared objects (inc. Windows DLLs)
|
||||||
*.dll
|
*.dll
|
||||||
*.so
|
|
||||||
*.so.*
|
|
||||||
*.dylib
|
*.dylib
|
||||||
|
|
||||||
# Executables
|
# Executables
|
||||||
|
|
27
LICENSE
27
LICENSE
|
@ -1,3 +1,5 @@
|
||||||
|
LICENSE FOR THE RANGITAKI SYNC LIBRARY AND THE TEST FILES
|
||||||
|
|
||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
||||||
Copyright (c) 2015 Marcel Kapfer
|
Copyright (c) 2015 Marcel Kapfer
|
||||||
|
@ -20,3 +22,28 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
SOFTWARE.
|
SOFTWARE.
|
||||||
|
|
||||||
|
LICENSE FOR ZED A. SHAW's AWESEOME DEBUGGING MACROS
|
||||||
|
|
||||||
|
Right know unknown. Will add it as soon as possible.
|
||||||
|
|
||||||
|
LICENSE FOR LIBSSH
|
||||||
|
|
||||||
|
COPYRIGHT (c) 2015 libssh
|
||||||
|
|
||||||
|
GNU LESSER GENERAL PUBLIC LICENSE
|
||||||
|
Version 2.1, February 1999
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
|
||||||
|
USA
|
||||||
|
|
10
Makefile
Normal file
10
Makefile
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
CFLAGS=-g -Wall -DNDEBUG
|
||||||
|
|
||||||
|
all: rsl-download-test rsl-upload-test
|
||||||
|
|
||||||
|
rsl-download-test: rangitaki-sync.o libssh.so
|
||||||
|
|
||||||
|
rsl-upload-test: rangitaki-sync.o libssh.so
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -r rangitaki-sync.o rsl-download-test rsl-upload-test
|
52
README.md
Normal file
52
README.md
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
# Rangitaki Sync Library
|
||||||
|
|
||||||
|
First of all: **I'm really sorry** for my bad code style, the bad design, all the ugliness , the missing comments (I will add them as soon as possible), for some things that may not work as expected, for every C developer who is used to read good code, for all the bugs that may happen. I'm sorry, but I'm not a good C developer. I just started coding in that language.
|
||||||
|
|
||||||
|
But, however, the funny part is: IT ACTUALLY WORKS! (or at least it should and did in my tests)
|
||||||
|
|
||||||
|
Anyway, this is a library written for synchronizing a Rangitaki blog with your device. (Actually you can download every directory recursive and upload single files...).
|
||||||
|
|
||||||
|
For testing purposes I wrote two test programs: One for uploading (single file), one for downloading (recursive, into /tmp).
|
||||||
|
|
||||||
|
*These library is written on Linux and tested on Linux. It may works on other systems, but I don't know.*
|
||||||
|
|
||||||
|
Even if I write all of my programs in the hope, that they will be useful for someone one day, I don't think that this will be used by anyone else than me. But look also in the 'Useful Stuff' section of this README.
|
||||||
|
|
||||||
|
## Test programs
|
||||||
|
|
||||||
|
After running `make` you have following programs:
|
||||||
|
|
||||||
|
### rsl-download-test
|
||||||
|
|
||||||
|
Just run it with `./rsl-download-test`. You don't need to give any arguments, since it will ask you everything.
|
||||||
|
|
||||||
|
This program will download you all files and subdirectory of the entered remote directory into `/tmp/rangitaki-sync`. Normally the program should create this directory, if it isn't already there. If it fails to create it and it isn't already there, you will receive a nice and friendly error message...
|
||||||
|
|
||||||
|
## rsl-upload-test
|
||||||
|
|
||||||
|
Just run it with `./rsl-upload-test`. You don't need to give any arguments, since it will ask you everything.
|
||||||
|
|
||||||
|
This program will upload a single file form the entered path to the entered path on your server.
|
||||||
|
|
||||||
|
## Credits
|
||||||
|
|
||||||
|
### libssh project ([libssh.org](http://libssh.org))
|
||||||
|
|
||||||
|
For there great ssh library and the awesome documentation.
|
||||||
|
|
||||||
|
## Zed A. Shaw ([zedshaw.com](http://zedshaw.com))
|
||||||
|
|
||||||
|
For his great book ["Learn C the hard way"](http://c.learncodethehardway.org/book/).
|
||||||
|
|
||||||
|
For his awesome debug macros (The `dbg.h` file).
|
||||||
|
|
||||||
|
## Useful Stuff
|
||||||
|
|
||||||
|
I wrote one function in this library which could be more useful for many people than the library: the **char \*getFilename(const char \*input)** function, which returns the filename of a path to a file.
|
||||||
|
|
||||||
|
E.g.
|
||||||
|
|
||||||
|
```
|
||||||
|
char *path = "/var/www/html/index.html";
|
||||||
|
printf("%s\n", getFilename(path)); // Will print 'index.html'
|
||||||
|
```
|
42
dbg.h
Normal file
42
dbg.h
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* This it NOT my work!!!
|
||||||
|
*
|
||||||
|
* All credit for these awesome macros goes to Zed A. Shaw
|
||||||
|
*
|
||||||
|
* http://zedshaw.com/
|
||||||
|
*
|
||||||
|
* Buy his book "Learn C the hard way" to support him and
|
||||||
|
* to learn this awesome language
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __dgb_h__
|
||||||
|
#define __dbg_h__
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#ifdef NDEBUG
|
||||||
|
#define debug(M, ...)
|
||||||
|
#else
|
||||||
|
#define debug(M, ...) fprintf(stderr, "DEBUG %s:%s:%d: " M "\n", __FILE__, __FUNCTION__, __LINE__, ##__VA_ARGS__)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define clean_errno() (errno == 0 ? "None" : strerror(errno))
|
||||||
|
|
||||||
|
#define log_err(M, ...) fprintf(stderr, "[ERROR] (%s:%s:%d: errno %s) " M "\n", __FILE__, __FUNCTION__, __LINE__, clean_errno(), ##__VA_ARGS__)
|
||||||
|
|
||||||
|
#define log_warn(M, ...) fprintf(stderr, "[WARN] (%s:%s:%d: errno %s) " M "\n", __FILE__, __FUNCTION__, __LINE__, clean_errno(), ##__VA_ARGS__)
|
||||||
|
|
||||||
|
#define log_info(M, ...) fprintf(stderr, "[INFO] (%s:%s:%d) " M "\n", __FILE__, __FUNCTION__, __LINE__, ##__VA_ARGS__)
|
||||||
|
|
||||||
|
#define check(A, M, ...) if(!(A)) {log_err(M, ##__VA_ARGS__); errno=0; goto error; }
|
||||||
|
|
||||||
|
#define sentinel(M, ...) { log_err(M, ##__VA_ARGS__); errno=0; goto error; }
|
||||||
|
|
||||||
|
#define check_mem(A) check((A), "Out of memory.")
|
||||||
|
|
||||||
|
#define check_debug(A, M, ...) if(!(A)) { debug(M, ##__VA_ARGS__); errno=0; goto error; }
|
||||||
|
|
||||||
|
#endif
|
BIN
libssh.so
Normal file
BIN
libssh.so
Normal file
Binary file not shown.
347
rangitaki-sync.c
Normal file
347
rangitaki-sync.c
Normal file
|
@ -0,0 +1,347 @@
|
||||||
|
/* Rangitaki Sync Library
|
||||||
|
*
|
||||||
|
* A program for downloading and uploading blog posts,
|
||||||
|
* blogs file and media files from a rangitaki blog.
|
||||||
|
*
|
||||||
|
* Proudly written in C and with use of libssh (libssh.org)
|
||||||
|
*
|
||||||
|
* Version: 0.1
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
*
|
||||||
|
* COPYRIGHT (c) 2015 The Rangitaki Project
|
||||||
|
* COPYRIGHT (c) 2015 Marcel Kapfer (mmk2410) <marcelmichaelkapfer@yahoo.co.nz>
|
||||||
|
*
|
||||||
|
* License: MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <libssh/libssh.h>
|
||||||
|
#include "rangitaki-sync.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "dbg.h"
|
||||||
|
|
||||||
|
char * combine(const char * begin, char * end){
|
||||||
|
char * result = malloc(strlen(begin) + strlen(end) + 1);
|
||||||
|
strcpy(result, begin);
|
||||||
|
strcat(result, end);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
char * getFilename(char *input)
|
||||||
|
{
|
||||||
|
check(input != NULL, "Invalid input");
|
||||||
|
char* string;
|
||||||
|
|
||||||
|
string = strdup(input);
|
||||||
|
|
||||||
|
int buffer[100];
|
||||||
|
int i = 0;
|
||||||
|
int j = 0;
|
||||||
|
for(i = 0; i <= strlen(string); i++) {
|
||||||
|
if(string[i] == '/') {
|
||||||
|
buffer[j] = i;
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
j--;
|
||||||
|
int size = strlen(string) - buffer[j]; // Includes the \0
|
||||||
|
char *result = malloc(size);
|
||||||
|
strcpy(result, &string[buffer[j]+1]);
|
||||||
|
result[size] = '\0';
|
||||||
|
free(string);
|
||||||
|
return result;
|
||||||
|
|
||||||
|
error:
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ssh_initialize(const char *host, const char *user, const char *password,
|
||||||
|
const char *remote_dir, const char *local_dir,
|
||||||
|
const unsigned int port, ssh_data *data)
|
||||||
|
{
|
||||||
|
data->host = strdup(host);
|
||||||
|
data->user = strdup(user);
|
||||||
|
data->password = strdup(password);
|
||||||
|
data->remote_dir = strdup(remote_dir);
|
||||||
|
data->local_dir = strdup(local_dir);
|
||||||
|
data->port = port;
|
||||||
|
data->verbosity = SSH_LOG_PROTOCOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ssh_server_auth(ssh_session ssh)
|
||||||
|
{
|
||||||
|
char *hexa;
|
||||||
|
int state;
|
||||||
|
unsigned char *hash = NULL;
|
||||||
|
size_t hlen;
|
||||||
|
ssh_key srv_pubkey;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
state = ssh_is_server_known(ssh);
|
||||||
|
|
||||||
|
rc = ssh_get_publickey(ssh, &srv_pubkey);
|
||||||
|
check(rc >= 0, "Couldn't not authenticate the server.");
|
||||||
|
|
||||||
|
rc = ssh_get_publickey_hash(srv_pubkey,
|
||||||
|
SSH_PUBLICKEY_HASH_SHA1,
|
||||||
|
&hash,
|
||||||
|
&hlen);
|
||||||
|
ssh_key_free(srv_pubkey);
|
||||||
|
check(rc >= 0, "Couldn't not authenticate the server.");
|
||||||
|
|
||||||
|
switch (state)
|
||||||
|
{
|
||||||
|
case SSH_SERVER_KNOWN_OK:
|
||||||
|
log_info("Found host key");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SSH_SERVER_KNOWN_CHANGED:
|
||||||
|
log_err("The host key of the server changed. Aborting connection.");
|
||||||
|
ssh_print_hexa("Public key hash", hash, hlen);
|
||||||
|
ssh_clean_pubkey_hash(&hash);
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
case SSH_SERVER_FOUND_OTHER:
|
||||||
|
log_err("The host key for this server was not found but an other. Aborting connection.");
|
||||||
|
ssh_clean_pubkey_hash(&hash);
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
case SSH_SERVER_FILE_NOT_FOUND:
|
||||||
|
log_warn("Couldn't find known hosts file.");
|
||||||
|
|
||||||
|
case SSH_SERVER_NOT_KNOWN:
|
||||||
|
hexa = ssh_get_hexa(hash, hlen);
|
||||||
|
log_info("Adding %s to known hosts.", hexa);
|
||||||
|
free(hexa);
|
||||||
|
if (ssh_write_knownhost(ssh) < 0) {
|
||||||
|
log_err("Error adding server to known hosts file: %s", strerror(errno));
|
||||||
|
ssh_clean_pubkey_hash(&hash);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
log_err("%s", ssh_get_error(ssh));
|
||||||
|
ssh_clean_pubkey_hash(&hash);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssh_clean_pubkey_hash(&hash);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error:
|
||||||
|
ssh_clean_pubkey_hash(&hash);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssh_session ssh_open(ssh_data *data)
|
||||||
|
{
|
||||||
|
int rc = 0;
|
||||||
|
ssh_session ssh = ssh_new();
|
||||||
|
|
||||||
|
if(ssh == NULL) {
|
||||||
|
log_err("Failed th create ssh session.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ssh_options_set(ssh, SSH_OPTIONS_HOST, data->host) < 0) {
|
||||||
|
ssh_free(ssh);
|
||||||
|
log_err("Failed to set host.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ssh_options_set(ssh, SSH_OPTIONS_USER, data->user) < 0) {
|
||||||
|
ssh_free(ssh);
|
||||||
|
log_err("Failed to set user.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ssh_options_set(ssh, SSH_OPTIONS_PORT, &data->port)) {
|
||||||
|
ssh_free(ssh);
|
||||||
|
log_err("Failed to set port.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ssh_options_set(ssh, SSH_OPTIONS_LOG_VERBOSITY, &data->verbosity)) {
|
||||||
|
ssh_free(ssh);
|
||||||
|
log_err("Failed to set verbosity.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ssh_connect(ssh)) {
|
||||||
|
log_err("Connection failed: %s.", ssh_get_error(ssh));
|
||||||
|
ssh_disconnect(ssh);
|
||||||
|
ssh_free(ssh);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ssh_server_auth < 0) {
|
||||||
|
log_err("Couldn't authenticate the server.");
|
||||||
|
ssh_disconnect(ssh);
|
||||||
|
ssh_free(ssh);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = ssh_userauth_password(ssh, data->user, data->password);
|
||||||
|
if(rc == SSH_AUTH_SUCCESS) {
|
||||||
|
return ssh;
|
||||||
|
} else if(rc == SSH_AUTH_DENIED) {
|
||||||
|
log_err("Authentication failed.");
|
||||||
|
} else {
|
||||||
|
log_err("Error while authenticating");
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int ssh_close(ssh_session ssh)
|
||||||
|
{
|
||||||
|
ssh_disconnect(ssh);
|
||||||
|
ssh_free(ssh);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssh_scp scp_open(ssh_session ssh, ssh_data *data, int mode)
|
||||||
|
{
|
||||||
|
int rc = 0;
|
||||||
|
ssh_scp scp = ssh_scp_new(ssh, mode, data->remote_dir);
|
||||||
|
check(scp != NULL, "Failed to create the scp session: %s", ssh_get_error(ssh));
|
||||||
|
|
||||||
|
rc = ssh_scp_init(scp);
|
||||||
|
if(rc == -1)
|
||||||
|
{
|
||||||
|
log_err("Failed to initialize the scp connection.");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
check(rc == SSH_OK, "Failed to initialize the scp session: %s", ssh_get_error(ssh));
|
||||||
|
|
||||||
|
return scp;
|
||||||
|
|
||||||
|
error:
|
||||||
|
if(scp) ssh_scp_free(scp);
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int scp_close(ssh_scp scp)
|
||||||
|
{
|
||||||
|
ssh_scp_close(scp);
|
||||||
|
ssh_scp_free(scp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int scp_download(ssh_session ssh, ssh_scp scp, ssh_data *data)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
int rv;
|
||||||
|
int size, mode;
|
||||||
|
char buffer[16384];
|
||||||
|
const char *local_dir = strdup(data->local_dir);
|
||||||
|
|
||||||
|
do {
|
||||||
|
rc = ssh_scp_pull_request(scp);
|
||||||
|
|
||||||
|
switch (rc) {
|
||||||
|
case SSH_SCP_REQUEST_NEWFILE:
|
||||||
|
size = ssh_scp_request_get_size(scp);
|
||||||
|
mode = ssh_scp_request_get_permissions(scp);
|
||||||
|
char *filename = strdup(ssh_scp_request_get_filename(scp));
|
||||||
|
check(filename != NULL, "Couldn't get the filename.");
|
||||||
|
printf("DOWNLOAD: %s %d %d\n", filename, size, mode);
|
||||||
|
char *dir = combine(local_dir, filename);
|
||||||
|
FILE *output = fopen(dir, "w+");
|
||||||
|
check(output != NULL, "FILE couldn't be created");
|
||||||
|
ssh_scp_accept_request(scp);
|
||||||
|
rc = ssh_scp_read(scp, buffer, sizeof(buffer));
|
||||||
|
check(rc != SSH_ERROR, "Error downloading the file. %s",
|
||||||
|
ssh_get_error(ssh));
|
||||||
|
rv = fwrite(buffer, size, 1, output);
|
||||||
|
check(rv != 0, "Failed to write file");
|
||||||
|
rv = fclose(output);
|
||||||
|
free(dir);
|
||||||
|
free(filename);
|
||||||
|
check(rv == 0, "Failed to close FILE");
|
||||||
|
printf("Done.\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SSH_ERROR:
|
||||||
|
log_err("Error: %s", ssh_get_error(ssh));
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
case SSH_SCP_REQUEST_WARNING:
|
||||||
|
log_warn("Warning: %s", ssh_scp_request_get_warning(scp));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SSH_SCP_REQUEST_NEWDIR:
|
||||||
|
filename = strdup(ssh_scp_request_get_filename(scp));
|
||||||
|
mode = ssh_scp_request_get_permissions(scp);
|
||||||
|
printf("DOWNLOAD: %s %d\n", filename, mode);
|
||||||
|
ssh_scp_accept_request(scp);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SSH_SCP_REQUEST_ENDDIR:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SSH_SCP_REQUEST_EOF:
|
||||||
|
log_info("DONE");
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
} while (1);
|
||||||
|
|
||||||
|
error:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int scp_upload(ssh_session ssh, ssh_scp scp, ssh_data *data)
|
||||||
|
{
|
||||||
|
int rc = 0;
|
||||||
|
FILE *fisz = fopen(data->local_dir, "rb");
|
||||||
|
fseek(fisz, 0L, SEEK_END);
|
||||||
|
int size = ftell(fisz);
|
||||||
|
fclose(fisz);
|
||||||
|
|
||||||
|
rc = ssh_scp_push_file64(scp, getFilename(data->local_dir), size,
|
||||||
|
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
|
||||||
|
check(rc == SSH_OK, "Failed to create file: %s", ssh_get_error(ssh));
|
||||||
|
|
||||||
|
char *buffer = malloc(size + 100);
|
||||||
|
FILE *file = fopen(data->local_dir, "r");
|
||||||
|
check(file != NULL, "Error opening local file.");
|
||||||
|
rc = 0;
|
||||||
|
rc = fread(buffer, size, 1, file);
|
||||||
|
rc = ssh_scp_write(scp, buffer, size);
|
||||||
|
check(rc == SSH_OK, "Error while writing remote file: %s", ssh_get_error(ssh));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error:
|
||||||
|
return -1;
|
||||||
|
}
|
64
rangitaki-sync.h
Normal file
64
rangitaki-sync.h
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
/* Rangitaki Sync Library
|
||||||
|
*
|
||||||
|
* A program for downloading and uploading blog posts,
|
||||||
|
* blogs file and media files from a rangitaki blog.
|
||||||
|
*
|
||||||
|
* Proudly written in C and with use of libssh (libssh.org)
|
||||||
|
*
|
||||||
|
* Version: 0.1
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
*
|
||||||
|
* COPYRIGHT (c) 2015 The Rangitaki Project
|
||||||
|
* COPYRIGHT (c) 2015 Marcel Kapfer (mmk2410) <marcelmichaelkapfer@yahoo.co.nz>
|
||||||
|
*
|
||||||
|
* License: MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _rangitakisync_h
|
||||||
|
#define _rangitakisync_h
|
||||||
|
|
||||||
|
#include <libssh/libssh.h>
|
||||||
|
|
||||||
|
typedef struct{
|
||||||
|
char *host;
|
||||||
|
char *user;
|
||||||
|
char *password;
|
||||||
|
char *remote_dir;
|
||||||
|
char *local_dir;
|
||||||
|
unsigned int port;
|
||||||
|
unsigned int verbosity;
|
||||||
|
} ssh_data;
|
||||||
|
|
||||||
|
|
||||||
|
void ssh_initialize(const char *host, const char *user, const char *password,
|
||||||
|
const char *remote_dir, const char *local_dir,
|
||||||
|
const unsigned int port, ssh_data *data);
|
||||||
|
ssh_session ssh_open(ssh_data *data);
|
||||||
|
int ssh_close(ssh_session ssh);
|
||||||
|
ssh_scp scp_open(ssh_session ssh, ssh_data *data, int mode);
|
||||||
|
int scp_close(ssh_scp scp);
|
||||||
|
int scp_download(ssh_session ssh, ssh_scp scp, ssh_data *data);
|
||||||
|
int scp_upload(ssh_session ssh, ssh_scp scp, ssh_data *data);
|
||||||
|
|
||||||
|
#endif
|
149
rsl-download-test.c
Normal file
149
rsl-download-test.c
Normal file
|
@ -0,0 +1,149 @@
|
||||||
|
/* Rangitaki Sync Library
|
||||||
|
*
|
||||||
|
* Download Test
|
||||||
|
*
|
||||||
|
* A program for downloading and uploading blog posts,
|
||||||
|
* blogs file and media files from a rangitaki blog.
|
||||||
|
*
|
||||||
|
* Proudly written in C and with use of libssh (libssh.org)
|
||||||
|
*
|
||||||
|
* Version: 0.1
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
*
|
||||||
|
* COPYRIGHT (c) 2015 The Rangitaki Project
|
||||||
|
* COPYRIGHT (c) 2015 Marcel Kapfer (mmk2410) <marcelmichaelkapfer@yahoo.co.nz>
|
||||||
|
*
|
||||||
|
* License: MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <libssh/libssh.h>
|
||||||
|
#include "rangitaki-sync.h"
|
||||||
|
#include "dbg.h"
|
||||||
|
|
||||||
|
#define MAX_DATA 512
|
||||||
|
|
||||||
|
int run(const char *host, const char *user, const char *password, const char *remote_dir, const int port)
|
||||||
|
{
|
||||||
|
// Print the ssh struct
|
||||||
|
ssh_data *data = malloc(sizeof(ssh_data));
|
||||||
|
ssh_session ssh;
|
||||||
|
ssh_scp scp;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
ssh_initialize(host, user, password,
|
||||||
|
remote_dir, "/tmp/rangitaki-sync/", port, data);
|
||||||
|
|
||||||
|
mkdir(data->local_dir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
|
||||||
|
|
||||||
|
ssh = ssh_open(data);
|
||||||
|
check(ssh != NULL, "Error while connecting to the server.");
|
||||||
|
|
||||||
|
scp = scp_open(ssh, data, SSH_SCP_READ | SSH_SCP_RECURSIVE);
|
||||||
|
check(scp != NULL, "Error while creating a scp connection");
|
||||||
|
|
||||||
|
rc = scp_download(ssh, scp, data);
|
||||||
|
check(rc == 0, "Error while downloading");
|
||||||
|
|
||||||
|
|
||||||
|
scp_close(scp);
|
||||||
|
|
||||||
|
ssh_close(ssh);
|
||||||
|
|
||||||
|
free(data->host);
|
||||||
|
free(data->user);
|
||||||
|
free(data->password);
|
||||||
|
free(data->remote_dir);
|
||||||
|
free(data->local_dir);
|
||||||
|
free(data);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error:
|
||||||
|
if(scp) scp_close(scp);
|
||||||
|
if(ssh) ssh_close(ssh);
|
||||||
|
|
||||||
|
free(data->host);
|
||||||
|
free(data->user);
|
||||||
|
free(data->password);
|
||||||
|
free(data->remote_dir);
|
||||||
|
free(data->local_dir);
|
||||||
|
free(data);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
check(argc == 1, "Too much arguments");
|
||||||
|
|
||||||
|
printf("RANGITAKI SYNC LIBRARY\n");
|
||||||
|
printf("Version: 0.1\n");
|
||||||
|
printf("COPYRIGHT (c) 2015 The Rangitaki Project\n");
|
||||||
|
printf("COPYRIGHT (c) 2015 Marcel Kapfer (mmk2410) <marcelmichaelkapfer@yahoo.co.nz>\n");
|
||||||
|
printf("MIT License\n\n");
|
||||||
|
printf("RSL Download test\n\n");
|
||||||
|
|
||||||
|
char *in = NULL;
|
||||||
|
int rc = 0;
|
||||||
|
char host[MAX_DATA];
|
||||||
|
char user[MAX_DATA];
|
||||||
|
char password[MAX_DATA];
|
||||||
|
char remote_dir[MAX_DATA];
|
||||||
|
int port;
|
||||||
|
|
||||||
|
printf("Host: ");
|
||||||
|
in = fgets(host, MAX_DATA - 1, stdin);
|
||||||
|
strtok(host, "\n");
|
||||||
|
check(in != NULL, "Failed to read host.");
|
||||||
|
|
||||||
|
printf("User: ");
|
||||||
|
in = fgets(user, MAX_DATA - 1, stdin);
|
||||||
|
strtok(user, "\n");
|
||||||
|
check(in != NULL, "Failed to read host.");
|
||||||
|
|
||||||
|
printf("Password: ");
|
||||||
|
in = fgets(password, MAX_DATA - 1, stdin);
|
||||||
|
strtok(password, "\n");
|
||||||
|
check(in != NULL, "Failed to read password.");
|
||||||
|
|
||||||
|
printf("Remote Directory: ");
|
||||||
|
in = fgets(remote_dir, MAX_DATA - 1, stdin);
|
||||||
|
strtok(remote_dir, "\n");
|
||||||
|
check(in != NULL, "Failed to read directory.");
|
||||||
|
|
||||||
|
printf("Port: ");
|
||||||
|
rc = fscanf(stdin, "%i", &port);
|
||||||
|
check(rc > 0, "Failed to read port.");
|
||||||
|
|
||||||
|
printf("\nRunning Download now.\n\n");
|
||||||
|
|
||||||
|
run(host, user, password, remote_dir, port);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error:
|
||||||
|
return -1;
|
||||||
|
}
|
157
rsl-upload-test.c
Normal file
157
rsl-upload-test.c
Normal file
|
@ -0,0 +1,157 @@
|
||||||
|
/* Rangitaki Sync Library
|
||||||
|
*
|
||||||
|
* Upload Test
|
||||||
|
*
|
||||||
|
* A program for downloading and uploading blog posts,
|
||||||
|
* blogs file and media files from a rangitaki blog.
|
||||||
|
*
|
||||||
|
* Proudly written in C and with use of libssh (libssh.org)
|
||||||
|
*
|
||||||
|
* Version: 0.1
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
*
|
||||||
|
* COPYRIGHT (c) 2015 The Rangitaki Project
|
||||||
|
* COPYRIGHT (c) 2015 Marcel Kapfer (mmk2410) <marcelmichaelkapfer@yahoo.co.nz>
|
||||||
|
*
|
||||||
|
* License: MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <libssh/libssh.h>
|
||||||
|
#include "rangitaki-sync.h"
|
||||||
|
#include "dbg.h"
|
||||||
|
|
||||||
|
#define MAX_DATA 512
|
||||||
|
|
||||||
|
int run(const char *host, const char *user, const char *password, const char *remote_dir,
|
||||||
|
const char *local_dir, const int port)
|
||||||
|
{
|
||||||
|
// Print the ssh struct
|
||||||
|
ssh_data *data = malloc(sizeof(ssh_data));
|
||||||
|
ssh_session ssh;
|
||||||
|
ssh_scp scp;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
ssh_initialize(host, user, password,
|
||||||
|
remote_dir, local_dir, port, data);
|
||||||
|
|
||||||
|
mkdir(data->local_dir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
|
||||||
|
|
||||||
|
ssh = ssh_open(data);
|
||||||
|
check(ssh != NULL, "Error while connecting to the server.");
|
||||||
|
|
||||||
|
scp = scp_open(ssh, data, SSH_SCP_WRITE);
|
||||||
|
check(scp != NULL, "Error while creating a scp connection");
|
||||||
|
|
||||||
|
rc = scp_upload(ssh, scp, data);
|
||||||
|
check(rc == 0, "Error while uploading");
|
||||||
|
|
||||||
|
|
||||||
|
scp_close(scp);
|
||||||
|
|
||||||
|
ssh_close(ssh);
|
||||||
|
|
||||||
|
free(data->host);
|
||||||
|
free(data->user);
|
||||||
|
free(data->password);
|
||||||
|
free(data->remote_dir);
|
||||||
|
free(data->local_dir);
|
||||||
|
free(data);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error:
|
||||||
|
if(scp) scp_close(scp);
|
||||||
|
if(ssh) ssh_close(ssh);
|
||||||
|
|
||||||
|
free(data->host);
|
||||||
|
free(data->user);
|
||||||
|
free(data->password);
|
||||||
|
free(data->remote_dir);
|
||||||
|
free(data->local_dir);
|
||||||
|
free(data);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
check(argc == 1, "Too much arguments");
|
||||||
|
|
||||||
|
printf("RANGITAKI SYNC LIBRARY\n");
|
||||||
|
printf("Version: 0.1\n");
|
||||||
|
printf("COPYRIGHT (c) 2015 The Rangitaki Project\n");
|
||||||
|
printf("COPYRIGHT (c) 2015 Marcel Kapfer (mmk2410) <marcelmichaelkapfer@yahoo.co.nz>\n");
|
||||||
|
printf("MIT License\n\n");
|
||||||
|
printf("RSL Download test\n\n");
|
||||||
|
|
||||||
|
char *in = NULL;
|
||||||
|
int rc = 0;
|
||||||
|
char host[MAX_DATA];
|
||||||
|
char user[MAX_DATA];
|
||||||
|
char password[MAX_DATA];
|
||||||
|
char remote_dir[MAX_DATA];
|
||||||
|
char local_dir[MAX_DATA];
|
||||||
|
int port;
|
||||||
|
|
||||||
|
printf("Host: ");
|
||||||
|
in = fgets(host, MAX_DATA - 1, stdin);
|
||||||
|
strtok(host, "\n");
|
||||||
|
check(in != NULL, "Failed to read host.");
|
||||||
|
|
||||||
|
printf("User: ");
|
||||||
|
in = fgets(user, MAX_DATA - 1, stdin);
|
||||||
|
strtok(user, "\n");
|
||||||
|
check(in != NULL, "Failed to read host.");
|
||||||
|
|
||||||
|
printf("Password: ");
|
||||||
|
in = fgets(password, MAX_DATA - 1, stdin);
|
||||||
|
strtok(password, "\n");
|
||||||
|
check(in != NULL, "Failed to read password.");
|
||||||
|
|
||||||
|
printf("Remote Directory: ");
|
||||||
|
in = fgets(remote_dir, MAX_DATA - 1, stdin);
|
||||||
|
strtok(remote_dir, "\n");
|
||||||
|
check(in != NULL, "Failed to read directory.");
|
||||||
|
|
||||||
|
printf("Local File: ");
|
||||||
|
in = fgets(local_dir, MAX_DATA - 1, stdin);
|
||||||
|
strtok(local_dir, "\n");
|
||||||
|
check(in != NULL, "Failed to read file");
|
||||||
|
|
||||||
|
printf("Port: ");
|
||||||
|
rc = fscanf(stdin, "%i", &port);
|
||||||
|
check(rc > 0, "Failed to read port.");
|
||||||
|
|
||||||
|
printf("\nRunning Upload now.\n\n");
|
||||||
|
|
||||||
|
run(host, user, password, remote_dir, local_dir, port);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error:
|
||||||
|
return -1;
|
||||||
|
}
|
Reference in a new issue