summaryrefslogtreecommitdiffstats
path: root/src/fuse
diff options
context:
space:
mode:
authorschwaer@HiWi.de2015-04-24 15:07:21 +0200
committerschwaer@HiWi.de2015-04-24 15:07:21 +0200
commitd6d983677e0412fdb08b4bcf02bcbaae4e36b3c4 (patch)
treeea0146cade84a5f0aad37d551b26dc2021b8f6d5 /src/fuse
parent[SERVER] Correct debug/error messages in altserver.c (diff)
downloaddnbd3-d6d983677e0412fdb08b4bcf02bcbaae4e36b3c4.tar.gz
dnbd3-d6d983677e0412fdb08b4bcf02bcbaae4e36b3c4.tar.xz
dnbd3-d6d983677e0412fdb08b4bcf02bcbaae4e36b3c4.zip
Fuse
Diffstat (limited to 'src/fuse')
-rwxr-xr-xsrc/fuse/imageFuse.c384
-rwxr-xr-xsrc/fuse/imageHelper.c84
-rwxr-xr-xsrc/fuse/imageHelper.h28
3 files changed, 496 insertions, 0 deletions
diff --git a/src/fuse/imageFuse.c b/src/fuse/imageFuse.c
new file mode 100755
index 0000000..2874b79
--- /dev/null
+++ b/src/fuse/imageFuse.c
@@ -0,0 +1,384 @@
+/*
+ * FUSE: Filesystem in Userspace
+ * Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
+ * This program can be distributed under the terms of the GNU GPL.
+ * See the file COPYING.
+ *
+ * Changed by Stephan Schwaer
+ * */
+
+#define FUSE_USE_VERSION 30
+#include <fuse.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+/* for socket */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include "protocol.h"
+#include "serialize.h"
+/* for printing uint */
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+#include "imageHelper.h"
+
+/* variables for socket */
+int sock = -1;
+int n;
+
+char* server_adress = NULL;
+int portno = -1;
+char* image_Name = NULL;
+char* imagePathName = NULL;
+uint16_t rid;
+uint8_t flags8;
+char buffer[1000];
+static uint64_t imageSize;
+/* Debug/Benchmark variables */
+bool useDebug = false;
+bool useLog = false;
+log_info logInfo;
+uint8_t printCount = 0;
+
+void error(const char *msg)
+{
+ perror(msg);
+ exit(0);
+}
+
+static int image_getattr(const char *path, struct stat *stbuf)
+{
+ int res = 0;
+ memset(stbuf, 0, sizeof(struct stat));
+ if (strcmp(path, "/") == 0) {
+ stbuf->st_mode = S_IFDIR | 0755;
+ stbuf->st_nlink = 2;
+ } else if (strcmp(path, imagePathName) == 0) {
+ stbuf->st_mode = S_IFREG | 0755;
+ stbuf->st_nlink = 1;
+ stbuf->st_size = imageSize;
+ } else
+ res = -ENOENT;
+ return res;
+}
+
+static int image_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
+ off_t offset, struct fuse_file_info *fi)
+{
+ (void) offset;
+ (void) fi;
+ if (strcmp(path, "/") != 0)
+ return -ENOENT;
+ filler(buf, ".", NULL, 0);
+ filler(buf, "..", NULL, 0);
+ filler(buf, imagePathName + 1, NULL, 0);
+ return 0;
+}
+
+static int image_open(const char *path, struct fuse_file_info *fi)
+{
+ if (strcmp(path, imagePathName) != 0)
+ return -ENOENT;
+ if ((fi->flags & 3) != O_RDONLY)
+ return -EACCES;
+ return 0;
+}
+
+static int image_read(const char *path, char *buf, size_t size, off_t offset,
+ struct fuse_file_info *fi)
+{
+ size_t len;
+ /* buffer for throwing away unwanted messages. */
+ char tBuf[100];
+
+ (void) fi;
+ if(strcmp(path, imagePathName) != 0)
+ return -ENOENT;
+ len = imageSize;
+ if (offset < len) {
+ if (offset + size > len)
+ size = len - offset;
+
+get_block:
+ /* seek inside the image */
+ if(!dnbd3_get_block(sock, offset, size, offset)){
+ printf("[ERROR] Get block error!\n");}
+ else {
+ printf("Get block success!\n");
+ }
+
+ /* count the requested blocks */
+ uint64_t startBlock = offset / (4096);
+ uint64_t endBlock = (offset + size - 1) / (4096);
+
+ printf("StartBlockRequest: %"PRIu64"\n", startBlock);
+ printf("EndBlockRequest: %"PRIu64"\n", endBlock);
+
+ if(useDebug) {
+ for (; startBlock <= endBlock; startBlock++){
+ logInfo.blockRequestCount[startBlock] += 1;
+ }
+ }
+
+ dnbd3_reply_t reply;
+
+ /*see if the received package is a requested block, throw away if not */
+ while(true){
+ if(!dnbd3_get_reply(sock, &reply)){
+ printf("[ERROR] Reply error\n");
+
+ /* Try to reconnect after reply error */
+ printf("Reconnecting!\n");
+ sock = connect_to_server(&server_adress, &portno);
+
+ if (sock == -1){
+ printf("[ERROR] Connection Error!");
+ exit(1);
+ }
+
+ printf("Selecting image ");
+
+ bzero(buffer,256);
+ rid = 0;
+ flags8 = 0;
+ serialized_buffer_t sbuffer;
+ uint16_t protocol_version;
+ char *name;
+ uint16_t rrid;
+
+ if(dnbd3_select_image(sock, image_Name, rid, flags8) != 1){
+ printf("- Error\n");
+ } else {printf("- Success\n");
+ }
+
+ if(!dnbd3_select_image_reply(&sbuffer, sock, &protocol_version, &name, &rrid, &imageSize)) {
+ printf("Error reading reply\n");
+ exit(1);
+ } else {printf("Reply successful\n");
+ }
+
+ printf("Protocol version: %i, Image: %s, RevisionID: %i, Size: %i MiB\n",(int) protocol_version, name, (int) rrid,(int) (imageSize/(1024*1024)));
+ goto get_block;
+
+ } else {
+ printf("Reply success\n");
+ }
+ if(reply.cmd == CMD_ERROR) {
+ printf("Got a CMD_ERROR!\n");
+ exit(1);
+ }
+ if(reply.cmd != CMD_GET_BLOCK) {
+ printf("Received block isn't a wanted block, throwing it away...\n");
+ int tDone = 0;
+ int todo;
+ while(tDone < reply.size){
+ todo = reply.size - tDone > 100 ? 100: reply.size - tDone;
+
+ n = read(sock, tBuf, todo);
+ if (n <= 0) {
+ if(n < 0 && (errno == EAGAIN || errno == EINTR)) continue;
+ printf("[ERROR] Errno %i and %i\n",errno, n);
+ exit(1);
+ }
+ tDone += n ;
+ }
+ continue;
+ }
+ break;
+ }
+
+ printf("Payloadsize: %i\n",(int) reply.size);
+ printf("Offset: %"PRIu64"\n", reply.handle);
+
+ if(size != reply.size){
+ printf("Size: %i, reply.size: %i!\n",(int) size,(int) reply.size);
+ exit(1);
+ }
+ /* read the data block data from received package */
+ int done = 0;
+ while (done < size ){
+ n = read(sock, buf + done, size - done);
+ if (n <= 0) {
+ if(n < 0 && (errno == EAGAIN || errno == EINTR)) continue;
+ printf("[ERROR] Error: %i and %i\n",errno, n);
+ exit(1);
+ }
+ done += n;
+ /* for benchmarking */
+ logInfo.receivedBytes += n;
+ }
+ } else
+ size = 0;
+ printf("Received bytes: %i MiB\n",(int) (logInfo.receivedBytes/(1024*1024)));
+
+ /* logfile stuff */
+ if( useLog ){
+ if (printCount == 0){
+ printLog(&logInfo);
+ }
+ printCount = printCount + 1 % 100;
+ }
+ return size;
+}
+
+/* close the connection */
+void image_destroy(void* private_data){
+ if ( useLog ){
+ printLog(&logInfo);
+ }
+ if (close(sock) != 0) {
+ printf("error closing file.\n");
+ exit(-1);
+ }
+ free(imagePathName);
+ return;
+}
+
+/* map the implemented fuse operations */
+static struct fuse_operations image_oper = {
+ .getattr = image_getattr,
+ .readdir = image_readdir,
+ .open = image_open,
+ .read = image_read,
+ .destroy = image_destroy,
+};
+
+int main (int argc, char *argv[])
+{
+ char* mountPoint = NULL;
+ int opt;
+ bool testOpt = false;
+
+ if(argc == 1 ||strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "--usage") == 0 ){
+exit_usage:
+ printf("Usage: %s [-l] [-d] [-t] -m <mountpoint> -s <serverAdress> -p <port> -i <imageName>\n", argv[0]);
+ printf(" -l: creates a logfile log.txt at program path\n");
+ printf(" -d: fuse debug mode\n");
+ printf(" -t: use hardcoded server, port and image for testing\n");
+ exit(EXIT_FAILURE);
+ }
+
+ while((opt = getopt(argc,argv,"m:s:p:i:tdl")) != -1){
+ switch(opt) {
+ case 'm':
+ mountPoint = optarg;
+ break;
+ case 's':
+ server_adress = optarg;
+ break;
+ case 'p':
+ portno = atoi(optarg);
+ break;
+ case 'i':
+ image_Name = optarg;
+ break;
+ case 't':
+ testOpt = true;
+ break;
+ case 'd':
+ useDebug = true;
+ break;
+ case 'l':
+ useLog = true;
+ useDebug = true;
+ break;
+ default:
+ goto exit_usage;
+ }
+ }
+
+ if(testOpt){
+ /* values for testing. */
+ server_adress = "132.230.4.1";
+ portno = 5003;
+ image_Name = "windows7-umwelt.vmdk";
+ useLog = true;
+ }
+
+ if(server_adress == NULL || portno == -1 || image_Name == NULL || mountPoint == NULL){
+ goto exit_usage;
+ }
+
+ int arg_count = 5;
+ if (useDebug){
+ arg_count++;
+ }
+ char * args[6] = {"foo", "-o", "ro,allow_other", "-s", mountPoint, "-d"};
+
+ sock = connect_to_server(&server_adress, &portno);
+
+ if (sock == -1){
+ printf("[ERROR] Connection Error!");
+ exit(1);
+ }
+
+ printf("Selecting image ");
+
+ bzero(buffer,256);
+ rid = 0;
+ flags8 = 0;
+
+ serialized_buffer_t sbuffer;
+ uint16_t protocol_version;
+ char *name;
+ uint16_t rrid;
+
+ if(dnbd3_select_image(sock, image_Name, rid, flags8) != 1){
+ printf("- Error\n");
+ } else {printf("- Success\n");
+ }
+
+ if(!dnbd3_select_image_reply(&sbuffer, sock, &protocol_version, &name, &rrid, &imageSize)) {
+ printf("Error reading reply\n");
+ exit(1);
+ } else {printf("Reply successful\n");
+ }
+
+ printf("Protocol version: %i, Image: %s, RevisionID: %i, Size: %i MiB\n",(int) protocol_version, name, (int) rrid,(int) (imageSize/(1024*1024)));
+
+ /* fix name of image if it contains '/' */
+ int len = strlen(image_Name) - 1;
+ bool fixName = false;
+ for(; len >= 0; len--){
+ if(image_Name[len] == '/'){
+ fixName = true;
+ break;
+ }
+ }
+ if( fixName) {
+ memmove(image_Name, image_Name + len + 1, strlen(image_Name) - len);
+ printf("image_Name: %s\n", image_Name);
+ }
+
+
+ char * str1 = "/";
+ char * tmpStr = (char *) malloc(1 + strlen(str1) + strlen(image_Name));
+ strcpy(tmpStr, str1);
+ strcat(tmpStr, image_Name);
+ imagePathName = tmpStr;
+
+ /* initialize benchmark variables */
+ logInfo.receivedBytes = 0;
+ logInfo.imageSize = imageSize;
+ logInfo.imageBlockCount = imageSize % 4096 == 0 ? imageSize/(4096) : imageSize/(4096) + 1;
+
+ uint8_t tmpShrt[logInfo.imageBlockCount];
+ uint64_t i = 0;
+ if ( useLog ){
+ for(; i < logInfo.imageBlockCount; i++){
+ tmpShrt[i] = 0;
+ }
+ }
+
+ logInfo.blockRequestCount = tmpShrt;
+
+ printf("ImagePathName: %s\n",imagePathName);
+ return fuse_main(arg_count, args, &image_oper, NULL);
+}
+
+
diff --git a/src/fuse/imageHelper.c b/src/fuse/imageHelper.c
new file mode 100755
index 0000000..b5bc9bd
--- /dev/null
+++ b/src/fuse/imageHelper.c
@@ -0,0 +1,84 @@
+/*
+ * Helper functions for imageFuse
+ * by Stephan Schwaer, January 2014
+ */
+
+#include "imageHelper.h"
+void printLog(log_info *info){
+ FILE *logFile;
+
+ // Create logfile
+
+ logFile = fopen("log.txt", "w+");
+ if ( logFile == NULL) {
+ printf("Error creating/opening log.txt\n");
+ return;
+ }
+
+ //rewind(file);
+ fprintf(logFile, "ImageSize: %"PRIu64" MiB\n", (uint64_t)(info->imageSize/(1024ll*1024ll)));
+ fprintf(logFile, "ReceivedMiB: %"PRIu64" MiB\n", (uint64_t)(info->receivedBytes/(1024ll*1024ll)));
+ fprintf(logFile, "imageBlockCount: %"PRIu64"\n", info->imageBlockCount);
+ fprintf(logFile, "Blocksize: 4KiB\n\n");
+ fprintf(logFile, "Block access count:\n");
+
+ uint64_t i = 0;
+ for (; i < info->imageBlockCount; i++){
+ if( i % 50 == 0 ) fprintf(logFile, "\n");
+ fprintf(logFile, "%i ",(int) info->blockRequestCount[i]);
+ }
+ fprintf(logFile, "\n");
+ fclose(logFile);
+}
+
+bool sock_printable(struct sockaddr *addr, socklen_t addrLen, char *output, int len)
+{
+ char host[100], port[10];
+ int ret = getnameinfo( addr, addrLen, host, 100, port, 10, NI_NUMERICHOST | NI_NUMERICSERV );
+ if ( ret == 0 ) snprintf( output, len, "[%s]:%s", host, port );
+ return ret == 0;
+}
+
+
+int connect_to_server(char ** server_adress, int * port){
+ const int on = 1;
+ int sock = -1;
+ struct addrinfo hints, *res, *ptr;
+ char portStr[6];
+
+ // Set hints for local addresses.
+ memset( &hints, 0, sizeof(hints) );
+ hints.ai_flags = AI_PASSIVE;
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ snprintf( portStr, sizeof portStr, "%d", *port );
+ if ( getaddrinfo( *server_adress, portStr, &hints, &res ) != 0 || res == NULL ) return false;
+ // Attempt to bind to all of the addresses as long as there's room in the poll list
+ for( ptr = res; ptr != NULL; ptr = ptr->ai_next ) {
+ char bla[100];
+ if ( !sock_printable( (struct sockaddr*)ptr->ai_addr, ptr->ai_addrlen, bla, 100 ) ) snprintf( bla, 100, "[invalid]" );
+ printf( "Trying to connect to %s ", bla );
+ sock = socket( ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol );
+ if ( sock < 0 ) {
+ printf( "...cannot create socket, errno=%d\n", errno );
+ sock = -1;
+ continue;
+ }
+ setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) );
+ if ( ptr->ai_family == PF_INET6 ) setsockopt( sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on) );
+ if (connect(sock, ptr->ai_addr, ptr->ai_addrlen) < 0) {
+ // if ( bind( sock, ptr->ai_addr, ptr->ai_addrlen ) == -1 ) {
+ printf( "...socket Error, errno=%d\n", errno );
+ close( sock );
+ sock = -1;
+ continue;
+ } else {
+ printf( "... connecting successful!\n");
+ break;
+ }
+ }
+
+ freeaddrinfo( res );
+ return sock;
+}
+
diff --git a/src/fuse/imageHelper.h b/src/fuse/imageHelper.h
new file mode 100755
index 0000000..60805cd
--- /dev/null
+++ b/src/fuse/imageHelper.h
@@ -0,0 +1,28 @@
+#ifndef IMAGEHELPER_H
+#define IMAGEHELPER_H
+
+#include <netdb.h>
+#include "protocol.h"
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+
+typedef struct log_info {
+ uint64_t imageSize;
+ uint64_t receivedBytes;
+ uint64_t imageBlockCount;
+ uint8_t * blockRequestCount;
+} log_info;
+
+
+
+void printLog(log_info *info);
+
+bool sock_printable(struct sockaddr *addr, socklen_t addrLen, char *output, int len);
+
+int connect_to_server(char ** server_adress, int * port);
+#endif