/*
* rgfs project
* Main GNUTLS code was borrowed from their public domain example. Thank you!
*/
#include "rgfs_config.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <netdb.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <endian.h>
#include <stdarg.h>
#include <fuse.h>
#include <gnutls/gnutls.h>
#include <gnutls/x509.h>
// a way to distinguish between clients
static char *rgfs_name = "unk";
static unsigned int rgfs_pkg_repo_id = 0;
static char *rgfs_key = "";
static int rgfs_port = 443;
static char *rgfs_server = "rgfs.rocketgit.com";
static char *rgfs_url = "/rgfs";
static int rgfs_debug = 0;
static char *rgfs_log = "rgfs.log";
static int rgfs_log_fd = 2;
static gnutls_session_t session;
static unsigned char connected = 0;
static int sd = -1;
static gnutls_certificate_credentials_t xcred;
static void xlog(char *format, ...)
{
va_list ap;
size_t len, len2;
char line[4096];
struct timeval tv;
if (rgfs_debug == 0)
return;
if (rgfs_log_fd == -1)
return;
gettimeofday(&tv, NULL);
len = snprintf(line, sizeof(line),
"%ld.%03ld ", tv.tv_sec, tv.tv_usec);
va_start(ap, format);
len2 = vsnprintf(line + len, sizeof(line) - len, format, ap);
if (len2 >= sizeof(line) - len)
len2 = sizeof(line);
else
len2 += len;
va_end(ap);
write(rgfs_log_fd, line, len2);
}
/*
* Receiving data
*/
static ssize_t rgfs_recv(void *buf, const size_t buf_max)
{
ssize_t r;
do {
r = gnutls_record_recv(session, buf, buf_max);
} while ((r == GNUTLS_E_AGAIN) || (r == GNUTLS_E_INTERRUPTED));
if (r < 0)
xlog("Cannot receive [%zd]!\n", r);
return r;
}
/*
* Sending data
*/
static ssize_t rgfs_send(const void *buf, size_t buf_len)
{
ssize_t r;
do {
r = gnutls_record_send(session, buf, buf_len);
} while ((r == GNUTLS_E_AGAIN) || (r == GNUTLS_E_INTERRUPTED));
if (r < 0) {
xlog("Cannot send [%zd]!\n", r);
exit(EXIT_FAILURE);
} else if ((size_t) r < buf_len) {
xlog("Invalid send r=%ld < buf_len=%zu!\n", r, buf_len);
exit(EXIT_FAILURE);
}
return r;
}
/*
* Connect to server
*/
static int rgfs_connect(void)
{
int r, fd;
struct addrinfo hints;
struct addrinfo *result, *rp;
char port[6];
snprintf(port, sizeof(port), "%d", rgfs_port);
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
r = getaddrinfo(rgfs_server, port, &hints, &result);
if (r != 0) {
xlog("getaddrinfo: %s\n", gai_strerror(r));
return -1;
}
for (rp = result; rp != NULL; rp = rp->ai_next) {
fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if (fd == -1)
continue;
r = connect(fd, rp->ai_addr, rp->ai_addrlen);
if (r != -1) {
char ip[49], service[NI_MAXSERV];
r = getnameinfo((struct sockaddr *) rp->ai_addr, rp->ai_addrlen,
ip, sizeof(ip), service, sizeof(service),
NI_NUMERICHOST | NI_NUMERICSERV);
if (r == 0)
xlog("Connected to %s/%s!\n", ip, service);
break;
}
xlog("connect error: %m\n");
}
freeaddrinfo(result);
if (rp == NULL) {
xlog("Could not connect!\n");
return -1;
}
return fd;
}
/*
* Send first websocket negotiation
*/
static ssize_t rgfs_ws1(void)
{
char out[4096];
int len;
len = snprintf(out, sizeof(out),
"GET %s HTTP/1.1\r\n"
"Host: %s:%d\r\n"
"Connection: keep-alive, Upgrade\r\n"
"Pragma: no-cache\r\n"
"Cache-Control: no-cache\r\n"
"Upgrade: websocket\r\n"
"\r\n",
rgfs_url, rgfs_server, rgfs_port);
//xlog("Sending:\n%s", out);
return rgfs_send(out, len);
}
/*
* Returns 0 if ok, 1 if we should abort the program else => retry.
*/
static int rgfs_tls(void)
{
int r, ret = -1, off;
char buf[8192], *desc;
int type;
unsigned status, len;
while (1) {
/* Destroy session */
xlog("session=%p sd=%d\n", session, sd);
if (session) {
r = gnutls_bye(session, GNUTLS_SHUT_RDWR);
if (r != GNUTLS_E_SUCCESS)
xlog("gnutls error: cannot say goodbye [%d]!\n", r);
}
if (sd != -1)
close(sd);
gnutls_deinit(session);
/* Initialize TLS session */
r = gnutls_init(&session, GNUTLS_CLIENT);
if (r != GNUTLS_E_SUCCESS) {
xlog("gnutls error: cannot init session!\n");
break;
}
r = gnutls_server_name_set(session, GNUTLS_NAME_DNS,
rgfs_server, strlen(rgfs_server));
if (r != GNUTLS_E_SUCCESS) {
xlog("gnutls error: cannot set name [%s]!\n", rgfs_server);
break;
}
/* It is recommended to use the default priorities */
r = gnutls_set_default_priority(session);
if (r != GNUTLS_E_SUCCESS) {
xlog("gnutls error: cannot set default priority!\n");
break;
}
/* put the x509 credentials to the current session */
r = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, xcred);
if (r != GNUTLS_E_SUCCESS) {
xlog("gnutls error: cannot set credentials!\n");
break;
}
gnutls_session_set_verify_cert(session, rgfs_server, 0);
// TODO - no error code?
sd = rgfs_connect();
if (sd == -1)
break;
gnutls_transport_set_int(session, sd);
gnutls_handshake_set_timeout(session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
/* Perform the TLS handshake */
do {
r = gnutls_handshake(session);
} while (r < 0 && gnutls_error_is_fatal(r) == 0);
if (r < 0) {
if (r == GNUTLS_E_CERTIFICATE_VERIFICATION_ERROR) {
gnutls_datum_t out;
/* check certificate verification status */
type = gnutls_certificate_type_get(session);
status = gnutls_session_get_verify_cert_status(session);
r = gnutls_certificate_verification_status_print(status, type, &out, 0);
if (r == GNUTLS_E_SUCCESS) {
xlog("cert verify output: %s\n", out.data);
gnutls_free(out.data);
}
}
xlog("Handshake failed: %s\n", gnutls_strerror(r));
break;
}
desc = gnutls_session_get_desc(session);
xlog("Session info: %s\n", desc);
gnutls_free(desc);
r = rgfs_ws1();
if (r == -1)
break;
//xlog("ws1 returned %d.\n", r);
off = 0;
while (1) {
r = rgfs_recv(buf + off, sizeof(buf) - off - 1);
if (r <= 0)
break;
buf[off + r] = '\0';
//xlog("Received[%d + %d]:\n%s\n", off, r, buf);
if (strstr(buf, "\r\n\r\n"))
break;
}
if (r == -1)
break;
if (strncmp(buf, "HTTP/1.1 101 Switching Protocols", 32) != 0) {
xlog("Invalid HTTP answer:\n%s\n", buf);
break;
}
xlog("Sending version...\n");
buf[0] = 0x01; // type=SEND_VERSION
buf[1] = 0; // len H
buf[2] = 1; // len L
buf[3] = RGFS_PROTOCOL_VERSION;
r = rgfs_send(buf, 4);
if (r <= 0)
break;
xlog("Receiving version...\n");
r = rgfs_recv(buf, sizeof(buf));
if (r <= 0)
break;
xlog("Server version: %hhu.\n", buf[4]);
xlog("Sending name...\n");
len = strlen(rgfs_name);
buf[0] = 0xFE; // type=SEND_NAME
buf[1] = len >> 8; // len H
buf[2] = len; // len L
memcpy(buf + 3, rgfs_name, len);
r = rgfs_send(buf, 3 + len);
if (r <= 0)
break;
xlog("Sending pkg_repo_id and key...\n");
len = strlen(rgfs_key);
buf[0] = 0xFF; // type=SEND_KEY
buf[1] = (4 + len) >> 8; // len H
buf[2] = 4 + len; // len L
buf[3] = rgfs_pkg_repo_id >> 24;
buf[4] = rgfs_pkg_repo_id >> 16;
buf[5] = rgfs_pkg_repo_id >> 8;
buf[6] = rgfs_pkg_repo_id;
memcpy(buf + 7, rgfs_key, len);
r = rgfs_send(buf, 7 + len);
if (r <= 0)
break;
xlog("Receiving send_key confirmation...\n");
r = rgfs_recv(buf, sizeof(buf));
if (r <= 0)
break;
if ((r < 5) || (buf[4] != 0x00)) {
ret = 1;
break;
}
ret = 0;
break;
}
return ret;
}
static void rgfs_reconnect(void)
{
int r;
while (1) {
xlog("Reconnecting...\n");
r = rgfs_tls();
if (r == 0) {
xlog("Reconnecting OK!\n");
connected = 1;
break;
}
if (r == 1) {
xlog("Exiting!");
exit(1);
}
xlog("Sleeping...\n");
sleep(1);
}
}
static int rgfs_recv_hl(void *buf, size_t buf_size)
{
int r;
uint32_t off, to_read = 0;
off = 0;
while (1) {
//xlog(" Waiting for data (off=%d to_read=%u)\n", off, to_read);
if (off == buf_size) {
xlog("Buffer is too small!\n");
exit(EXIT_FAILURE);
}
r = rgfs_recv(buf + off, buf_size - off);
if (r <= 0)
return r;
off += r;
if (off >= 4)
to_read = be32toh(*(uint32_t *) buf);
#if 0
xlog(" RECV: ");
for (unsigned int i = 0; i < off; i++)
xlog("%02hhx", * (unsigned char *) (buf + i));
xlog("\n");
#endif
if (off == 4 + to_read) {
//xlog(" Readed 4 + %u\n", to_read);
return off;
}
}
}
static ssize_t rgfs_send_recv(const void *out_buf, size_t out_buf_len,
void *in_buf, size_t in_buf_size)
{
int r;
if (connected == 0)
rgfs_reconnect();
while (1) {
//xlog(" Sending %zu bytes\n", out_buf_len);
r = rgfs_send(out_buf, out_buf_len);
if (r <= 0) {
rgfs_reconnect();
continue;
}
r = rgfs_recv_hl(in_buf, in_buf_size);
if (r <= 0) {
rgfs_reconnect();
continue;
}
return r;
}
}
///////////////////////////////////////////////////////////////////// fuse stuff
static int rgfs_fuse_getattr(const char *path, struct stat *s)
{
int r, i, err = 0;
unsigned char buf[4 * 4096], cmd;
uint16_t path_len, len;
//xlog("getattr: path=%s\n", path);
path_len = strlen(path);
len = 1 + 2 + path_len;
if (len > sizeof(buf)) {
xlog(" buffer too small\n");
return -EIO;
}
i = 0;
buf[i++] = 0x02;
buf[i++] = (len - 1 - 2) >> 8;
buf[i++] = len - 1 - 2;
memcpy(buf + i, path, path_len); i += path_len;
r = rgfs_send_recv(buf, i, buf, sizeof(buf));
memset(s, 0, sizeof(struct stat));
i = 4;
while (i < r) {
cmd = buf[i++];
//xlog(" cmd=0x%02hhx\n", cmd);
switch (cmd) {
case 0x00: err = - be32toh(*(uint32_t *) (buf + i)); i += 4; break;
case 0x01: s->st_mode = be32toh(*(uint32_t *) (buf + i)); i += 4; break;
case 0x02: s->st_nlink = be64toh(*(uint64_t *) (buf + i)); i += 8; break;
case 0x03: s->st_size = be64toh(*(uint64_t *) (buf + i)); i += 8; break;
case 0x04: s->st_atime = be32toh(*(uint32_t *) (buf + i)); i += 4; break;
case 0x05: s->st_mtime = be32toh(*(uint32_t *) (buf + i)); i += 4; break;
case 0x06: s->st_ctime = be32toh(*(uint32_t *) (buf + i)); i += 4; break;
default: xlog("Unexpected subcode 0x%02hhx!\n", cmd); exit(EXIT_FAILURE);
}
}
if (err != 0) {
//xlog(" server returned error %d!\n", err);
return err;
}
//xlog(" mode=%o nlink=%lu size=%lu\n",
// s->st_mode, s->st_nlink, s->st_size);
return 0;
}
static int rgfs_fuse_readdir(const char *dir, void *out,
fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi)
{
int r, ret, i, err = 0;
unsigned char buf[4 * 4096], cmd;
uint16_t u16, path_len, len;
char path[512];
uint64_t u64;
(void) offset;
(void) fi;
//xlog("readdir: dir=%s offset=%zd\n", dir, offset);
path_len = strlen(dir);
len = 1 + 2 + 8 + path_len;
if (len > sizeof(buf)) {
xlog(" buffer too small\n");
return -EIO;
}
i = 0;
buf[i++] = 0x03;
buf[i++] = (len - 1 - 2) >> 8;
buf[i++] = len - 1 - 2;
u64 = htobe64(offset); memcpy(buf + i, &u64, 8); i += 8;
memcpy(buf + i, dir, path_len); i += path_len;
r = rgfs_send_recv(buf, i, buf, sizeof(buf));
// standard
filler(out, ".", NULL, 0);
filler(out, "..", NULL, 0);
i = 4;
while (i < r) {
cmd = buf[i++];
//xlog(" cmd=0x%02hhx\n", cmd);
switch (cmd) {
case 0x00: err = - be32toh(*(uint32_t *) (buf + i)); i += 4; break;
case 0x01: /* entry */
u16 = be16toh(*(uint16_t *) (buf + i)); i += 2;
if (u16 > sizeof(path) - 1) {
xlog("path len bigger than buf!\n");
i += u16;
break;
}
memcpy(path, buf + i, u16); i += u16;
path[u16] = '\0';
//xlog(" received path %s\n", path);
ret = filler(out, path, NULL, 0);
if (ret != 0)
xlog(" FILLTER RETURNS 1!\n");
break;
default: xlog("Unexpected subcode 0x%02hhx!\n", cmd); exit(EXIT_FAILURE);
}
}
if (err != 0) {
//xlog(" server returned error %d!\n", err);
return err;
}
return 0;
}
static int rgfs_fuse_open(const char *path, struct fuse_file_info *fi)
{
(void) path;
(void) fi;
//xlog("open: path=%s\n", path);
//if ((fi->flags & O_ACCMODE) != O_RDONLY)
// return -EACCES;
return 0;
}
static int rgfs_fuse_create(const char *path, mode_t mode,
struct fuse_file_info *fi)
{
int err = 0, r, i;
uint16_t u16, path_len, len;
unsigned char buf[4 * 4096], cmd;
(void) mode;
(void) fi;
//xlog("create: path=%s\n", path);
path_len = strlen(path);
len = 1 + 2 + 2 + path_len;
if (len > sizeof(buf)) {
xlog(" buffer too small\n");
return -EIO;
}
i = 0;
buf[i++] = 0x06;
buf[i++] = (len - 1 - 2) >> 8;
buf[i++] = len - 1 - 2;
u16 = htobe16(path_len); memcpy(buf + i, &u16, 2); i += 2;
memcpy(buf + i, path, path_len); i += path_len;
r = rgfs_send_recv(buf, i, buf, sizeof(buf));
i = 4;
while (i < r) {
cmd = buf[i++];
//xlog(" cmd=0x%02hhx\n", cmd);
switch (cmd) {
case 0x00: err = - be32toh(*(uint32_t *) (buf + i)); i += 4; break;
default: xlog("Unexpected subcode 0x%02hhx!\n", cmd); exit(EXIT_FAILURE);
}
}
if (err != 0) {
//xlog(" server returned error %d!\n", err);
return err;
}
return 0;
}
static int rgfs_fuse_mkdir(const char *path, mode_t mode)
{
int err = 0, r, i;
uint16_t u16, path_len, len;
unsigned char buf[4 * 4096], cmd;
(void) mode;
//xlog("mkdir: path=%s\n", path);
path_len = strlen(path);
len = 1 + 2 + 2 + path_len;
if (len > sizeof(buf)) {
xlog(" buffer too small\n");
return -EIO;
}
i = 0;
buf[i++] = 0x07;
buf[i++] = (2 + path_len) / 256;
buf[i++] = 2 + path_len;
u16 = htobe16(path_len); memcpy(buf + i, &u16, 2); i += 2;
memcpy(buf + i, path, path_len); i += path_len;
r = rgfs_send_recv(buf, i, buf, sizeof(buf));
i = 4;
while (i < r) {
cmd = buf[i++];
//xlog(" cmd=0x%02hhx\n", cmd);
switch (cmd) {
case 0x00: err = - be32toh(*(uint32_t *) (buf + i)); i += 4; break;
default: xlog("Unexpected subcode 0x%02hhx!\n", cmd); exit(EXIT_FAILURE);
}
}
if (err != 0) {
//xlog(" server returned error %d!\n", err);
return err;
}
return 0;
}
static int rgfs_fuse_unlink(const char *path)
{
int err = 0, r, i;
uint16_t u16, path_len, len;
unsigned char buf[4 * 4096], cmd;
//xlog("unlink: path=%s\n", path);
path_len = strlen(path);
len = 1 + 2 + 2 + path_len;
if (len > sizeof(buf)) {
xlog(" buffer too small\n");
return -EIO;
}
i = 0;
buf[i++] = 0x08;
buf[i++] = (len - 1 - 2) >> 8;
buf[i++] = len - 1 - 2;
u16 = htobe16(path_len); memcpy(buf + i, &u16, 2); i += 2;
memcpy(buf + i, path, path_len); i += path_len;
r = rgfs_send_recv(buf, i, buf, sizeof(buf));
i = 4;
while (i < r) {
cmd = buf[i++];
//xlog(" cmd=0x%02hhx\n", cmd);
switch (cmd) {
case 0x00: err = - be32toh(*(uint32_t *) (buf + i)); i += 4; break;
default: xlog("Unexpected subcode 0x%02hhx!\n", cmd); exit(EXIT_FAILURE);
}
}
if (err != 0) {
//xlog(" server returned error %d!\n", err);
return err;
}
return 0;
}
static int rgfs_fuse_rmdir(const char *path)
{
int err = 0, r, i;
uint16_t u16, path_len, len;
unsigned char buf[4096], cmd;
//xlog("rmdir: path=%s\n", path);
path_len = strlen(path);
len = 1 + 2 + 2 + path_len;
if (len > sizeof(buf)) {
xlog(" buffer too small\n");
return -EIO;
}
i = 0;
buf[i++] = 0x09;
buf[i++] = (len - 1 - 2) >> 8;
buf[i++] = len - 1 - 2;
u16 = htobe16(path_len); memcpy(buf + i, &u16, 2); i += 2;
memcpy(buf + i, path, path_len); i += path_len;
r = rgfs_send_recv(buf, i, buf, sizeof(buf));
i = 4;
while (i < r) {
cmd = buf[i++];
//xlog(" cmd=0x%02hhx\n", cmd);
switch (cmd) {
case 0x00: err = - be32toh(*(uint32_t *) (buf + i)); i += 4; break;
default: xlog("Unexpected subcode 0x%02hhx!\n", cmd); exit(EXIT_FAILURE);
}
}
if (err != 0) {
//xlog(" server returned error %d!\n", err);
return err;
}
return 0;
}
static int rgfs_fuse_truncate(const char *path, off_t off)
{
int err = 0, r, i;
uint16_t u16, path_len, len;
uint64_t u64;
unsigned char buf[4096], cmd;
//xlog("truncate: path=%s off=%ld\n", path, off);
path_len = strlen(path);
len = 1 + 2 + 2 + 8 + path_len;
if (len > sizeof(buf)) {
xlog(" buffer too small\n");
return -EIO;
}
i = 0;
buf[i++] = 0x0b;
buf[i++] = (len - 1 - 2) >> 8;
buf[i++] = len - 1 - 2;
u16 = htobe16(path_len); memcpy(buf + i, &u16, 2); i += 2;
u64 = htobe64(off); memcpy(buf + i, &u64, 8); i += 8;
memcpy(buf + i, path, path_len); i += path_len;
r = rgfs_send_recv(buf, i, buf, sizeof(buf));
i = 4;
while (i < r) {
cmd = buf[i++];
xlog(" cmd=0x%02hhx\n", cmd);
switch (cmd) {
case 0x00: err = - be32toh(*(uint32_t *) (buf + i)); i += 4; break;
default: xlog("Unexpected subcode 0x%02hhx!\n", cmd); exit(EXIT_FAILURE);
}
}
if (err != 0) {
//xlog(" server returned error %d!\n", err);
return err;
}
return 0;
}
static int rgfs_fuse_read(const char *path, char *out, size_t size,
off_t offset, struct fuse_file_info *fi)
{
int r, err = 0, i;
unsigned char buf[16 * 4096], cmd;
uint16_t path_len, len;
uint64_t u64;
(void) fi;
//xlog("read: path=%s size=%zu offset=%zd\n",
// path, size, offset);
if (size > sizeof(buf) - 1 - 4 - 1 - 8)
size = sizeof(buf) - 1 - 4 - 1 - 8;
path_len = strlen(path);
len = 1 + 2 + 8 + 8 + path_len;
if (len > sizeof(buf)) {
xlog(" buffer too small\n");
return -EIO;
}
i = 0;
buf[i++] = 0x04;
buf[i++] = (len - 1 - 2) >> 8;
buf[i++] = len - 1 - 2;
u64 = htobe64(offset); memcpy(buf + i, &u64, 8); i += 8;
u64 = htobe64(size); memcpy(buf + i, &u64, 8); i += 8;
memcpy(buf + i, path, path_len); i += path_len;
r = rgfs_send_recv(buf, i, buf, sizeof(buf));
i = 4;
while (i < r) {
cmd = buf[i++];
//xlog(" cmd=0x%02hhx\n", cmd);
switch (cmd) {
case 0x00: err = - be32toh(*(uint32_t *) (buf + i)); i += 4; break;
case 0x01: /* block */
u64 = be64toh(*(uint64_t *) (buf + i)); i += 8;
//xlog(" received %lu bytes block\n", u64);
if (i + u64 > (unsigned int) r) {
xlog(" i=%d + u64=%lu > r=%d\n",
i, u64, r);
i += u64;
break;
}
memcpy(out, buf + i, u64); i += u64;
break;
default: xlog("Unexpected subcode 0x%02hhx!\n", cmd); exit(EXIT_FAILURE);
}
}
if (err != 0) {
//xlog(" server returned error %d!\n", err);
return err;
}
return u64;
}
static int rgfs_fuse_write(const char *path, const char *in, size_t size,
off_t offset, struct fuse_file_info *fi)
{
int r, err = 0, i;
unsigned char buf[4 * 4096], cmd;
uint16_t u16, path_len, len;
uint64_t u64;
(void) fi;
#if 0
xlog("write: path=%s size=%zu offset=%zd: ", path, size, offset);
for (unsigned int j = 0; j < 32; j++)
xlog("%02hhx", in[j]);
xlog("\n");
#endif
path_len = strlen(path);
len = 1 + 2 + 2 + 8 + path_len + size;
if (len > sizeof(buf)) {
xlog(" buffer too small\n");
return -EIO;
}
i = 0;
buf[i++] = 0x05;
buf[i++] = (len - 1 - 2) >> 8;
buf[i++] = len - 1 - 2;
u16 = htobe16(path_len); memcpy(buf + i, &u16, 2); i += 2;
u64 = htobe64(offset); memcpy(buf + i, &u64, 8); i += 8;
memcpy(buf + i, path, path_len); i += path_len;
memcpy(buf + i, in, size); i += size;
r = rgfs_send_recv(buf, i, buf, sizeof(buf));
i = 4;
while (i < r) {
cmd = buf[i++];
//xlog(" cmd=0x%02hhx\n", cmd);
switch (cmd) {
case 0x00: err = - be32toh(*(uint32_t *) (buf + i)); i += 4; break;
case 0x01: /* block */
u64 = be64toh(*(uint64_t *) (buf + i)); i += 8;
if (u64 != size)
xlog(" wrote only %lu bytes\n", u64);
break;
default: xlog("Unexpected subcode 0x%02hhx!\n", cmd); exit(EXIT_FAILURE);
}
}
if (err != 0) {
//xlog(" server returned error %d!\n", err);
return err;
}
return u64;
}
static int rgfs_fuse_rename(const char *old, const char *new)
{
int r, err = 0, i;
unsigned char buf[4 * 4096], cmd;
uint16_t u16, old_len, new_len, len;
//xlog("rename: old=%s new=%s\n", old, new);
old_len = strlen(old);
new_len = strlen(new);
len = 1 + 2 + 2 + 2 + old_len + new_len;
if (len > sizeof(buf)) {
xlog(" buffer too small\n");
return -EIO;
}
i = 0;
buf[i++] = 0x0a;
buf[i++] = (len - 1 - 2) >> 8;
buf[i++] = len - 1 - 2;
u16 = htobe16(old_len); memcpy(buf + i, &u16, 2); i += 2;
u16 = htobe16(new_len); memcpy(buf + i, &u16, 2); i += 2;
memcpy(buf + i, old, old_len); i += old_len;
memcpy(buf + i, new, new_len); i += new_len;
r = rgfs_send_recv(buf, i, buf, sizeof(buf));
i = 4;
while (i < r) {
cmd = buf[i++];
//xlog(" cmd=0x%02hhx\n", cmd);
switch (cmd) {
case 0x00: err = - be32toh(*(uint32_t *) (buf + i)); i += 4; break;
default: xlog("Unexpected subcode 0x%02hhx!\n", cmd); exit(EXIT_FAILURE);
}
}
if (err != 0) {
//xlog(" server returned error %d!\n", err);
return err;
}
return 0;
}
static const struct fuse_operations fuse_rgfs = {
.getattr = rgfs_fuse_getattr,
.readdir = rgfs_fuse_readdir,
.open = rgfs_fuse_open,
.create = rgfs_fuse_create,
.mkdir = rgfs_fuse_mkdir,
.unlink = rgfs_fuse_unlink,
.rmdir = rgfs_fuse_rmdir,
.truncate = rgfs_fuse_truncate,
.read = rgfs_fuse_read,
.write = rgfs_fuse_write,
.rename = rgfs_fuse_rename,
};
int main(int argc, char *argv[])
{
int r;
char *s;
s = getenv("RGFS_NAME");
if (s)
rgfs_name = s;
s = getenv("RGFS_PKG_REPO_ID");
if (s)
rgfs_pkg_repo_id = atol(s);
s = getenv("RGFS_KEY");
if (s)
rgfs_key = s;
s = getenv("RGFS_DEBUG");
if (s)
rgfs_debug = atoi(s);
s = getenv("RGFS_LOG");
if (s)
rgfs_log = s;
rgfs_log_fd = open(rgfs_log, O_CREAT | O_WRONLY | O_TRUNC | O_APPEND, 0600);
s = getenv("RGFS_PORT");
if (s)
rgfs_port = atoi(s);
s = getenv("RGFS_SERVER");
if (s)
rgfs_server = s;
s = getenv("RGFS_URL");
if (s)
rgfs_url = s;
xlog("name=%s server=%s port=%d url=%s pkg_repo_id=%u\n",
rgfs_name, rgfs_server, rgfs_port, rgfs_url, rgfs_pkg_repo_id);
if (gnutls_check_version("3.4.6") == NULL) {
xlog("GnuTLS 3.4.6 or later is required!\n");
exit(EXIT_FAILURE);
}
/* for backwards compatibility with gnutls < 3.3.0 */
r = gnutls_global_init();
if (r != GNUTLS_E_SUCCESS) {
xlog("gnutls error: cannot init!\n");
exit(EXIT_FAILURE);
}
/* X509 stuff */
r = gnutls_certificate_allocate_credentials(&xcred);
if (r != GNUTLS_E_SUCCESS) {
xlog("gnutls error: cannot allocate credentials!\n");
exit(EXIT_FAILURE);
}
/* sets the system trusted CAs for Internet PKI */
r = gnutls_certificate_set_x509_system_trust(xcred);
if (r < 0) {
xlog("gnutls error: cannot set system trust [%d]!\n", r);
exit(EXIT_FAILURE);
}
/* If client holds a certificate it can be set using the following:
gnutls_certificate_set_x509_key_file (xcred, "cert.pem", "key.pem",
GNUTLS_X509_FMT_PEM);
*/
xlog("Running fuse...\n");
return fuse_main(argc, argv, &fuse_rgfs, NULL);
#if 0
if (r < 0 && gnutls_error_is_fatal(r) == 0) {
xlog("Warning: %s\n", gnutls_strerror(r));
} else if (r < 0) {
xlog("Error: %s\n", gnutls_strerror(r));
exit(EXIT_FAILURE);
}
#endif
}