* clean on 32 bit machines. Anton Altaparmakov <aia21@cam.ac.uk>
* Version 2.0 - Version synchronised with client
* Version 2.1 - Reap zombie client processes when they exit. Removed
- * (uncommented) the _IO magic, it's no longer necessary.
+ * (uncommented) the _IO magic, it's no longer necessary. Wouter
+ * Verhelst <wouter@debian.org>
+ * Version 2.2 - Auto switch to read-only mode (usefull for floppies).
+ * Version 2.3 - Fixed code so that Large File Support works. This
+ * removes the FS_32BIT compile-time directive; define
+ * _FILE_OFFSET_BITS=64 and _LARGEFILE_SOURCE if you used to be
+ * using FS_32BIT. This will allow you to use files >2GB instead of
+ * having to use the -m option. Wouter Verhelst <wouter@debian.org>
*/
-#define VERSION "2.1"
+#define VERSION "2.3"
#define GIGA (1*1024*1024*1024)
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/mount.h> /* For BLKGETSIZE */
-#ifdef FS_32BIT
-typedef u32 fsoffset_t;
-#define htonll htonl
-#define ntohll ntohl
-#else
-typedef u64 fsoffset_t;
-#endif
-
-
//#define DODBG
#ifdef DODBG
#define DEBUG( a ) printf( a )
#define DEBUG3( a,b,c )
#endif
-#if defined(HAVE_LLSEEK) && !defined(sun)
-/* Solaris already has llseek defined in unistd.h */
-extern long long llseek(unsigned int, long long, unsigned int);
-#endif
-
void serveconnection(int net);
void set_peername(int net,char *clientname);
#define LINELEN 256
char difffilename[256];
unsigned int timeout = 0;
+int autoreadonly = 0;
int authorized_client(char *name)
/* 0 - authorization refused, 1 - OK
}
}
+#define OFFT_MAX (((off_t)1)<<(sizeof(off_t)*8))-1
int port; /* Port I'm listening at */
char *exportname; /* File I'm exporting */
-fsoffset_t exportsize = (fsoffset_t)-1; /* ...and its length */
-fsoffset_t hunksize = (fsoffset_t)-1;
+off_t exportsize = OFFT_MAX; /* ...and its length */
+off_t hunksize = OFFT_MAX;
int flags = 0;
int export[1024];
int difffile=-1 ;
}
}
} else {
- fsoffset_t es;
+ off_t es;
int last = strlen(argv[i])-1;
char suffix = argv[i][last];
if (suffix == 'k' || suffix == 'K' ||
suffix == 'm' || suffix == 'M')
argv[i][last] = '\0';
- es = (fsoffset_t)atol(argv[i]);
+ es = (off_t)atol(argv[i]);
switch (suffix) {
case 'm':
case 'M': es <<= 10;
#define SEND writeit( net, &reply, sizeof( reply ));
#define ERROR { reply.error = htonl(-1); SEND; reply.error = 0; lastpoint = -1; }
-fsoffset_t lastpoint = (fsoffset_t)-1;
+off_t lastpoint = (off_t)-1;
-void maybeseek(int handle, fsoffset_t a)
+void maybeseek(int handle, off_t a)
{
- if (a > exportsize)
- err("Can not happen\n");
- if (lastpoint != a) {
-#if defined(HAVE_LLSEEK) && !defined(FS_32BIT)
- if (llseek(handle, a, SEEK_SET) < 0)
-#else
- if (lseek(handle, (long)a, SEEK_SET) < 0)
-#endif
- err("Can not seek locally!\n");
- lastpoint = a;
- } else {
- DEBUG("@");
- }
+if (a > exportsize)
+ err("Can not happen\n");
+if (lastpoint != a) {
+ if (lseek(handle, a, SEEK_SET) < 0)
+ err("Can not seek locally!\n");
+ lastpoint = a;
+} else {
+ DEBUG("@");
+}
}
-void myseek(int handle,fsoffset_t a)
+void myseek(int handle,off_t a)
{
-#if HAVE_LLSEEK && !defined(FS_32BIT)
- if (llseek(handle, a, SEEK_SET) < 0)
-#else
- if (lseek(handle, (long)a, SEEK_SET) < 0)
-#endif
- err("Can not seek locally!\n");
+ if (lseek(handle, a, SEEK_SET) < 0)
+ err("Can not seek locally!\n");
}
-char pagebuf[DIFFPAGESIZE] ;
-
+char pagebuf[DIFFPAGESIZE];
-int rawexpread(fsoffset_t a, char *buf, int len)
+int rawexpread(off_t a, char *buf, int len)
{
maybeseek(export[a/hunksize], a%hunksize);
return (read(export[a/hunksize], buf, len) != len);
}
-int expread(fsoffset_t a, char *buf, int len)
+int expread(off_t a, char *buf, int len)
{
int rdlen, offset;
- fsoffset_t mapcnt, mapl, maph, pagestart;
+ off_t mapcnt, mapl, maph, pagestart;
- if (flags & F_COPYONWRITE) {
- DEBUG3("Asked to read %d bytes at %Lu.\n", len, (unsigned long long)a);
-
- mapl=a/DIFFPAGESIZE ; maph=(a+len-1)/DIFFPAGESIZE ;
-
- for (mapcnt=mapl;mapcnt<=maph;mapcnt++) {
- pagestart=mapcnt*DIFFPAGESIZE ;
- offset=a-pagestart ;
- rdlen=(len<DIFFPAGESIZE-offset) ? len : DIFFPAGESIZE-offset ;
- if (difmap[mapcnt]!=(u32)(-1)) { /* the block is already there */
- DEBUG3("Page %Lu is at %lu\n", (unsigned long long)mapcnt,
- (unsigned long)difmap[mapcnt]);
- myseek(difffile,difmap[mapcnt]*DIFFPAGESIZE+offset) ;
- if (read(difffile, buf, rdlen) != rdlen) return -1 ;
- } else { /* the block is not there */
- DEBUG2("Page %Lu is not here, we read the original one\n",
- (unsigned long long)mapcnt) ;
- if (rawexpread(a,buf,rdlen)) return -1 ;
- }
- len-=rdlen ; a+=rdlen ; buf+=rdlen ;
- }
- } else return rawexpread(a,buf,len) ;
- return 0 ;
+ if (!(flags & F_COPYONWRITE))
+ return rawexpread(a, buf, len);
+ DEBUG3("Asked to read %d bytes at %Lu.\n", len, (unsigned long long)a);
+
+ mapl=a/DIFFPAGESIZE; maph=(a+len-1)/DIFFPAGESIZE;
+
+ for (mapcnt=mapl;mapcnt<=maph;mapcnt++) {
+ pagestart=mapcnt*DIFFPAGESIZE;
+ offset=a-pagestart;
+ rdlen=(len<DIFFPAGESIZE-offset) ? len : DIFFPAGESIZE-offset;
+ if (difmap[mapcnt]!=(u32)(-1)) { /* the block is already there */
+ DEBUG3("Page %Lu is at %lu\n", (unsigned long long)mapcnt,
+ (unsigned long)difmap[mapcnt]);
+ myseek(difffile, difmap[mapcnt]*DIFFPAGESIZE+offset);
+ if (read(difffile, buf, rdlen) != rdlen) return -1;
+ } else { /* the block is not there */
+ DEBUG2("Page %Lu is not here, we read the original one\n",
+ (unsigned long long)mapcnt);
+ return rawexpread(a, buf, rdlen);
+ }
+ len-=rdlen; a+=rdlen; buf+=rdlen;
+ }
+ return 0;
}
-int rawexpwrite(fsoffset_t a, char *buf, int len)
+int rawexpwrite(off_t a, char *buf, int len)
{
maybeseek(export[a/hunksize], a%hunksize);
return (write(export[a/hunksize], buf, len) != len);
}
-int expwrite(fsoffset_t a, char *buf, int len)
-{ u32 mapcnt,mapl,maph ; int wrlen,rdlen ;
- fsoffset_t pagestart ; int offset ;
-
- if (flags & F_COPYONWRITE) {
- DEBUG3("Asked to write %d bytes at %Lu.\n", len, (unsigned long long)a);
-
- mapl=a/DIFFPAGESIZE ; maph=(a+len-1)/DIFFPAGESIZE ;
-
- for (mapcnt=mapl;mapcnt<=maph;mapcnt++) {
- pagestart=mapcnt*DIFFPAGESIZE ;
- offset=a-pagestart ;
- wrlen=(len<DIFFPAGESIZE-offset) ? len : DIFFPAGESIZE-offset ;
-
- if (difmap[mapcnt]!=(u32)(-1)) { /* the block is already there */
- DEBUG3("Page %Lu is at %lu\n", (unsigned long long)mapcnt,
- (unsigned long)difmap[mapcnt]) ;
- myseek(difffile,difmap[mapcnt]*DIFFPAGESIZE+offset) ;
- if (write(difffile, buf, wrlen) != wrlen) return -1 ;
- } else { /* the block is not there */
- myseek(difffile,difffilelen*DIFFPAGESIZE) ;
- difmap[mapcnt]=difffilelen++ ;
- DEBUG3("Page %Lu is not here, we put it at %lu\n",
- (unsigned long long)mapcnt,
- (unsigned long)difmap[mapcnt]);
- rdlen=DIFFPAGESIZE ;
- if (rdlen+pagestart%hunksize>hunksize)
- rdlen=hunksize-(pagestart%hunksize) ;
- if (rawexpread(pagestart,pagebuf,rdlen)) return -1 ;
- memcpy(pagebuf+offset,buf,wrlen) ;
- if (write(difffile,pagebuf,DIFFPAGESIZE)!=DIFFPAGESIZE) return -1 ;
- }
- len-=wrlen ; a+=wrlen ; buf+=wrlen ;
- }
- } else return(rawexpwrite(a,buf,len));
- return 0 ;
+int expwrite(off_t a, char *buf, int len)
+{
+ u32 mapcnt,mapl,maph ; int wrlen,rdlen ;
+ off_t pagestart ; int offset ;
+
+ if (!(flags & F_COPYONWRITE))
+ return(rawexpwrite(a,buf,len));
+ DEBUG3("Asked to write %d bytes at %Lu.\n", len, (unsigned long long)a);
+
+ mapl=a/DIFFPAGESIZE ; maph=(a+len-1)/DIFFPAGESIZE ;
+
+ for (mapcnt=mapl;mapcnt<=maph;mapcnt++) {
+ pagestart=mapcnt*DIFFPAGESIZE ;
+ offset=a-pagestart ;
+ wrlen=(len<DIFFPAGESIZE-offset) ? len : DIFFPAGESIZE-offset ;
+
+ if (difmap[mapcnt]!=(u32)(-1)) { /* the block is already there */
+ DEBUG3("Page %Lu is at %lu\n", (unsigned long long)mapcnt,
+ (unsigned long)difmap[mapcnt]) ;
+ myseek(difffile,difmap[mapcnt]*DIFFPAGESIZE+offset) ;
+ if (write(difffile, buf, wrlen) != wrlen) return -1 ;
+ } else { /* the block is not there */
+ myseek(difffile,difffilelen*DIFFPAGESIZE) ;
+ difmap[mapcnt]=difffilelen++ ;
+ DEBUG3("Page %Lu is not here, we put it at %lu\n",
+ (unsigned long long)mapcnt,
+ (unsigned long)difmap[mapcnt]);
+ rdlen=DIFFPAGESIZE ;
+ if (rdlen+pagestart%hunksize>hunksize)
+ rdlen=hunksize-(pagestart%hunksize) ;
+ if (rawexpread(pagestart,pagebuf,rdlen)) return -1 ;
+ memcpy(pagebuf+offset,buf,wrlen) ;
+ if (write(difffile,pagebuf,DIFFPAGESIZE)!=DIFFPAGESIZE) return -1 ;
+ }
+ len-=wrlen ; a+=wrlen ; buf+=wrlen ;
+ }
+ return 0;
}
int mainloop(int net)
struct nbd_reply reply;
char zeros[300];
int i = 0;
- fsoffset_t size_host;
+ off_t size_host;
memset(zeros, 0, 290);
if (write(net, INIT_PASSWD, 8) < 0)
err("Negotiation failed: %m");
-#ifndef FS_32BIT
cliserv_magic = htonll(cliserv_magic);
-#endif
if (write(net, &cliserv_magic, sizeof(cliserv_magic)) < 0)
err("Negotiation failed: %m");
size_host = htonll(exportsize);
-#ifdef FS_32BIT
- if (write(net, zeros, 4) < 0 || write(net, &size_host, 4) < 0)
-#else
if (write(net, &size_host, 8) < 0)
-#endif
err("Negotiation failed: %m");
if (write(net, zeros, 128) < 0)
err("Negotiation failed: %m");
(unsigned long long)request.from / 512, len);
#endif
memcpy(reply.handle, request.handle, sizeof(reply.handle));
- if (((request.from + len) > exportsize) ||
+ if ((request.from + len) > (OFFT_MAX)) {
+ DEBUG("[Number too large!]");
+ ERROR;
+ continue;
+ }
+ if ((((off_t)request.from + len) > exportsize) ||
((flags & F_READONLY) && request.type)) {
DEBUG("[RANGE!]");
ERROR;
DEBUG("wr: net->buf, ");
readit(net, buf, len);
DEBUG("buf->exp, ");
- if (expwrite(request.from, buf, len)) {
+ if ((autoreadonly == 1) || expwrite(request.from, buf, len)) {
DEBUG("Write failed: %m" );
ERROR;
continue;
strncpy(clientname,peername,255) ;
}
-fsoffset_t size_autodetect(int export)
+off_t size_autodetect(int export)
{
- fsoffset_t es;
+ off_t es;
u32 es32;
struct stat stat_buf;
int error;
DEBUG("looking for export size with lseek SEEK_END\n");
- es = (fsoffset_t)lseek(export, 0, SEEK_END);
- if ((signed long long)es > 0LL)
+ es = lseek(export, (off_t)0, SEEK_END);
+ if (es > ((off_t)0))
return es;
DEBUG("looking for export size with fstat\n");
stat_buf.st_size = 0;
error = fstat(export, &stat_buf);
if (!error && stat_buf.st_size > 0)
- return (fsoffset_t)stat_buf.st_size;
+ return (off_t)stat_buf.st_size;
#ifdef BLKGETSIZE
DEBUG("looking for export size with ioctl BLKGETSIZE\n");
if (!ioctl(export, BLKGETSIZE, &es32) && es32) {
- es = (fsoffset_t)es32 * (fsoffset_t)512;
+ es = (off_t)es32 * (off_t)512;
return es;
}
#endif
err("Could not find size of exported block device: %m");
- return (fsoffset_t)-1;
+ return (off_t)-1;
}
int main(int argc, char *argv[])
{
int net;
- fsoffset_t i;
+ off_t i;
if (sizeof( struct nbd_request )!=28) {
fprintf(stderr,"Bad size of structure. Alignment problems?\n");
void serveconnection(int net)
{
- u64 i ;
+ off_t i ;
for (i=0; i<exportsize; i+=hunksize) {
char exportname3[1024];
sprintf(exportname3, exportname2, i/hunksize);
printf( "Opening %s\n", exportname3 );
- if ((export[i/hunksize] = open(exportname3, (flags & F_READONLY) ? O_RDONLY : O_RDWR)) == -1)
- err("Could not open exported file: %m");
+ if ((export[i/hunksize] = open(exportname3, (flags & F_READONLY) ? O_RDONLY : O_RDWR)) == -1) {
+ /* Read WRITE ACCESS was requested by media is only read only */
+ autoreadonly = 1;
+ flags |= F_READONLY;
+ if ((export[i/hunksize] = open(exportname3, O_RDONLY)) == -1)
+ err("Could not open exported file: %m");
+ }
}
-
- if (exportsize == (fsoffset_t)-1) {
+
+ if (exportsize == (off_t)OFFT_MAX) {
exportsize = size_autodetect(export[0]);
}
- if (exportsize > ((fsoffset_t)-1 >> 1)) {
-#ifdef HAVE_LLSEEK
- if ((exportsize >> 10) > ((fsoffset_t)-1 >> 1))
- msg3(LOG_INFO, "size of exported file/device is %LuMB",
- (unsigned long long)(exportsize >> 20));
- else
- msg3(LOG_INFO, "size of exported file/device is %LuKB",
- (unsigned long long)(exportsize >> 10));
- }
-#else
+ if (exportsize > (off_t)OFFT_MAX) {
err("Size of exported file is too big\n");
}
-#endif
else
msg3(LOG_INFO, "size of exported file/device is %Lu",
(unsigned long long)exportsize);