r7: Added gzipped nbd code from marc <marc@jade.cs.uct.ac.za>.
authorpavel <pavel>
Sun, 10 Dec 2000 21:37:05 +0000 (21:37 +0000)
committerpavel <pavel>
Sun, 10 Dec 2000 21:37:05 +0000 (21:37 +0000)
gznbd/Makefile [new file with mode: 0644]
gznbd/gznbd.c [new file with mode: 0644]

diff --git a/gznbd/Makefile b/gznbd/Makefile
new file mode 100644 (file)
index 0000000..5245ef6
--- /dev/null
@@ -0,0 +1,2 @@
+gznbd: gznbd.c
+       gcc -s -Wall -O2 -DTRACE gznbd.c -o gznbd -lz
diff --git a/gznbd/gznbd.c b/gznbd/gznbd.c
new file mode 100644 (file)
index 0000000..e5c1e49
--- /dev/null
@@ -0,0 +1,256 @@
+/* 
+   (c) Marc Welz 2000, released under GPL, tested under Linux 2.2.17
+
+   Most of the stuff cribbed from the nbd package written by Pavel Machek
+
+   Unfortunately quite slow since zlib has to decompress all the stuff between
+   seeks, so only suited to smaller files
+   
+   Could be a neat way to do userland encryption/steganography if you have 
+   a crypto library which has a stdiolike interface to replace zlib
+
+   Usage
+
+     dd if=/dev/zero of=/tmp/image bs=1024 count=1024
+     mke2fs -f /tmp/image
+     mount -o loop /tmp/image /mnt/
+     cp /bin/ls /mnt/
+     umount /mnt
+     sync
+     gzip -9 /tmp/image
+     gznbd /dev/nbd0 /tmp/image.gz
+
+   gznbd does not background, from another terminal type
+
+     mount -o ro,nocheck /dev/nbd0 /mnt/
+     cd /mnt
+     ls
+     df
+
+   ro is important, since writes will fail horribly and nochecks
+   speeds the mount up nicely
+
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <zlib.h>
+#include <errno.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+
+/* asm/types defines __u??, at least on my system */
+#include <asm/types.h>
+
+#define u32 __u32
+#define u64 __u64
+
+#include <linux/nbd.h>
+
+#define BLOCK 1024
+
+/* don't ask me why this value, I only copied it */
+#define CHUNK BLOCK*20
+
+/* taken litterally from the original nbd */
+#ifdef WORDS_BIGENDIAN
+u64 ntohll(u64 a)
+{
+  return a;
+}
+#else
+u64 ntohll(u64 a)
+{
+  u32 lo = a & 0xffffffff;
+  u32 hi = a >> 32U;
+  lo = ntohl(lo);
+  hi = ntohl(hi);
+  return ((u64) lo) << 32U | hi;
+}
+#endif
+
+
+int main(int argc, char **argv)
+{
+  int pr[2];
+  int sk;
+  int nbd;
+  gzFile *gz;
+  int gzerr;
+
+  char chunk[CHUNK];
+  struct nbd_request request;
+  struct nbd_reply reply;
+
+  u64 size;
+  u64 from;
+  u32 len;
+
+  if(argc<3){
+    printf("Usage: %s nbdevice gzfile [size]\n",argv[0]);
+    exit(1);
+  }
+
+  gz=gzopen(argv[2], "rb");
+  if(gz==NULL){
+    fprintf(stderr,"%s: unable open compressed file %s\n",argv[0],argv[2]);
+    exit(1);
+  }
+
+  if(argc>3){
+    size=atol(argv[3]);
+    if((size==0)||(size%BLOCK)){
+      fprintf(stderr,"%s: %s does not appear to be a valid size\n",argv[0],argv[3]);
+      exit(1);
+    }
+    printf("%s: file=%s, size=%Ld\n",argv[0],argv[2],size);
+  } else {
+    char buffer[BLOCK];
+    int result;
+
+    size=0;
+    printf("%s: file=%s, seeking, ",argv[0],argv[2]);
+    fflush(stdout);
+
+    /* expensive seek to get file size */
+    while(BLOCK==(result=gzread(gz,buffer,BLOCK))){
+      size+=BLOCK;
+    }
+
+    if(result==0){
+      printf("size=%Ld\n",size);
+    } else {
+      printf("failed\n");
+      if(result<0){
+        fprintf(stderr,"%s: read failed: %s\n",argv[0],gzerror(gz,&gzerr));
+      } else {
+        fprintf(stderr,"%s: incomplete last read, file has to be a multiple of %d\n",argv[0],BLOCK);
+      }
+      exit(1);
+    }
+
+    if(gzrewind(gz)!=0){
+      fprintf(stderr,"%s: unable to rewind gzfile\n",argv[0]);
+      exit(1);
+    }
+
+  }
+
+  if(socketpair(AF_UNIX, SOCK_STREAM, 0, pr)){
+    fprintf(stderr,"%s: unable to create socketpair: %s\n",argv[0],strerror(errno));
+    exit(1);
+  }
+
+  switch(fork()){
+    case -1 :
+      fprintf(stderr,"%s: unable to fork: %s\n",argv[0],strerror(errno));
+      exit(1);
+      break;
+    case 0 : /* child */
+      gzclose(gz);
+
+      close(pr[0]);
+
+      sk=pr[1];
+
+      nbd=open(argv[1], O_RDWR);
+      if(nbd<0){
+        fprintf(stderr,"%s: unable to open %s: %s\n",argv[0],argv[1],strerror(errno));
+        exit(1);
+      }
+
+      if(ioctl(nbd,NBD_SET_SIZE,size)<0){
+        fprintf(stderr,"%s: failed to set size for %s: %s\n",argv[0],argv[1],strerror(errno));
+        exit(1);
+      }
+
+      ioctl(nbd, NBD_CLEAR_SOCK);
+
+      if(ioctl(nbd,NBD_SET_SOCK,sk)<0){
+        fprintf(stderr,"%s: failed to set socket for %s: %s\n",argv[0],argv[1],strerror(errno));
+        exit(1);
+      }
+
+      if(ioctl(nbd,NBD_DO_IT)<0){
+        fprintf(stderr,"%s: block device %s terminated: %s\n",argv[0],argv[1],strerror(errno));
+      }
+
+      ioctl(nbd, NBD_CLEAR_QUE);
+      ioctl(nbd, NBD_CLEAR_SOCK);
+
+      exit(0);
+      
+      break;
+  }
+
+  /* only parent here, child always exits */
+
+  close(pr[1]);
+  sk=pr[0];
+
+  reply.magic=htonl(NBD_REPLY_MAGIC);
+  reply.error=htonl(0);
+
+  while(1){
+
+    if(read(sk,&request,sizeof(request))!=sizeof(request)){
+      fprintf(stderr,"%s: incomplete request\n",argv[0]);
+    }
+
+    memcpy(reply.handle,request.handle,sizeof(reply.handle));
+
+    len=ntohl(request.len);
+    from=ntohll(request.from);
+
+#ifdef TRACE
+fprintf(stderr,"%s: len=%d, from=%Ld\n",argv[0],len,from);
+#endif
+
+    if(request.magic!=htonl(NBD_REQUEST_MAGIC)){
+      fprintf(stderr,"%s: bad magic\n",argv[0]);
+      reply.error=htonl(EIO); /* is that the right way of doing things ? */
+    }
+
+    if(ntohl(request.type)){
+      fprintf(stderr,"%s: unsupported write request\n",argv[0]);
+      reply.error=htonl(EROFS);
+    }
+
+    if(len+sizeof(struct nbd_reply)>CHUNK){
+      fprintf(stderr,"%s: request too long\n",argv[0]);
+      reply.error=htonl(EIO);
+    }
+
+    if(len+from>size){
+      fprintf(stderr,"%s: request outside range\n",argv[0]);
+      reply.error=htonl(EIO);
+    }
+
+    if(reply.error==htonl(0)){
+      gzseek(gz,from,0);
+      if(gzread(gz,chunk+sizeof(struct nbd_reply),len)!=len){
+        fprintf(stderr,"%s: unable to read\n",argv[0]);
+        reply.error=htonl(EIO);
+        len=0;
+      }
+    } else {
+      len=0;
+    }
+
+    memcpy(chunk,&reply,sizeof(struct nbd_reply));
+    if(write(sk,chunk,len+sizeof(struct nbd_reply))!=(len+sizeof(struct nbd_reply))){
+      fprintf(stderr,"%s: write failed: %s\n",argv[0],strerror(errno));
+    }
+  }
+
+  gzclose(gz);
+
+  return 0;
+}