From: pavel Date: Sun, 10 Dec 2000 21:37:05 +0000 (+0000) Subject: r7: Added gzipped nbd code from marc . X-Git-Url: http://git.alex.org.uk r7: Added gzipped nbd code from marc . --- diff --git a/gznbd/Makefile b/gznbd/Makefile new file mode 100644 index 0000000..5245ef6 --- /dev/null +++ b/gznbd/Makefile @@ -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 index 0000000..e5c1e49 --- /dev/null +++ b/gznbd/gznbd.c @@ -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 +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +/* asm/types defines __u??, at least on my system */ +#include + +#define u32 __u32 +#define u64 __u64 + +#include + +#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; +}