--- block-nbd.c | 16 ++++++++++++++ nbd.c | 47 +++++++++++++++++++++++++++++++++++++++++ nbd.h | 2 + qemu-nbd.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++-------- 4 files changed, 124 insertions(+), 9 deletions(-) Index: qemu/nbd.c =================================================================== --- qemu.orig/nbd.c 2008-09-08 09:43:45.000000000 +0200 +++ qemu/nbd.c 2008-09-08 09:53:05.000000000 +0200 @@ -337,6 +337,53 @@ int nbd_receive_negotiate(int csock, off return 0; } +int nbd_filename(int csock, const char *filename) +{ + uint8_t len; + + if (!filename || strlen(filename) > 254) { + errno = EINVAL; + return -1; + } + + len = strlen(filename) + 1; + if (write_sync(csock, &len, sizeof(uint8_t)) != + sizeof(uint8_t)) { + LOG("read failed"); + errno = EINVAL; + return -1; + } + if (len && write_sync(csock, (char*)filename, len) != len) { + LOG("read failed"); + errno = EINVAL; + return -1; + } + return 0; +} + +int nbd_receive_filename(int csock, char *filename) +{ + uint8_t len; + filename[0] = '\0'; + if (read_sync(csock, &len, sizeof(uint8_t)) != sizeof(uint8_t)) { + LOG("read failed"); + errno = EINVAL; + return -1; + } + if (len == 0) { + LOG("read failed"); + errno = EINVAL; + return -1; + } + if (read_sync(csock, filename, len) != len) { + LOG("read failed"); + errno = EINVAL; + return -1; + } + filename[len] = 0; + return 0; +} + int nbd_init(int fd, int csock, off_t size, size_t blocksize) { TRACE("Setting block size to %lu", (unsigned long)blocksize); Index: qemu/nbd.h =================================================================== --- qemu.orig/nbd.h 2008-09-08 09:43:45.000000000 +0200 +++ qemu/nbd.h 2008-09-08 09:53:05.000000000 +0200 @@ -52,6 +52,8 @@ int unix_socket_incoming(const char *pat int nbd_negotiate(int csock, off_t size); int nbd_receive_negotiate(int csock, off_t *size, size_t *blocksize); +int nbd_filename(int csock, const char *filename); +int nbd_receive_filename(int csock, char *filename); int nbd_init(int fd, int csock, off_t size, size_t blocksize); int nbd_send_request(int csock, struct nbd_request *request); int nbd_receive_reply(int csock, struct nbd_reply *reply); Index: qemu/block-nbd.c =================================================================== --- qemu.orig/block-nbd.c 2008-09-08 09:31:04.000000000 +0200 +++ qemu/block-nbd.c 2008-09-08 09:53:05.000000000 +0200 @@ -47,6 +47,7 @@ static int nbd_open(BlockDriverState *bs off_t size; size_t blocksize; int ret; + const char *name = NULL; if ((flags & BDRV_O_CREAT)) return -EINVAL; @@ -79,6 +80,10 @@ static int nbd_open(BlockDriverState *bs if (r == p) return -EINVAL; sock = tcp_socket_outgoing(hostname, port); + if (*r == ':') { + r++; + name = r; + } } if (sock == -1) @@ -88,6 +93,17 @@ static int nbd_open(BlockDriverState *bs if (ret == -1) return -errno; + if (size == 0) { + if (name == NULL) + return -EINVAL; + ret = nbd_filename(sock, name); + if (ret == -1) + return -errno; + ret = nbd_receive_negotiate(sock, &size, &blocksize); + if (ret == -1) + return -errno; + } + s->sock = sock; s->size = size; s->blocksize = blocksize; Index: qemu/qemu-nbd.c =================================================================== --- qemu.orig/qemu-nbd.c 2008-09-08 09:49:06.000000000 +0200 +++ qemu/qemu-nbd.c 2008-09-08 10:23:37.000000000 +0200 @@ -158,6 +158,42 @@ static int find_partition(BlockDriverSta return -1; } +static int negotiate_filename(int csock, BlockDriverState *bs, int flags, + const char *directory, off_t *fd_size) +{ + char filename[255]; + char path[PATH_MAX]; + const char *name; + int ret; + + ret = nbd_negotiate(csock, *fd_size); + if (ret == -1) + return -1; + + if (*fd_size) + return 0; + + if (directory == NULL) + return -1; + + if (nbd_receive_filename(csock, filename) == -1) + return -1; + + name = basename(filename); + if (strlen(directory) + strlen(name) + 1 > PATH_MAX) + return -1; + + sprintf(path, "%s/%s", directory, name); + if (bdrv_open(bs, path, flags) == -1) + return -1; + + *fd_size = bs->total_sectors * 512; + + ret = nbd_negotiate(csock, *fd_size); + + return ret; +} + static void show_parts(const char *device) { if (fork() == 0) { @@ -189,8 +225,9 @@ int main(int argc, char **argv) off_t fd_size; char *device = NULL; char *socket = NULL; + char *directory = NULL; char sockpath[128]; - const char *sopt = "hVbo:p:rsnP:c:dvk:e:t"; + const char *sopt = "hVbo:p:rsnP:c:dvk:e:ti:"; struct option lopt[] = { { "help", 0, 0, 'h' }, { "version", 0, 0, 'V' }, @@ -207,6 +244,7 @@ int main(int argc, char **argv) { "shared", 1, 0, 'e' }, { "persistent", 0, 0, 't' }, { "verbose", 0, 0, 'v' }, + { "directory", 1, 0, 'i' }, { NULL, 0, 0, 0 } }; int ch; @@ -300,13 +338,16 @@ int main(int argc, char **argv) usage(argv[0]); exit(0); break; + case 'i': + directory = optarg; + break; case '?': errx(EINVAL, "Try `%s --help' for more information.", argv[0]); } } - if ((argc - optind) != 1) { + if (directory == NULL && (argc - optind) != 1) { errx(EINVAL, "Invalid number of argument.\n" "Try `%s --help' for more information.", argv[0]); @@ -330,20 +371,28 @@ int main(int argc, char **argv) errx(EINVAL, "You cannot set port to 0 and use shared"); } + if (directory && port) { + errx(EINVAL, "--directory can only be used with --port=0"); + } + bdrv_init(); bs = bdrv_new("hda"); if (bs == NULL) return 1; - if (bdrv_open(bs, argv[optind], flags) == -1) - return 1; + if (directory) { + fd_size = 0; + } else { + if (bdrv_open(bs, argv[optind], flags) == -1) + return 1; - fd_size = bs->total_sectors * 512; + fd_size = bs->total_sectors * 512; - if (partition != -1 && - find_partition(bs, partition, &dev_offset, &fd_size)) - errx(errno, "Could not find partition %d", partition); + if (partition != -1 && + find_partition(bs, partition, &dev_offset, &fd_size)) + errx(errno, "Could not find partition %d", partition); + } if (device) { pid_t pid; @@ -425,7 +474,8 @@ int main(int argc, char **argv) } else { if (port == 0) { /* read and write on stdin/stdout */ - ret = nbd_negotiate(STDIN_FILENO, fd_size); + ret = negotiate_filename(STDIN_FILENO, bs, flags, directory, + &fd_size); while (ret != -1) { ret = nbd_trip(bs, STDIN_FILENO, fd_size, dev_offset, &offset, readonly, data, NBD_BUFFER_SIZE);