/* * FUSE: Filesystem in Userspace * Copyright (C) 2001-2007 Miklos Szeredi * This program can be distributed under the terms of the GNU GPL. * See the file COPYING. * * Changed by Stephan Schwaer * */ #include "../protocol.h" #include "../serialize.h" #include "helper.h" #define FUSE_USE_VERSION 30 #include #include #include #include #include #include #include /* for socket */ #include #include #include #include /* for printing uint */ #define __STDC_FORMAT_MACROS #include /* variables for socket */ int sock = -1; int n; char *server_address = NULL; int portno = -1; char *image_Name = NULL; const char *imagePathName = "/image"; uint16_t rid; 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 void dnbd3_connect() { while ( true ) { if ( sock != -1 ) { close( sock ); } sock = connect_to_server( server_address, portno ); if ( sock == -1 ) { printf( "[ERROR] Connection Error!\n" ); goto fail; } printf( "Selecting image " ); serialized_buffer_t sbuffer; uint16_t protocol_version; char *name; uint16_t rrid; if ( dnbd3_select_image( sock, image_Name, rid, 0 ) != 1 ) { printf( "- Error\n" ); goto fail; } printf( "- Success\n" ); if ( !dnbd3_select_image_reply( &sbuffer, sock, &protocol_version, &name, &rrid, &imageSize ) ) { printf( "Error reading reply\n" ); goto fail; } printf( "Reply successful\n" ); if ( rid != 0 && rid != rrid ) { printf( "Got unexpected rid %d, wanted %d\n", (int)rrid, (int)rid ); sleep( 10 ); goto fail; } rid = rrid; printf( "Protocol version: %i, Image: %s, RevisionID: %i, Size: %i MiB\n", (int)protocol_version, name, (int) rrid, (int)( imageSize/ ( 1024*1024 ) ) ); return; fail: ; sleep( 2 ); } } 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 UNUSED, struct fuse_file_info *fi UNUSED) { 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 UNUSED) { /* buffer for throwing away unwanted messages. */ char tBuf[100]; if ( strcmp( path, imagePathName ) != 0 ) { return -ENOENT; } if ( offset >= imageSize ) { return 0; } if ( offset + size > imageSize ) { size = imageSize - offset; } if ( sock == -1 ) { retry: ; dnbd3_connect(); } /* seek inside the image */ if ( !dnbd3_get_block( sock, offset, size, offset ) ) { printf( "[ERROR] Get block error!\n" ); goto retry; } /* 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" ); goto retry; } printf( "Reply success\n" ); if ( reply.cmd == CMD_ERROR ) { printf( "Got a CMD_ERROR!\n" ); goto retry; } 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 ); goto retry; } tDone += n; } continue; } break; } printf( "Payloadsize: %i\n", ( int ) reply.size ); printf( "Offset: %"PRIu64"\n", reply.handle ); if ( size != reply.size || offset != reply.handle ) { printf( "Size: %i, reply.size: %i!\n", ( int ) size, ( int ) reply.size ); printf( "Handle: %" PRIu64 ", reply.handle: %" PRIu64 "!\n", offset, reply.handle ); goto retry; } /* 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 ); goto retry; } done += n; /* for benchmarking */ logInfo.receivedBytes += n; } printf( "Received bytes: %i MiB\n", ( int )( logInfo.receivedBytes/ ( 1024*1024 ) ) ); /* logfile stuff */ if ( useLog ) { if ( printCount == 0 ) { printLog( &logInfo ); } printCount++; } return size; } /* close the connection */ void image_destroy(void *private_data) { if ( useLog ) { printLog( &logInfo ); } if ( sock != -1 ) { close( sock ); sock = -1; } 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 -s -p -i \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_address = 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_address = "132.230.4.1"; portno = 5003; image_Name = "windows7-umwelt.vmdk"; useLog = true; } if ( server_address == 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"}; dnbd3_connect(); /* initialize benchmark variables */ logInfo.receivedBytes = 0; logInfo.imageSize = imageSize; logInfo.imageBlockCount = ( imageSize + 4095 ) / 4096; uint8_t tmpShrt[logInfo.imageBlockCount]; memset( tmpShrt, 0, sizeof tmpShrt ); logInfo.blockRequestCount = tmpShrt; printf( "ImagePathName: %s\n",imagePathName ); return fuse_main( arg_count, args, &image_oper, NULL ); }