2 (c) Marc Welz 2000, released under GPL, tested under Linux 2.2.17
4 Most of the stuff cribbed from the nbd package written by Pavel Machek
6 Unfortunately quite slow since zlib has to decompress all the stuff between
7 seeks, so only suited to smaller files
9 Could be a neat way to do userland encryption/steganography if you have
10 a crypto library which has a stdiolike interface to replace zlib
14 dd if=/dev/zero of=/tmp/image bs=1024 count=1024
16 mount -o loop /tmp/image /mnt/
21 gznbd /dev/nbd0 /tmp/image.gz
23 gznbd does not background, from another terminal type
25 mount -o ro,nocheck /dev/nbd0 /mnt/
30 ro is important, since writes will fail horribly and nochecks
31 speeds the mount up nicely
43 #include <sys/ioctl.h>
44 #include <sys/types.h>
45 #include <sys/socket.h>
47 #include <netinet/in.h>
49 /* asm/types defines __u??, at least on my system */
50 #include <asm/types.h>
55 #include <linux/nbd.h>
59 /* don't ask me why this value, I only copied it */
60 #define CHUNK BLOCK*20
62 /* taken litterally from the original nbd */
63 #ifdef WORDS_BIGENDIAN
71 u32 lo = a & 0xffffffff;
75 return ((u64) lo) << 32U | hi;
80 int main(int argc, char **argv)
89 struct nbd_request request;
90 struct nbd_reply reply;
97 printf("Usage: %s nbdevice gzfile [size]\n",argv[0]);
101 gz=gzopen(argv[2], "rb");
103 fprintf(stderr,"%s: unable open compressed file %s\n",argv[0],argv[2]);
109 if((size==0)||(size%BLOCK)){
110 fprintf(stderr,"%s: %s does not appear to be a valid size\n",argv[0],argv[3]);
113 printf("%s: file=%s, size=%Ld\n",argv[0],argv[2],size);
119 printf("%s: file=%s, seeking, ",argv[0],argv[2]);
122 /* expensive seek to get file size */
123 while(BLOCK==(result=gzread(gz,buffer,BLOCK))){
128 printf("size=%Ld\n",size);
132 fprintf(stderr,"%s: read failed: %s\n",argv[0],gzerror(gz,&gzerr));
134 fprintf(stderr,"%s: incomplete last read, file has to be a multiple of %d\n",argv[0],BLOCK);
140 fprintf(stderr,"%s: unable to rewind gzfile\n",argv[0]);
146 if(socketpair(AF_UNIX, SOCK_STREAM, 0, pr)){
147 fprintf(stderr,"%s: unable to create socketpair: %s\n",argv[0],strerror(errno));
153 fprintf(stderr,"%s: unable to fork: %s\n",argv[0],strerror(errno));
163 nbd=open(argv[1], O_RDWR);
165 fprintf(stderr,"%s: unable to open %s: %s\n",argv[0],argv[1],strerror(errno));
169 if(ioctl(nbd,NBD_SET_SIZE,size)<0){
170 fprintf(stderr,"%s: failed to set size for %s: %s\n",argv[0],argv[1],strerror(errno));
174 ioctl(nbd, NBD_CLEAR_SOCK);
176 if(ioctl(nbd,NBD_SET_SOCK,sk)<0){
177 fprintf(stderr,"%s: failed to set socket for %s: %s\n",argv[0],argv[1],strerror(errno));
181 if(ioctl(nbd,NBD_DO_IT)<0){
182 fprintf(stderr,"%s: block device %s terminated: %s\n",argv[0],argv[1],strerror(errno));
185 ioctl(nbd, NBD_CLEAR_QUE);
186 ioctl(nbd, NBD_CLEAR_SOCK);
193 /* only parent here, child always exits */
198 reply.magic=htonl(NBD_REPLY_MAGIC);
199 reply.error=htonl(0);
203 if(read(sk,&request,sizeof(request))!=sizeof(request)){
204 fprintf(stderr,"%s: incomplete request\n",argv[0]);
207 memcpy(reply.handle,request.handle,sizeof(reply.handle));
209 len=ntohl(request.len);
210 from=ntohll(request.from);
213 fprintf(stderr,"%s: len=%d, from=%Ld\n",argv[0],len,from);
216 if(request.magic!=htonl(NBD_REQUEST_MAGIC)){
217 fprintf(stderr,"%s: bad magic\n",argv[0]);
218 reply.error=htonl(EIO); /* is that the right way of doing things ? */
221 if(ntohl(request.type)){
222 fprintf(stderr,"%s: unsupported write request\n",argv[0]);
223 reply.error=htonl(EROFS);
226 if(len+sizeof(struct nbd_reply)>CHUNK){
227 fprintf(stderr,"%s: request too long\n",argv[0]);
228 reply.error=htonl(EIO);
232 fprintf(stderr,"%s: request outside range\n",argv[0]);
233 reply.error=htonl(EIO);
236 if(reply.error==htonl(0)){
238 if(gzread(gz,chunk+sizeof(struct nbd_reply),len)!=len){
239 fprintf(stderr,"%s: unable to read\n",argv[0]);
240 reply.error=htonl(EIO);
247 memcpy(chunk,&reply,sizeof(struct nbd_reply));
248 if(write(sk,chunk,len+sizeof(struct nbd_reply))!=(len+sizeof(struct nbd_reply))){
249 fprintf(stderr,"%s: write failed: %s\n",argv[0],strerror(errno));