[PATCH] support colon in filenames

Ram Pai
2009-06-24T16:58:59Z

Problem: It is impossible to feed filenames with the character colon because
qemu interprets such names as a protocol. For example a filename scsi:0,
is interpreted as a protocol by name "scsi".

This patch allows users to espace colon characters. For example the above filename
can now be expressed as 'scsi\:0'

Here are couple of examples:

ndb:\::9999 is treated as a ndb protocol with a hostname ':' on port 9999
scsi\:0\:abc is a local file scsi:0:abc
http\://myweb is a local file by name http://myweb
nbd\::localhost:2558 is a protocol by name nbd:

Signed-off-by: Ram Pai <linuxram@us.ibm.com>
-----------------------------------------------------------------------

block.c | 26 +++++++++++++++++---------
block/nbd.c | 19 ++++++++++++++-----
block/raw-posix.c | 24 +++++++++++++++++-------
cutils.c | 22 ++++++++++++++++++++++
qemu-common.h | 1 +
vl.c | 3 +--
6 files changed, 72 insertions(+), 23 deletions(-)

diff --git a/block.c b/block.c
index aca5a6d..80bded9 100644
--- a/block.c
+++ b/block.c
@@ -225,22 +225,30 @@ static BlockDriver *find_protocol(const char *filename)
{
BlockDriver *drv1;
char protocol[128];
- int len;
- const char *p;
+ char *p = protocol;
+ const char *f=filename;
+ int len = strnlen(filename, 128);

#ifdef _WIN32
if (is_windows_drive(filename) ||
is_windows_drive_prefix(filename))
return bdrv_find_format("raw");
#endif
- p = strchr(filename, ':');
- if (!p)
+ while ( f < filename+len ) {
+ if ( *f == ':' )
+ break;
+ if ( *f == '\\') {
+ f++;
+ if ( *f == '\0')
+ break;
+ }
+ *p++ = *f++;
+ }
+ *p='\0';
+
+ if (*f != ':')
return bdrv_find_format("raw");
- len = p - filename;
- if (len > sizeof(protocol) - 1)
- len = sizeof(protocol) - 1;
- memcpy(protocol, filename, len);
- protocol[len] = '\0';
+
for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) {
if (drv1->protocol_name &&
!strcmp(drv1->protocol_name, protocol))
diff --git a/block/nbd.c b/block/nbd.c
index 47d4778..a011cc7 100644
--- a/block/nbd.c
+++ b/block/nbd.c
@@ -64,18 +64,27 @@ static int nbd_open(BlockDriverState *bs, const char* filename, int flags)

} else {
uint16_t port;
- char *p, *r;
+ char *q, *p, *r;
char hostname[128];

pstrcpy(hostname, 128, host);

- p = strchr(hostname, ':');
- if (p == NULL)
+ q=p=hostname;
+ while ( p < hostname+128 ) {
+ if (*p == ':')
+ break;
+ if ( *p == '\\' ) {
+ p++;
+ if (*p =='\0')
+ break;
+ }
+ *q++=*p++;
+ }
+ if (*p != ':')
return -EINVAL;

- *p = '\0';
+ *q='\0';
p++;
-
port = strtol(p, &r, 0);
if (r == p)
return -EINVAL;
diff --git a/block/raw-posix.c b/block/raw-posix.c
index 41bfa37..98ede17 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -124,6 +124,16 @@ static int fd_open(BlockDriverState *bs);
static int cdrom_reopen(BlockDriverState *bs);
#endif

+static int _open(const char *filename, int flags, ...)
+{
+ char myfile[PATH_MAX];
+ va_list ap;
+ va_start(ap, flags);
+ return open(esc_string(myfile, PATH_MAX, filename),
+ flags, ap);
+}
+
+
static int raw_open_common(BlockDriverState *bs, const char *filename,
int flags)
{
@@ -151,7 +161,7 @@ static int raw_open_common(BlockDriverState *bs, const char *filename,
s->open_flags |= O_DSYNC;

s->fd = -1;
- fd = open(filename, s->open_flags, 0644);
+ fd = _open(filename, s->open_flags, 0644);
if (fd < 0) {
ret = -errno;
if (ret == -EROFS)
@@ -844,7 +854,7 @@ static int raw_create(const char *filename, QEMUOptionParameter *options)
options++;
}

- fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
+ fd = _open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
0644);
if (fd < 0)
return -EIO;
@@ -985,7 +995,7 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
if ( bsdPath[ 0 ] != '\0' ) {
strcat(bsdPath,"s0");
/* some CDs don't have a partition 0 */
- fd = open(bsdPath, O_RDONLY | O_BINARY | O_LARGEFILE);
+ fd = _open(bsdPath, O_RDONLY | O_BINARY | O_LARGEFILE);
if (fd < 0) {
bsdPath[strlen(bsdPath)-1] = '1';
} else {
@@ -1037,7 +1047,7 @@ static int fd_open(BlockDriverState *bs)
#endif
return -EIO;
}
- s->fd = open(bs->filename, s->open_flags & ~O_NONBLOCK);
+ s->fd = _open(bs->filename, s->open_flags & ~O_NONBLOCK);
if (s->fd < 0) {
s->fd_error_time = qemu_get_clock(rt_clock);
s->fd_got_error = 1;
@@ -1133,7 +1143,7 @@ static int hdev_create(const char *filename, QEMUOptionParameter *options)
options++;
}

- fd = open(filename, O_WRONLY | O_BINARY);
+ fd = _open(filename, O_WRONLY | O_BINARY);
if (fd < 0)
return -EIO;

@@ -1239,7 +1249,7 @@ static int floppy_eject(BlockDriverState *bs, int eject_flag)
close(s->fd);
s->fd = -1;
}
- fd = open(bs->filename, s->open_flags | O_NONBLOCK);
+ fd = _open(bs->filename, s->open_flags | O_NONBLOCK);
if (fd >= 0) {
if (ioctl(fd, FDEJECT, 0) < 0)
perror("FDEJECT");
@@ -1399,7 +1409,7 @@ static int cdrom_reopen(BlockDriverState *bs)
*/
if (s->fd >= 0)
close(s->fd);
- fd = open(bs->filename, s->open_flags, 0644);
+ fd = _open(bs->filename, s->open_flags, 0644);
if (fd < 0) {
s->fd = -1;
return -EIO;
diff --git a/cutils.c b/cutils.c
index 6ea0c49..63c196d 100644
--- a/cutils.c
+++ b/cutils.c
@@ -24,6 +24,28 @@
#include "qemu-common.h"
#include "host-utils.h"

+/*
+ * prune escape character '\'
+ */
+char *esc_string(char *buf, int buf_size, const char *str)
+{
+ const char *p=str;
+ int len = strlen(str);
+ char *q=buf;
+
+ len = (buf_size < len) ? buf_size: len;
+ while (p < str+len) {
+ if (*p == '\\') {
+ p++;
+ if (*p == '\0')
+ break;
+ }
+ *q++ = *p++;
+ }
+ *q='\0';
+ return buf;
+}
+
void pstrcpy(char *buf, int buf_size, const char *str)
{
int c;
diff --git a/qemu-common.h b/qemu-common.h
index 2dcb224..1e510dc 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -104,6 +104,7 @@ void qemu_get_timedate(struct tm *tm, int offset);
int qemu_timedate_diff(struct tm *tm);

/* cutils.c */
+char *esc_string(char *buf, int buf_size, const char *str);
void pstrcpy(char *buf, int buf_size, const char *str);
char *pstrcat(char *buf, int buf_size, const char *s);
int strstart(const char *str, const char *val, const char **ptr);
diff --git a/vl.c b/vl.c
index 7278999..5d7b024 100644
--- a/vl.c
+++ b/vl.c
@@ -2583,8 +2583,7 @@ int drive_init(struct drive_opt *arg, int snapshot, void *opaque)
else if (cache == 3) /* not specified */
bdrv_flags |= BDRV_O_CACHE_DEF;
if (bdrv_open2(bdrv, file, bdrv_flags, drv) < 0) {
- fprintf(stderr, "qemu: could not open disk image %s\n",
- file);
+ fprintf(stderr, "qemu: could not open disk image %s\n", file);
return -1;
}
if (bdrv_key_required(bdrv))