1
The following changes since commit 136c67e07869227b21b3f627316e03679ce7b738:
1
The following changes since commit 474f3938d79ab36b9231c9ad3b5a9314c2aeacde:
2
2
3
Merge remote-tracking branch 'remotes/bkoppelmann/tags/pull-tricore-2018-03-02' into staging (2018-03-02 16:56:20 +0000)
3
Merge remote-tracking branch 'remotes/amarkovic/tags/mips-queue-jun-21-2019' into staging (2019-06-21 15:40:50 +0100)
4
4
5
are available in the Git repository at:
5
are available in the Git repository at:
6
6
7
git://github.com/stefanha/qemu.git tags/block-pull-request
7
https://github.com/XanClic/qemu.git tags/pull-block-2019-06-24
8
8
9
for you to fetch changes up to 23500c6a9409efc80d696aede0629bfbe7556a90:
9
for you to fetch changes up to ab5d4a30f7f3803ca5106b370969c1b7b54136f8:
10
10
11
README: Document 'git-publish' workflow (2018-03-05 09:03:17 +0000)
11
iotests: Fix 205 for concurrent runs (2019-06-24 16:01:40 +0200)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
Pull request
14
Block patches:
15
- The SSH block driver now uses libssh instead of libssh2
16
- The VMDK block driver gets read-only support for the seSparse
17
subformat
18
- Various fixes
15
19
16
Mostly patches that are only indirectly related to the block layer, but I've
20
---
17
reviewed them and there is no maintainer.
21
22
v2:
23
- Squashed Pino's fix for pre-0.8 libssh into the libssh patch
18
24
19
----------------------------------------------------------------
25
----------------------------------------------------------------
26
Anton Nefedov (1):
27
iotest 134: test cluster-misaligned encrypted write
20
28
21
Fam Zheng (2):
29
Klaus Birkelund Jensen (1):
22
Add a git-publish configuration file
30
nvme: do not advertise support for unsupported arbitration mechanism
23
README: Document 'git-publish' workflow
24
31
25
Su Hang (3):
32
Max Reitz (1):
26
util/uri.c: Coding style check, Only whitespace involved
33
iotests: Fix 205 for concurrent runs
27
util/uri.c: remove brackets that wrap `return` statement's content.
28
util/uri.c: wrap single statement blocks with braces {}
29
34
30
Thomas Huth (1):
35
Pino Toscano (1):
31
tests/libqos: Check for valid dev pointer when looking for PCI devices
36
ssh: switch from libssh2 to libssh
32
37
33
tests/libqos/virtio-pci.c | 4 +-
38
Sam Eiderman (3):
34
util/uri.c | 1733 ++++++++++++++++++++++++---------------------
39
vmdk: Fix comment regarding max l1_size coverage
35
.gitpublish | 51 ++
40
vmdk: Reduce the max bound for L1 table size
36
README | 31 +-
41
vmdk: Add read-only support for seSparse snapshots
37
4 files changed, 1014 insertions(+), 805 deletions(-)
42
38
create mode 100644 .gitpublish
43
Vladimir Sementsov-Ogievskiy (1):
44
blockdev: enable non-root nodes for transaction drive-backup source
45
46
configure | 65 +-
47
block/Makefile.objs | 6 +-
48
block/ssh.c | 652 ++++++++++--------
49
block/vmdk.c | 372 +++++++++-
50
blockdev.c | 2 +-
51
hw/block/nvme.c | 1 -
52
.travis.yml | 4 +-
53
block/trace-events | 14 +-
54
docs/qemu-block-drivers.texi | 2 +-
55
.../dockerfiles/debian-win32-cross.docker | 1 -
56
.../dockerfiles/debian-win64-cross.docker | 1 -
57
tests/docker/dockerfiles/fedora.docker | 4 +-
58
tests/docker/dockerfiles/ubuntu.docker | 2 +-
59
tests/docker/dockerfiles/ubuntu1804.docker | 2 +-
60
tests/qemu-iotests/059.out | 2 +-
61
tests/qemu-iotests/134 | 9 +
62
tests/qemu-iotests/134.out | 10 +
63
tests/qemu-iotests/205 | 2 +-
64
tests/qemu-iotests/207 | 54 +-
65
tests/qemu-iotests/207.out | 2 +-
66
20 files changed, 823 insertions(+), 384 deletions(-)
39
67
40
--
68
--
41
2.14.3
69
2.21.0
42
70
43
71
diff view generated by jsdifflib
New patch
1
From: Klaus Birkelund Jensen <klaus@birkelund.eu>
1
2
3
The device mistakenly reports that the Weighted Round Robin with Urgent
4
Priority Class arbitration mechanism is supported.
5
6
It is not.
7
8
Signed-off-by: Klaus Birkelund Jensen <klaus.jensen@cnexlabs.com>
9
Message-id: 20190606092530.14206-1-klaus@birkelund.eu
10
Acked-by: Maxim Levitsky <mlevitsk@redhat.com>
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
12
---
13
hw/block/nvme.c | 1 -
14
1 file changed, 1 deletion(-)
15
16
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
17
index XXXXXXX..XXXXXXX 100644
18
--- a/hw/block/nvme.c
19
+++ b/hw/block/nvme.c
20
@@ -XXX,XX +XXX,XX @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp)
21
n->bar.cap = 0;
22
NVME_CAP_SET_MQES(n->bar.cap, 0x7ff);
23
NVME_CAP_SET_CQR(n->bar.cap, 1);
24
- NVME_CAP_SET_AMS(n->bar.cap, 1);
25
NVME_CAP_SET_TO(n->bar.cap, 0xf);
26
NVME_CAP_SET_CSS(n->bar.cap, 1);
27
NVME_CAP_SET_MPSMAX(n->bar.cap, 4);
28
--
29
2.21.0
30
31
diff view generated by jsdifflib
New patch
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
2
3
We forget to enable it for transaction .prepare, while it is already
4
enabled in do_drive_backup since commit a2d665c1bc362
5
"blockdev: loosen restrictions on drive-backup source node"
6
7
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
8
Message-id: 20190618140804.59214-1-vsementsov@virtuozzo.com
9
Reviewed-by: John Snow <jsnow@redhat.com>
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
---
12
blockdev.c | 2 +-
13
1 file changed, 1 insertion(+), 1 deletion(-)
14
15
diff --git a/blockdev.c b/blockdev.c
16
index XXXXXXX..XXXXXXX 100644
17
--- a/blockdev.c
18
+++ b/blockdev.c
19
@@ -XXX,XX +XXX,XX @@ static void drive_backup_prepare(BlkActionState *common, Error **errp)
20
assert(common->action->type == TRANSACTION_ACTION_KIND_DRIVE_BACKUP);
21
backup = common->action->u.drive_backup.data;
22
23
- bs = qmp_get_root_bs(backup->device, errp);
24
+ bs = bdrv_lookup_bs(backup->device, backup->device, errp);
25
if (!bs) {
26
return;
27
}
28
--
29
2.21.0
30
31
diff view generated by jsdifflib
1
From: Fam Zheng <famz@redhat.com>
1
From: Anton Nefedov <anton.nefedov@virtuozzo.com>
2
2
3
git-publish [1] is a convenient tool to send patches and has been
3
COW (even empty/zero) areas require encryption too
4
popular among QEMU developers. Recently it has been made available in
5
Fedora/Debian official repo.
6
4
7
One nice feature of the tool is a per-project configuration with
5
Signed-off-by: Anton Nefedov <anton.nefedov@virtuozzo.com>
8
profiles, especially in which the cccmd option is a handy method to
6
Reviewed-by: Eric Blake <eblake@redhat.com>
9
create the Cc list.
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
Reviewed-by: Alberto Garcia <berto@igalia.com>
9
Message-id: 20190516143028.81155-1-anton.nefedov@virtuozzo.com
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
---
12
tests/qemu-iotests/134 | 9 +++++++++
13
tests/qemu-iotests/134.out | 10 ++++++++++
14
2 files changed, 19 insertions(+)
10
15
11
[1]: https://github.com/stefanha/git-publish
16
diff --git a/tests/qemu-iotests/134 b/tests/qemu-iotests/134
12
17
index XXXXXXX..XXXXXXX 100755
13
Signed-off-by: Fam Zheng <famz@redhat.com>
18
--- a/tests/qemu-iotests/134
14
Message-id: 20180226030326.20219-2-famz@redhat.com
19
+++ b/tests/qemu-iotests/134
15
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
20
@@ -XXX,XX +XXX,XX @@ echo
16
---
21
echo "== reading whole image =="
17
.gitpublish | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++
22
$QEMU_IO --object $SECRET -c "read 0 $size" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir
18
1 file changed, 51 insertions(+)
23
19
create mode 100644 .gitpublish
24
+echo
20
25
+echo "== rewriting cluster part =="
21
diff --git a/.gitpublish b/.gitpublish
26
+$QEMU_IO --object $SECRET -c "write -P 0xb 512 512" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir
22
new file mode 100644
23
index XXXXXXX..XXXXXXX
24
--- /dev/null
25
+++ b/.gitpublish
26
@@ -XXX,XX +XXX,XX @@
27
+#
28
+# Common git-publish profiles that can be used to send patches to QEMU upstream.
29
+#
30
+# See https://github.com/stefanha/git-publish for more information
31
+#
32
+[gitpublishprofile "default"]
33
+base = master
34
+to = qemu-devel@nongnu.org
35
+cccmd = scripts/get_maintainer.pl --noroles --norolestats --nogit --nogit-fallback 2>/dev/null
36
+
27
+
37
+[gitpublishprofile "rfc"]
28
+echo
38
+base = master
29
+echo "== verify pattern =="
39
+prefix = RFC PATCH
30
+$QEMU_IO --object $SECRET -c "read -P 0 0 512" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir
40
+to = qemu-devel@nongnu.org
31
+$QEMU_IO --object $SECRET -c "read -P 0xb 512 512" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir
41
+cccmd = scripts/get_maintainer.pl --noroles --norolestats --nogit --nogit-fallback 2>/dev/null
42
+
32
+
43
+[gitpublishprofile "stable"]
33
echo
44
+base = master
34
echo "== rewriting whole image =="
45
+to = qemu-devel@nongnu.org
35
$QEMU_IO --object $SECRET -c "write -P 0xa 0 $size" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir
46
+cc = qemu-stable@nongnu.org
36
diff --git a/tests/qemu-iotests/134.out b/tests/qemu-iotests/134.out
47
+cccmd = scripts/get_maintainer.pl --noroles --norolestats --nogit --nogit-fallback 2>/dev/null
37
index XXXXXXX..XXXXXXX 100644
38
--- a/tests/qemu-iotests/134.out
39
+++ b/tests/qemu-iotests/134.out
40
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encryption=on encrypt.
41
read 134217728/134217728 bytes at offset 0
42
128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
43
44
+== rewriting cluster part ==
45
+wrote 512/512 bytes at offset 512
46
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
48
+
47
+
49
+[gitpublishprofile "trivial"]
48
+== verify pattern ==
50
+base = master
49
+read 512/512 bytes at offset 0
51
+to = qemu-devel@nongnu.org
50
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
52
+cc = qemu-trivial@nongnu.org
51
+read 512/512 bytes at offset 512
53
+cccmd = scripts/get_maintainer.pl --noroles --norolestats --nogit --nogit-fallback 2>/dev/null
52
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
54
+
53
+
55
+[gitpublishprofile "block"]
54
== rewriting whole image ==
56
+base = master
55
wrote 134217728/134217728 bytes at offset 0
57
+to = qemu-devel@nongnu.org
56
128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
58
+cc = qemu-block@nongnu.org
59
+cccmd = scripts/get_maintainer.pl --noroles --norolestats --nogit --nogit-fallback 2>/dev/null
60
+
61
+[gitpublishprofile "arm"]
62
+base = master
63
+to = qemu-devel@nongnu.org
64
+cc = qemu-arm@nongnu.org
65
+cccmd = scripts/get_maintainer.pl --noroles --norolestats --nogit --nogit-fallback 2>/dev/null
66
+
67
+[gitpublishprofile "s390"]
68
+base = master
69
+to = qemu-devel@nongnu.org
70
+cc = qemu-s390@nongnu.org
71
+cccmd = scripts/get_maintainer.pl --noroles --norolestats --nogit --nogit-fallback 2>/dev/null
72
+
73
+[gitpublishprofile "ppc"]
74
+base = master
75
+to = qemu-devel@nongnu.org
76
+cc = qemu-ppc@nongnu.org
77
+cccmd = scripts/get_maintainer.pl --noroles --norolestats --nogit --nogit-fallback 2>/dev/null
78
--
57
--
79
2.14.3
58
2.21.0
80
59
81
60
diff view generated by jsdifflib
1
From: Thomas Huth <thuth@redhat.com>
1
From: Sam Eiderman <shmuel.eiderman@oracle.com>
2
2
3
dev could be NULL if the PCI device can not be found due to some
3
Commit b0651b8c246d ("vmdk: Move l1_size check into vmdk_add_extent")
4
reasons, so we must not dereference the pointer in this case.
4
extended the l1_size check from VMDK4 to VMDK3 but did not update the
5
default coverage in the moved comment.
5
6
6
Signed-off-by: Thomas Huth <thuth@redhat.com>
7
The previous vmdk4 calculation:
7
Message-id: 1519713884-2346-1-git-send-email-thuth@redhat.com
8
8
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
9
(512 * 1024 * 1024) * 512(l2 entries) * 65536(grain) = 16PB
10
11
The added vmdk3 calculation:
12
13
(512 * 1024 * 1024) * 4096(l2 entries) * 512(grain) = 1PB
14
15
Adding the calculation of vmdk3 to the comment.
16
17
In any case, VMware does not offer virtual disks more than 2TB for
18
vmdk4/vmdk3 or 64TB for the new undocumented seSparse format which is
19
not implemented yet in qemu.
20
21
Reviewed-by: Karl Heubaum <karl.heubaum@oracle.com>
22
Reviewed-by: Eyal Moscovici <eyal.moscovici@oracle.com>
23
Reviewed-by: Liran Alon <liran.alon@oracle.com>
24
Reviewed-by: Arbel Moshe <arbel.moshe@oracle.com>
25
Signed-off-by: Sam Eiderman <shmuel.eiderman@oracle.com>
26
Message-id: 20190620091057.47441-2-shmuel.eiderman@oracle.com
27
Reviewed-by: yuchenlin <yuchenlin@synology.com>
28
Reviewed-by: Max Reitz <mreitz@redhat.com>
29
Signed-off-by: Max Reitz <mreitz@redhat.com>
9
---
30
---
10
tests/libqos/virtio-pci.c | 4 +++-
31
block/vmdk.c | 11 ++++++++---
11
1 file changed, 3 insertions(+), 1 deletion(-)
32
1 file changed, 8 insertions(+), 3 deletions(-)
12
33
13
diff --git a/tests/libqos/virtio-pci.c b/tests/libqos/virtio-pci.c
34
diff --git a/block/vmdk.c b/block/vmdk.c
14
index XXXXXXX..XXXXXXX 100644
35
index XXXXXXX..XXXXXXX 100644
15
--- a/tests/libqos/virtio-pci.c
36
--- a/block/vmdk.c
16
+++ b/tests/libqos/virtio-pci.c
37
+++ b/block/vmdk.c
17
@@ -XXX,XX +XXX,XX @@ QVirtioPCIDevice *qvirtio_pci_device_find(QPCIBus *bus, uint16_t device_type)
38
@@ -XXX,XX +XXX,XX @@ static int vmdk_add_extent(BlockDriverState *bs,
18
qvirtio_pci_foreach(bus, device_type, false, 0,
39
return -EFBIG;
19
qvirtio_pci_assign_device, &dev);
40
}
20
41
if (l1_size > 512 * 1024 * 1024) {
21
- dev->vdev.bus = &qvirtio_pci;
42
- /* Although with big capacity and small l1_entry_sectors, we can get a
22
+ if (dev) {
43
+ /*
23
+ dev->vdev.bus = &qvirtio_pci;
44
+ * Although with big capacity and small l1_entry_sectors, we can get a
24
+ }
45
* big l1_size, we don't want unbounded value to allocate the table.
25
46
- * Limit it to 512M, which is 16PB for default cluster and L2 table
26
return dev;
47
- * size */
27
}
48
+ * Limit it to 512M, which is:
49
+ * 16PB - for default "Hosted Sparse Extent" (VMDK4)
50
+ * cluster size: 64KB, L2 table size: 512 entries
51
+ * 1PB - for default "ESXi Host Sparse Extent" (VMDK3/vmfsSparse)
52
+ * cluster size: 512B, L2 table size: 4096 entries
53
+ */
54
error_setg(errp, "L1 size too big");
55
return -EFBIG;
56
}
28
--
57
--
29
2.14.3
58
2.21.0
30
59
31
60
diff view generated by jsdifflib
1
From: Su Hang <suhang16@mails.ucas.ac.cn>
1
From: Sam Eiderman <shmuel.eiderman@oracle.com>
2
2
3
only remove brackets that wrap `return` statements' content.
3
512M of L1 entries is a very loose bound, only 32M are required to store
4
the maximal supported VMDK file size of 2TB.
4
5
5
use `perl -pi -e "s/return \((.*?)\);/return \1;/g" util/uri.c`
6
Fixed qemu-iotest 59# - now failure occures before on impossible L1
6
to remove pattern like this: "return (1);"
7
table size.
7
8
8
Signed-off-by: Su Hang <suhang16@mails.ucas.ac.cn>
9
Reviewed-by: Karl Heubaum <karl.heubaum@oracle.com>
9
Reviewed-by: Thomas Huth <thuth@redhat.com>
10
Reviewed-by: Eyal Moscovici <eyal.moscovici@oracle.com>
10
Message-id: 1519533358-13759-3-git-send-email-suhang16@mails.ucas.ac.cn
11
Reviewed-by: Liran Alon <liran.alon@oracle.com>
11
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
12
Reviewed-by: Arbel Moshe <arbel.moshe@oracle.com>
13
Signed-off-by: Sam Eiderman <shmuel.eiderman@oracle.com>
14
Message-id: 20190620091057.47441-3-shmuel.eiderman@oracle.com
15
Reviewed-by: Max Reitz <mreitz@redhat.com>
16
Signed-off-by: Max Reitz <mreitz@redhat.com>
12
---
17
---
13
util/uri.c | 160 ++++++++++++++++++++++++++++++-------------------------------
18
block/vmdk.c | 13 +++++++------
14
1 file changed, 80 insertions(+), 80 deletions(-)
19
tests/qemu-iotests/059.out | 2 +-
20
2 files changed, 8 insertions(+), 7 deletions(-)
15
21
16
diff --git a/util/uri.c b/util/uri.c
22
diff --git a/block/vmdk.c b/block/vmdk.c
17
index XXXXXXX..XXXXXXX 100644
23
index XXXXXXX..XXXXXXX 100644
18
--- a/util/uri.c
24
--- a/block/vmdk.c
19
+++ b/util/uri.c
25
+++ b/block/vmdk.c
20
@@ -XXX,XX +XXX,XX @@ static int rfc3986_parse_scheme(URI *uri, const char **str)
26
@@ -XXX,XX +XXX,XX @@ static int vmdk_add_extent(BlockDriverState *bs,
21
const char *cur;
27
error_setg(errp, "Invalid granularity, image may be corrupt");
22
28
return -EFBIG;
23
if (str == NULL)
24
- return (-1);
25
+ return -1;
26
27
cur = *str;
28
if (!ISA_ALPHA(cur))
29
- return (2);
30
+ return 2;
31
cur++;
32
while (ISA_ALPHA(cur) || ISA_DIGIT(cur) || (*cur == '+') || (*cur == '-') ||
33
(*cur == '.'))
34
@@ -XXX,XX +XXX,XX @@ static int rfc3986_parse_scheme(URI *uri, const char **str)
35
uri->scheme = g_strndup(*str, cur - *str);
36
}
29
}
37
*str = cur;
30
- if (l1_size > 512 * 1024 * 1024) {
38
- return (0);
31
+ if (l1_size > 32 * 1024 * 1024) {
39
+ return 0;
32
/*
40
}
33
* Although with big capacity and small l1_entry_sectors, we can get a
41
34
* big l1_size, we don't want unbounded value to allocate the table.
42
/**
35
- * Limit it to 512M, which is:
43
@@ -XXX,XX +XXX,XX @@ static int rfc3986_parse_fragment(URI *uri, const char **str)
36
- * 16PB - for default "Hosted Sparse Extent" (VMDK4)
44
const char *cur;
37
- * cluster size: 64KB, L2 table size: 512 entries
45
38
- * 1PB - for default "ESXi Host Sparse Extent" (VMDK3/vmfsSparse)
46
if (str == NULL)
39
- * cluster size: 512B, L2 table size: 4096 entries
47
- return (-1);
40
+ * Limit it to 32M, which is enough to store:
48
+ return -1;
41
+ * 8TB - for both VMDK3 & VMDK4 with
49
42
+ * minimal cluster size: 512B
50
cur = *str;
43
+ * minimal L2 table size: 512 entries
51
44
+ * 8 TB is still more than the maximal value supported for
52
@@ -XXX,XX +XXX,XX @@ static int rfc3986_parse_fragment(URI *uri, const char **str)
45
+ * VMDK3 & VMDK4 which is 2TB.
53
uri->fragment = uri_string_unescape(*str, cur - *str, NULL);
46
*/
54
}
47
error_setg(errp, "L1 size too big");
55
*str = cur;
48
return -EFBIG;
56
- return (0);
49
diff --git a/tests/qemu-iotests/059.out b/tests/qemu-iotests/059.out
57
+ return 0;
50
index XXXXXXX..XXXXXXX 100644
58
}
51
--- a/tests/qemu-iotests/059.out
59
52
+++ b/tests/qemu-iotests/059.out
60
/**
53
@@ -XXX,XX +XXX,XX @@ Offset Length Mapped to File
61
@@ -XXX,XX +XXX,XX @@ static int rfc3986_parse_query(URI *uri, const char **str)
54
0x140000000 0x10000 0x50000 TEST_DIR/t-s003.vmdk
62
const char *cur;
55
63
56
=== Testing afl image with a very large capacity ===
64
if (str == NULL)
57
-qemu-img: Can't get image size 'TEST_DIR/afl9.IMGFMT': File too large
65
- return (-1);
58
+qemu-img: Could not open 'TEST_DIR/afl9.IMGFMT': L1 size too big
66
+ return -1;
59
*** done
67
68
cur = *str;
69
70
@@ -XXX,XX +XXX,XX @@ static int rfc3986_parse_query(URI *uri, const char **str)
71
uri->query = g_strndup(*str, cur - *str);
72
}
73
*str = cur;
74
- return (0);
75
+ return 0;
76
}
77
78
/**
79
@@ -XXX,XX +XXX,XX @@ static int rfc3986_parse_user_info(URI *uri, const char **str)
80
uri->user = uri_string_unescape(*str, cur - *str, NULL);
81
}
82
*str = cur;
83
- return (0);
84
+ return 0;
85
}
86
- return (1);
87
+ return 1;
88
}
89
90
/**
91
@@ -XXX,XX +XXX,XX @@ static int rfc3986_parse_dec_octet(const char **str)
92
const char *cur = *str;
93
94
if (!(ISA_DIGIT(cur)))
95
- return (1);
96
+ return 1;
97
if (!ISA_DIGIT(cur + 1))
98
cur++;
99
else if ((*cur != '0') && (ISA_DIGIT(cur + 1)) && (!ISA_DIGIT(cur + 2)))
100
@@ -XXX,XX +XXX,XX @@ static int rfc3986_parse_dec_octet(const char **str)
101
(*(cur + 1) <= '5'))
102
cur += 3;
103
else
104
- return (1);
105
+ return 1;
106
*str = cur;
107
- return (0);
108
+ return 0;
109
}
110
/**
111
* rfc3986_parse_host:
112
@@ -XXX,XX +XXX,XX @@ static int rfc3986_parse_host(URI *uri, const char **str)
113
while ((*cur != ']') && (*cur != 0))
114
cur++;
115
if (*cur != ']')
116
- return (1);
117
+ return 1;
118
cur++;
119
goto found;
120
}
121
@@ -XXX,XX +XXX,XX @@ found:
122
uri->server = NULL;
123
}
124
*str = cur;
125
- return (0);
126
+ return 0;
127
}
128
129
/**
130
@@ -XXX,XX +XXX,XX @@ static int rfc3986_parse_authority(URI *uri, const char **str)
131
cur++;
132
ret = rfc3986_parse_host(uri, &cur);
133
if (ret != 0)
134
- return (ret);
135
+ return ret;
136
if (*cur == ':') {
137
cur++;
138
ret = rfc3986_parse_port(uri, &cur);
139
if (ret != 0)
140
- return (ret);
141
+ return ret;
142
}
143
*str = cur;
144
- return (0);
145
+ return 0;
146
}
147
148
/**
149
@@ -XXX,XX +XXX,XX @@ static int rfc3986_parse_segment(const char **str, char forbid, int empty)
150
cur = *str;
151
if (!ISA_PCHAR(cur)) {
152
if (empty)
153
- return (0);
154
- return (1);
155
+ return 0;
156
+ return 1;
157
}
158
while (ISA_PCHAR(cur) && (*cur != forbid))
159
NEXT(cur);
160
*str = cur;
161
- return (0);
162
+ return 0;
163
}
164
165
/**
166
@@ -XXX,XX +XXX,XX @@ static int rfc3986_parse_path_ab_empty(URI *uri, const char **str)
167
cur++;
168
ret = rfc3986_parse_segment(&cur, 0, 1);
169
if (ret != 0)
170
- return (ret);
171
+ return ret;
172
}
173
if (uri != NULL) {
174
g_free(uri->path);
175
@@ -XXX,XX +XXX,XX @@ static int rfc3986_parse_path_ab_empty(URI *uri, const char **str)
176
}
177
}
178
*str = cur;
179
- return (0);
180
+ return 0;
181
}
182
183
/**
184
@@ -XXX,XX +XXX,XX @@ static int rfc3986_parse_path_absolute(URI *uri, const char **str)
185
cur = *str;
186
187
if (*cur != '/')
188
- return (1);
189
+ return 1;
190
cur++;
191
ret = rfc3986_parse_segment(&cur, 0, 0);
192
if (ret == 0) {
193
@@ -XXX,XX +XXX,XX @@ static int rfc3986_parse_path_absolute(URI *uri, const char **str)
194
cur++;
195
ret = rfc3986_parse_segment(&cur, 0, 1);
196
if (ret != 0)
197
- return (ret);
198
+ return ret;
199
}
200
}
201
if (uri != NULL) {
202
@@ -XXX,XX +XXX,XX @@ static int rfc3986_parse_path_absolute(URI *uri, const char **str)
203
}
204
}
205
*str = cur;
206
- return (0);
207
+ return 0;
208
}
209
210
/**
211
@@ -XXX,XX +XXX,XX @@ static int rfc3986_parse_path_rootless(URI *uri, const char **str)
212
213
ret = rfc3986_parse_segment(&cur, 0, 0);
214
if (ret != 0)
215
- return (ret);
216
+ return ret;
217
while (*cur == '/') {
218
cur++;
219
ret = rfc3986_parse_segment(&cur, 0, 1);
220
if (ret != 0)
221
- return (ret);
222
+ return ret;
223
}
224
if (uri != NULL) {
225
g_free(uri->path);
226
@@ -XXX,XX +XXX,XX @@ static int rfc3986_parse_path_rootless(URI *uri, const char **str)
227
}
228
}
229
*str = cur;
230
- return (0);
231
+ return 0;
232
}
233
234
/**
235
@@ -XXX,XX +XXX,XX @@ static int rfc3986_parse_path_no_scheme(URI *uri, const char **str)
236
237
ret = rfc3986_parse_segment(&cur, ':', 0);
238
if (ret != 0)
239
- return (ret);
240
+ return ret;
241
while (*cur == '/') {
242
cur++;
243
ret = rfc3986_parse_segment(&cur, 0, 1);
244
if (ret != 0)
245
- return (ret);
246
+ return ret;
247
}
248
if (uri != NULL) {
249
g_free(uri->path);
250
@@ -XXX,XX +XXX,XX @@ static int rfc3986_parse_path_no_scheme(URI *uri, const char **str)
251
}
252
}
253
*str = cur;
254
- return (0);
255
+ return 0;
256
}
257
258
/**
259
@@ -XXX,XX +XXX,XX @@ static int rfc3986_parse_hier_part(URI *uri, const char **str)
260
cur += 2;
261
ret = rfc3986_parse_authority(uri, &cur);
262
if (ret != 0)
263
- return (ret);
264
+ return ret;
265
ret = rfc3986_parse_path_ab_empty(uri, &cur);
266
if (ret != 0)
267
- return (ret);
268
+ return ret;
269
*str = cur;
270
- return (0);
271
+ return 0;
272
} else if (*cur == '/') {
273
ret = rfc3986_parse_path_absolute(uri, &cur);
274
if (ret != 0)
275
- return (ret);
276
+ return ret;
277
} else if (ISA_PCHAR(cur)) {
278
ret = rfc3986_parse_path_rootless(uri, &cur);
279
if (ret != 0)
280
- return (ret);
281
+ return ret;
282
} else {
283
/* path-empty is effectively empty */
284
if (uri != NULL) {
285
@@ -XXX,XX +XXX,XX @@ static int rfc3986_parse_hier_part(URI *uri, const char **str)
286
}
287
}
288
*str = cur;
289
- return (0);
290
+ return 0;
291
}
292
293
/**
294
@@ -XXX,XX +XXX,XX @@ static int rfc3986_parse_relative_ref(URI *uri, const char *str)
295
str += 2;
296
ret = rfc3986_parse_authority(uri, &str);
297
if (ret != 0)
298
- return (ret);
299
+ return ret;
300
ret = rfc3986_parse_path_ab_empty(uri, &str);
301
if (ret != 0)
302
- return (ret);
303
+ return ret;
304
} else if (*str == '/') {
305
ret = rfc3986_parse_path_absolute(uri, &str);
306
if (ret != 0)
307
- return (ret);
308
+ return ret;
309
} else if (ISA_PCHAR(str)) {
310
ret = rfc3986_parse_path_no_scheme(uri, &str);
311
if (ret != 0)
312
- return (ret);
313
+ return ret;
314
} else {
315
/* path-empty is effectively empty */
316
if (uri != NULL) {
317
@@ -XXX,XX +XXX,XX @@ static int rfc3986_parse_relative_ref(URI *uri, const char *str)
318
str++;
319
ret = rfc3986_parse_query(uri, &str);
320
if (ret != 0)
321
- return (ret);
322
+ return ret;
323
}
324
if (*str == '#') {
325
str++;
326
ret = rfc3986_parse_fragment(uri, &str);
327
if (ret != 0)
328
- return (ret);
329
+ return ret;
330
}
331
if (*str != 0) {
332
uri_clean(uri);
333
- return (1);
334
+ return 1;
335
}
336
- return (0);
337
+ return 0;
338
}
339
340
/**
341
@@ -XXX,XX +XXX,XX @@ static int rfc3986_parse(URI *uri, const char *str)
342
343
ret = rfc3986_parse_scheme(uri, &str);
344
if (ret != 0)
345
- return (ret);
346
+ return ret;
347
if (*str != ':') {
348
- return (1);
349
+ return 1;
350
}
351
str++;
352
ret = rfc3986_parse_hier_part(uri, &str);
353
if (ret != 0)
354
- return (ret);
355
+ return ret;
356
if (*str == '?') {
357
str++;
358
ret = rfc3986_parse_query(uri, &str);
359
if (ret != 0)
360
- return (ret);
361
+ return ret;
362
}
363
if (*str == '#') {
364
str++;
365
ret = rfc3986_parse_fragment(uri, &str);
366
if (ret != 0)
367
- return (ret);
368
+ return ret;
369
}
370
if (*str != 0) {
371
uri_clean(uri);
372
- return (1);
373
+ return 1;
374
}
375
- return (0);
376
+ return 0;
377
}
378
379
/**
380
@@ -XXX,XX +XXX,XX @@ static int rfc3986_parse_uri_reference(URI *uri, const char *str)
381
int ret;
382
383
if (str == NULL)
384
- return (-1);
385
+ return -1;
386
uri_clean(uri);
387
388
/*
389
@@ -XXX,XX +XXX,XX @@ static int rfc3986_parse_uri_reference(URI *uri, const char *str)
390
ret = rfc3986_parse_relative_ref(uri, str);
391
if (ret != 0) {
392
uri_clean(uri);
393
- return (ret);
394
+ return ret;
395
}
396
}
397
- return (0);
398
+ return 0;
399
}
400
401
/**
402
@@ -XXX,XX +XXX,XX @@ URI *uri_parse(const char *str)
403
int ret;
404
405
if (str == NULL)
406
- return (NULL);
407
+ return NULL;
408
uri = uri_new();
409
ret = rfc3986_parse_uri_reference(uri, str);
410
if (ret) {
411
uri_free(uri);
412
- return (NULL);
413
+ return NULL;
414
}
415
- return (uri);
416
+ return uri;
417
}
418
419
/**
420
@@ -XXX,XX +XXX,XX @@ URI *uri_parse(const char *str)
421
*/
422
int uri_parse_into(URI *uri, const char *str)
423
{
424
- return (rfc3986_parse_uri_reference(uri, str));
425
+ return rfc3986_parse_uri_reference(uri, str);
426
}
427
428
/**
429
@@ -XXX,XX +XXX,XX @@ URI *uri_parse_raw(const char *str, int raw)
430
int ret;
431
432
if (str == NULL)
433
- return (NULL);
434
+ return NULL;
435
uri = uri_new();
436
if (raw) {
437
uri->cleanup |= 2;
438
@@ -XXX,XX +XXX,XX @@ URI *uri_parse_raw(const char *str, int raw)
439
ret = uri_parse_into(uri, str);
440
if (ret) {
441
uri_free(uri);
442
- return (NULL);
443
+ return NULL;
444
}
445
- return (uri);
446
+ return uri;
447
}
448
449
/************************************************************************
450
@@ -XXX,XX +XXX,XX @@ URI *uri_new(void)
451
URI *ret;
452
453
ret = g_new0(URI, 1);
454
- return (ret);
455
+ return ret;
456
}
457
458
/**
459
@@ -XXX,XX +XXX,XX @@ static char *realloc2n(char *ret, int *max)
460
tmp = *max * 2;
461
temp = g_realloc(ret, (tmp + 1));
462
*max = tmp;
463
- return (temp);
464
+ return temp;
465
}
466
467
/**
468
@@ -XXX,XX +XXX,XX @@ char *uri_to_string(URI *uri)
469
int max;
470
471
if (uri == NULL)
472
- return (NULL);
473
+ return NULL;
474
475
max = 80;
476
ret = g_malloc(max + 1);
477
@@ -XXX,XX +XXX,XX @@ char *uri_to_string(URI *uri)
478
ret = temp;
479
}
480
ret[len] = 0;
481
- return (ret);
482
+ return ret;
483
}
484
485
/**
486
@@ -XXX,XX +XXX,XX @@ static int normalize_uri_path(char *path)
487
char *cur, *out;
488
489
if (path == NULL)
490
- return (-1);
491
+ return -1;
492
493
/* Skip all initial "/" chars. We want to get to the beginning of the
494
* first non-empty segment.
495
@@ -XXX,XX +XXX,XX @@ static int normalize_uri_path(char *path)
496
while (cur[0] == '/')
497
++cur;
498
if (cur[0] == '\0')
499
- return (0);
500
+ return 0;
501
502
/* Keep everything we've seen so far. */
503
out = cur;
504
@@ -XXX,XX +XXX,XX @@ done_cd:
505
while (cur[0] == '/')
506
++cur;
507
if (cur[0] == '\0')
508
- return (0);
509
+ return 0;
510
511
/*
512
* Analyze each segment in sequence for cases (e) and (f).
513
@@ -XXX,XX +XXX,XX @@ done_cd:
514
}
515
}
516
517
- return (0);
518
+ return 0;
519
}
520
521
static int is_hex(char c)
522
{
523
if (((c >= '0') && (c <= '9')) || ((c >= 'a') && (c <= 'f')) ||
524
((c >= 'A') && (c <= 'F')))
525
- return (1);
526
- return (0);
527
+ return 1;
528
+ return 0;
529
}
530
531
/**
532
@@ -XXX,XX +XXX,XX @@ char *uri_string_unescape(const char *str, int len, char *target)
533
const char *in;
534
535
if (str == NULL)
536
- return (NULL);
537
+ return NULL;
538
if (len <= 0)
539
len = strlen(str);
540
if (len < 0)
541
- return (NULL);
542
+ return NULL;
543
544
if (target == NULL) {
545
ret = g_malloc(len + 1);
546
@@ -XXX,XX +XXX,XX @@ char *uri_string_unescape(const char *str, int len, char *target)
547
}
548
}
549
*out = 0;
550
- return (ret);
551
+ return ret;
552
}
553
554
/**
555
@@ -XXX,XX +XXX,XX @@ char *uri_string_escape(const char *str, const char *list)
556
int len, out;
557
558
if (str == NULL)
559
- return (NULL);
560
+ return NULL;
561
if (str[0] == 0)
562
- return (g_strdup(str));
563
+ return g_strdup(str);
564
len = strlen(str);
565
if (!(len > 0))
566
- return (NULL);
567
+ return NULL;
568
569
len += 20;
570
ret = g_malloc(len);
571
@@ -XXX,XX +XXX,XX @@ char *uri_string_escape(const char *str, const char *list)
572
}
573
}
574
ret[out] = 0;
575
- return (ret);
576
+ return ret;
577
}
578
579
/************************************************************************
580
@@ -XXX,XX +XXX,XX @@ done:
581
uri_free(bas);
582
if (res != NULL)
583
uri_free(res);
584
- return (val);
585
+ return val;
586
}
587
588
/**
589
--
60
--
590
2.14.3
61
2.21.0
591
62
592
63
diff view generated by jsdifflib
1
From: Su Hang <suhang16@mails.ucas.ac.cn>
1
From: Sam Eiderman <shmuel.eiderman@oracle.com>
2
2
3
For this patch, using curly braces to wrap `if` `while` `else` statements,
3
Until ESXi 6.5 VMware used the vmfsSparse format for snapshots (VMDK3 in
4
which only hold single statement. For example:
4
QEMU).
5
'''
5
6
if (cond)
6
This format was lacking in the following:
7
statement;
7
8
'''
8
* Grain directory (L1) and grain table (L2) entries were 32-bit,
9
to
9
allowing access to only 2TB (slightly less) of data.
10
'''
10
* The grain size (default) was 512 bytes - leading to data
11
if (cond) {
11
fragmentation and many grain tables.
12
statement;
12
* For space reclamation purposes, it was necessary to find all the
13
}
13
grains which are not pointed to by any grain table - so a reverse
14
'''
14
mapping of "offset of grain in vmdk" to "grain table" must be
15
15
constructed - which takes large amounts of CPU/RAM.
16
And using tricks that compare the disassemblies before and after
16
17
code changes, to make sure code logic isn't changed:
17
The format specification can be found in VMware's documentation:
18
'''
18
https://www.vmware.com/support/developer/vddk/vmdk_50_technote.pdf
19
git checkout master
19
20
make util/uri.o
20
In ESXi 6.5, to support snapshot files larger than 2TB, a new format was
21
strip util/uri.o
21
introduced: SESparse (Space Efficient).
22
objdump -Drx util/uri.o > /tmp/uri-master.txt
22
23
git checkout cleanupbranch
23
This format fixes the above issues:
24
make util/uri.o
24
25
strip util/uri.o
25
* All entries are now 64-bit.
26
objdump -Drx util/uri.o > /tmp/uri-cleanup.txt
26
* The grain size (default) is 4KB.
27
27
* Grain directory and grain tables are now located at the beginning
28
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
28
of the file.
29
+ seSparse format reserves space for all grain tables.
30
+ Grain tables can be addressed using an index.
31
+ Grains are located in the end of the file and can also be
32
addressed with an index.
33
- seSparse vmdks of large disks (64TB) have huge preallocated
34
headers - mainly due to L2 tables, even for empty snapshots.
35
* The header contains a reverse mapping ("backmap") of "offset of
36
grain in vmdk" to "grain table" and a bitmap ("free bitmap") which
37
specifies for each grain - whether it is allocated or not.
38
Using these data structures we can implement space reclamation
39
efficiently.
40
* Due to the fact that the header now maintains two mappings:
41
* The regular one (grain directory & grain tables)
42
* A reverse one (backmap and free bitmap)
43
These data structures can lose consistency upon crash and result
44
in a corrupted VMDK.
45
Therefore, a journal is also added to the VMDK and is replayed
46
when the VMware reopens the file after a crash.
47
48
Since ESXi 6.7 - SESparse is the only snapshot format available.
49
50
Unfortunately, VMware does not provide documentation regarding the new
51
seSparse format.
52
53
This commit is based on black-box research of the seSparse format.
54
Various in-guest block operations and their effect on the snapshot file
55
were tested.
56
57
The only VMware provided source of information (regarding the underlying
58
implementation) was a log file on the ESXi:
59
60
/var/log/hostd.log
61
62
Whenever an seSparse snapshot is created - the log is being populated
63
with seSparse records.
64
65
Relevant log records are of the form:
66
67
[...] Const Header:
68
[...] constMagic = 0xcafebabe
69
[...] version = 2.1
70
[...] capacity = 204800
71
[...] grainSize = 8
72
[...] grainTableSize = 64
73
[...] flags = 0
74
[...] Extents:
75
[...] Header : <1 : 1>
76
[...] JournalHdr : <2 : 2>
77
[...] Journal : <2048 : 2048>
78
[...] GrainDirectory : <4096 : 2048>
79
[...] GrainTables : <6144 : 2048>
80
[...] FreeBitmap : <8192 : 2048>
81
[...] BackMap : <10240 : 2048>
82
[...] Grain : <12288 : 204800>
83
[...] Volatile Header:
84
[...] volatileMagic = 0xcafecafe
85
[...] FreeGTNumber = 0
86
[...] nextTxnSeqNumber = 0
87
[...] replayJournal = 0
88
89
The sizes that are seen in the log file are in sectors.
90
Extents are of the following format: <offset : size>
91
92
This commit is a strict implementation which enforces:
93
* magics
94
* version number 2.1
95
* grain size of 8 sectors (4KB)
96
* grain table size of 64 sectors
97
* zero flags
98
* extent locations
99
100
Additionally, this commit proivdes only a subset of the functionality
101
offered by seSparse's format:
102
* Read-only
103
* No journal replay
104
* No space reclamation
105
* No unmap support
106
107
Hence, journal header, journal, free bitmap and backmap extents are
108
unused, only the "classic" (L1 -> L2 -> data) grain access is
109
implemented.
110
111
However there are several differences in the grain access itself.
112
Grain directory (L1):
113
* Grain directory entries are indexes (not offsets) to grain
114
tables.
115
* Valid grain directory entries have their highest nibble set to
116
0x1.
117
* Since grain tables are always located in the beginning of the
118
file - the index can fit into 32 bits - so we can use its low
119
part if it's valid.
120
Grain table (L2):
121
* Grain table entries are indexes (not offsets) to grains.
122
* If the highest nibble of the entry is:
123
0x0:
124
The grain in not allocated.
125
The rest of the bytes are 0.
126
0x1:
127
The grain is unmapped - guest sees a zero grain.
128
The rest of the bits point to the previously mapped grain,
129
see 0x3 case.
130
0x2:
131
The grain is zero.
132
0x3:
133
The grain is allocated - to get the index calculate:
134
((entry & 0x0fff000000000000) >> 48) |
135
((entry & 0x0000ffffffffffff) << 12)
136
* The difference between 0x1 and 0x2 is that 0x1 is an unallocated
137
grain which results from the guest using sg_unmap to unmap the
138
grain - but the grain itself still exists in the grain extent - a
139
space reclamation procedure should delete it.
140
Unmapping a zero grain has no effect (0x2 will not change to 0x1)
141
but unmapping an unallocated grain will (0x0 to 0x1) - naturally.
142
143
In order to implement seSparse some fields had to be changed to support
144
both 32-bit and 64-bit entry sizes.
145
146
Reviewed-by: Karl Heubaum <karl.heubaum@oracle.com>
147
Reviewed-by: Eyal Moscovici <eyal.moscovici@oracle.com>
148
Reviewed-by: Arbel Moshe <arbel.moshe@oracle.com>
149
Signed-off-by: Sam Eiderman <shmuel.eiderman@oracle.com>
150
Message-id: 20190620091057.47441-4-shmuel.eiderman@oracle.com
151
Signed-off-by: Max Reitz <mreitz@redhat.com>
29
---
152
---
30
util/uri.c | 463 +++++++++++++++++++++++++++++++++++++++----------------------
153
block/vmdk.c | 358 ++++++++++++++++++++++++++++++++++++++++++++++++---
31
1 file changed, 294 insertions(+), 169 deletions(-)
154
1 file changed, 342 insertions(+), 16 deletions(-)
32
155
33
diff --git a/util/uri.c b/util/uri.c
156
diff --git a/block/vmdk.c b/block/vmdk.c
34
index XXXXXXX..XXXXXXX 100644
157
index XXXXXXX..XXXXXXX 100644
35
--- a/util/uri.c
158
--- a/block/vmdk.c
36
+++ b/util/uri.c
159
+++ b/block/vmdk.c
37
@@ -XXX,XX +XXX,XX @@ static int rfc3986_parse_scheme(URI *uri, const char **str)
160
@@ -XXX,XX +XXX,XX @@ typedef struct {
38
{
161
uint16_t compressAlgorithm;
39
const char *cur;
162
} QEMU_PACKED VMDK4Header;
40
163
41
- if (str == NULL)
164
+typedef struct VMDKSESparseConstHeader {
42
+ if (str == NULL) {
165
+ uint64_t magic;
43
return -1;
166
+ uint64_t version;
44
+ }
167
+ uint64_t capacity;
45
168
+ uint64_t grain_size;
46
cur = *str;
169
+ uint64_t grain_table_size;
47
- if (!ISA_ALPHA(cur))
170
+ uint64_t flags;
48
+ if (!ISA_ALPHA(cur)) {
171
+ uint64_t reserved1;
49
return 2;
172
+ uint64_t reserved2;
50
+ }
173
+ uint64_t reserved3;
51
cur++;
174
+ uint64_t reserved4;
52
while (ISA_ALPHA(cur) || ISA_DIGIT(cur) || (*cur == '+') || (*cur == '-') ||
175
+ uint64_t volatile_header_offset;
53
- (*cur == '.'))
176
+ uint64_t volatile_header_size;
54
+ (*cur == '.')) {
177
+ uint64_t journal_header_offset;
55
cur++;
178
+ uint64_t journal_header_size;
56
+ }
179
+ uint64_t journal_offset;
57
if (uri != NULL) {
180
+ uint64_t journal_size;
58
g_free(uri->scheme);
181
+ uint64_t grain_dir_offset;
59
uri->scheme = g_strndup(*str, cur - *str);
182
+ uint64_t grain_dir_size;
60
@@ -XXX,XX +XXX,XX @@ static int rfc3986_parse_fragment(URI *uri, const char **str)
183
+ uint64_t grain_tables_offset;
61
{
184
+ uint64_t grain_tables_size;
62
const char *cur;
185
+ uint64_t free_bitmap_offset;
63
186
+ uint64_t free_bitmap_size;
64
- if (str == NULL)
187
+ uint64_t backmap_offset;
65
+ if (str == NULL) {
188
+ uint64_t backmap_size;
66
return -1;
189
+ uint64_t grains_offset;
67
+ }
190
+ uint64_t grains_size;
68
191
+ uint8_t pad[304];
69
cur = *str;
192
+} QEMU_PACKED VMDKSESparseConstHeader;
70
193
+
71
while ((ISA_PCHAR(cur)) || (*cur == '/') || (*cur == '?') ||
194
+typedef struct VMDKSESparseVolatileHeader {
72
(*cur == '[') || (*cur == ']') ||
195
+ uint64_t magic;
73
- ((uri != NULL) && (uri->cleanup & 1) && (IS_UNWISE(cur))))
196
+ uint64_t free_gt_number;
74
+ ((uri != NULL) && (uri->cleanup & 1) && (IS_UNWISE(cur)))) {
197
+ uint64_t next_txn_seq_number;
75
NEXT(cur);
198
+ uint64_t replay_journal;
76
+ }
199
+ uint8_t pad[480];
77
if (uri != NULL) {
200
+} QEMU_PACKED VMDKSESparseVolatileHeader;
78
g_free(uri->fragment);
201
+
79
- if (uri->cleanup & 2)
202
#define L2_CACHE_SIZE 16
80
+ if (uri->cleanup & 2) {
203
81
uri->fragment = g_strndup(*str, cur - *str);
204
typedef struct VmdkExtent {
82
- else
205
@@ -XXX,XX +XXX,XX @@ typedef struct VmdkExtent {
206
bool compressed;
207
bool has_marker;
208
bool has_zero_grain;
209
+ bool sesparse;
210
+ uint64_t sesparse_l2_tables_offset;
211
+ uint64_t sesparse_clusters_offset;
212
+ int32_t entry_size;
213
int version;
214
int64_t sectors;
215
int64_t end_sector;
216
int64_t flat_start_offset;
217
int64_t l1_table_offset;
218
int64_t l1_backup_table_offset;
219
- uint32_t *l1_table;
220
+ void *l1_table;
221
uint32_t *l1_backup_table;
222
unsigned int l1_size;
223
uint32_t l1_entry_sectors;
224
225
unsigned int l2_size;
226
- uint32_t *l2_cache;
227
+ void *l2_cache;
228
uint32_t l2_cache_offsets[L2_CACHE_SIZE];
229
uint32_t l2_cache_counts[L2_CACHE_SIZE];
230
231
@@ -XXX,XX +XXX,XX @@ static int vmdk_add_extent(BlockDriverState *bs,
232
* minimal L2 table size: 512 entries
233
* 8 TB is still more than the maximal value supported for
234
* VMDK3 & VMDK4 which is 2TB.
235
+ * 64TB - for "ESXi seSparse Extent"
236
+ * minimal cluster size: 512B (default is 4KB)
237
+ * L2 table size: 4096 entries (const).
238
+ * 64TB is more than the maximal value supported for
239
+ * seSparse VMDKs (which is slightly less than 64TB)
240
*/
241
error_setg(errp, "L1 size too big");
242
return -EFBIG;
243
@@ -XXX,XX +XXX,XX @@ static int vmdk_add_extent(BlockDriverState *bs,
244
extent->l2_size = l2_size;
245
extent->cluster_sectors = flat ? sectors : cluster_sectors;
246
extent->next_cluster_sector = ROUND_UP(nb_sectors, cluster_sectors);
247
+ extent->entry_size = sizeof(uint32_t);
248
249
if (s->num_extents > 1) {
250
extent->end_sector = (*(extent - 1)).end_sector + extent->sectors;
251
@@ -XXX,XX +XXX,XX @@ static int vmdk_init_tables(BlockDriverState *bs, VmdkExtent *extent,
252
int i;
253
254
/* read the L1 table */
255
- l1_size = extent->l1_size * sizeof(uint32_t);
256
+ l1_size = extent->l1_size * extent->entry_size;
257
extent->l1_table = g_try_malloc(l1_size);
258
if (l1_size && extent->l1_table == NULL) {
259
return -ENOMEM;
260
@@ -XXX,XX +XXX,XX @@ static int vmdk_init_tables(BlockDriverState *bs, VmdkExtent *extent,
261
goto fail_l1;
262
}
263
for (i = 0; i < extent->l1_size; i++) {
264
- le32_to_cpus(&extent->l1_table[i]);
265
+ if (extent->entry_size == sizeof(uint64_t)) {
266
+ le64_to_cpus((uint64_t *)extent->l1_table + i);
83
+ } else {
267
+ } else {
84
uri->fragment = uri_string_unescape(*str, cur - *str, NULL);
268
+ assert(extent->entry_size == sizeof(uint32_t));
269
+ le32_to_cpus((uint32_t *)extent->l1_table + i);
85
+ }
270
+ }
86
}
271
}
87
*str = cur;
272
273
if (extent->l1_backup_table_offset) {
274
+ assert(!extent->sesparse);
275
extent->l1_backup_table = g_try_malloc(l1_size);
276
if (l1_size && extent->l1_backup_table == NULL) {
277
ret = -ENOMEM;
278
@@ -XXX,XX +XXX,XX @@ static int vmdk_init_tables(BlockDriverState *bs, VmdkExtent *extent,
279
}
280
281
extent->l2_cache =
282
- g_new(uint32_t, extent->l2_size * L2_CACHE_SIZE);
283
+ g_malloc(extent->entry_size * extent->l2_size * L2_CACHE_SIZE);
88
return 0;
284
return 0;
89
@@ -XXX,XX +XXX,XX @@ static int rfc3986_parse_query(URI *uri, const char **str)
285
fail_l1b:
90
{
286
g_free(extent->l1_backup_table);
91
const char *cur;
287
@@ -XXX,XX +XXX,XX @@ static int vmdk_open_vmfs_sparse(BlockDriverState *bs,
92
288
return ret;
93
- if (str == NULL)
94
+ if (str == NULL) {
95
return -1;
96
+ }
97
98
cur = *str;
99
100
while ((ISA_PCHAR(cur)) || (*cur == '/') || (*cur == '?') ||
101
- ((uri != NULL) && (uri->cleanup & 1) && (IS_UNWISE(cur))))
102
+ ((uri != NULL) && (uri->cleanup & 1) && (IS_UNWISE(cur)))) {
103
NEXT(cur);
104
+ }
105
if (uri != NULL) {
106
g_free(uri->query);
107
uri->query = g_strndup(*str, cur - *str);
108
@@ -XXX,XX +XXX,XX @@ static int rfc3986_parse_user_info(URI *uri, const char **str)
109
110
cur = *str;
111
while (ISA_UNRESERVED(cur) || ISA_PCT_ENCODED(cur) || ISA_SUB_DELIM(cur) ||
112
- (*cur == ':'))
113
+ (*cur == ':')) {
114
NEXT(cur);
115
+ }
116
if (*cur == '@') {
117
if (uri != NULL) {
118
g_free(uri->user);
119
- if (uri->cleanup & 2)
120
+ if (uri->cleanup & 2) {
121
uri->user = g_strndup(*str, cur - *str);
122
- else
123
+ } else {
124
uri->user = uri_string_unescape(*str, cur - *str, NULL);
125
+ }
126
}
127
*str = cur;
128
return 0;
129
@@ -XXX,XX +XXX,XX @@ static int rfc3986_parse_dec_octet(const char **str)
130
{
131
const char *cur = *str;
132
133
- if (!(ISA_DIGIT(cur)))
134
+ if (!(ISA_DIGIT(cur))) {
135
return 1;
136
- if (!ISA_DIGIT(cur + 1))
137
+ }
138
+ if (!ISA_DIGIT(cur + 1)) {
139
cur++;
140
- else if ((*cur != '0') && (ISA_DIGIT(cur + 1)) && (!ISA_DIGIT(cur + 2)))
141
+ } else if ((*cur != '0') && (ISA_DIGIT(cur + 1)) && (!ISA_DIGIT(cur + 2))) {
142
cur += 2;
143
- else if ((*cur == '1') && (ISA_DIGIT(cur + 1)) && (ISA_DIGIT(cur + 2)))
144
+ } else if ((*cur == '1') && (ISA_DIGIT(cur + 1)) && (ISA_DIGIT(cur + 2))) {
145
cur += 3;
146
- else if ((*cur == '2') && (*(cur + 1) >= '0') && (*(cur + 1) <= '4') &&
147
- (ISA_DIGIT(cur + 2)))
148
+ } else if ((*cur == '2') && (*(cur + 1) >= '0') && (*(cur + 1) <= '4') &&
149
+ (ISA_DIGIT(cur + 2))) {
150
cur += 3;
151
- else if ((*cur == '2') && (*(cur + 1) == '5') && (*(cur + 2) >= '0') &&
152
- (*(cur + 1) <= '5'))
153
+ } else if ((*cur == '2') && (*(cur + 1) == '5') && (*(cur + 2) >= '0') &&
154
+ (*(cur + 1) <= '5')) {
155
cur += 3;
156
- else
157
+ } else {
158
return 1;
159
+ }
160
*str = cur;
161
return 0;
162
}
289
}
163
@@ -XXX,XX +XXX,XX @@ static int rfc3986_parse_host(URI *uri, const char **str)
290
164
*/
291
+#define SESPARSE_CONST_HEADER_MAGIC UINT64_C(0x00000000cafebabe)
165
if (*cur == '[') {
292
+#define SESPARSE_VOLATILE_HEADER_MAGIC UINT64_C(0x00000000cafecafe)
166
cur++;
293
+
167
- while ((*cur != ']') && (*cur != 0))
294
+/* Strict checks - format not officially documented */
168
+ while ((*cur != ']') && (*cur != 0)) {
295
+static int check_se_sparse_const_header(VMDKSESparseConstHeader *header,
169
cur++;
296
+ Error **errp)
170
- if (*cur != ']')
297
+{
171
+ }
298
+ header->magic = le64_to_cpu(header->magic);
172
+ if (*cur != ']') {
299
+ header->version = le64_to_cpu(header->version);
173
return 1;
300
+ header->grain_size = le64_to_cpu(header->grain_size);
174
+ }
301
+ header->grain_table_size = le64_to_cpu(header->grain_table_size);
175
cur++;
302
+ header->flags = le64_to_cpu(header->flags);
176
goto found;
303
+ header->reserved1 = le64_to_cpu(header->reserved1);
177
}
304
+ header->reserved2 = le64_to_cpu(header->reserved2);
178
@@ -XXX,XX +XXX,XX @@ static int rfc3986_parse_host(URI *uri, const char **str)
305
+ header->reserved3 = le64_to_cpu(header->reserved3);
179
* try to parse an IPv4
306
+ header->reserved4 = le64_to_cpu(header->reserved4);
180
*/
307
+
181
if (ISA_DIGIT(cur)) {
308
+ header->volatile_header_offset =
182
- if (rfc3986_parse_dec_octet(&cur) != 0)
309
+ le64_to_cpu(header->volatile_header_offset);
183
+ if (rfc3986_parse_dec_octet(&cur) != 0) {
310
+ header->volatile_header_size = le64_to_cpu(header->volatile_header_size);
184
goto not_ipv4;
311
+
185
- if (*cur != '.')
312
+ header->journal_header_offset = le64_to_cpu(header->journal_header_offset);
186
+ }
313
+ header->journal_header_size = le64_to_cpu(header->journal_header_size);
187
+ if (*cur != '.') {
314
+
188
goto not_ipv4;
315
+ header->journal_offset = le64_to_cpu(header->journal_offset);
189
+ }
316
+ header->journal_size = le64_to_cpu(header->journal_size);
190
cur++;
317
+
191
- if (rfc3986_parse_dec_octet(&cur) != 0)
318
+ header->grain_dir_offset = le64_to_cpu(header->grain_dir_offset);
192
+ if (rfc3986_parse_dec_octet(&cur) != 0) {
319
+ header->grain_dir_size = le64_to_cpu(header->grain_dir_size);
193
goto not_ipv4;
320
+
194
- if (*cur != '.')
321
+ header->grain_tables_offset = le64_to_cpu(header->grain_tables_offset);
195
+ }
322
+ header->grain_tables_size = le64_to_cpu(header->grain_tables_size);
196
+ if (*cur != '.') {
323
+
197
goto not_ipv4;
324
+ header->free_bitmap_offset = le64_to_cpu(header->free_bitmap_offset);
198
- if (rfc3986_parse_dec_octet(&cur) != 0)
325
+ header->free_bitmap_size = le64_to_cpu(header->free_bitmap_size);
199
+ }
326
+
200
+ if (rfc3986_parse_dec_octet(&cur) != 0) {
327
+ header->backmap_offset = le64_to_cpu(header->backmap_offset);
201
goto not_ipv4;
328
+ header->backmap_size = le64_to_cpu(header->backmap_size);
202
- if (*cur != '.')
329
+
203
+ }
330
+ header->grains_offset = le64_to_cpu(header->grains_offset);
204
+ if (*cur != '.') {
331
+ header->grains_size = le64_to_cpu(header->grains_size);
205
goto not_ipv4;
332
+
206
- if (rfc3986_parse_dec_octet(&cur) != 0)
333
+ if (header->magic != SESPARSE_CONST_HEADER_MAGIC) {
207
+ }
334
+ error_setg(errp, "Bad const header magic: 0x%016" PRIx64,
208
+ if (rfc3986_parse_dec_octet(&cur) != 0) {
335
+ header->magic);
209
goto not_ipv4;
336
+ return -EINVAL;
210
+ }
337
+ }
211
goto found;
338
+
212
not_ipv4:
339
+ if (header->version != 0x0000000200000001) {
213
cur = *str;
340
+ error_setg(errp, "Unsupported version: 0x%016" PRIx64,
214
@@ -XXX,XX +XXX,XX @@ static int rfc3986_parse_host(URI *uri, const char **str)
341
+ header->version);
215
/*
342
+ return -ENOTSUP;
216
* then this should be a hostname which can be empty
343
+ }
217
*/
344
+
218
- while (ISA_UNRESERVED(cur) || ISA_PCT_ENCODED(cur) || ISA_SUB_DELIM(cur))
345
+ if (header->grain_size != 8) {
219
+ while (ISA_UNRESERVED(cur) || ISA_PCT_ENCODED(cur) || ISA_SUB_DELIM(cur)) {
346
+ error_setg(errp, "Unsupported grain size: %" PRIu64,
220
NEXT(cur);
347
+ header->grain_size);
221
+ }
348
+ return -ENOTSUP;
222
found:
349
+ }
223
if (uri != NULL) {
350
+
224
g_free(uri->authority);
351
+ if (header->grain_table_size != 64) {
225
uri->authority = NULL;
352
+ error_setg(errp, "Unsupported grain table size: %" PRIu64,
226
g_free(uri->server);
353
+ header->grain_table_size);
227
if (cur != host) {
354
+ return -ENOTSUP;
228
- if (uri->cleanup & 2)
355
+ }
229
+ if (uri->cleanup & 2) {
356
+
230
uri->server = g_strndup(host, cur - host);
357
+ if (header->flags != 0) {
231
- else
358
+ error_setg(errp, "Unsupported flags: 0x%016" PRIx64,
232
+ } else {
359
+ header->flags);
233
uri->server = uri_string_unescape(host, cur - host, NULL);
360
+ return -ENOTSUP;
234
- } else
361
+ }
235
+ }
362
+
236
+ } else {
363
+ if (header->reserved1 != 0 || header->reserved2 != 0 ||
237
uri->server = NULL;
364
+ header->reserved3 != 0 || header->reserved4 != 0) {
238
+ }
365
+ error_setg(errp, "Unsupported reserved bits:"
239
}
366
+ " 0x%016" PRIx64 " 0x%016" PRIx64
240
*str = cur;
367
+ " 0x%016" PRIx64 " 0x%016" PRIx64,
241
return 0;
368
+ header->reserved1, header->reserved2,
242
@@ -XXX,XX +XXX,XX @@ static int rfc3986_parse_authority(URI *uri, const char **str)
369
+ header->reserved3, header->reserved4);
243
* try to parse a userinfo and check for the trailing @
370
+ return -ENOTSUP;
244
*/
371
+ }
245
ret = rfc3986_parse_user_info(uri, &cur);
372
+
246
- if ((ret != 0) || (*cur != '@'))
373
+ /* check that padding is 0 */
247
+ if ((ret != 0) || (*cur != '@')) {
374
+ if (!buffer_is_zero(header->pad, sizeof(header->pad))) {
248
cur = *str;
375
+ error_setg(errp, "Unsupported non-zero const header padding");
249
- else
376
+ return -ENOTSUP;
250
+ } else {
377
+ }
251
cur++;
378
+
252
+ }
379
+ return 0;
253
ret = rfc3986_parse_host(uri, &cur);
380
+}
254
- if (ret != 0)
381
+
255
+ if (ret != 0) {
382
+static int check_se_sparse_volatile_header(VMDKSESparseVolatileHeader *header,
256
return ret;
383
+ Error **errp)
257
+ }
384
+{
258
if (*cur == ':') {
385
+ header->magic = le64_to_cpu(header->magic);
259
cur++;
386
+ header->free_gt_number = le64_to_cpu(header->free_gt_number);
260
ret = rfc3986_parse_port(uri, &cur);
387
+ header->next_txn_seq_number = le64_to_cpu(header->next_txn_seq_number);
261
- if (ret != 0)
388
+ header->replay_journal = le64_to_cpu(header->replay_journal);
262
+ if (ret != 0) {
389
+
263
return ret;
390
+ if (header->magic != SESPARSE_VOLATILE_HEADER_MAGIC) {
264
+ }
391
+ error_setg(errp, "Bad volatile header magic: 0x%016" PRIx64,
265
}
392
+ header->magic);
266
*str = cur;
393
+ return -EINVAL;
267
return 0;
394
+ }
268
@@ -XXX,XX +XXX,XX @@ static int rfc3986_parse_segment(const char **str, char forbid, int empty)
395
+
269
396
+ if (header->replay_journal) {
270
cur = *str;
397
+ error_setg(errp, "Image is dirty, Replaying journal not supported");
271
if (!ISA_PCHAR(cur)) {
398
+ return -ENOTSUP;
272
- if (empty)
399
+ }
273
+ if (empty) {
400
+
274
return 0;
401
+ /* check that padding is 0 */
275
+ }
402
+ if (!buffer_is_zero(header->pad, sizeof(header->pad))) {
276
return 1;
403
+ error_setg(errp, "Unsupported non-zero volatile header padding");
277
}
404
+ return -ENOTSUP;
278
- while (ISA_PCHAR(cur) && (*cur != forbid))
405
+ }
279
+ while (ISA_PCHAR(cur) && (*cur != forbid)) {
406
+
280
NEXT(cur);
407
+ return 0;
281
+ }
408
+}
282
*str = cur;
409
+
283
return 0;
410
+static int vmdk_open_se_sparse(BlockDriverState *bs,
284
}
411
+ BdrvChild *file,
285
@@ -XXX,XX +XXX,XX @@ static int rfc3986_parse_path_ab_empty(URI *uri, const char **str)
412
+ int flags, Error **errp)
286
while (*cur == '/') {
413
+{
287
cur++;
414
+ int ret;
288
ret = rfc3986_parse_segment(&cur, 0, 1);
415
+ VMDKSESparseConstHeader const_header;
289
- if (ret != 0)
416
+ VMDKSESparseVolatileHeader volatile_header;
290
+ if (ret != 0) {
417
+ VmdkExtent *extent;
291
return ret;
418
+
292
+ }
419
+ ret = bdrv_apply_auto_read_only(bs,
293
}
420
+ "No write support for seSparse images available", errp);
294
if (uri != NULL) {
421
+ if (ret < 0) {
295
g_free(uri->path);
422
+ return ret;
296
if (*str != cur) {
423
+ }
297
- if (uri->cleanup & 2)
424
+
298
+ if (uri->cleanup & 2) {
425
+ assert(sizeof(const_header) == SECTOR_SIZE);
299
uri->path = g_strndup(*str, cur - *str);
426
+
300
- else
427
+ ret = bdrv_pread(file, 0, &const_header, sizeof(const_header));
301
+ } else {
428
+ if (ret < 0) {
302
uri->path = uri_string_unescape(*str, cur - *str, NULL);
429
+ bdrv_refresh_filename(file->bs);
303
+ }
430
+ error_setg_errno(errp, -ret,
304
} else {
431
+ "Could not read const header from file '%s'",
305
uri->path = NULL;
432
+ file->bs->filename);
306
}
433
+ return ret;
307
@@ -XXX,XX +XXX,XX @@ static int rfc3986_parse_path_absolute(URI *uri, const char **str)
434
+ }
308
435
+
309
cur = *str;
436
+ /* check const header */
310
437
+ ret = check_se_sparse_const_header(&const_header, errp);
311
- if (*cur != '/')
438
+ if (ret < 0) {
312
+ if (*cur != '/') {
439
+ return ret;
313
return 1;
440
+ }
314
+ }
441
+
315
cur++;
442
+ assert(sizeof(volatile_header) == SECTOR_SIZE);
316
ret = rfc3986_parse_segment(&cur, 0, 0);
443
+
317
if (ret == 0) {
444
+ ret = bdrv_pread(file,
318
while (*cur == '/') {
445
+ const_header.volatile_header_offset * SECTOR_SIZE,
319
cur++;
446
+ &volatile_header, sizeof(volatile_header));
320
ret = rfc3986_parse_segment(&cur, 0, 1);
447
+ if (ret < 0) {
321
- if (ret != 0)
448
+ bdrv_refresh_filename(file->bs);
322
+ if (ret != 0) {
449
+ error_setg_errno(errp, -ret,
323
return ret;
450
+ "Could not read volatile header from file '%s'",
324
+ }
451
+ file->bs->filename);
325
}
452
+ return ret;
326
}
453
+ }
327
if (uri != NULL) {
454
+
328
g_free(uri->path);
455
+ /* check volatile header */
329
if (cur != *str) {
456
+ ret = check_se_sparse_volatile_header(&volatile_header, errp);
330
- if (uri->cleanup & 2)
457
+ if (ret < 0) {
331
+ if (uri->cleanup & 2) {
458
+ return ret;
332
uri->path = g_strndup(*str, cur - *str);
459
+ }
333
- else
460
+
334
+ } else {
461
+ ret = vmdk_add_extent(bs, file, false,
335
uri->path = uri_string_unescape(*str, cur - *str, NULL);
462
+ const_header.capacity,
336
+ }
463
+ const_header.grain_dir_offset * SECTOR_SIZE,
337
} else {
464
+ 0,
338
uri->path = NULL;
465
+ const_header.grain_dir_size *
339
}
466
+ SECTOR_SIZE / sizeof(uint64_t),
340
@@ -XXX,XX +XXX,XX @@ static int rfc3986_parse_path_rootless(URI *uri, const char **str)
467
+ const_header.grain_table_size *
341
cur = *str;
468
+ SECTOR_SIZE / sizeof(uint64_t),
342
469
+ const_header.grain_size,
343
ret = rfc3986_parse_segment(&cur, 0, 0);
470
+ &extent,
344
- if (ret != 0)
471
+ errp);
345
+ if (ret != 0) {
472
+ if (ret < 0) {
346
return ret;
473
+ return ret;
347
+ }
474
+ }
348
while (*cur == '/') {
475
+
349
cur++;
476
+ extent->sesparse = true;
350
ret = rfc3986_parse_segment(&cur, 0, 1);
477
+ extent->sesparse_l2_tables_offset = const_header.grain_tables_offset;
351
- if (ret != 0)
478
+ extent->sesparse_clusters_offset = const_header.grains_offset;
352
+ if (ret != 0) {
479
+ extent->entry_size = sizeof(uint64_t);
353
return ret;
480
+
354
+ }
481
+ ret = vmdk_init_tables(bs, extent, errp);
355
}
482
+ if (ret) {
356
if (uri != NULL) {
483
+ /* free extent allocated by vmdk_add_extent */
357
g_free(uri->path);
484
+ vmdk_free_last_extent(bs);
358
if (cur != *str) {
485
+ }
359
- if (uri->cleanup & 2)
486
+
360
+ if (uri->cleanup & 2) {
487
+ return ret;
361
uri->path = g_strndup(*str, cur - *str);
488
+}
362
- else
489
+
363
+ } else {
490
static int vmdk_open_desc_file(BlockDriverState *bs, int flags, char *buf,
364
uri->path = uri_string_unescape(*str, cur - *str, NULL);
491
QDict *options, Error **errp);
365
+ }
492
366
} else {
493
@@ -XXX,XX +XXX,XX @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
367
uri->path = NULL;
494
* RW [size in sectors] SPARSE "file-name.vmdk"
368
}
495
* RW [size in sectors] VMFS "file-name.vmdk"
369
@@ -XXX,XX +XXX,XX @@ static int rfc3986_parse_path_no_scheme(URI *uri, const char **str)
496
* RW [size in sectors] VMFSSPARSE "file-name.vmdk"
370
cur = *str;
497
+ * RW [size in sectors] SESPARSE "file-name.vmdk"
371
498
*/
372
ret = rfc3986_parse_segment(&cur, ':', 0);
499
flat_offset = -1;
373
- if (ret != 0)
500
matches = sscanf(p, "%10s %" SCNd64 " %10s \"%511[^\n\r\"]\" %" SCNd64,
374
+ if (ret != 0) {
501
@@ -XXX,XX +XXX,XX @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
375
return ret;
502
376
+ }
503
if (sectors <= 0 ||
377
while (*cur == '/') {
504
(strcmp(type, "FLAT") && strcmp(type, "SPARSE") &&
378
cur++;
505
- strcmp(type, "VMFS") && strcmp(type, "VMFSSPARSE")) ||
379
ret = rfc3986_parse_segment(&cur, 0, 1);
506
+ strcmp(type, "VMFS") && strcmp(type, "VMFSSPARSE") &&
380
- if (ret != 0)
507
+ strcmp(type, "SESPARSE")) ||
381
+ if (ret != 0) {
508
(strcmp(access, "RW"))) {
382
return ret;
383
+ }
384
}
385
if (uri != NULL) {
386
g_free(uri->path);
387
if (cur != *str) {
388
- if (uri->cleanup & 2)
389
+ if (uri->cleanup & 2) {
390
uri->path = g_strndup(*str, cur - *str);
391
- else
392
+ } else {
393
uri->path = uri_string_unescape(*str, cur - *str, NULL);
394
+ }
395
} else {
396
uri->path = NULL;
397
}
398
@@ -XXX,XX +XXX,XX @@ static int rfc3986_parse_hier_part(URI *uri, const char **str)
399
if ((*cur == '/') && (*(cur + 1) == '/')) {
400
cur += 2;
401
ret = rfc3986_parse_authority(uri, &cur);
402
- if (ret != 0)
403
+ if (ret != 0) {
404
return ret;
405
+ }
406
ret = rfc3986_parse_path_ab_empty(uri, &cur);
407
- if (ret != 0)
408
+ if (ret != 0) {
409
return ret;
410
+ }
411
*str = cur;
412
return 0;
413
} else if (*cur == '/') {
414
ret = rfc3986_parse_path_absolute(uri, &cur);
415
- if (ret != 0)
416
+ if (ret != 0) {
417
return ret;
418
+ }
419
} else if (ISA_PCHAR(cur)) {
420
ret = rfc3986_parse_path_rootless(uri, &cur);
421
- if (ret != 0)
422
+ if (ret != 0) {
423
return ret;
424
+ }
425
} else {
426
/* path-empty is effectively empty */
427
if (uri != NULL) {
428
@@ -XXX,XX +XXX,XX @@ static int rfc3986_parse_relative_ref(URI *uri, const char *str)
429
if ((*str == '/') && (*(str + 1) == '/')) {
430
str += 2;
431
ret = rfc3986_parse_authority(uri, &str);
432
- if (ret != 0)
433
+ if (ret != 0) {
434
return ret;
435
+ }
436
ret = rfc3986_parse_path_ab_empty(uri, &str);
437
- if (ret != 0)
438
+ if (ret != 0) {
439
return ret;
440
+ }
441
} else if (*str == '/') {
442
ret = rfc3986_parse_path_absolute(uri, &str);
443
- if (ret != 0)
444
+ if (ret != 0) {
445
return ret;
446
+ }
447
} else if (ISA_PCHAR(str)) {
448
ret = rfc3986_parse_path_no_scheme(uri, &str);
449
- if (ret != 0)
450
+ if (ret != 0) {
451
return ret;
452
+ }
453
} else {
454
/* path-empty is effectively empty */
455
if (uri != NULL) {
456
@@ -XXX,XX +XXX,XX @@ static int rfc3986_parse_relative_ref(URI *uri, const char *str)
457
if (*str == '?') {
458
str++;
459
ret = rfc3986_parse_query(uri, &str);
460
- if (ret != 0)
461
+ if (ret != 0) {
462
return ret;
463
+ }
464
}
465
if (*str == '#') {
466
str++;
467
ret = rfc3986_parse_fragment(uri, &str);
468
- if (ret != 0)
469
+ if (ret != 0) {
470
return ret;
471
+ }
472
}
473
if (*str != 0) {
474
uri_clean(uri);
475
@@ -XXX,XX +XXX,XX @@ static int rfc3986_parse(URI *uri, const char *str)
476
int ret;
477
478
ret = rfc3986_parse_scheme(uri, &str);
479
- if (ret != 0)
480
+ if (ret != 0) {
481
return ret;
482
+ }
483
if (*str != ':') {
484
return 1;
485
}
486
str++;
487
ret = rfc3986_parse_hier_part(uri, &str);
488
- if (ret != 0)
489
+ if (ret != 0) {
490
return ret;
491
+ }
492
if (*str == '?') {
493
str++;
494
ret = rfc3986_parse_query(uri, &str);
495
- if (ret != 0)
496
+ if (ret != 0) {
497
return ret;
498
+ }
499
}
500
if (*str == '#') {
501
str++;
502
ret = rfc3986_parse_fragment(uri, &str);
503
- if (ret != 0)
504
+ if (ret != 0) {
505
return ret;
506
+ }
507
}
508
if (*str != 0) {
509
uri_clean(uri);
510
@@ -XXX,XX +XXX,XX @@ static int rfc3986_parse_uri_reference(URI *uri, const char *str)
511
{
512
int ret;
513
514
- if (str == NULL)
515
+ if (str == NULL) {
516
return -1;
517
+ }
518
uri_clean(uri);
519
520
/*
521
@@ -XXX,XX +XXX,XX @@ URI *uri_parse(const char *str)
522
URI *uri;
523
int ret;
524
525
- if (str == NULL)
526
+ if (str == NULL) {
527
return NULL;
528
+ }
529
uri = uri_new();
530
ret = rfc3986_parse_uri_reference(uri, str);
531
if (ret) {
532
@@ -XXX,XX +XXX,XX @@ URI *uri_parse_raw(const char *str, int raw)
533
URI *uri;
534
int ret;
535
536
- if (str == NULL)
537
+ if (str == NULL) {
538
return NULL;
539
+ }
540
uri = uri_new();
541
if (raw) {
542
uri->cleanup |= 2;
543
@@ -XXX,XX +XXX,XX @@ char *uri_to_string(URI *uri)
544
int len;
545
int max;
546
547
- if (uri == NULL)
548
+ if (uri == NULL) {
549
return NULL;
550
+ }
551
552
max = 80;
553
ret = g_malloc(max + 1);
554
@@ -XXX,XX +XXX,XX @@ char *uri_to_string(URI *uri)
555
temp = realloc2n(ret, &max);
556
ret = temp;
557
}
558
- if (IS_RESERVED(*(p)) || IS_UNRESERVED(*(p)))
559
+ if (IS_RESERVED(*(p)) || IS_UNRESERVED(*(p))) {
560
ret[len++] = *p++;
561
- else {
562
+ } else {
563
int val = *(unsigned char *)p++;
564
int hi = val / 0x10, lo = val % 0x10;
565
ret[len++] = '%';
566
@@ -XXX,XX +XXX,XX @@ char *uri_to_string(URI *uri)
567
}
568
if ((IS_UNRESERVED(*(p))) || ((*(p) == ';')) ||
569
((*(p) == ':')) || ((*(p) == '&')) || ((*(p) == '=')) ||
570
- ((*(p) == '+')) || ((*(p) == '$')) || ((*(p) == ',')))
571
+ ((*(p) == '+')) || ((*(p) == '$')) || ((*(p) == ','))) {
572
ret[len++] = *p++;
573
- else {
574
+ } else {
575
int val = *(unsigned char *)p++;
576
int hi = val / 0x10, lo = val % 0x10;
577
ret[len++] = '%';
578
@@ -XXX,XX +XXX,XX @@ char *uri_to_string(URI *uri)
579
if ((IS_UNRESERVED(*(p))) || ((*(p) == '$')) ||
580
((*(p) == ',')) || ((*(p) == ';')) || ((*(p) == ':')) ||
581
((*(p) == '@')) || ((*(p) == '&')) || ((*(p) == '=')) ||
582
- ((*(p) == '+')))
583
+ ((*(p) == '+'))) {
584
ret[len++] = *p++;
585
- else {
586
+ } else {
587
int val = *(unsigned char *)p++;
588
int hi = val / 0x10, lo = val % 0x10;
589
ret[len++] = '%';
590
@@ -XXX,XX +XXX,XX @@ char *uri_to_string(URI *uri)
591
if ((IS_UNRESERVED(*(p))) || ((*(p) == '/')) ||
592
((*(p) == ';')) || ((*(p) == '@')) || ((*(p) == '&')) ||
593
((*(p) == '=')) || ((*(p) == '+')) || ((*(p) == '$')) ||
594
- ((*(p) == ',')))
595
+ ((*(p) == ','))) {
596
ret[len++] = *p++;
597
- else {
598
+ } else {
599
int val = *(unsigned char *)p++;
600
int hi = val / 0x10, lo = val % 0x10;
601
ret[len++] = '%';
602
@@ -XXX,XX +XXX,XX @@ char *uri_to_string(URI *uri)
603
temp = realloc2n(ret, &max);
604
ret = temp;
605
}
606
- if ((IS_UNRESERVED(*(p))) || (IS_RESERVED(*(p))))
607
+ if ((IS_UNRESERVED(*(p))) || (IS_RESERVED(*(p)))) {
608
ret[len++] = *p++;
609
- else {
610
+ } else {
611
int val = *(unsigned char *)p++;
612
int hi = val / 0x10, lo = val % 0x10;
613
ret[len++] = '%';
614
@@ -XXX,XX +XXX,XX @@ char *uri_to_string(URI *uri)
615
*/
616
static void uri_clean(URI *uri)
617
{
618
- if (uri == NULL)
619
+ if (uri == NULL) {
620
return;
621
+ }
622
623
g_free(uri->scheme);
624
uri->scheme = NULL;
625
@@ -XXX,XX +XXX,XX @@ static int normalize_uri_path(char *path)
626
{
627
char *cur, *out;
628
629
- if (path == NULL)
630
+ if (path == NULL) {
631
return -1;
632
+ }
633
634
/* Skip all initial "/" chars. We want to get to the beginning of the
635
* first non-empty segment.
636
*/
637
cur = path;
638
- while (cur[0] == '/')
639
+ while (cur[0] == '/') {
640
++cur;
641
- if (cur[0] == '\0')
642
+ }
643
+ if (cur[0] == '\0') {
644
return 0;
645
+ }
646
647
/* Keep everything we've seen so far. */
648
out = cur;
649
@@ -XXX,XX +XXX,XX @@ static int normalize_uri_path(char *path)
650
if ((cur[0] == '.') && (cur[1] == '/')) {
651
cur += 2;
652
/* '//' normalization should be done at this point too */
653
- while (cur[0] == '/')
654
+ while (cur[0] == '/') {
655
cur++;
656
+ }
657
continue;
509
continue;
658
}
510
}
659
511
@@ -XXX,XX +XXX,XX @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
660
@@ -XXX,XX +XXX,XX @@ static int normalize_uri_path(char *path)
512
return ret;
661
* d) If the buffer string ends with "." as a complete path segment,
513
}
662
* that "." is removed.
514
extent = &s->extents[s->num_extents - 1];
663
*/
515
+ } else if (!strcmp(type, "SESPARSE")) {
664
- if ((cur[0] == '.') && (cur[1] == '\0'))
516
+ ret = vmdk_open_se_sparse(bs, extent_file, bs->open_flags, errp);
665
+ if ((cur[0] == '.') && (cur[1] == '\0')) {
517
+ if (ret) {
666
break;
518
+ bdrv_unref_child(bs, extent_file);
667
+ }
519
+ return ret;
668
669
/* Otherwise keep the segment. */
670
while (cur[0] != '/') {
671
- if (cur[0] == '\0')
672
+ if (cur[0] == '\0') {
673
goto done_cd;
674
+ }
520
+ }
675
(out++)[0] = (cur++)[0];
521
+ extent = &s->extents[s->num_extents - 1];
676
}
522
} else {
677
/* nomalize // */
523
error_setg(errp, "Unsupported extent type '%s'", type);
678
- while ((cur[0] == '/') && (cur[1] == '/'))
524
bdrv_unref_child(bs, extent_file);
679
+ while ((cur[0] == '/') && (cur[1] == '/')) {
525
@@ -XXX,XX +XXX,XX @@ static int vmdk_open_desc_file(BlockDriverState *bs, int flags, char *buf,
680
cur++;
526
if (strcmp(ct, "monolithicFlat") &&
681
+ }
527
strcmp(ct, "vmfs") &&
682
528
strcmp(ct, "vmfsSparse") &&
683
(out++)[0] = (cur++)[0];
529
+ strcmp(ct, "seSparse") &&
684
}
530
strcmp(ct, "twoGbMaxExtentSparse") &&
685
@@ -XXX,XX +XXX,XX @@ done_cd:
531
strcmp(ct, "twoGbMaxExtentFlat")) {
686
532
error_setg(errp, "Unsupported image type '%s'", ct);
687
/* Reset to the beginning of the first segment for the next sequence. */
533
@@ -XXX,XX +XXX,XX @@ static int get_cluster_offset(BlockDriverState *bs,
688
cur = path;
534
{
689
- while (cur[0] == '/')
535
unsigned int l1_index, l2_offset, l2_index;
690
+ while (cur[0] == '/') {
536
int min_index, i, j;
691
++cur;
537
- uint32_t min_count, *l2_table;
692
- if (cur[0] == '\0')
538
+ uint32_t min_count;
693
+ }
539
+ void *l2_table;
694
+ if (cur[0] == '\0') {
540
bool zeroed = false;
695
return 0;
541
int64_t ret;
696
+ }
542
int64_t cluster_sector;
697
543
+ unsigned int l2_size_bytes = extent->l2_size * extent->entry_size;
698
/*
544
699
* Analyze each segment in sequence for cases (e) and (f).
545
if (m_data) {
700
@@ -XXX,XX +XXX,XX @@ done_cd:
546
m_data->valid = 0;
701
547
@@ -XXX,XX +XXX,XX @@ static int get_cluster_offset(BlockDriverState *bs,
702
/* Find the end of the current segment. */
548
if (l1_index >= extent->l1_size) {
703
segp = cur;
549
return VMDK_ERROR;
704
- while ((segp[0] != '/') && (segp[0] != '\0'))
550
}
705
+ while ((segp[0] != '/') && (segp[0] != '\0')) {
551
- l2_offset = extent->l1_table[l1_index];
706
++segp;
552
+ if (extent->sesparse) {
707
+ }
553
+ uint64_t l2_offset_u64;
708
554
+
709
/* If this is the last segment, we're done (we need at least two
555
+ assert(extent->entry_size == sizeof(uint64_t));
710
* segments to meet the criteria for the (e) and (f) cases).
556
+
711
*/
557
+ l2_offset_u64 = ((uint64_t *)extent->l1_table)[l1_index];
712
- if (segp[0] == '\0')
558
+ if (l2_offset_u64 == 0) {
713
+ if (segp[0] == '\0') {
559
+ l2_offset = 0;
714
break;
560
+ } else if ((l2_offset_u64 & 0xffffffff00000000) != 0x1000000000000000) {
715
+ }
561
+ /*
716
562
+ * Top most nibble is 0x1 if grain table is allocated.
717
/* If the first segment is "..", or if the next segment _isn't_ "..",
563
+ * strict check - top most 4 bytes must be 0x10000000 since max
718
* keep this segment and try the next one.
564
+ * supported size is 64TB for disk - so no more than 64TB / 16MB
719
@@ -XXX,XX +XXX,XX @@ done_cd:
565
+ * grain directories which is smaller than uint32,
720
/* string will overlap, do not use strcpy */
566
+ * where 16MB is the only supported default grain table coverage.
721
tmp = cur;
567
+ */
722
segp += 3;
568
+ return VMDK_ERROR;
723
- while ((*tmp++ = *segp++) != 0)
569
+ } else {
724
- ;
570
+ l2_offset_u64 = l2_offset_u64 & 0x00000000ffffffff;
725
+ while ((*tmp++ = *segp++) != 0) {
571
+ l2_offset_u64 = extent->sesparse_l2_tables_offset +
726
+ /* No further work */
572
+ l2_offset_u64 * l2_size_bytes / SECTOR_SIZE;
727
+ }
573
+ if (l2_offset_u64 > 0x00000000ffffffff) {
728
574
+ return VMDK_ERROR;
729
/* If there are no previous segments, then keep going from here. */
730
segp = cur;
731
- while ((segp > path) && ((--segp)[0] == '/'))
732
- ;
733
- if (segp == path)
734
+ while ((segp > path) && ((--segp)[0] == '/')) {
735
+ /* No further work */
736
+ }
737
+ if (segp == path) {
738
continue;
739
+ }
740
741
/* "segp" is pointing to the end of a previous segment; find it's
742
* start. We need to back up to the previous segment and start
743
@@ -XXX,XX +XXX,XX @@ done_cd:
744
* remove the "foo/..".
745
*/
746
cur = segp;
747
- while ((cur > path) && (cur[-1] != '/'))
748
+ while ((cur > path) && (cur[-1] != '/')) {
749
--cur;
750
+ }
751
}
752
out[0] = '\0';
753
754
@@ -XXX,XX +XXX,XX @@ done_cd:
755
if (path[0] == '/') {
756
cur = path;
757
while ((cur[0] == '/') && (cur[1] == '.') && (cur[2] == '.') &&
758
- ((cur[3] == '/') || (cur[3] == '\0')))
759
+ ((cur[3] == '/') || (cur[3] == '\0'))) {
760
cur += 3;
761
+ }
762
763
if (cur != path) {
764
out = path;
765
- while (cur[0] != '\0')
766
+ while (cur[0] != '\0') {
767
(out++)[0] = (cur++)[0];
768
+ }
575
+ }
769
out[0] = 0;
576
+ l2_offset = (unsigned int)(l2_offset_u64);
770
}
771
}
772
@@ -XXX,XX +XXX,XX @@ done_cd:
773
static int is_hex(char c)
774
{
775
if (((c >= '0') && (c <= '9')) || ((c >= 'a') && (c <= 'f')) ||
776
- ((c >= 'A') && (c <= 'F')))
777
+ ((c >= 'A') && (c <= 'F'))) {
778
return 1;
779
+ }
780
return 0;
781
}
782
783
@@ -XXX,XX +XXX,XX @@ char *uri_string_unescape(const char *str, int len, char *target)
784
char *ret, *out;
785
const char *in;
786
787
- if (str == NULL)
788
+ if (str == NULL) {
789
return NULL;
790
- if (len <= 0)
791
+ }
792
+ if (len <= 0) {
793
len = strlen(str);
794
- if (len < 0)
795
+ }
796
+ if (len < 0) {
797
return NULL;
798
+ }
799
800
if (target == NULL) {
801
ret = g_malloc(len + 1);
802
- } else
803
+ } else {
804
ret = target;
805
+ }
806
in = str;
807
out = ret;
808
while (len > 0) {
809
if ((len > 2) && (*in == '%') && (is_hex(in[1])) && (is_hex(in[2]))) {
810
in++;
811
- if ((*in >= '0') && (*in <= '9'))
812
+ if ((*in >= '0') && (*in <= '9')) {
813
*out = (*in - '0');
814
- else if ((*in >= 'a') && (*in <= 'f'))
815
+ } else if ((*in >= 'a') && (*in <= 'f')) {
816
*out = (*in - 'a') + 10;
817
- else if ((*in >= 'A') && (*in <= 'F'))
818
+ } else if ((*in >= 'A') && (*in <= 'F')) {
819
*out = (*in - 'A') + 10;
820
+ }
821
in++;
822
- if ((*in >= '0') && (*in <= '9'))
823
+ if ((*in >= '0') && (*in <= '9')) {
824
*out = *out * 16 + (*in - '0');
825
- else if ((*in >= 'a') && (*in <= 'f'))
826
+ } else if ((*in >= 'a') && (*in <= 'f')) {
827
*out = *out * 16 + (*in - 'a') + 10;
828
- else if ((*in >= 'A') && (*in <= 'F'))
829
+ } else if ((*in >= 'A') && (*in <= 'F')) {
830
*out = *out * 16 + (*in - 'A') + 10;
831
+ }
832
in++;
833
len -= 3;
834
out++;
835
@@ -XXX,XX +XXX,XX @@ char *uri_string_escape(const char *str, const char *list)
836
const char *in;
837
int len, out;
838
839
- if (str == NULL)
840
+ if (str == NULL) {
841
return NULL;
842
- if (str[0] == 0)
843
+ }
844
+ if (str[0] == 0) {
845
return g_strdup(str);
846
+ }
847
len = strlen(str);
848
- if (!(len > 0))
849
+ if (!(len > 0)) {
850
return NULL;
851
+ }
852
853
len += 20;
854
ret = g_malloc(len);
855
@@ -XXX,XX +XXX,XX @@ char *uri_string_escape(const char *str, const char *list)
856
unsigned char val;
857
ret[out++] = '%';
858
val = ch >> 4;
859
- if (val <= 9)
860
+ if (val <= 9) {
861
ret[out++] = '0' + val;
862
- else
863
+ } else {
864
ret[out++] = 'A' + val - 0xA;
865
+ }
866
val = ch & 0xF;
867
- if (val <= 9)
868
+ if (val <= 9) {
869
ret[out++] = '0' + val;
870
- else
871
+ } else {
872
ret[out++] = 'A' + val - 0xA;
873
+ }
874
in++;
875
} else {
876
ret[out++] = *in++;
877
@@ -XXX,XX +XXX,XX @@ char *uri_resolve(const char *uri, const char *base)
878
* as a reference to "." rather than as a synonym for the current
879
* URI. Should we do that here?
880
*/
881
- if (uri == NULL)
882
+ if (uri == NULL) {
883
ret = -1;
884
- else {
885
+ } else {
886
if (*uri) {
887
ref = uri_new();
888
ret = uri_parse_into(ref, uri);
889
- } else
890
+ } else {
891
ret = 0;
892
+ }
893
}
894
- if (ret != 0)
895
+ if (ret != 0) {
896
goto done;
897
+ }
898
if ((ref != NULL) && (ref->scheme != NULL)) {
899
/*
900
* The URI is absolute don't modify.
901
@@ -XXX,XX +XXX,XX @@ char *uri_resolve(const char *uri, const char *base)
902
val = g_strdup(uri);
903
goto done;
904
}
905
- if (base == NULL)
906
+ if (base == NULL) {
907
ret = -1;
908
- else {
909
+ } else {
910
bas = uri_new();
911
ret = uri_parse_into(bas, base);
912
}
913
if (ret != 0) {
914
- if (ref)
915
+ if (ref) {
916
val = uri_to_string(ref);
917
+ }
918
goto done;
919
}
920
if (ref == NULL) {
921
@@ -XXX,XX +XXX,XX @@ char *uri_resolve(const char *uri, const char *base)
922
if ((ref->scheme == NULL) && (ref->path == NULL) &&
923
((ref->authority == NULL) && (ref->server == NULL))) {
924
res->scheme = g_strdup(bas->scheme);
925
- if (bas->authority != NULL)
926
+ if (bas->authority != NULL) {
927
res->authority = g_strdup(bas->authority);
928
- else if (bas->server != NULL) {
929
+ } else if (bas->server != NULL) {
930
res->server = g_strdup(bas->server);
931
res->user = g_strdup(bas->user);
932
res->port = bas->port;
933
@@ -XXX,XX +XXX,XX @@ char *uri_resolve(const char *uri, const char *base)
934
* use an authority component.
935
*/
936
if ((ref->authority != NULL) || (ref->server != NULL)) {
937
- if (ref->authority != NULL)
938
+ if (ref->authority != NULL) {
939
res->authority = g_strdup(ref->authority);
940
- else {
941
+ } else {
942
res->server = g_strdup(ref->server);
943
res->user = g_strdup(ref->user);
944
res->port = ref->port;
945
@@ -XXX,XX +XXX,XX @@ char *uri_resolve(const char *uri, const char *base)
946
res->path = g_strdup(ref->path);
947
goto step_7;
948
}
949
- if (bas->authority != NULL)
950
+ if (bas->authority != NULL) {
951
res->authority = g_strdup(bas->authority);
952
- else if (bas->server != NULL) {
953
+ } else if (bas->server != NULL) {
954
res->server = g_strdup(bas->server);
955
res->user = g_strdup(bas->user);
956
res->port = bas->port;
957
@@ -XXX,XX +XXX,XX @@ char *uri_resolve(const char *uri, const char *base)
958
* Allocate a buffer large enough for the result string.
959
*/
960
len = 2; /* extra / and 0 */
961
- if (ref->path != NULL)
962
+ if (ref->path != NULL) {
963
len += strlen(ref->path);
964
- if (bas->path != NULL)
965
+ }
966
+ if (bas->path != NULL) {
967
len += strlen(bas->path);
968
+ }
969
res->path = g_malloc(len);
970
res->path[0] = 0;
971
972
@@ -XXX,XX +XXX,XX @@ char *uri_resolve(const char *uri, const char *base)
973
out = 0;
974
if (bas->path != NULL) {
975
while (bas->path[cur] != 0) {
976
- while ((bas->path[cur] != 0) && (bas->path[cur] != '/'))
977
+ while ((bas->path[cur] != 0) && (bas->path[cur] != '/')) {
978
cur++;
979
- if (bas->path[cur] == 0)
980
+ }
981
+ if (bas->path[cur] == 0) {
982
break;
983
+ }
984
985
cur++;
986
while (out < cur) {
987
@@ -XXX,XX +XXX,XX @@ char *uri_resolve(const char *uri, const char *base)
988
/*
989
* Ensure the path includes a '/'
990
*/
991
- if ((out == 0) && (bas->server != NULL))
992
+ if ((out == 0) && (bas->server != NULL)) {
993
res->path[out++] = '/';
994
+ }
995
while (ref->path[indx] != 0) {
996
res->path[out++] = ref->path[indx++];
997
}
998
@@ -XXX,XX +XXX,XX @@ step_7:
999
val = uri_to_string(res);
1000
1001
done:
1002
- if (ref != NULL)
1003
+ if (ref != NULL) {
1004
uri_free(ref);
1005
- if (bas != NULL)
1006
+ }
1007
+ if (bas != NULL) {
1008
uri_free(bas);
1009
- if (res != NULL)
1010
+ }
1011
+ if (res != NULL) {
1012
uri_free(res);
1013
+ }
1014
return val;
1015
}
1016
1017
@@ -XXX,XX +XXX,XX @@ char *uri_resolve_relative(const char *uri, const char *base)
1018
char *bptr, *uptr, *vptr;
1019
int remove_path = 0;
1020
1021
- if ((uri == NULL) || (*uri == 0))
1022
+ if ((uri == NULL) || (*uri == 0)) {
1023
return NULL;
1024
+ }
1025
1026
/*
1027
* First parse URI into a standard form
1028
@@ -XXX,XX +XXX,XX @@ char *uri_resolve_relative(const char *uri, const char *base)
1029
/* If URI not already in "relative" form */
1030
if (uri[0] != '.') {
1031
ret = uri_parse_into(ref, uri);
1032
- if (ret != 0)
1033
+ if (ret != 0) {
1034
goto done; /* Error in URI, return NULL */
1035
- } else
1036
+ }
577
+ }
1037
+ } else {
578
+ } else {
1038
ref->path = g_strdup(uri);
579
+ assert(extent->entry_size == sizeof(uint32_t));
1039
+ }
580
+ l2_offset = ((uint32_t *)extent->l1_table)[l1_index];
1040
581
+ }
1041
/*
582
if (!l2_offset) {
1042
* Next parse base into the same standard form
583
return VMDK_UNALLOC;
1043
@@ -XXX,XX +XXX,XX @@ char *uri_resolve_relative(const char *uri, const char *base)
584
}
1044
bas = uri_new();
585
@@ -XXX,XX +XXX,XX @@ static int get_cluster_offset(BlockDriverState *bs,
1045
if (base[0] != '.') {
586
extent->l2_cache_counts[j] >>= 1;
1046
ret = uri_parse_into(bas, base);
587
}
1047
- if (ret != 0)
588
}
1048
+ if (ret != 0) {
589
- l2_table = extent->l2_cache + (i * extent->l2_size);
1049
goto done; /* Error in base, return NULL */
590
+ l2_table = (char *)extent->l2_cache + (i * l2_size_bytes);
1050
- } else
591
goto found;
592
}
593
}
594
@@ -XXX,XX +XXX,XX @@ static int get_cluster_offset(BlockDriverState *bs,
595
min_index = i;
596
}
597
}
598
- l2_table = extent->l2_cache + (min_index * extent->l2_size);
599
+ l2_table = (char *)extent->l2_cache + (min_index * l2_size_bytes);
600
BLKDBG_EVENT(extent->file, BLKDBG_L2_LOAD);
601
if (bdrv_pread(extent->file,
602
(int64_t)l2_offset * 512,
603
l2_table,
604
- extent->l2_size * sizeof(uint32_t)
605
- ) != extent->l2_size * sizeof(uint32_t)) {
606
+ l2_size_bytes
607
+ ) != l2_size_bytes) {
608
return VMDK_ERROR;
609
}
610
611
@@ -XXX,XX +XXX,XX @@ static int get_cluster_offset(BlockDriverState *bs,
612
extent->l2_cache_counts[min_index] = 1;
613
found:
614
l2_index = ((offset >> 9) / extent->cluster_sectors) % extent->l2_size;
615
- cluster_sector = le32_to_cpu(l2_table[l2_index]);
616
617
- if (extent->has_zero_grain && cluster_sector == VMDK_GTE_ZEROED) {
618
- zeroed = true;
619
+ if (extent->sesparse) {
620
+ cluster_sector = le64_to_cpu(((uint64_t *)l2_table)[l2_index]);
621
+ switch (cluster_sector & 0xf000000000000000) {
622
+ case 0x0000000000000000:
623
+ /* unallocated grain */
624
+ if (cluster_sector != 0) {
625
+ return VMDK_ERROR;
626
+ }
627
+ break;
628
+ case 0x1000000000000000:
629
+ /* scsi-unmapped grain - fallthrough */
630
+ case 0x2000000000000000:
631
+ /* zero grain */
632
+ zeroed = true;
633
+ break;
634
+ case 0x3000000000000000:
635
+ /* allocated grain */
636
+ cluster_sector = (((cluster_sector & 0x0fff000000000000) >> 48) |
637
+ ((cluster_sector & 0x0000ffffffffffff) << 12));
638
+ cluster_sector = extent->sesparse_clusters_offset +
639
+ cluster_sector * extent->cluster_sectors;
640
+ break;
641
+ default:
642
+ return VMDK_ERROR;
1051
+ }
643
+ }
1052
+ } else {
644
+ } else {
1053
bas->path = g_strdup(base);
645
+ cluster_sector = le32_to_cpu(((uint32_t *)l2_table)[l2_index]);
1054
+ }
646
+
1055
647
+ if (extent->has_zero_grain && cluster_sector == VMDK_GTE_ZEROED) {
1056
/*
648
+ zeroed = true;
1057
* If the scheme / server on the URI differs from the base,
649
+ }
1058
@@ -XXX,XX +XXX,XX @@ char *uri_resolve_relative(const char *uri, const char *base)
650
}
1059
if (bas->path == NULL) {
651
1060
if (ref->path != NULL) {
652
if (!cluster_sector || zeroed) {
1061
uptr = ref->path;
653
if (!allocate) {
1062
- if (*uptr == '/')
654
return zeroed ? VMDK_ZEROED : VMDK_UNALLOC;
1063
+ if (*uptr == '/') {
1064
uptr++;
1065
+ }
1066
/* exception characters from uri_to_string */
1067
val = uri_string_escape(uptr, "/;&=+$,");
1068
}
655
}
1069
@@ -XXX,XX +XXX,XX @@ char *uri_resolve_relative(const char *uri, const char *base)
656
+ assert(!extent->sesparse);
1070
bptr = bas->path;
657
1071
if (ref->path == NULL) {
658
if (extent->next_cluster_sector >= VMDK_EXTENT_MAX_SECTORS) {
1072
for (ix = 0; bptr[ix] != 0; ix++) {
659
return VMDK_ERROR;
1073
- if (bptr[ix] == '/')
660
@@ -XXX,XX +XXX,XX @@ static int get_cluster_offset(BlockDriverState *bs,
1074
+ if (bptr[ix] == '/') {
661
m_data->l1_index = l1_index;
1075
nbslash++;
662
m_data->l2_index = l2_index;
1076
+ }
663
m_data->l2_offset = l2_offset;
664
- m_data->l2_cache_entry = &l2_table[l2_index];
665
+ m_data->l2_cache_entry = ((uint32_t *)l2_table) + l2_index;
1077
}
666
}
1078
uptr = NULL;
667
}
1079
len = 1; /* this is for a string terminator only */
668
*cluster_offset = cluster_sector << BDRV_SECTOR_BITS;
1080
@@ -XXX,XX +XXX,XX @@ char *uri_resolve_relative(const char *uri, const char *base)
669
@@ -XXX,XX +XXX,XX @@ static int vmdk_pwritev(BlockDriverState *bs, uint64_t offset,
1081
/*
670
if (!extent) {
1082
* Next we compare the two strings and find where they first differ
671
return -EIO;
1083
*/
672
}
1084
- if ((ref->path[pos] == '.') && (ref->path[pos + 1] == '/'))
673
+ if (extent->sesparse) {
1085
+ if ((ref->path[pos] == '.') && (ref->path[pos + 1] == '/')) {
674
+ return -ENOTSUP;
1086
pos += 2;
1087
- if ((*bptr == '.') && (bptr[1] == '/'))
1088
+ }
675
+ }
1089
+ if ((*bptr == '.') && (bptr[1] == '/')) {
676
offset_in_cluster = vmdk_find_offset_in_cluster(extent, offset);
1090
bptr += 2;
677
n_bytes = MIN(bytes, extent->cluster_sectors * BDRV_SECTOR_SIZE
1091
- else if ((*bptr == '/') && (ref->path[pos] != '/'))
678
- offset_in_cluster);
1092
+ } else if ((*bptr == '/') && (ref->path[pos] != '/')) {
1093
bptr++;
1094
- while ((bptr[pos] == ref->path[pos]) && (bptr[pos] != 0))
1095
+ }
1096
+ while ((bptr[pos] == ref->path[pos]) && (bptr[pos] != 0)) {
1097
pos++;
1098
+ }
1099
1100
if (bptr[pos] == ref->path[pos]) {
1101
val = g_strdup("");
1102
@@ -XXX,XX +XXX,XX @@ char *uri_resolve_relative(const char *uri, const char *base)
1103
* beginning of the "unique" suffix of URI
1104
*/
1105
ix = pos;
1106
- if ((ref->path[ix] == '/') && (ix > 0))
1107
+ if ((ref->path[ix] == '/') && (ix > 0)) {
1108
ix--;
1109
- else if ((ref->path[ix] == 0) && (ix > 1) && (ref->path[ix - 1] == '/'))
1110
+ } else if ((ref->path[ix] == 0) && (ix > 1)
1111
+ && (ref->path[ix - 1] == '/')) {
1112
ix -= 2;
1113
+ }
1114
for (; ix > 0; ix--) {
1115
- if (ref->path[ix] == '/')
1116
+ if (ref->path[ix] == '/') {
1117
break;
1118
+ }
1119
}
1120
if (ix == 0) {
1121
uptr = ref->path;
1122
@@ -XXX,XX +XXX,XX @@ char *uri_resolve_relative(const char *uri, const char *base)
1123
*/
1124
if (bptr[pos] != ref->path[pos]) { /* check for trivial URI == base */
1125
for (; bptr[ix] != 0; ix++) {
1126
- if (bptr[ix] == '/')
1127
+ if (bptr[ix] == '/') {
1128
nbslash++;
1129
+ }
1130
}
1131
}
1132
len = strlen(uptr) + 1;
1133
}
1134
1135
if (nbslash == 0) {
1136
- if (uptr != NULL)
1137
+ if (uptr != NULL) {
1138
/* exception characters from uri_to_string */
1139
val = uri_string_escape(uptr, "/;&=+$,");
1140
+ }
1141
goto done;
1142
}
1143
1144
@@ -XXX,XX +XXX,XX @@ done:
1145
/*
1146
* Free the working variables
1147
*/
1148
- if (remove_path != 0)
1149
+ if (remove_path != 0) {
1150
ref->path = NULL;
1151
- if (ref != NULL)
1152
+ }
1153
+ if (ref != NULL) {
1154
uri_free(ref);
1155
- if (bas != NULL)
1156
+ }
1157
+ if (bas != NULL) {
1158
uri_free(bas);
1159
+ }
1160
1161
return val;
1162
}
1163
@@ -XXX,XX +XXX,XX @@ struct QueryParams *query_params_new(int init_alloc)
1164
{
1165
struct QueryParams *ps;
1166
1167
- if (init_alloc <= 0)
1168
+ if (init_alloc <= 0) {
1169
init_alloc = 1;
1170
+ }
1171
1172
ps = g_new(QueryParams, 1);
1173
ps->n = 0;
1174
@@ -XXX,XX +XXX,XX @@ struct QueryParams *query_params_parse(const char *query)
1175
const char *end, *eq;
1176
1177
ps = query_params_new(0);
1178
- if (!query || query[0] == '\0')
1179
+ if (!query || query[0] == '\0') {
1180
return ps;
1181
+ }
1182
1183
while (*query) {
1184
char *name = NULL, *value = NULL;
1185
1186
/* Find the next separator, or end of the string. */
1187
end = strchr(query, '&');
1188
- if (!end)
1189
+ if (!end) {
1190
end = strchr(query, ';');
1191
- if (!end)
1192
+ }
1193
+ if (!end) {
1194
end = query + strlen(query);
1195
+ }
1196
1197
/* Find the first '=' character between here and end. */
1198
eq = strchr(query, '=');
1199
- if (eq && eq >= end)
1200
+ if (eq && eq >= end) {
1201
eq = NULL;
1202
+ }
1203
1204
/* Empty section (eg. "&&"). */
1205
- if (end == query)
1206
+ if (end == query) {
1207
goto next;
1208
+ }
1209
1210
/* If there is no '=' character, then we have just "name"
1211
* and consistent with CGI.pm we assume value is "".
1212
@@ -XXX,XX +XXX,XX @@ struct QueryParams *query_params_parse(const char *query)
1213
/* If the '=' character is at the beginning then we have
1214
* "=value" and consistent with CGI.pm we _ignore_ this.
1215
*/
1216
- else if (query == eq)
1217
+ else if (query == eq) {
1218
goto next;
1219
+ }
1220
1221
/* Otherwise it's "name=value". */
1222
else {
1223
@@ -XXX,XX +XXX,XX @@ struct QueryParams *query_params_parse(const char *query)
1224
1225
next:
1226
query = end;
1227
- if (*query)
1228
+ if (*query) {
1229
query++; /* skip '&' separator */
1230
+ }
1231
}
1232
1233
return ps;
1234
--
679
--
1235
2.14.3
680
2.21.0
1236
681
1237
682
diff view generated by jsdifflib
1
From: Su Hang <suhang16@mails.ucas.ac.cn>
1
From: Pino Toscano <ptoscano@redhat.com>
2
2
3
Using `clang-format -i util/uri.c` first, then change back few code
3
Rewrite the implementation of the ssh block driver to use libssh instead
4
manually, to make sure only whitespace involved.
4
of libssh2. The libssh library has various advantages over libssh2:
5
- easier API for authentication (for example for using ssh-agent)
6
- easier API for known_hosts handling
7
- supports newer types of keys in known_hosts
5
8
6
Signed-off-by: Su Hang <suhang16@mails.ucas.ac.cn>
9
Use APIs/features available in libssh 0.8 conditionally, to support
7
Reviewed-by: Thomas Huth <thuth@redhat.com>
10
older versions (which are not recommended though).
8
Message-id: 1519533358-13759-2-git-send-email-suhang16@mails.ucas.ac.cn
11
9
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
12
Adjust the iotest 207 according to the different error message, and to
13
find the default key type for localhost (to properly compare the
14
fingerprint with).
15
Contributed-by: Max Reitz <mreitz@redhat.com>
16
17
Adjust the various Docker/Travis scripts to use libssh when available
18
instead of libssh2. The mingw/mxe testing is dropped for now, as there
19
are no packages for it.
20
21
Signed-off-by: Pino Toscano <ptoscano@redhat.com>
22
Tested-by: Philippe Mathieu-Daudé <philmd@redhat.com>
23
Acked-by: Alex Bennée <alex.bennee@linaro.org>
24
Message-id: 20190620200840.17655-1-ptoscano@redhat.com
25
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
26
Message-id: 5873173.t2JhDm7DL7@lindworm.usersys.redhat.com
27
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
---
28
---
11
util/uri.c | 1450 ++++++++++++++++++++++++++++++------------------------------
29
configure | 65 +-
12
1 file changed, 726 insertions(+), 724 deletions(-)
30
block/Makefile.objs | 6 +-
31
block/ssh.c | 652 ++++++++++--------
32
.travis.yml | 4 +-
33
block/trace-events | 14 +-
34
docs/qemu-block-drivers.texi | 2 +-
35
.../dockerfiles/debian-win32-cross.docker | 1 -
36
.../dockerfiles/debian-win64-cross.docker | 1 -
37
tests/docker/dockerfiles/fedora.docker | 4 +-
38
tests/docker/dockerfiles/ubuntu.docker | 2 +-
39
tests/docker/dockerfiles/ubuntu1804.docker | 2 +-
40
tests/qemu-iotests/207 | 54 +-
41
tests/qemu-iotests/207.out | 2 +-
42
13 files changed, 449 insertions(+), 360 deletions(-)
13
43
14
diff --git a/util/uri.c b/util/uri.c
44
diff --git a/configure b/configure
45
index XXXXXXX..XXXXXXX 100755
46
--- a/configure
47
+++ b/configure
48
@@ -XXX,XX +XXX,XX @@ auth_pam=""
49
vte=""
50
virglrenderer=""
51
tpm=""
52
-libssh2=""
53
+libssh=""
54
live_block_migration="yes"
55
numa=""
56
tcmalloc="no"
57
@@ -XXX,XX +XXX,XX @@ for opt do
58
;;
59
--enable-tpm) tpm="yes"
60
;;
61
- --disable-libssh2) libssh2="no"
62
+ --disable-libssh) libssh="no"
63
;;
64
- --enable-libssh2) libssh2="yes"
65
+ --enable-libssh) libssh="yes"
66
;;
67
--disable-live-block-migration) live_block_migration="no"
68
;;
69
@@ -XXX,XX +XXX,XX @@ disabled with --disable-FEATURE, default is enabled if available:
70
coroutine-pool coroutine freelist (better performance)
71
glusterfs GlusterFS backend
72
tpm TPM support
73
- libssh2 ssh block device support
74
+ libssh ssh block device support
75
numa libnuma support
76
libxml2 for Parallels image format
77
tcmalloc tcmalloc support
78
@@ -XXX,XX +XXX,XX @@ EOF
79
fi
80
81
##########################################
82
-# libssh2 probe
83
-min_libssh2_version=1.2.8
84
-if test "$libssh2" != "no" ; then
85
- if $pkg_config --atleast-version=$min_libssh2_version libssh2; then
86
- libssh2_cflags=$($pkg_config libssh2 --cflags)
87
- libssh2_libs=$($pkg_config libssh2 --libs)
88
- libssh2=yes
89
+# libssh probe
90
+if test "$libssh" != "no" ; then
91
+ if $pkg_config --exists libssh; then
92
+ libssh_cflags=$($pkg_config libssh --cflags)
93
+ libssh_libs=$($pkg_config libssh --libs)
94
+ libssh=yes
95
else
96
- if test "$libssh2" = "yes" ; then
97
- error_exit "libssh2 >= $min_libssh2_version required for --enable-libssh2"
98
+ if test "$libssh" = "yes" ; then
99
+ error_exit "libssh required for --enable-libssh"
100
fi
101
- libssh2=no
102
+ libssh=no
103
fi
104
fi
105
106
##########################################
107
-# libssh2_sftp_fsync probe
108
+# Check for libssh 0.8
109
+# This is done like this instead of using the LIBSSH_VERSION_* and
110
+# SSH_VERSION_* macros because some distributions in the past shipped
111
+# snapshots of the future 0.8 from Git, and those snapshots did not
112
+# have updated version numbers (still referring to 0.7.0).
113
114
-if test "$libssh2" = "yes"; then
115
+if test "$libssh" = "yes"; then
116
cat > $TMPC <<EOF
117
-#include <stdio.h>
118
-#include <libssh2.h>
119
-#include <libssh2_sftp.h>
120
-int main(void) {
121
- LIBSSH2_SESSION *session;
122
- LIBSSH2_SFTP *sftp;
123
- LIBSSH2_SFTP_HANDLE *sftp_handle;
124
- session = libssh2_session_init ();
125
- sftp = libssh2_sftp_init (session);
126
- sftp_handle = libssh2_sftp_open (sftp, "/", 0, 0);
127
- libssh2_sftp_fsync (sftp_handle);
128
- return 0;
129
-}
130
+#include <libssh/libssh.h>
131
+int main(void) { return ssh_get_server_publickey(NULL, NULL); }
132
EOF
133
- # libssh2_cflags/libssh2_libs defined in previous test.
134
- if compile_prog "$libssh2_cflags" "$libssh2_libs" ; then
135
- QEMU_CFLAGS="-DHAS_LIBSSH2_SFTP_FSYNC $QEMU_CFLAGS"
136
+ if compile_prog "$libssh_cflags" "$libssh_libs"; then
137
+ libssh_cflags="-DHAVE_LIBSSH_0_8 $libssh_cflags"
138
fi
139
fi
140
141
@@ -XXX,XX +XXX,XX @@ echo "GlusterFS support $glusterfs"
142
echo "gcov $gcov_tool"
143
echo "gcov enabled $gcov"
144
echo "TPM support $tpm"
145
-echo "libssh2 support $libssh2"
146
+echo "libssh support $libssh"
147
echo "QOM debugging $qom_cast_debug"
148
echo "Live block migration $live_block_migration"
149
echo "lzo support $lzo"
150
@@ -XXX,XX +XXX,XX @@ if test "$glusterfs_iocb_has_stat" = "yes" ; then
151
echo "CONFIG_GLUSTERFS_IOCB_HAS_STAT=y" >> $config_host_mak
152
fi
153
154
-if test "$libssh2" = "yes" ; then
155
- echo "CONFIG_LIBSSH2=m" >> $config_host_mak
156
- echo "LIBSSH2_CFLAGS=$libssh2_cflags" >> $config_host_mak
157
- echo "LIBSSH2_LIBS=$libssh2_libs" >> $config_host_mak
158
+if test "$libssh" = "yes" ; then
159
+ echo "CONFIG_LIBSSH=m" >> $config_host_mak
160
+ echo "LIBSSH_CFLAGS=$libssh_cflags" >> $config_host_mak
161
+ echo "LIBSSH_LIBS=$libssh_libs" >> $config_host_mak
162
fi
163
164
if test "$live_block_migration" = "yes" ; then
165
diff --git a/block/Makefile.objs b/block/Makefile.objs
15
index XXXXXXX..XXXXXXX 100644
166
index XXXXXXX..XXXXXXX 100644
16
--- a/util/uri.c
167
--- a/block/Makefile.objs
17
+++ b/util/uri.c
168
+++ b/block/Makefile.objs
18
@@ -XXX,XX +XXX,XX @@ static void uri_clean(URI *uri);
169
@@ -XXX,XX +XXX,XX @@ block-obj-$(CONFIG_CURL) += curl.o
170
block-obj-$(CONFIG_RBD) += rbd.o
171
block-obj-$(CONFIG_GLUSTERFS) += gluster.o
172
block-obj-$(CONFIG_VXHS) += vxhs.o
173
-block-obj-$(CONFIG_LIBSSH2) += ssh.o
174
+block-obj-$(CONFIG_LIBSSH) += ssh.o
175
block-obj-y += accounting.o dirty-bitmap.o
176
block-obj-y += write-threshold.o
177
block-obj-y += backup.o
178
@@ -XXX,XX +XXX,XX @@ rbd.o-libs := $(RBD_LIBS)
179
gluster.o-cflags := $(GLUSTERFS_CFLAGS)
180
gluster.o-libs := $(GLUSTERFS_LIBS)
181
vxhs.o-libs := $(VXHS_LIBS)
182
-ssh.o-cflags := $(LIBSSH2_CFLAGS)
183
-ssh.o-libs := $(LIBSSH2_LIBS)
184
+ssh.o-cflags := $(LIBSSH_CFLAGS)
185
+ssh.o-libs := $(LIBSSH_LIBS)
186
block-obj-dmg-bz2-$(CONFIG_BZIP2) += dmg-bz2.o
187
block-obj-$(if $(CONFIG_DMG),m,n) += $(block-obj-dmg-bz2-y)
188
dmg-bz2.o-libs := $(BZIP2_LIBS)
189
diff --git a/block/ssh.c b/block/ssh.c
190
index XXXXXXX..XXXXXXX 100644
191
--- a/block/ssh.c
192
+++ b/block/ssh.c
193
@@ -XXX,XX +XXX,XX @@
194
195
#include "qemu/osdep.h"
196
197
-#include <libssh2.h>
198
-#include <libssh2_sftp.h>
199
+#include <libssh/libssh.h>
200
+#include <libssh/sftp.h>
201
202
#include "block/block_int.h"
203
#include "block/qdict.h"
204
@@ -XXX,XX +XXX,XX @@
205
#include "trace.h"
206
207
/*
208
- * TRACE_LIBSSH2=<bitmask> enables tracing in libssh2 itself. Note
209
- * that this requires that libssh2 was specially compiled with the
210
- * `./configure --enable-debug' option, so most likely you will have
211
- * to compile it yourself. The meaning of <bitmask> is described
212
- * here: http://www.libssh2.org/libssh2_trace.html
213
+ * TRACE_LIBSSH=<level> enables tracing in libssh itself.
214
+ * The meaning of <level> is described here:
215
+ * http://api.libssh.org/master/group__libssh__log.html
19
*/
216
*/
20
#define IS_ALPHA(x) (IS_LOWALPHA(x) || IS_UPALPHA(x))
217
-#define TRACE_LIBSSH2 0 /* or try: LIBSSH2_TRACE_SFTP */
21
218
+#define TRACE_LIBSSH 0 /* see: SSH_LOG_* */
219
220
typedef struct BDRVSSHState {
221
/* Coroutine. */
222
@@ -XXX,XX +XXX,XX @@ typedef struct BDRVSSHState {
223
224
/* SSH connection. */
225
int sock; /* socket */
226
- LIBSSH2_SESSION *session; /* ssh session */
227
- LIBSSH2_SFTP *sftp; /* sftp session */
228
- LIBSSH2_SFTP_HANDLE *sftp_handle; /* sftp remote file handle */
229
+ ssh_session session; /* ssh session */
230
+ sftp_session sftp; /* sftp session */
231
+ sftp_file sftp_handle; /* sftp remote file handle */
232
233
- /* See ssh_seek() function below. */
234
- int64_t offset;
235
- bool offset_op_read;
22
-
236
-
23
/*
237
- /* File attributes at open. We try to keep the .filesize field
24
* lowalpha = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" |
238
+ /*
25
* "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" |
239
+ * File attributes at open. We try to keep the .size field
26
@@ -XXX,XX +XXX,XX @@ static void uri_clean(URI *uri);
240
* updated if it changes (eg by writing at the end of the file).
27
* mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
241
*/
28
*/
242
- LIBSSH2_SFTP_ATTRIBUTES attrs;
29
243
+ sftp_attributes attrs;
30
-#define IS_MARK(x) (((x) == '-') || ((x) == '_') || ((x) == '.') || \
244
31
- ((x) == '!') || ((x) == '~') || ((x) == '*') || ((x) == '\'') || \
245
InetSocketAddress *inet;
32
+#define IS_MARK(x) (((x) == '-') || ((x) == '_') || ((x) == '.') || \
246
33
+ ((x) == '!') || ((x) == '~') || ((x) == '*') || ((x) == '\'') || \
247
@@ -XXX,XX +XXX,XX @@ static void ssh_state_init(BDRVSSHState *s)
34
((x) == '(') || ((x) == ')'))
248
{
35
249
memset(s, 0, sizeof *s);
36
/*
250
s->sock = -1;
37
* unwise = "{" | "}" | "|" | "\" | "^" | "`"
251
- s->offset = -1;
38
*/
252
qemu_co_mutex_init(&s->lock);
39
253
}
40
-#define IS_UNWISE(p) \
254
41
- (((*(p) == '{')) || ((*(p) == '}')) || ((*(p) == '|')) || \
255
@@ -XXX,XX +XXX,XX @@ static void ssh_state_free(BDRVSSHState *s)
42
- ((*(p) == '\\')) || ((*(p) == '^')) || ((*(p) == '[')) || \
256
{
43
- ((*(p) == ']')) || ((*(p) == '`')))
257
g_free(s->user);
44
+#define IS_UNWISE(p) \
258
45
+ (((*(p) == '{')) || ((*(p) == '}')) || ((*(p) == '|')) || \
259
+ if (s->attrs) {
46
+ ((*(p) == '\\')) || ((*(p) == '^')) || ((*(p) == '[')) || \
260
+ sftp_attributes_free(s->attrs);
47
+ ((*(p) == ']')) || ((*(p) == '`')))
261
+ }
48
/*
262
if (s->sftp_handle) {
49
* reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | "," |
263
- libssh2_sftp_close(s->sftp_handle);
50
* "[" | "]"
264
+ sftp_close(s->sftp_handle);
51
*/
265
}
52
266
if (s->sftp) {
53
-#define IS_RESERVED(x) (((x) == ';') || ((x) == '/') || ((x) == '?') || \
267
- libssh2_sftp_shutdown(s->sftp);
54
- ((x) == ':') || ((x) == '@') || ((x) == '&') || ((x) == '=') || \
268
+ sftp_free(s->sftp);
55
- ((x) == '+') || ((x) == '$') || ((x) == ',') || ((x) == '[') || \
269
}
56
- ((x) == ']'))
270
if (s->session) {
57
+#define IS_RESERVED(x) (((x) == ';') || ((x) == '/') || ((x) == '?') || \
271
- libssh2_session_disconnect(s->session,
58
+ ((x) == ':') || ((x) == '@') || ((x) == '&') || ((x) == '=') || \
272
- "from qemu ssh client: "
59
+ ((x) == '+') || ((x) == '$') || ((x) == ',') || ((x) == '[') || \
273
- "user closed the connection");
60
+ ((x) == ']'))
274
- libssh2_session_free(s->session);
61
275
- }
62
/*
276
- if (s->sock >= 0) {
63
* unreserved = alphanum | mark
277
- close(s->sock);
64
@@ -XXX,XX +XXX,XX @@ static void uri_clean(URI *uri);
278
+ ssh_disconnect(s->session);
65
* Skip to next pointer char, handle escaped sequences
279
+ ssh_free(s->session); /* This frees s->sock */
66
*/
280
}
67
281
}
68
-#define NEXT(p) ((*p == '%')? p += 3 : p++)
282
69
+#define NEXT(p) ((*p == '%') ? p += 3 : p++)
283
@@ -XXX,XX +XXX,XX @@ session_error_setg(Error **errp, BDRVSSHState *s, const char *fs, ...)
70
284
va_end(args);
71
/*
285
72
* Productions from the spec.
286
if (s->session) {
73
@@ -XXX,XX +XXX,XX @@ static void uri_clean(URI *uri);
287
- char *ssh_err;
74
* path = [ abs_path | opaque_part ]
288
+ const char *ssh_err;
75
*/
289
int ssh_err_code;
76
290
291
- /* This is not an errno. See <libssh2.h>. */
292
- ssh_err_code = libssh2_session_last_error(s->session,
293
- &ssh_err, NULL, 0);
294
- error_setg(errp, "%s: %s (libssh2 error code: %d)",
295
+ /* This is not an errno. See <libssh/libssh.h>. */
296
+ ssh_err = ssh_get_error(s->session);
297
+ ssh_err_code = ssh_get_error_code(s->session);
298
+ error_setg(errp, "%s: %s (libssh error code: %d)",
299
msg, ssh_err, ssh_err_code);
300
} else {
301
error_setg(errp, "%s", msg);
302
@@ -XXX,XX +XXX,XX @@ sftp_error_setg(Error **errp, BDRVSSHState *s, const char *fs, ...)
303
va_end(args);
304
305
if (s->sftp) {
306
- char *ssh_err;
307
+ const char *ssh_err;
308
int ssh_err_code;
309
- unsigned long sftp_err_code;
310
+ int sftp_err_code;
311
312
- /* This is not an errno. See <libssh2.h>. */
313
- ssh_err_code = libssh2_session_last_error(s->session,
314
- &ssh_err, NULL, 0);
315
- /* See <libssh2_sftp.h>. */
316
- sftp_err_code = libssh2_sftp_last_error((s)->sftp);
317
+ /* This is not an errno. See <libssh/libssh.h>. */
318
+ ssh_err = ssh_get_error(s->session);
319
+ ssh_err_code = ssh_get_error_code(s->session);
320
+ /* See <libssh/sftp.h>. */
321
+ sftp_err_code = sftp_get_error(s->sftp);
322
323
error_setg(errp,
324
- "%s: %s (libssh2 error code: %d, sftp error code: %lu)",
325
+ "%s: %s (libssh error code: %d, sftp error code: %d)",
326
msg, ssh_err, ssh_err_code, sftp_err_code);
327
} else {
328
error_setg(errp, "%s", msg);
329
@@ -XXX,XX +XXX,XX @@ sftp_error_setg(Error **errp, BDRVSSHState *s, const char *fs, ...)
330
331
static void sftp_error_trace(BDRVSSHState *s, const char *op)
332
{
333
- char *ssh_err;
334
+ const char *ssh_err;
335
int ssh_err_code;
336
- unsigned long sftp_err_code;
337
+ int sftp_err_code;
338
339
- /* This is not an errno. See <libssh2.h>. */
340
- ssh_err_code = libssh2_session_last_error(s->session,
341
- &ssh_err, NULL, 0);
342
- /* See <libssh2_sftp.h>. */
343
- sftp_err_code = libssh2_sftp_last_error((s)->sftp);
344
+ /* This is not an errno. See <libssh/libssh.h>. */
345
+ ssh_err = ssh_get_error(s->session);
346
+ ssh_err_code = ssh_get_error_code(s->session);
347
+ /* See <libssh/sftp.h>. */
348
+ sftp_err_code = sftp_get_error(s->sftp);
349
350
trace_sftp_error(op, ssh_err, ssh_err_code, sftp_err_code);
351
}
352
@@ -XXX,XX +XXX,XX @@ static void ssh_parse_filename(const char *filename, QDict *options,
353
parse_uri(filename, options, errp);
354
}
355
356
-static int check_host_key_knownhosts(BDRVSSHState *s,
357
- const char *host, int port, Error **errp)
358
+static int check_host_key_knownhosts(BDRVSSHState *s, Error **errp)
359
{
360
- const char *home;
361
- char *knh_file = NULL;
362
- LIBSSH2_KNOWNHOSTS *knh = NULL;
363
- struct libssh2_knownhost *found;
364
- int ret, r;
365
- const char *hostkey;
366
- size_t len;
367
- int type;
77
-
368
-
78
/************************************************************************
369
- hostkey = libssh2_session_hostkey(s->session, &len, &type);
79
- *                                    *
370
- if (!hostkey) {
80
- * RFC 3986 parser                *
371
+ int ret;
81
- *                                    *
372
+#ifdef HAVE_LIBSSH_0_8
82
+ * *
373
+ enum ssh_known_hosts_e state;
83
+ * RFC 3986 parser *
374
+ int r;
84
+ * *
375
+ ssh_key pubkey;
85
************************************************************************/
376
+ enum ssh_keytypes_e pubkey_type;
86
377
+ unsigned char *server_hash = NULL;
87
#define ISA_DIGIT(p) ((*(p) >= '0') && (*(p) <= '9'))
378
+ size_t server_hash_len;
88
-#define ISA_ALPHA(p) (((*(p) >= 'a') && (*(p) <= 'z')) ||        \
379
+ char *fingerprint = NULL;
89
+#define ISA_ALPHA(p) (((*(p) >= 'a') && (*(p) <= 'z')) || \
380
+
90
((*(p) >= 'A') && (*(p) <= 'Z')))
381
+ state = ssh_session_is_known_server(s->session);
91
-#define ISA_HEXDIG(p)                            \
382
+ trace_ssh_server_status(state);
92
- (ISA_DIGIT(p) || ((*(p) >= 'a') && (*(p) <= 'f')) ||        \
383
+
93
- ((*(p) >= 'A') && (*(p) <= 'F')))
384
+ switch (state) {
94
+#define ISA_HEXDIG(p) \
385
+ case SSH_KNOWN_HOSTS_OK:
95
+ (ISA_DIGIT(p) || ((*(p) >= 'a') && (*(p) <= 'f')) || \
386
+ /* OK */
96
+ ((*(p) >= 'A') && (*(p) <= 'F')))
387
+ trace_ssh_check_host_key_knownhosts();
97
388
+ break;
98
/*
389
+ case SSH_KNOWN_HOSTS_CHANGED:
99
* sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
390
ret = -EINVAL;
100
* / "*" / "+" / "," / ";" / "="
391
- session_error_setg(errp, s, "failed to read remote host key");
101
*/
392
+ r = ssh_get_server_publickey(s->session, &pubkey);
102
-#define ISA_SUB_DELIM(p)                        \
393
+ if (r == 0) {
103
- (((*(p) == '!')) || ((*(p) == '$')) || ((*(p) == '&')) ||        \
394
+ r = ssh_get_publickey_hash(pubkey, SSH_PUBLICKEY_HASH_SHA256,
104
- ((*(p) == '(')) || ((*(p) == ')')) || ((*(p) == '*')) ||        \
395
+ &server_hash, &server_hash_len);
105
- ((*(p) == '+')) || ((*(p) == ',')) || ((*(p) == ';')) ||        \
396
+ pubkey_type = ssh_key_type(pubkey);
106
- ((*(p) == '=')) || ((*(p) == '\'')))
397
+ ssh_key_free(pubkey);
107
+#define ISA_SUB_DELIM(p) \
398
+ }
108
+ (((*(p) == '!')) || ((*(p) == '$')) || ((*(p) == '&')) || \
399
+ if (r == 0) {
109
+ ((*(p) == '(')) || ((*(p) == ')')) || ((*(p) == '*')) || \
400
+ fingerprint = ssh_get_fingerprint_hash(SSH_PUBLICKEY_HASH_SHA256,
110
+ ((*(p) == '+')) || ((*(p) == ',')) || ((*(p) == ';')) || \
401
+ server_hash,
111
+ ((*(p) == '=')) || ((*(p) == '\'')))
402
+ server_hash_len);
112
403
+ ssh_clean_pubkey_hash(&server_hash);
113
/*
404
+ }
114
* gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
405
+ if (fingerprint) {
115
*/
406
+ error_setg(errp,
116
-#define ISA_GEN_DELIM(p)                        \
407
+ "host key (%s key with fingerprint %s) does not match "
117
- (((*(p) == ':')) || ((*(p) == '/')) || ((*(p) == '?')) || \
408
+ "the one in known_hosts; this may be a possible attack",
118
- ((*(p) == '#')) || ((*(p) == '[')) || ((*(p) == ']')) || \
409
+ ssh_key_type_to_char(pubkey_type), fingerprint);
119
- ((*(p) == '@')))
410
+ ssh_string_free_char(fingerprint);
120
+#define ISA_GEN_DELIM(p) \
411
+ } else {
121
+ (((*(p) == ':')) || ((*(p) == '/')) || ((*(p) == '?')) || \
412
+ error_setg(errp,
122
+ ((*(p) == '#')) || ((*(p) == '[')) || ((*(p) == ']')) || \
413
+ "host key does not match the one in known_hosts; this "
123
+ ((*(p) == '@')))
414
+ "may be a possible attack");
124
415
+ }
125
/*
416
goto out;
126
* reserved = gen-delims / sub-delims
417
- }
127
@@ -XXX,XX +XXX,XX @@ static void uri_clean(URI *uri);
418
-
128
/*
419
- knh = libssh2_knownhost_init(s->session);
129
* unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
420
- if (!knh) {
130
*/
421
+ case SSH_KNOWN_HOSTS_OTHER:
131
-#define ISA_UNRESERVED(p)                        \
422
ret = -EINVAL;
132
- ((ISA_ALPHA(p)) || (ISA_DIGIT(p)) || ((*(p) == '-')) ||        \
423
- session_error_setg(errp, s,
133
- ((*(p) == '.')) || ((*(p) == '_')) || ((*(p) == '~')))
424
- "failed to initialize known hosts support");
134
+#define ISA_UNRESERVED(p) \
425
+ error_setg(errp,
135
+ ((ISA_ALPHA(p)) || (ISA_DIGIT(p)) || ((*(p) == '-')) || \
426
+ "host key for this server not found, another type exists");
136
+ ((*(p) == '.')) || ((*(p) == '_')) || ((*(p) == '~')))
427
+ goto out;
137
428
+ case SSH_KNOWN_HOSTS_UNKNOWN:
138
/*
429
+ ret = -EINVAL;
139
* pct-encoded = "%" HEXDIG HEXDIG
430
+ error_setg(errp, "no host key was found in known_hosts");
140
*/
431
+ goto out;
141
-#define ISA_PCT_ENCODED(p)                        \
432
+ case SSH_KNOWN_HOSTS_NOT_FOUND:
142
- ((*(p) == '%') && (ISA_HEXDIG(p + 1)) && (ISA_HEXDIG(p + 2)))
433
+ ret = -ENOENT;
143
+#define ISA_PCT_ENCODED(p) \
434
+ error_setg(errp, "known_hosts file not found");
144
+ ((*(p) == '%') && (ISA_HEXDIG(p + 1)) && (ISA_HEXDIG(p + 2)))
435
+ goto out;
145
436
+ case SSH_KNOWN_HOSTS_ERROR:
146
/*
437
+ ret = -EINVAL;
147
* pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
438
+ error_setg(errp, "error while checking the host");
148
*/
439
+ goto out;
149
-#define ISA_PCHAR(p)                            \
440
+ default:
150
- (ISA_UNRESERVED(p) || ISA_PCT_ENCODED(p) || ISA_SUB_DELIM(p) ||    \
441
+ ret = -EINVAL;
151
- ((*(p) == ':')) || ((*(p) == '@')))
442
+ error_setg(errp, "error while checking for known server (%d)", state);
152
+#define ISA_PCHAR(p) \
443
goto out;
153
+ (ISA_UNRESERVED(p) || ISA_PCT_ENCODED(p) || ISA_SUB_DELIM(p) || \
444
}
154
+ ((*(p) == ':')) || ((*(p) == '@')))
445
+#else /* !HAVE_LIBSSH_0_8 */
155
446
+ int state;
156
/**
447
157
* rfc3986_parse_scheme:
448
- home = getenv("HOME");
158
@@ -XXX,XX +XXX,XX @@ static void uri_clean(URI *uri);
449
- if (home) {
159
*
450
- knh_file = g_strdup_printf("%s/.ssh/known_hosts", home);
160
* Returns 0 or the error code
451
- } else {
161
*/
452
- knh_file = g_strdup_printf("/root/.ssh/known_hosts");
162
-static int
453
- }
163
-rfc3986_parse_scheme(URI *uri, const char **str) {
454
-
164
+static int rfc3986_parse_scheme(URI *uri, const char **str)
455
- /* Read all known hosts from OpenSSH-style known_hosts file. */
165
+{
456
- libssh2_knownhost_readfile(knh, knh_file, LIBSSH2_KNOWNHOST_FILE_OPENSSH);
166
const char *cur;
457
+ state = ssh_is_server_known(s->session);
167
458
+ trace_ssh_server_status(state);
168
if (str == NULL)
459
169
-    return(-1);
460
- r = libssh2_knownhost_checkp(knh, host, port, hostkey, len,
170
+ return (-1);
461
- LIBSSH2_KNOWNHOST_TYPE_PLAIN|
171
462
- LIBSSH2_KNOWNHOST_KEYENC_RAW,
172
cur = *str;
463
- &found);
173
if (!ISA_ALPHA(cur))
464
- switch (r) {
174
-    return(2);
465
- case LIBSSH2_KNOWNHOST_CHECK_MATCH:
175
+ return (2);
466
+ switch (state) {
176
cur++;
467
+ case SSH_SERVER_KNOWN_OK:
177
- while (ISA_ALPHA(cur) || ISA_DIGIT(cur) ||
468
/* OK */
178
- (*cur == '+') || (*cur == '-') || (*cur == '.')) cur++;
469
- trace_ssh_check_host_key_knownhosts(found->key);
179
+ while (ISA_ALPHA(cur) || ISA_DIGIT(cur) || (*cur == '+') || (*cur == '-') ||
470
+ trace_ssh_check_host_key_knownhosts();
180
+ (*cur == '.'))
471
break;
181
+ cur++;
472
- case LIBSSH2_KNOWNHOST_CHECK_MISMATCH:
182
if (uri != NULL) {
473
+ case SSH_SERVER_KNOWN_CHANGED:
183
g_free(uri->scheme);
474
ret = -EINVAL;
184
-    uri->scheme = g_strndup(*str, cur - *str);
475
- session_error_setg(errp, s,
185
+ uri->scheme = g_strndup(*str, cur - *str);
476
- "host key does not match the one in known_hosts"
186
}
477
- " (found key %s)", found->key);
187
*str = cur;
478
+ error_setg(errp,
188
- return(0);
479
+ "host key does not match the one in known_hosts; this "
189
+ return (0);
480
+ "may be a possible attack");
481
goto out;
482
- case LIBSSH2_KNOWNHOST_CHECK_NOTFOUND:
483
+ case SSH_SERVER_FOUND_OTHER:
484
ret = -EINVAL;
485
- session_error_setg(errp, s, "no host key was found in known_hosts");
486
+ error_setg(errp,
487
+ "host key for this server not found, another type exists");
488
+ goto out;
489
+ case SSH_SERVER_FILE_NOT_FOUND:
490
+ ret = -ENOENT;
491
+ error_setg(errp, "known_hosts file not found");
492
goto out;
493
- case LIBSSH2_KNOWNHOST_CHECK_FAILURE:
494
+ case SSH_SERVER_NOT_KNOWN:
495
ret = -EINVAL;
496
- session_error_setg(errp, s,
497
- "failure matching the host key with known_hosts");
498
+ error_setg(errp, "no host key was found in known_hosts");
499
+ goto out;
500
+ case SSH_SERVER_ERROR:
501
+ ret = -EINVAL;
502
+ error_setg(errp, "server error");
503
goto out;
504
default:
505
ret = -EINVAL;
506
- session_error_setg(errp, s, "unknown error matching the host key"
507
- " with known_hosts (%d)", r);
508
+ error_setg(errp, "error while checking for known server (%d)", state);
509
goto out;
510
}
511
+#endif /* !HAVE_LIBSSH_0_8 */
512
513
/* known_hosts checking successful. */
514
ret = 0;
515
516
out:
517
- if (knh != NULL) {
518
- libssh2_knownhost_free(knh);
519
- }
520
- g_free(knh_file);
521
return ret;
190
}
522
}
191
523
192
/**
524
@@ -XXX,XX +XXX,XX @@ static int compare_fingerprint(const unsigned char *fingerprint, size_t len,
193
@@ -XXX,XX +XXX,XX @@ rfc3986_parse_scheme(URI *uri, const char **str) {
525
194
*
526
static int
195
* Returns 0 or the error code
527
check_host_key_hash(BDRVSSHState *s, const char *hash,
196
*/
528
- int hash_type, size_t fingerprint_len, Error **errp)
197
-static int
529
+ enum ssh_publickey_hash_type type, Error **errp)
198
-rfc3986_parse_fragment(URI *uri, const char **str)
199
+static int rfc3986_parse_fragment(URI *uri, const char **str)
200
{
530
{
201
const char *cur;
531
- const char *fingerprint;
202
203
@@ -XXX,XX +XXX,XX @@ rfc3986_parse_fragment(URI *uri, const char **str)
204
NEXT(cur);
205
if (uri != NULL) {
206
g_free(uri->fragment);
207
-    if (uri->cleanup & 2)
208
-     uri->fragment = g_strndup(*str, cur - *str);
209
-    else
210
-     uri->fragment = uri_string_unescape(*str, cur - *str, NULL);
211
+ if (uri->cleanup & 2)
212
+ uri->fragment = g_strndup(*str, cur - *str);
213
+ else
214
+ uri->fragment = uri_string_unescape(*str, cur - *str, NULL);
215
}
216
*str = cur;
217
return (0);
218
@@ -XXX,XX +XXX,XX @@ rfc3986_parse_fragment(URI *uri, const char **str)
219
*
220
* Returns 0 or the error code
221
*/
222
-static int
223
-rfc3986_parse_query(URI *uri, const char **str)
224
+static int rfc3986_parse_query(URI *uri, const char **str)
225
{
226
const char *cur;
227
228
@@ -XXX,XX +XXX,XX @@ rfc3986_parse_query(URI *uri, const char **str)
229
NEXT(cur);
230
if (uri != NULL) {
231
g_free(uri->query);
232
-    uri->query = g_strndup (*str, cur - *str);
233
+ uri->query = g_strndup(*str, cur - *str);
234
}
235
*str = cur;
236
return (0);
237
@@ -XXX,XX +XXX,XX @@ rfc3986_parse_query(URI *uri, const char **str)
238
*
239
* Returns 0 or the error code
240
*/
241
-static int
242
-rfc3986_parse_port(URI *uri, const char **str)
243
+static int rfc3986_parse_port(URI *uri, const char **str)
244
{
245
const char *cur = *str;
246
int port = 0;
247
@@ -XXX,XX +XXX,XX @@ rfc3986_parse_port(URI *uri, const char **str)
248
*
249
* Returns 0 or the error code
250
*/
251
-static int
252
-rfc3986_parse_user_info(URI *uri, const char **str)
253
+static int rfc3986_parse_user_info(URI *uri, const char **str)
254
{
255
const char *cur;
256
257
cur = *str;
258
- while (ISA_UNRESERVED(cur) || ISA_PCT_ENCODED(cur) ||
259
- ISA_SUB_DELIM(cur) || (*cur == ':'))
260
-    NEXT(cur);
261
+ while (ISA_UNRESERVED(cur) || ISA_PCT_ENCODED(cur) || ISA_SUB_DELIM(cur) ||
262
+ (*cur == ':'))
263
+ NEXT(cur);
264
if (*cur == '@') {
265
-    if (uri != NULL) {
266
+ if (uri != NULL) {
267
g_free(uri->user);
268
-     if (uri->cleanup & 2)
269
-        uri->user = g_strndup(*str, cur - *str);
270
-     else
271
-        uri->user = uri_string_unescape(*str, cur - *str, NULL);
272
-    }
273
-    *str = cur;
274
-    return(0);
275
+ if (uri->cleanup & 2)
276
+ uri->user = g_strndup(*str, cur - *str);
277
+ else
278
+ uri->user = uri_string_unescape(*str, cur - *str, NULL);
279
+ }
280
+ *str = cur;
281
+ return (0);
282
}
283
- return(1);
284
+ return (1);
285
}
286
287
/**
288
@@ -XXX,XX +XXX,XX @@ rfc3986_parse_user_info(URI *uri, const char **str)
289
*
290
* Returns 0 if found and skipped, 1 otherwise
291
*/
292
-static int
293
-rfc3986_parse_dec_octet(const char **str) {
294
+static int rfc3986_parse_dec_octet(const char **str)
295
+{
296
const char *cur = *str;
297
298
if (!(ISA_DIGIT(cur)))
299
- return(1);
300
- if (!ISA_DIGIT(cur+1))
301
-    cur++;
302
- else if ((*cur != '0') && (ISA_DIGIT(cur + 1)) && (!ISA_DIGIT(cur+2)))
303
-    cur += 2;
304
+ return (1);
305
+ if (!ISA_DIGIT(cur + 1))
306
+ cur++;
307
+ else if ((*cur != '0') && (ISA_DIGIT(cur + 1)) && (!ISA_DIGIT(cur + 2)))
308
+ cur += 2;
309
else if ((*cur == '1') && (ISA_DIGIT(cur + 1)) && (ISA_DIGIT(cur + 2)))
310
-    cur += 3;
311
- else if ((*cur == '2') && (*(cur + 1) >= '0') &&
312
-     (*(cur + 1) <= '4') && (ISA_DIGIT(cur + 2)))
313
-    cur += 3;
314
- else if ((*cur == '2') && (*(cur + 1) == '5') &&
315
-     (*(cur + 2) >= '0') && (*(cur + 1) <= '5'))
316
-    cur += 3;
317
+ cur += 3;
318
+ else if ((*cur == '2') && (*(cur + 1) >= '0') && (*(cur + 1) <= '4') &&
319
+ (ISA_DIGIT(cur + 2)))
320
+ cur += 3;
321
+ else if ((*cur == '2') && (*(cur + 1) == '5') && (*(cur + 2) >= '0') &&
322
+ (*(cur + 1) <= '5'))
323
+ cur += 3;
324
else
325
- return(1);
326
+ return (1);
327
*str = cur;
328
- return(0);
329
+ return (0);
330
}
331
/**
332
* rfc3986_parse_host:
333
@@ -XXX,XX +XXX,XX @@ rfc3986_parse_dec_octet(const char **str) {
334
*
335
* Returns 0 or the error code
336
*/
337
-static int
338
-rfc3986_parse_host(URI *uri, const char **str)
339
+static int rfc3986_parse_host(URI *uri, const char **str)
340
{
341
const char *cur = *str;
342
const char *host;
343
@@ -XXX,XX +XXX,XX @@ rfc3986_parse_host(URI *uri, const char **str)
344
*/
345
if (*cur == '[') {
346
cur++;
347
-    while ((*cur != ']') && (*cur != 0))
348
-     cur++;
349
-    if (*cur != ']')
350
-     return(1);
351
-    cur++;
352
-    goto found;
353
+ while ((*cur != ']') && (*cur != 0))
354
+ cur++;
355
+ if (*cur != ']')
356
+ return (1);
357
+ cur++;
358
+ goto found;
359
}
360
/*
361
* try to parse an IPv4
362
*/
363
if (ISA_DIGIT(cur)) {
364
if (rfc3986_parse_dec_octet(&cur) != 0)
365
-     goto not_ipv4;
366
-    if (*cur != '.')
367
-     goto not_ipv4;
368
-    cur++;
369
+ goto not_ipv4;
370
+ if (*cur != '.')
371
+ goto not_ipv4;
372
+ cur++;
373
if (rfc3986_parse_dec_octet(&cur) != 0)
374
-     goto not_ipv4;
375
-    if (*cur != '.')
376
-     goto not_ipv4;
377
+ goto not_ipv4;
378
+ if (*cur != '.')
379
+ goto not_ipv4;
380
if (rfc3986_parse_dec_octet(&cur) != 0)
381
-     goto not_ipv4;
382
-    if (*cur != '.')
383
-     goto not_ipv4;
384
+ goto not_ipv4;
385
+ if (*cur != '.')
386
+ goto not_ipv4;
387
if (rfc3986_parse_dec_octet(&cur) != 0)
388
-     goto not_ipv4;
389
-    goto found;
390
-not_ipv4:
391
+ goto not_ipv4;
392
+ goto found;
393
+ not_ipv4:
394
cur = *str;
395
}
396
/*
397
@@ -XXX,XX +XXX,XX @@ not_ipv4:
398
found:
399
if (uri != NULL) {
400
g_free(uri->authority);
401
-    uri->authority = NULL;
402
+ uri->authority = NULL;
403
g_free(uri->server);
404
-    if (cur != host) {
405
-     if (uri->cleanup & 2)
406
-        uri->server = g_strndup(host, cur - host);
407
-     else
408
-        uri->server = uri_string_unescape(host, cur - host, NULL);
409
-    } else
410
-     uri->server = NULL;
411
+ if (cur != host) {
412
+ if (uri->cleanup & 2)
413
+ uri->server = g_strndup(host, cur - host);
414
+ else
415
+ uri->server = uri_string_unescape(host, cur - host, NULL);
416
+ } else
417
+ uri->server = NULL;
418
}
419
*str = cur;
420
- return(0);
421
+ return (0);
422
}
423
424
/**
425
@@ -XXX,XX +XXX,XX @@ found:
426
*
427
* Returns 0 or the error code
428
*/
429
-static int
430
-rfc3986_parse_authority(URI *uri, const char **str)
431
+static int rfc3986_parse_authority(URI *uri, const char **str)
432
{
433
const char *cur;
434
int ret;
435
@@ -XXX,XX +XXX,XX @@ rfc3986_parse_authority(URI *uri, const char **str)
436
else
437
cur++;
438
ret = rfc3986_parse_host(uri, &cur);
439
- if (ret != 0) return(ret);
440
+ if (ret != 0)
441
+ return (ret);
442
if (*cur == ':') {
443
cur++;
444
ret = rfc3986_parse_port(uri, &cur);
445
-    if (ret != 0) return(ret);
446
+ if (ret != 0)
447
+ return (ret);
448
}
449
*str = cur;
450
- return(0);
451
+ return (0);
452
}
453
454
/**
455
@@ -XXX,XX +XXX,XX @@ rfc3986_parse_authority(URI *uri, const char **str)
456
*
457
* Returns 0 or the error code
458
*/
459
-static int
460
-rfc3986_parse_segment(const char **str, char forbid, int empty)
461
+static int rfc3986_parse_segment(const char **str, char forbid, int empty)
462
{
463
const char *cur;
464
465
cur = *str;
466
if (!ISA_PCHAR(cur)) {
467
if (empty)
468
-     return(0);
469
-    return(1);
470
+ return (0);
471
+ return (1);
472
}
473
while (ISA_PCHAR(cur) && (*cur != forbid))
474
NEXT(cur);
475
@@ -XXX,XX +XXX,XX @@ rfc3986_parse_segment(const char **str, char forbid, int empty)
476
*
477
* Returns 0 or the error code
478
*/
479
-static int
480
-rfc3986_parse_path_ab_empty(URI *uri, const char **str)
481
+static int rfc3986_parse_path_ab_empty(URI *uri, const char **str)
482
{
483
const char *cur;
484
int ret;
485
@@ -XXX,XX +XXX,XX @@ rfc3986_parse_path_ab_empty(URI *uri, const char **str)
486
487
while (*cur == '/') {
488
cur++;
489
-    ret = rfc3986_parse_segment(&cur, 0, 1);
490
-    if (ret != 0) return(ret);
491
+ ret = rfc3986_parse_segment(&cur, 0, 1);
492
+ if (ret != 0)
493
+ return (ret);
494
}
495
if (uri != NULL) {
496
g_free(uri->path);
497
@@ -XXX,XX +XXX,XX @@ rfc3986_parse_path_ab_empty(URI *uri, const char **str)
498
*
499
* Returns 0 or the error code
500
*/
501
-static int
502
-rfc3986_parse_path_absolute(URI *uri, const char **str)
503
+static int rfc3986_parse_path_absolute(URI *uri, const char **str)
504
{
505
const char *cur;
506
int ret;
507
@@ -XXX,XX +XXX,XX @@ rfc3986_parse_path_absolute(URI *uri, const char **str)
508
cur = *str;
509
510
if (*cur != '/')
511
- return(1);
512
+ return (1);
513
cur++;
514
ret = rfc3986_parse_segment(&cur, 0, 0);
515
if (ret == 0) {
516
-    while (*cur == '/') {
517
-     cur++;
518
-     ret = rfc3986_parse_segment(&cur, 0, 1);
519
-     if (ret != 0) return(ret);
520
-    }
521
+ while (*cur == '/') {
522
+ cur++;
523
+ ret = rfc3986_parse_segment(&cur, 0, 1);
524
+ if (ret != 0)
525
+ return (ret);
526
+ }
527
}
528
if (uri != NULL) {
529
g_free(uri->path);
530
@@ -XXX,XX +XXX,XX @@ rfc3986_parse_path_absolute(URI *uri, const char **str)
531
*
532
* Returns 0 or the error code
533
*/
534
-static int
535
-rfc3986_parse_path_rootless(URI *uri, const char **str)
536
+static int rfc3986_parse_path_rootless(URI *uri, const char **str)
537
{
538
const char *cur;
539
int ret;
540
@@ -XXX,XX +XXX,XX @@ rfc3986_parse_path_rootless(URI *uri, const char **str)
541
cur = *str;
542
543
ret = rfc3986_parse_segment(&cur, 0, 0);
544
- if (ret != 0) return(ret);
545
+ if (ret != 0)
546
+ return (ret);
547
while (*cur == '/') {
548
cur++;
549
-    ret = rfc3986_parse_segment(&cur, 0, 1);
550
-    if (ret != 0) return(ret);
551
+ ret = rfc3986_parse_segment(&cur, 0, 1);
552
+ if (ret != 0)
553
+ return (ret);
554
}
555
if (uri != NULL) {
556
g_free(uri->path);
557
@@ -XXX,XX +XXX,XX @@ rfc3986_parse_path_rootless(URI *uri, const char **str)
558
*
559
* Returns 0 or the error code
560
*/
561
-static int
562
-rfc3986_parse_path_no_scheme(URI *uri, const char **str)
563
+static int rfc3986_parse_path_no_scheme(URI *uri, const char **str)
564
{
565
const char *cur;
566
int ret;
567
@@ -XXX,XX +XXX,XX @@ rfc3986_parse_path_no_scheme(URI *uri, const char **str)
568
cur = *str;
569
570
ret = rfc3986_parse_segment(&cur, ':', 0);
571
- if (ret != 0) return(ret);
572
+ if (ret != 0)
573
+ return (ret);
574
while (*cur == '/') {
575
cur++;
576
-    ret = rfc3986_parse_segment(&cur, 0, 1);
577
-    if (ret != 0) return(ret);
578
+ ret = rfc3986_parse_segment(&cur, 0, 1);
579
+ if (ret != 0)
580
+ return (ret);
581
}
582
if (uri != NULL) {
583
g_free(uri->path);
584
@@ -XXX,XX +XXX,XX @@ rfc3986_parse_path_no_scheme(URI *uri, const char **str)
585
*
586
* Returns 0 or the error code
587
*/
588
-static int
589
-rfc3986_parse_hier_part(URI *uri, const char **str)
590
+static int rfc3986_parse_hier_part(URI *uri, const char **str)
591
{
592
const char *cur;
593
int ret;
594
@@ -XXX,XX +XXX,XX @@ rfc3986_parse_hier_part(URI *uri, const char **str)
595
596
if ((*cur == '/') && (*(cur + 1) == '/')) {
597
cur += 2;
598
-    ret = rfc3986_parse_authority(uri, &cur);
599
-    if (ret != 0) return(ret);
600
-    ret = rfc3986_parse_path_ab_empty(uri, &cur);
601
-    if (ret != 0) return(ret);
602
-    *str = cur;
603
-    return(0);
604
+ ret = rfc3986_parse_authority(uri, &cur);
605
+ if (ret != 0)
606
+ return (ret);
607
+ ret = rfc3986_parse_path_ab_empty(uri, &cur);
608
+ if (ret != 0)
609
+ return (ret);
610
+ *str = cur;
611
+ return (0);
612
} else if (*cur == '/') {
613
ret = rfc3986_parse_path_absolute(uri, &cur);
614
-    if (ret != 0) return(ret);
615
+ if (ret != 0)
616
+ return (ret);
617
} else if (ISA_PCHAR(cur)) {
618
ret = rfc3986_parse_path_rootless(uri, &cur);
619
-    if (ret != 0) return(ret);
620
+ if (ret != 0)
621
+ return (ret);
622
} else {
623
-    /* path-empty is effectively empty */
624
-    if (uri != NULL) {
625
+ /* path-empty is effectively empty */
626
+ if (uri != NULL) {
627
g_free(uri->path);
628
-     uri->path = NULL;
629
-    }
630
+ uri->path = NULL;
631
+ }
632
}
633
*str = cur;
634
return (0);
635
@@ -XXX,XX +XXX,XX @@ rfc3986_parse_hier_part(URI *uri, const char **str)
636
*
637
* Returns 0 or the error code
638
*/
639
-static int
640
-rfc3986_parse_relative_ref(URI *uri, const char *str) {
641
+static int rfc3986_parse_relative_ref(URI *uri, const char *str)
642
+{
643
int ret;
644
645
if ((*str == '/') && (*(str + 1) == '/')) {
646
str += 2;
647
-    ret = rfc3986_parse_authority(uri, &str);
648
-    if (ret != 0) return(ret);
649
-    ret = rfc3986_parse_path_ab_empty(uri, &str);
650
-    if (ret != 0) return(ret);
651
+ ret = rfc3986_parse_authority(uri, &str);
652
+ if (ret != 0)
653
+ return (ret);
654
+ ret = rfc3986_parse_path_ab_empty(uri, &str);
655
+ if (ret != 0)
656
+ return (ret);
657
} else if (*str == '/') {
658
-    ret = rfc3986_parse_path_absolute(uri, &str);
659
-    if (ret != 0) return(ret);
660
+ ret = rfc3986_parse_path_absolute(uri, &str);
661
+ if (ret != 0)
662
+ return (ret);
663
} else if (ISA_PCHAR(str)) {
664
ret = rfc3986_parse_path_no_scheme(uri, &str);
665
-    if (ret != 0) return(ret);
666
+ if (ret != 0)
667
+ return (ret);
668
} else {
669
-    /* path-empty is effectively empty */
670
-    if (uri != NULL) {
671
+ /* path-empty is effectively empty */
672
+ if (uri != NULL) {
673
g_free(uri->path);
674
-     uri->path = NULL;
675
-    }
676
+ uri->path = NULL;
677
+ }
678
}
679
680
if (*str == '?') {
681
-    str++;
682
-    ret = rfc3986_parse_query(uri, &str);
683
-    if (ret != 0) return(ret);
684
+ str++;
685
+ ret = rfc3986_parse_query(uri, &str);
686
+ if (ret != 0)
687
+ return (ret);
688
}
689
if (*str == '#') {
690
-    str++;
691
-    ret = rfc3986_parse_fragment(uri, &str);
692
-    if (ret != 0) return(ret);
693
+ str++;
694
+ ret = rfc3986_parse_fragment(uri, &str);
695
+ if (ret != 0)
696
+ return (ret);
697
}
698
if (*str != 0) {
699
-    uri_clean(uri);
700
-    return(1);
701
+ uri_clean(uri);
702
+ return (1);
703
}
704
- return(0);
705
+ return (0);
706
}
707
708
-
532
-
709
/**
533
- fingerprint = libssh2_hostkey_hash(s->session, hash_type);
710
* rfc3986_parse:
534
- if (!fingerprint) {
711
* @uri: pointer to an URI structure
535
+ int r;
712
@@ -XXX,XX +XXX,XX @@ rfc3986_parse_relative_ref(URI *uri, const char *str) {
536
+ ssh_key pubkey;
713
*
537
+ unsigned char *server_hash;
714
* Returns 0 or the error code
538
+ size_t server_hash_len;
715
*/
539
+
716
-static int
540
+#ifdef HAVE_LIBSSH_0_8
717
-rfc3986_parse(URI *uri, const char *str) {
541
+ r = ssh_get_server_publickey(s->session, &pubkey);
718
+static int rfc3986_parse(URI *uri, const char *str)
542
+#else
719
+{
543
+ r = ssh_get_publickey(s->session, &pubkey);
720
int ret;
544
+#endif
721
545
+ if (r != SSH_OK) {
722
ret = rfc3986_parse_scheme(uri, &str);
546
session_error_setg(errp, s, "failed to read remote host key");
723
- if (ret != 0) return(ret);
547
return -EINVAL;
724
+ if (ret != 0)
548
}
725
+ return (ret);
549
726
if (*str != ':') {
550
- if(compare_fingerprint((unsigned char *) fingerprint, fingerprint_len,
727
-    return(1);
551
- hash) != 0) {
728
+ return (1);
552
+ r = ssh_get_publickey_hash(pubkey, type, &server_hash, &server_hash_len);
729
}
553
+ ssh_key_free(pubkey);
730
str++;
554
+ if (r != 0) {
731
ret = rfc3986_parse_hier_part(uri, &str);
555
+ session_error_setg(errp, s,
732
- if (ret != 0) return(ret);
556
+ "failed reading the hash of the server SSH key");
733
+ if (ret != 0)
557
+ return -EINVAL;
734
+ return (ret);
558
+ }
735
if (*str == '?') {
559
+
736
-    str++;
560
+ r = compare_fingerprint(server_hash, server_hash_len, hash);
737
-    ret = rfc3986_parse_query(uri, &str);
561
+ ssh_clean_pubkey_hash(&server_hash);
738
-    if (ret != 0) return(ret);
562
+ if (r != 0) {
739
+ str++;
563
error_setg(errp, "remote host key does not match host_key_check '%s'",
740
+ ret = rfc3986_parse_query(uri, &str);
564
hash);
741
+ if (ret != 0)
565
return -EPERM;
742
+ return (ret);
566
@@ -XXX,XX +XXX,XX @@ check_host_key_hash(BDRVSSHState *s, const char *hash,
743
}
744
if (*str == '#') {
745
-    str++;
746
-    ret = rfc3986_parse_fragment(uri, &str);
747
-    if (ret != 0) return(ret);
748
+ str++;
749
+ ret = rfc3986_parse_fragment(uri, &str);
750
+ if (ret != 0)
751
+ return (ret);
752
}
753
if (*str != 0) {
754
-    uri_clean(uri);
755
-    return(1);
756
+ uri_clean(uri);
757
+ return (1);
758
}
759
- return(0);
760
+ return (0);
761
}
762
763
/**
764
@@ -XXX,XX +XXX,XX @@ rfc3986_parse(URI *uri, const char *str) {
765
*
766
* Returns 0 or the error code
767
*/
768
-static int
769
-rfc3986_parse_uri_reference(URI *uri, const char *str) {
770
+static int rfc3986_parse_uri_reference(URI *uri, const char *str)
771
+{
772
int ret;
773
774
if (str == NULL)
775
-    return(-1);
776
+ return (-1);
777
uri_clean(uri);
778
779
/*
780
@@ -XXX,XX +XXX,XX @@ rfc3986_parse_uri_reference(URI *uri, const char *str) {
781
*/
782
ret = rfc3986_parse(uri, str);
783
if (ret != 0) {
784
-    uri_clean(uri);
785
+ uri_clean(uri);
786
ret = rfc3986_parse_relative_ref(uri, str);
787
-    if (ret != 0) {
788
-     uri_clean(uri);
789
-     return(ret);
790
-    }
791
+ if (ret != 0) {
792
+ uri_clean(uri);
793
+ return (ret);
794
+ }
795
}
796
- return(0);
797
+ return (0);
798
}
799
800
/**
801
@@ -XXX,XX +XXX,XX @@ rfc3986_parse_uri_reference(URI *uri, const char *str) {
802
*
803
* Returns a newly built URI or NULL in case of error
804
*/
805
-URI *
806
-uri_parse(const char *str) {
807
+URI *uri_parse(const char *str)
808
+{
809
URI *uri;
810
int ret;
811
812
if (str == NULL)
813
-    return(NULL);
814
+ return (NULL);
815
uri = uri_new();
816
ret = rfc3986_parse_uri_reference(uri, str);
817
if (ret) {
818
uri_free(uri);
819
- return(NULL);
820
+ return (NULL);
821
}
822
- return(uri);
823
+ return (uri);
824
}
825
826
/**
827
@@ -XXX,XX +XXX,XX @@ uri_parse(const char *str) {
828
*
829
* Returns 0 or the error code
830
*/
831
-int
832
-uri_parse_into(URI *uri, const char *str) {
833
- return(rfc3986_parse_uri_reference(uri, str));
834
+int uri_parse_into(URI *uri, const char *str)
835
+{
836
+ return (rfc3986_parse_uri_reference(uri, str));
837
}
838
839
/**
840
@@ -XXX,XX +XXX,XX @@ uri_parse_into(URI *uri, const char *str) {
841
*
842
* Returns a newly built URI or NULL in case of error
843
*/
844
-URI *
845
-uri_parse_raw(const char *str, int raw) {
846
+URI *uri_parse_raw(const char *str, int raw)
847
+{
848
URI *uri;
849
int ret;
850
851
if (str == NULL)
852
-    return(NULL);
853
+ return (NULL);
854
uri = uri_new();
855
if (raw) {
856
uri->cleanup |= 2;
857
@@ -XXX,XX +XXX,XX @@ uri_parse_raw(const char *str, int raw) {
858
ret = uri_parse_into(uri, str);
859
if (ret) {
860
uri_free(uri);
861
- return(NULL);
862
+ return (NULL);
863
}
864
- return(uri);
865
+ return (uri);
866
}
867
868
/************************************************************************
869
- *                                    *
870
- *            Generic URI structure functions            *
871
- *                                    *
872
+ * *
873
+ * Generic URI structure functions *
874
+ * *
875
************************************************************************/
876
877
/**
878
@@ -XXX,XX +XXX,XX @@ uri_parse_raw(const char *str, int raw) {
879
*
880
* Returns the new structure or NULL in case of error
881
*/
882
-URI *
883
-uri_new(void) {
884
+URI *uri_new(void)
885
+{
886
URI *ret;
887
888
ret = g_new0(URI, 1);
889
- return(ret);
890
+ return (ret);
891
}
892
893
/**
894
@@ -XXX,XX +XXX,XX @@ uri_new(void) {
895
* Function to handle properly a reallocation when saving an URI
896
* Also imposes some limit on the length of an URI string output
897
*/
898
-static char *
899
-realloc2n(char *ret, int *max) {
900
+static char *realloc2n(char *ret, int *max)
901
+{
902
char *temp;
903
int tmp;
904
905
tmp = *max * 2;
906
temp = g_realloc(ret, (tmp + 1));
907
*max = tmp;
908
- return(temp);
909
+ return (temp);
910
}
911
912
/**
913
@@ -XXX,XX +XXX,XX @@ realloc2n(char *ret, int *max) {
914
*
915
* Returns a new string (to be deallocated by caller)
916
*/
917
-char *
918
-uri_to_string(URI *uri) {
919
+char *uri_to_string(URI *uri)
920
+{
921
char *ret = NULL;
922
char *temp;
923
const char *p;
924
int len;
925
int max;
926
927
- if (uri == NULL) return(NULL);
928
-
929
+ if (uri == NULL)
930
+ return (NULL);
931
932
max = 80;
933
ret = g_malloc(max + 1);
934
len = 0;
935
936
if (uri->scheme != NULL) {
937
-    p = uri->scheme;
938
-    while (*p != 0) {
939
-     if (len >= max) {
940
+ p = uri->scheme;
941
+ while (*p != 0) {
942
+ if (len >= max) {
943
temp = realloc2n(ret, &max);
944
-        ret = temp;
945
-     }
946
-     ret[len++] = *p++;
947
-    }
948
-    if (len >= max) {
949
+ ret = temp;
950
+ }
951
+ ret[len++] = *p++;
952
+ }
953
+ if (len >= max) {
954
temp = realloc2n(ret, &max);
955
ret = temp;
956
-    }
957
-    ret[len++] = ':';
958
+ }
959
+ ret[len++] = ':';
960
}
961
if (uri->opaque != NULL) {
962
-    p = uri->opaque;
963
-    while (*p != 0) {
964
-     if (len + 3 >= max) {
965
+ p = uri->opaque;
966
+ while (*p != 0) {
967
+ if (len + 3 >= max) {
968
temp = realloc2n(ret, &max);
969
ret = temp;
970
-     }
971
-     if (IS_RESERVED(*(p)) || IS_UNRESERVED(*(p)))
972
-        ret[len++] = *p++;
973
-     else {
974
-        int val = *(unsigned char *)p++;
975
-        int hi = val / 0x10, lo = val % 0x10;
976
-        ret[len++] = '%';
977
-        ret[len++] = hi + (hi > 9? 'A'-10 : '0');
978
-        ret[len++] = lo + (lo > 9? 'A'-10 : '0');
979
-     }
980
-    }
981
+ }
982
+ if (IS_RESERVED(*(p)) || IS_UNRESERVED(*(p)))
983
+ ret[len++] = *p++;
984
+ else {
985
+ int val = *(unsigned char *)p++;
986
+ int hi = val / 0x10, lo = val % 0x10;
987
+ ret[len++] = '%';
988
+ ret[len++] = hi + (hi > 9 ? 'A' - 10 : '0');
989
+ ret[len++] = lo + (lo > 9 ? 'A' - 10 : '0');
990
+ }
991
+ }
992
} else {
993
-    if (uri->server != NULL) {
994
-     if (len + 3 >= max) {
995
+ if (uri->server != NULL) {
996
+ if (len + 3 >= max) {
997
temp = realloc2n(ret, &max);
998
ret = temp;
999
-     }
1000
-     ret[len++] = '/';
1001
-     ret[len++] = '/';
1002
-     if (uri->user != NULL) {
1003
-        p = uri->user;
1004
-        while (*p != 0) {
1005
-         if (len + 3 >= max) {
1006
+ }
1007
+ ret[len++] = '/';
1008
+ ret[len++] = '/';
1009
+ if (uri->user != NULL) {
1010
+ p = uri->user;
1011
+ while (*p != 0) {
1012
+ if (len + 3 >= max) {
1013
temp = realloc2n(ret, &max);
1014
ret = temp;
1015
-         }
1016
-         if ((IS_UNRESERVED(*(p))) ||
1017
-            ((*(p) == ';')) || ((*(p) == ':')) ||
1018
-            ((*(p) == '&')) || ((*(p) == '=')) ||
1019
-            ((*(p) == '+')) || ((*(p) == '$')) ||
1020
-            ((*(p) == ',')))
1021
-            ret[len++] = *p++;
1022
-         else {
1023
-            int val = *(unsigned char *)p++;
1024
-            int hi = val / 0x10, lo = val % 0x10;
1025
-            ret[len++] = '%';
1026
-            ret[len++] = hi + (hi > 9? 'A'-10 : '0');
1027
-            ret[len++] = lo + (lo > 9? 'A'-10 : '0');
1028
-         }
1029
-        }
1030
-        if (len + 3 >= max) {
1031
+ }
1032
+ if ((IS_UNRESERVED(*(p))) || ((*(p) == ';')) ||
1033
+ ((*(p) == ':')) || ((*(p) == '&')) || ((*(p) == '=')) ||
1034
+ ((*(p) == '+')) || ((*(p) == '$')) || ((*(p) == ',')))
1035
+ ret[len++] = *p++;
1036
+ else {
1037
+ int val = *(unsigned char *)p++;
1038
+ int hi = val / 0x10, lo = val % 0x10;
1039
+ ret[len++] = '%';
1040
+ ret[len++] = hi + (hi > 9 ? 'A' - 10 : '0');
1041
+ ret[len++] = lo + (lo > 9 ? 'A' - 10 : '0');
1042
+ }
1043
+ }
1044
+ if (len + 3 >= max) {
1045
temp = realloc2n(ret, &max);
1046
ret = temp;
1047
-        }
1048
-        ret[len++] = '@';
1049
-     }
1050
-     p = uri->server;
1051
-     while (*p != 0) {
1052
-        if (len >= max) {
1053
+ }
1054
+ ret[len++] = '@';
1055
+ }
1056
+ p = uri->server;
1057
+ while (*p != 0) {
1058
+ if (len >= max) {
1059
temp = realloc2n(ret, &max);
1060
ret = temp;
1061
-        }
1062
-        ret[len++] = *p++;
1063
-     }
1064
-     if (uri->port > 0) {
1065
-        if (len + 10 >= max) {
1066
+ }
1067
+ ret[len++] = *p++;
1068
+ }
1069
+ if (uri->port > 0) {
1070
+ if (len + 10 >= max) {
1071
temp = realloc2n(ret, &max);
1072
ret = temp;
1073
-        }
1074
-        len += snprintf(&ret[len], max - len, ":%d", uri->port);
1075
-     }
1076
-    } else if (uri->authority != NULL) {
1077
-     if (len + 3 >= max) {
1078
+ }
1079
+ len += snprintf(&ret[len], max - len, ":%d", uri->port);
1080
+ }
1081
+ } else if (uri->authority != NULL) {
1082
+ if (len + 3 >= max) {
1083
temp = realloc2n(ret, &max);
1084
ret = temp;
1085
-     }
1086
-     ret[len++] = '/';
1087
-     ret[len++] = '/';
1088
-     p = uri->authority;
1089
-     while (*p != 0) {
1090
-        if (len + 3 >= max) {
1091
+ }
1092
+ ret[len++] = '/';
1093
+ ret[len++] = '/';
1094
+ p = uri->authority;
1095
+ while (*p != 0) {
1096
+ if (len + 3 >= max) {
1097
temp = realloc2n(ret, &max);
1098
ret = temp;
1099
-        }
1100
-        if ((IS_UNRESERVED(*(p))) ||
1101
- ((*(p) == '$')) || ((*(p) == ',')) || ((*(p) == ';')) ||
1102
- ((*(p) == ':')) || ((*(p) == '@')) || ((*(p) == '&')) ||
1103
- ((*(p) == '=')) || ((*(p) == '+')))
1104
-         ret[len++] = *p++;
1105
-        else {
1106
-         int val = *(unsigned char *)p++;
1107
-         int hi = val / 0x10, lo = val % 0x10;
1108
-         ret[len++] = '%';
1109
-         ret[len++] = hi + (hi > 9? 'A'-10 : '0');
1110
-         ret[len++] = lo + (lo > 9? 'A'-10 : '0');
1111
-        }
1112
-     }
1113
-    } else if (uri->scheme != NULL) {
1114
-     if (len + 3 >= max) {
1115
+ }
1116
+ if ((IS_UNRESERVED(*(p))) || ((*(p) == '$')) ||
1117
+ ((*(p) == ',')) || ((*(p) == ';')) || ((*(p) == ':')) ||
1118
+ ((*(p) == '@')) || ((*(p) == '&')) || ((*(p) == '=')) ||
1119
+ ((*(p) == '+')))
1120
+ ret[len++] = *p++;
1121
+ else {
1122
+ int val = *(unsigned char *)p++;
1123
+ int hi = val / 0x10, lo = val % 0x10;
1124
+ ret[len++] = '%';
1125
+ ret[len++] = hi + (hi > 9 ? 'A' - 10 : '0');
1126
+ ret[len++] = lo + (lo > 9 ? 'A' - 10 : '0');
1127
+ }
1128
+ }
1129
+ } else if (uri->scheme != NULL) {
1130
+ if (len + 3 >= max) {
1131
temp = realloc2n(ret, &max);
1132
ret = temp;
1133
-     }
1134
-     ret[len++] = '/';
1135
-     ret[len++] = '/';
1136
-    }
1137
-    if (uri->path != NULL) {
1138
-     p = uri->path;
1139
-     /*
1140
-     * the colon in file:///d: should not be escaped or
1141
-     * Windows accesses fail later.
1142
-     */
1143
-     if ((uri->scheme != NULL) &&
1144
-        (p[0] == '/') &&
1145
-        (((p[1] >= 'a') && (p[1] <= 'z')) ||
1146
-         ((p[1] >= 'A') && (p[1] <= 'Z'))) &&
1147
-        (p[2] == ':') &&
1148
-     (!strcmp(uri->scheme, "file"))) {
1149
-        if (len + 3 >= max) {
1150
+ }
1151
+ ret[len++] = '/';
1152
+ ret[len++] = '/';
1153
+ }
1154
+ if (uri->path != NULL) {
1155
+ p = uri->path;
1156
+ /*
1157
+ * the colon in file:///d: should not be escaped or
1158
+ * Windows accesses fail later.
1159
+ */
1160
+ if ((uri->scheme != NULL) && (p[0] == '/') &&
1161
+ (((p[1] >= 'a') && (p[1] <= 'z')) ||
1162
+ ((p[1] >= 'A') && (p[1] <= 'Z'))) &&
1163
+ (p[2] == ':') && (!strcmp(uri->scheme, "file"))) {
1164
+ if (len + 3 >= max) {
1165
temp = realloc2n(ret, &max);
1166
ret = temp;
1167
-        }
1168
-        ret[len++] = *p++;
1169
-        ret[len++] = *p++;
1170
-        ret[len++] = *p++;
1171
-     }
1172
-     while (*p != 0) {
1173
-        if (len + 3 >= max) {
1174
+ }
1175
+ ret[len++] = *p++;
1176
+ ret[len++] = *p++;
1177
+ ret[len++] = *p++;
1178
+ }
1179
+ while (*p != 0) {
1180
+ if (len + 3 >= max) {
1181
temp = realloc2n(ret, &max);
1182
ret = temp;
1183
-        }
1184
-        if ((IS_UNRESERVED(*(p))) || ((*(p) == '/')) ||
1185
+ }
1186
+ if ((IS_UNRESERVED(*(p))) || ((*(p) == '/')) ||
1187
((*(p) == ';')) || ((*(p) == '@')) || ((*(p) == '&')) ||
1188
-     ((*(p) == '=')) || ((*(p) == '+')) || ((*(p) == '$')) ||
1189
-     ((*(p) == ',')))
1190
-         ret[len++] = *p++;
1191
-        else {
1192
-         int val = *(unsigned char *)p++;
1193
-         int hi = val / 0x10, lo = val % 0x10;
1194
-         ret[len++] = '%';
1195
-         ret[len++] = hi + (hi > 9? 'A'-10 : '0');
1196
-         ret[len++] = lo + (lo > 9? 'A'-10 : '0');
1197
-        }
1198
-     }
1199
-    }
1200
-    if (uri->query != NULL) {
1201
-     if (len + 1 >= max) {
1202
+ ((*(p) == '=')) || ((*(p) == '+')) || ((*(p) == '$')) ||
1203
+ ((*(p) == ',')))
1204
+ ret[len++] = *p++;
1205
+ else {
1206
+ int val = *(unsigned char *)p++;
1207
+ int hi = val / 0x10, lo = val % 0x10;
1208
+ ret[len++] = '%';
1209
+ ret[len++] = hi + (hi > 9 ? 'A' - 10 : '0');
1210
+ ret[len++] = lo + (lo > 9 ? 'A' - 10 : '0');
1211
+ }
1212
+ }
1213
+ }
1214
+ if (uri->query != NULL) {
1215
+ if (len + 1 >= max) {
1216
temp = realloc2n(ret, &max);
1217
ret = temp;
1218
-     }
1219
-     ret[len++] = '?';
1220
-     p = uri->query;
1221
-     while (*p != 0) {
1222
-        if (len + 1 >= max) {
1223
+ }
1224
+ ret[len++] = '?';
1225
+ p = uri->query;
1226
+ while (*p != 0) {
1227
+ if (len + 1 >= max) {
1228
temp = realloc2n(ret, &max);
1229
ret = temp;
1230
-        }
1231
-        ret[len++] = *p++;
1232
-     }
1233
-    }
1234
+ }
1235
+ ret[len++] = *p++;
1236
+ }
1237
+ }
1238
}
1239
if (uri->fragment != NULL) {
1240
-    if (len + 3 >= max) {
1241
+ if (len + 3 >= max) {
1242
temp = realloc2n(ret, &max);
1243
ret = temp;
1244
-    }
1245
-    ret[len++] = '#';
1246
-    p = uri->fragment;
1247
-    while (*p != 0) {
1248
-     if (len + 3 >= max) {
1249
+ }
1250
+ ret[len++] = '#';
1251
+ p = uri->fragment;
1252
+ while (*p != 0) {
1253
+ if (len + 3 >= max) {
1254
temp = realloc2n(ret, &max);
1255
ret = temp;
1256
-     }
1257
-     if ((IS_UNRESERVED(*(p))) || (IS_RESERVED(*(p))))
1258
-        ret[len++] = *p++;
1259
-     else {
1260
-        int val = *(unsigned char *)p++;
1261
-        int hi = val / 0x10, lo = val % 0x10;
1262
-        ret[len++] = '%';
1263
-        ret[len++] = hi + (hi > 9? 'A'-10 : '0');
1264
-        ret[len++] = lo + (lo > 9? 'A'-10 : '0');
1265
-     }
1266
-    }
1267
+ }
1268
+ if ((IS_UNRESERVED(*(p))) || (IS_RESERVED(*(p))))
1269
+ ret[len++] = *p++;
1270
+ else {
1271
+ int val = *(unsigned char *)p++;
1272
+ int hi = val / 0x10, lo = val % 0x10;
1273
+ ret[len++] = '%';
1274
+ ret[len++] = hi + (hi > 9 ? 'A' - 10 : '0');
1275
+ ret[len++] = lo + (lo > 9 ? 'A' - 10 : '0');
1276
+ }
1277
+ }
1278
}
1279
if (len >= max) {
1280
temp = realloc2n(ret, &max);
1281
ret = temp;
1282
}
1283
ret[len] = 0;
1284
- return(ret);
1285
+ return (ret);
1286
}
1287
1288
/**
1289
@@ -XXX,XX +XXX,XX @@ uri_to_string(URI *uri) {
1290
*
1291
* Make sure the URI struct is free of content
1292
*/
1293
-static void
1294
-uri_clean(URI *uri) {
1295
- if (uri == NULL) return;
1296
+static void uri_clean(URI *uri)
1297
+{
1298
+ if (uri == NULL)
1299
+ return;
1300
1301
g_free(uri->scheme);
1302
uri->scheme = NULL;
1303
@@ -XXX,XX +XXX,XX @@ uri_clean(URI *uri) {
1304
*
1305
* Free up the URI struct
1306
*/
1307
-void
1308
-uri_free(URI *uri) {
1309
+void uri_free(URI *uri)
1310
+{
1311
uri_clean(uri);
1312
g_free(uri);
1313
}
1314
1315
/************************************************************************
1316
- *                                    *
1317
- *            Helper functions                *
1318
- *                                    *
1319
+ * *
1320
+ * Helper functions *
1321
+ * *
1322
************************************************************************/
1323
1324
/**
1325
@@ -XXX,XX +XXX,XX @@ uri_free(URI *uri) {
1326
*
1327
* Returns 0 or an error code
1328
*/
1329
-static int
1330
-normalize_uri_path(char *path) {
1331
+static int normalize_uri_path(char *path)
1332
+{
1333
char *cur, *out;
1334
1335
if (path == NULL)
1336
-    return(-1);
1337
+ return (-1);
1338
1339
/* Skip all initial "/" chars. We want to get to the beginning of the
1340
* first non-empty segment.
1341
*/
1342
cur = path;
1343
while (cur[0] == '/')
1344
- ++cur;
1345
+ ++cur;
1346
if (cur[0] == '\0')
1347
- return(0);
1348
+ return (0);
1349
1350
/* Keep everything we've seen so far. */
1351
out = cur;
1352
@@ -XXX,XX +XXX,XX @@ normalize_uri_path(char *path) {
1353
* Analyze each segment in sequence for cases (c) and (d).
1354
*/
1355
while (cur[0] != '\0') {
1356
-    /*
1357
-     * c) All occurrences of "./", where "." is a complete path segment,
1358
-     * are removed from the buffer string.
1359
-     */
1360
-    if ((cur[0] == '.') && (cur[1] == '/')) {
1361
-     cur += 2;
1362
-     /* '//' normalization should be done at this point too */
1363
-     while (cur[0] == '/')
1364
-        cur++;
1365
-     continue;
1366
-    }
1367
+ /*
1368
+ * c) All occurrences of "./", where "." is a complete path segment,
1369
+ * are removed from the buffer string.
1370
+ */
1371
+ if ((cur[0] == '.') && (cur[1] == '/')) {
1372
+ cur += 2;
1373
+ /* '//' normalization should be done at this point too */
1374
+ while (cur[0] == '/')
1375
+ cur++;
1376
+ continue;
1377
+ }
1378
1379
-    /*
1380
-     * d) If the buffer string ends with "." as a complete path segment,
1381
-     * that "." is removed.
1382
-     */
1383
-    if ((cur[0] == '.') && (cur[1] == '\0'))
1384
-     break;
1385
+ /*
1386
+ * d) If the buffer string ends with "." as a complete path segment,
1387
+ * that "." is removed.
1388
+ */
1389
+ if ((cur[0] == '.') && (cur[1] == '\0'))
1390
+ break;
1391
1392
-    /* Otherwise keep the segment. */
1393
-    while (cur[0] != '/') {
1394
+ /* Otherwise keep the segment. */
1395
+ while (cur[0] != '/') {
1396
if (cur[0] == '\0')
1397
- goto done_cd;
1398
-     (out++)[0] = (cur++)[0];
1399
-    }
1400
-    /* nomalize // */
1401
-    while ((cur[0] == '/') && (cur[1] == '/'))
1402
-     cur++;
1403
+ goto done_cd;
1404
+ (out++)[0] = (cur++)[0];
1405
+ }
1406
+ /* nomalize // */
1407
+ while ((cur[0] == '/') && (cur[1] == '/'))
1408
+ cur++;
1409
1410
(out++)[0] = (cur++)[0];
1411
}
1412
- done_cd:
1413
+done_cd:
1414
out[0] = '\0';
1415
1416
/* Reset to the beginning of the first segment for the next sequence. */
1417
cur = path;
1418
while (cur[0] == '/')
1419
- ++cur;
1420
+ ++cur;
1421
if (cur[0] == '\0')
1422
-    return(0);
1423
+ return (0);
1424
1425
/*
1426
* Analyze each segment in sequence for cases (e) and (f).
1427
@@ -XXX,XX +XXX,XX @@ normalize_uri_path(char *path) {
1428
/* Find the end of the current segment. */
1429
segp = cur;
1430
while ((segp[0] != '/') && (segp[0] != '\0'))
1431
- ++segp;
1432
+ ++segp;
1433
1434
/* If this is the last segment, we're done (we need at least two
1435
* segments to meet the criteria for the (e) and (f) cases).
1436
*/
1437
if (segp[0] == '\0')
1438
- break;
1439
+ break;
1440
1441
/* If the first segment is "..", or if the next segment _isn't_ "..",
1442
* keep this segment and try the next one.
1443
*/
1444
++segp;
1445
- if (((cur[0] == '.') && (cur[1] == '.') && (segp == cur+3))
1446
- || ((segp[0] != '.') || (segp[1] != '.')
1447
- || ((segp[2] != '/') && (segp[2] != '\0')))) {
1448
- cur = segp;
1449
- continue;
1450
+ if (((cur[0] == '.') && (cur[1] == '.') && (segp == cur + 3)) ||
1451
+ ((segp[0] != '.') || (segp[1] != '.') ||
1452
+ ((segp[2] != '/') && (segp[2] != '\0')))) {
1453
+ cur = segp;
1454
+ continue;
1455
}
1456
1457
/* If we get here, remove this segment and the next one and back up
1458
@@ -XXX,XX +XXX,XX @@ normalize_uri_path(char *path) {
1459
1460
/* If this is the end of the buffer, we're done. */
1461
if (segp[2] == '\0') {
1462
- cur[0] = '\0';
1463
- break;
1464
+ cur[0] = '\0';
1465
+ break;
1466
}
1467
/* Valgrind complained, strcpy(cur, segp + 3); */
1468
/* string will overlap, do not use strcpy */
1469
tmp = cur;
1470
segp += 3;
1471
while ((*tmp++ = *segp++) != 0)
1472
- ;
1473
+ ;
1474
1475
/* If there are no previous segments, then keep going from here. */
1476
segp = cur;
1477
while ((segp > path) && ((--segp)[0] == '/'))
1478
- ;
1479
+ ;
1480
if (segp == path)
1481
- continue;
1482
+ continue;
1483
1484
/* "segp" is pointing to the end of a previous segment; find it's
1485
* start. We need to back up to the previous segment and start
1486
@@ -XXX,XX +XXX,XX @@ normalize_uri_path(char *path) {
1487
*/
1488
cur = segp;
1489
while ((cur > path) && (cur[-1] != '/'))
1490
- --cur;
1491
+ --cur;
1492
}
1493
out[0] = '\0';
1494
1495
@@ -XXX,XX +XXX,XX @@ normalize_uri_path(char *path) {
1496
* We discard them from the final path.
1497
*/
1498
if (path[0] == '/') {
1499
- cur = path;
1500
- while ((cur[0] == '/') && (cur[1] == '.') && (cur[2] == '.')
1501
- && ((cur[3] == '/') || (cur[3] == '\0')))
1502
-    cur += 3;
1503
+ cur = path;
1504
+ while ((cur[0] == '/') && (cur[1] == '.') && (cur[2] == '.') &&
1505
+ ((cur[3] == '/') || (cur[3] == '\0')))
1506
+ cur += 3;
1507
1508
- if (cur != path) {
1509
-    out = path;
1510
-    while (cur[0] != '\0')
1511
- (out++)[0] = (cur++)[0];
1512
-    out[0] = 0;
1513
- }
1514
+ if (cur != path) {
1515
+ out = path;
1516
+ while (cur[0] != '\0')
1517
+ (out++)[0] = (cur++)[0];
1518
+ out[0] = 0;
1519
+ }
1520
}
1521
1522
- return(0);
1523
+ return (0);
1524
}
1525
1526
-static int is_hex(char c) {
1527
- if (((c >= '0') && (c <= '9')) ||
1528
- ((c >= 'a') && (c <= 'f')) ||
1529
+static int is_hex(char c)
1530
+{
1531
+ if (((c >= '0') && (c <= '9')) || ((c >= 'a') && (c <= 'f')) ||
1532
((c >= 'A') && (c <= 'F')))
1533
-    return(1);
1534
- return(0);
1535
+ return (1);
1536
+ return (0);
1537
}
1538
1539
-
1540
/**
1541
* uri_string_unescape:
1542
* @str: the string to unescape
1543
@@ -XXX,XX +XXX,XX @@ static int is_hex(char c) {
1544
* Returns a copy of the string, but unescaped, will return NULL only in case
1545
* of error
1546
*/
1547
-char *
1548
-uri_string_unescape(const char *str, int len, char *target) {
1549
+char *uri_string_unescape(const char *str, int len, char *target)
1550
+{
1551
char *ret, *out;
1552
const char *in;
1553
1554
if (str == NULL)
1555
-    return(NULL);
1556
- if (len <= 0) len = strlen(str);
1557
- if (len < 0) return(NULL);
1558
+ return (NULL);
1559
+ if (len <= 0)
1560
+ len = strlen(str);
1561
+ if (len < 0)
1562
+ return (NULL);
1563
1564
if (target == NULL) {
1565
-    ret = g_malloc(len + 1);
1566
+ ret = g_malloc(len + 1);
1567
} else
1568
-    ret = target;
1569
+ ret = target;
1570
in = str;
1571
out = ret;
1572
- while(len > 0) {
1573
-    if ((len > 2) && (*in == '%') && (is_hex(in[1])) && (is_hex(in[2]))) {
1574
-     in++;
1575
-     if ((*in >= '0') && (*in <= '9'))
1576
-     *out = (*in - '0');
1577
-     else if ((*in >= 'a') && (*in <= 'f'))
1578
-     *out = (*in - 'a') + 10;
1579
-     else if ((*in >= 'A') && (*in <= 'F'))
1580
-     *out = (*in - 'A') + 10;
1581
-     in++;
1582
-     if ((*in >= '0') && (*in <= '9'))
1583
-     *out = *out * 16 + (*in - '0');
1584
-     else if ((*in >= 'a') && (*in <= 'f'))
1585
-     *out = *out * 16 + (*in - 'a') + 10;
1586
-     else if ((*in >= 'A') && (*in <= 'F'))
1587
-     *out = *out * 16 + (*in - 'A') + 10;
1588
-     in++;
1589
-     len -= 3;
1590
-     out++;
1591
-    } else {
1592
-     *out++ = *in++;
1593
-     len--;
1594
-    }
1595
+ while (len > 0) {
1596
+ if ((len > 2) && (*in == '%') && (is_hex(in[1])) && (is_hex(in[2]))) {
1597
+ in++;
1598
+ if ((*in >= '0') && (*in <= '9'))
1599
+ *out = (*in - '0');
1600
+ else if ((*in >= 'a') && (*in <= 'f'))
1601
+ *out = (*in - 'a') + 10;
1602
+ else if ((*in >= 'A') && (*in <= 'F'))
1603
+ *out = (*in - 'A') + 10;
1604
+ in++;
1605
+ if ((*in >= '0') && (*in <= '9'))
1606
+ *out = *out * 16 + (*in - '0');
1607
+ else if ((*in >= 'a') && (*in <= 'f'))
1608
+ *out = *out * 16 + (*in - 'a') + 10;
1609
+ else if ((*in >= 'A') && (*in <= 'F'))
1610
+ *out = *out * 16 + (*in - 'A') + 10;
1611
+ in++;
1612
+ len -= 3;
1613
+ out++;
1614
+ } else {
1615
+ *out++ = *in++;
1616
+ len--;
1617
+ }
1618
}
1619
*out = 0;
1620
- return(ret);
1621
+ return (ret);
1622
}
1623
1624
/**
1625
@@ -XXX,XX +XXX,XX @@ uri_string_unescape(const char *str, int len, char *target) {
1626
*
1627
* Returns a new escaped string or NULL in case of error.
1628
*/
1629
-char *
1630
-uri_string_escape(const char *str, const char *list) {
1631
+char *uri_string_escape(const char *str, const char *list)
1632
+{
1633
char *ret, ch;
1634
char *temp;
1635
const char *in;
1636
int len, out;
1637
1638
if (str == NULL)
1639
-    return(NULL);
1640
+ return (NULL);
1641
if (str[0] == 0)
1642
-    return(g_strdup(str));
1643
+ return (g_strdup(str));
1644
len = strlen(str);
1645
- if (!(len > 0)) return(NULL);
1646
+ if (!(len > 0))
1647
+ return (NULL);
1648
1649
len += 20;
1650
ret = g_malloc(len);
1651
in = str;
1652
out = 0;
1653
- while(*in != 0) {
1654
-    if (len - out <= 3) {
1655
+ while (*in != 0) {
1656
+ if (len - out <= 3) {
1657
temp = realloc2n(ret, &len);
1658
-     ret = temp;
1659
-    }
1660
+ ret = temp;
1661
+ }
1662
1663
-    ch = *in;
1664
-
1665
-    if ((ch != '@') && (!IS_UNRESERVED(ch)) && (!strchr(list, ch))) {
1666
-     unsigned char val;
1667
-     ret[out++] = '%';
1668
-     val = ch >> 4;
1669
-     if (val <= 9)
1670
-        ret[out++] = '0' + val;
1671
-     else
1672
-        ret[out++] = 'A' + val - 0xA;
1673
-     val = ch & 0xF;
1674
-     if (val <= 9)
1675
-        ret[out++] = '0' + val;
1676
-     else
1677
-        ret[out++] = 'A' + val - 0xA;
1678
-     in++;
1679
-    } else {
1680
-     ret[out++] = *in++;
1681
-    }
1682
+ ch = *in;
1683
1684
+ if ((ch != '@') && (!IS_UNRESERVED(ch)) && (!strchr(list, ch))) {
1685
+ unsigned char val;
1686
+ ret[out++] = '%';
1687
+ val = ch >> 4;
1688
+ if (val <= 9)
1689
+ ret[out++] = '0' + val;
1690
+ else
1691
+ ret[out++] = 'A' + val - 0xA;
1692
+ val = ch & 0xF;
1693
+ if (val <= 9)
1694
+ ret[out++] = '0' + val;
1695
+ else
1696
+ ret[out++] = 'A' + val - 0xA;
1697
+ in++;
1698
+ } else {
1699
+ ret[out++] = *in++;
1700
+ }
1701
}
1702
ret[out] = 0;
1703
- return(ret);
1704
+ return (ret);
1705
}
1706
1707
/************************************************************************
1708
- *                                    *
1709
- *            Public functions                *
1710
- *                                    *
1711
+ * *
1712
+ * Public functions *
1713
+ * *
1714
************************************************************************/
1715
1716
/**
1717
@@ -XXX,XX +XXX,XX @@ uri_string_escape(const char *str, const char *list) {
1718
* Returns a new URI string (to be freed by the caller) or NULL in case
1719
* of error.
1720
*/
1721
-char *
1722
-uri_resolve(const char *uri, const char *base) {
1723
+char *uri_resolve(const char *uri, const char *base)
1724
+{
1725
char *val = NULL;
1726
int ret, len, indx, cur, out;
1727
URI *ref = NULL;
1728
@@ -XXX,XX +XXX,XX @@ uri_resolve(const char *uri, const char *base) {
1729
* URI. Should we do that here?
1730
*/
1731
if (uri == NULL)
1732
-    ret = -1;
1733
+ ret = -1;
1734
else {
1735
-    if (*uri) {
1736
-     ref = uri_new();
1737
-     ret = uri_parse_into(ref, uri);
1738
-    }
1739
-    else
1740
-     ret = 0;
1741
+ if (*uri) {
1742
+ ref = uri_new();
1743
+ ret = uri_parse_into(ref, uri);
1744
+ } else
1745
+ ret = 0;
1746
}
1747
if (ret != 0)
1748
-    goto done;
1749
+ goto done;
1750
if ((ref != NULL) && (ref->scheme != NULL)) {
1751
-    /*
1752
-     * The URI is absolute don't modify.
1753
-     */
1754
-    val = g_strdup(uri);
1755
-    goto done;
1756
+ /*
1757
+ * The URI is absolute don't modify.
1758
+ */
1759
+ val = g_strdup(uri);
1760
+ goto done;
1761
}
1762
if (base == NULL)
1763
-    ret = -1;
1764
+ ret = -1;
1765
else {
1766
-    bas = uri_new();
1767
-    ret = uri_parse_into(bas, base);
1768
+ bas = uri_new();
1769
+ ret = uri_parse_into(bas, base);
1770
}
1771
if (ret != 0) {
1772
-    if (ref)
1773
-     val = uri_to_string(ref);
1774
-    goto done;
1775
+ if (ref)
1776
+ val = uri_to_string(ref);
1777
+ goto done;
1778
}
1779
if (ref == NULL) {
1780
-    /*
1781
-     * the base fragment must be ignored
1782
-     */
1783
+ /*
1784
+ * the base fragment must be ignored
1785
+ */
1786
g_free(bas->fragment);
1787
bas->fragment = NULL;
1788
-    val = uri_to_string(bas);
1789
-    goto done;
1790
+ val = uri_to_string(bas);
1791
+ goto done;
1792
}
1793
1794
/*
1795
@@ -XXX,XX +XXX,XX @@ uri_resolve(const char *uri, const char *base) {
1796
*/
1797
res = uri_new();
1798
if ((ref->scheme == NULL) && (ref->path == NULL) &&
1799
-    ((ref->authority == NULL) && (ref->server == NULL))) {
1800
+ ((ref->authority == NULL) && (ref->server == NULL))) {
1801
res->scheme = g_strdup(bas->scheme);
1802
-    if (bas->authority != NULL)
1803
-     res->authority = g_strdup(bas->authority);
1804
-    else if (bas->server != NULL) {
1805
+ if (bas->authority != NULL)
1806
+ res->authority = g_strdup(bas->authority);
1807
+ else if (bas->server != NULL) {
1808
res->server = g_strdup(bas->server);
1809
res->user = g_strdup(bas->user);
1810
res->port = bas->port;
1811
-    }
1812
+ }
1813
res->path = g_strdup(bas->path);
1814
if (ref->query != NULL) {
1815
-     res->query = g_strdup (ref->query);
1816
+ res->query = g_strdup(ref->query);
1817
} else {
1818
res->query = g_strdup(bas->query);
1819
}
1820
res->fragment = g_strdup(ref->fragment);
1821
-    goto step_7;
1822
+ goto step_7;
1823
}
1824
1825
/*
1826
@@ -XXX,XX +XXX,XX @@ uri_resolve(const char *uri, const char *base) {
1827
* scheme is inherited from the base URI's scheme component.
1828
*/
1829
if (ref->scheme != NULL) {
1830
-    val = uri_to_string(ref);
1831
-    goto done;
1832
+ val = uri_to_string(ref);
1833
+ goto done;
1834
}
1835
res->scheme = g_strdup(bas->scheme);
1836
1837
@@ -XXX,XX +XXX,XX @@ uri_resolve(const char *uri, const char *base) {
1838
* use an authority component.
1839
*/
1840
if ((ref->authority != NULL) || (ref->server != NULL)) {
1841
-    if (ref->authority != NULL)
1842
-     res->authority = g_strdup(ref->authority);
1843
-    else {
1844
-     res->server = g_strdup(ref->server);
1845
+ if (ref->authority != NULL)
1846
+ res->authority = g_strdup(ref->authority);
1847
+ else {
1848
+ res->server = g_strdup(ref->server);
1849
res->user = g_strdup(ref->user);
1850
res->port = ref->port;
1851
-    }
1852
+ }
1853
res->path = g_strdup(ref->path);
1854
-    goto step_7;
1855
+ goto step_7;
1856
}
1857
if (bas->authority != NULL)
1858
-    res->authority = g_strdup(bas->authority);
1859
+ res->authority = g_strdup(bas->authority);
1860
else if (bas->server != NULL) {
1861
res->server = g_strdup(bas->server);
1862
res->user = g_strdup(bas->user);
1863
-    res->port = bas->port;
1864
+ res->port = bas->port;
1865
}
1866
1867
/*
1868
@@ -XXX,XX +XXX,XX @@ uri_resolve(const char *uri, const char *base) {
1869
* the reference is an absolute-path and we skip to step 7.
1870
*/
1871
if ((ref->path != NULL) && (ref->path[0] == '/')) {
1872
-    res->path = g_strdup(ref->path);
1873
-    goto step_7;
1874
+ res->path = g_strdup(ref->path);
1875
+ goto step_7;
1876
}
1877
1878
-
1879
/*
1880
* 6) If this step is reached, then we are resolving a relative-path
1881
* reference. The relative path needs to be merged with the base
1882
@@ -XXX,XX +XXX,XX @@ uri_resolve(const char *uri, const char *base) {
1883
*/
1884
len = 2; /* extra / and 0 */
1885
if (ref->path != NULL)
1886
-    len += strlen(ref->path);
1887
+ len += strlen(ref->path);
1888
if (bas->path != NULL)
1889
-    len += strlen(bas->path);
1890
+ len += strlen(bas->path);
1891
res->path = g_malloc(len);
1892
res->path[0] = 0;
1893
1894
@@ -XXX,XX +XXX,XX @@ uri_resolve(const char *uri, const char *base) {
1895
cur = 0;
1896
out = 0;
1897
if (bas->path != NULL) {
1898
-    while (bas->path[cur] != 0) {
1899
-     while ((bas->path[cur] != 0) && (bas->path[cur] != '/'))
1900
-        cur++;
1901
-     if (bas->path[cur] == 0)
1902
-        break;
1903
+ while (bas->path[cur] != 0) {
1904
+ while ((bas->path[cur] != 0) && (bas->path[cur] != '/'))
1905
+ cur++;
1906
+ if (bas->path[cur] == 0)
1907
+ break;
1908
1909
-     cur++;
1910
-     while (out < cur) {
1911
-        res->path[out] = bas->path[out];
1912
-        out++;
1913
-     }
1914
-    }
1915
+ cur++;
1916
+ while (out < cur) {
1917
+ res->path[out] = bas->path[out];
1918
+ out++;
1919
+ }
1920
+ }
1921
}
1922
res->path[out] = 0;
1923
1924
@@ -XXX,XX +XXX,XX @@ uri_resolve(const char *uri, const char *base) {
1925
* string.
1926
*/
1927
if (ref->path != NULL && ref->path[0] != 0) {
1928
-    indx = 0;
1929
-    /*
1930
-     * Ensure the path includes a '/'
1931
-     */
1932
-    if ((out == 0) && (bas->server != NULL))
1933
-     res->path[out++] = '/';
1934
-    while (ref->path[indx] != 0) {
1935
-     res->path[out++] = ref->path[indx++];
1936
-    }
1937
+ indx = 0;
1938
+ /*
1939
+ * Ensure the path includes a '/'
1940
+ */
1941
+ if ((out == 0) && (bas->server != NULL))
1942
+ res->path[out++] = '/';
1943
+ while (ref->path[indx] != 0) {
1944
+ res->path[out++] = ref->path[indx++];
1945
+ }
1946
}
1947
res->path[out] = 0;
1948
1949
@@ -XXX,XX +XXX,XX @@ step_7:
1950
1951
done:
1952
if (ref != NULL)
1953
-    uri_free(ref);
1954
+ uri_free(ref);
1955
if (bas != NULL)
1956
-    uri_free(bas);
1957
+ uri_free(bas);
1958
if (res != NULL)
1959
-    uri_free(res);
1960
- return(val);
1961
+ uri_free(res);
1962
+ return (val);
1963
}
1964
1965
/**
1966
@@ -XXX,XX +XXX,XX @@ done:
1967
* Returns a new URI string (to be freed by the caller) or NULL in case
1968
* error.
1969
*/
1970
-char *
1971
-uri_resolve_relative (const char *uri, const char * base)
1972
+char *uri_resolve_relative(const char *uri, const char *base)
1973
{
1974
char *val = NULL;
1975
int ret;
1976
@@ -XXX,XX +XXX,XX @@ uri_resolve_relative (const char *uri, const char * base)
1977
int remove_path = 0;
1978
1979
if ((uri == NULL) || (*uri == 0))
1980
-    return NULL;
1981
+ return NULL;
1982
1983
/*
1984
* First parse URI into a standard form
1985
*/
1986
- ref = uri_new ();
1987
+ ref = uri_new();
1988
/* If URI not already in "relative" form */
1989
if (uri[0] != '.') {
1990
-    ret = uri_parse_into (ref, uri);
1991
-    if (ret != 0)
1992
-     goto done;        /* Error in URI, return NULL */
1993
+ ret = uri_parse_into(ref, uri);
1994
+ if (ret != 0)
1995
+ goto done; /* Error in URI, return NULL */
1996
} else
1997
-    ref->path = g_strdup(uri);
1998
+ ref->path = g_strdup(uri);
1999
2000
/*
2001
* Next parse base into the same standard form
2002
*/
2003
if ((base == NULL) || (*base == 0)) {
2004
-    val = g_strdup (uri);
2005
-    goto done;
2006
+ val = g_strdup(uri);
2007
+ goto done;
2008
}
2009
- bas = uri_new ();
2010
+ bas = uri_new();
2011
if (base[0] != '.') {
2012
-    ret = uri_parse_into (bas, base);
2013
-    if (ret != 0)
2014
-     goto done;        /* Error in base, return NULL */
2015
+ ret = uri_parse_into(bas, base);
2016
+ if (ret != 0)
2017
+ goto done; /* Error in base, return NULL */
2018
} else
2019
-    bas->path = g_strdup(base);
2020
+ bas->path = g_strdup(base);
2021
2022
/*
2023
* If the scheme / server on the URI differs from the base,
2024
* just return the URI
2025
*/
2026
if ((ref->scheme != NULL) &&
2027
-    ((bas->scheme == NULL) ||
2028
-     (strcmp (bas->scheme, ref->scheme)) ||
2029
-     (strcmp (bas->server, ref->server)))) {
2030
-    val = g_strdup (uri);
2031
-    goto done;
2032
+ ((bas->scheme == NULL) || (strcmp(bas->scheme, ref->scheme)) ||
2033
+ (strcmp(bas->server, ref->server)))) {
2034
+ val = g_strdup(uri);
2035
+ goto done;
2036
}
2037
if (bas->path == ref->path ||
2038
(bas->path && ref->path && !strcmp(bas->path, ref->path))) {
2039
-    val = g_strdup("");
2040
-    goto done;
2041
+ val = g_strdup("");
2042
+ goto done;
2043
}
2044
if (bas->path == NULL) {
2045
-    val = g_strdup(ref->path);
2046
-    goto done;
2047
+ val = g_strdup(ref->path);
2048
+ goto done;
2049
}
2050
if (ref->path == NULL) {
2051
- ref->path = (char *) "/";
2052
-    remove_path = 1;
2053
+ ref->path = (char *)"/";
2054
+ remove_path = 1;
2055
}
2056
2057
/*
2058
@@ -XXX,XX +XXX,XX @@ uri_resolve_relative (const char *uri, const char * base)
2059
* two path components may be missing (bug 316224)
2060
*/
2061
if (bas->path == NULL) {
2062
-    if (ref->path != NULL) {
2063
-     uptr = ref->path;
2064
-     if (*uptr == '/')
2065
-        uptr++;
2066
-     /* exception characters from uri_to_string */
2067
-     val = uri_string_escape(uptr, "/;&=+$,");
2068
-    }
2069
-    goto done;
2070
+ if (ref->path != NULL) {
2071
+ uptr = ref->path;
2072
+ if (*uptr == '/')
2073
+ uptr++;
2074
+ /* exception characters from uri_to_string */
2075
+ val = uri_string_escape(uptr, "/;&=+$,");
2076
+ }
2077
+ goto done;
2078
}
2079
bptr = bas->path;
2080
if (ref->path == NULL) {
2081
-    for (ix = 0; bptr[ix] != 0; ix++) {
2082
-     if (bptr[ix] == '/')
2083
-        nbslash++;
2084
-    }
2085
-    uptr = NULL;
2086
-    len = 1;    /* this is for a string terminator only */
2087
+ for (ix = 0; bptr[ix] != 0; ix++) {
2088
+ if (bptr[ix] == '/')
2089
+ nbslash++;
2090
+ }
2091
+ uptr = NULL;
2092
+ len = 1; /* this is for a string terminator only */
2093
} else {
2094
- /*
2095
- * Next we compare the two strings and find where they first differ
2096
- */
2097
-    if ((ref->path[pos] == '.') && (ref->path[pos+1] == '/'))
2098
+ /*
2099
+ * Next we compare the two strings and find where they first differ
2100
+ */
2101
+ if ((ref->path[pos] == '.') && (ref->path[pos + 1] == '/'))
2102
pos += 2;
2103
-    if ((*bptr == '.') && (bptr[1] == '/'))
2104
+ if ((*bptr == '.') && (bptr[1] == '/'))
2105
bptr += 2;
2106
-    else if ((*bptr == '/') && (ref->path[pos] != '/'))
2107
-     bptr++;
2108
-    while ((bptr[pos] == ref->path[pos]) && (bptr[pos] != 0))
2109
-     pos++;
2110
+ else if ((*bptr == '/') && (ref->path[pos] != '/'))
2111
+ bptr++;
2112
+ while ((bptr[pos] == ref->path[pos]) && (bptr[pos] != 0))
2113
+ pos++;
2114
2115
-    if (bptr[pos] == ref->path[pos]) {
2116
-     val = g_strdup("");
2117
-     goto done;        /* (I can't imagine why anyone would do this) */
2118
-    }
2119
+ if (bptr[pos] == ref->path[pos]) {
2120
+ val = g_strdup("");
2121
+ goto done; /* (I can't imagine why anyone would do this) */
2122
+ }
2123
2124
-    /*
2125
-     * In URI, "back up" to the last '/' encountered. This will be the
2126
-     * beginning of the "unique" suffix of URI
2127
-     */
2128
-    ix = pos;
2129
-    if ((ref->path[ix] == '/') && (ix > 0))
2130
-     ix--;
2131
-    else if ((ref->path[ix] == 0) && (ix > 1) && (ref->path[ix - 1] == '/'))
2132
-     ix -= 2;
2133
-    for (; ix > 0; ix--) {
2134
-     if (ref->path[ix] == '/')
2135
-        break;
2136
-    }
2137
-    if (ix == 0) {
2138
-     uptr = ref->path;
2139
-    } else {
2140
-     ix++;
2141
-     uptr = &ref->path[ix];
2142
-    }
2143
+ /*
2144
+ * In URI, "back up" to the last '/' encountered. This will be the
2145
+ * beginning of the "unique" suffix of URI
2146
+ */
2147
+ ix = pos;
2148
+ if ((ref->path[ix] == '/') && (ix > 0))
2149
+ ix--;
2150
+ else if ((ref->path[ix] == 0) && (ix > 1) && (ref->path[ix - 1] == '/'))
2151
+ ix -= 2;
2152
+ for (; ix > 0; ix--) {
2153
+ if (ref->path[ix] == '/')
2154
+ break;
2155
+ }
2156
+ if (ix == 0) {
2157
+ uptr = ref->path;
2158
+ } else {
2159
+ ix++;
2160
+ uptr = &ref->path[ix];
2161
+ }
2162
2163
-    /*
2164
-     * In base, count the number of '/' from the differing point
2165
-     */
2166
-    if (bptr[pos] != ref->path[pos]) {/* check for trivial URI == base */
2167
-     for (; bptr[ix] != 0; ix++) {
2168
-        if (bptr[ix] == '/')
2169
-         nbslash++;
2170
-     }
2171
-    }
2172
-    len = strlen (uptr) + 1;
2173
+ /*
2174
+ * In base, count the number of '/' from the differing point
2175
+ */
2176
+ if (bptr[pos] != ref->path[pos]) { /* check for trivial URI == base */
2177
+ for (; bptr[ix] != 0; ix++) {
2178
+ if (bptr[ix] == '/')
2179
+ nbslash++;
2180
+ }
2181
+ }
2182
+ len = strlen(uptr) + 1;
2183
}
2184
2185
if (nbslash == 0) {
2186
-    if (uptr != NULL)
2187
-     /* exception characters from uri_to_string */
2188
-     val = uri_string_escape(uptr, "/;&=+$,");
2189
-    goto done;
2190
+ if (uptr != NULL)
2191
+ /* exception characters from uri_to_string */
2192
+ val = uri_string_escape(uptr, "/;&=+$,");
2193
+ goto done;
2194
}
2195
2196
/*
2197
@@ -XXX,XX +XXX,XX @@ uri_resolve_relative (const char *uri, const char * base)
2198
* length of the remainder of the URI, plus enough space
2199
* for the "../" groups, plus one for the terminator
2200
*/
2201
- val = g_malloc (len + 3 * nbslash);
2202
+ val = g_malloc(len + 3 * nbslash);
2203
vptr = val;
2204
/*
2205
* Put in as many "../" as needed
2206
*/
2207
- for (; nbslash>0; nbslash--) {
2208
-    *vptr++ = '.';
2209
-    *vptr++ = '.';
2210
-    *vptr++ = '/';
2211
+ for (; nbslash > 0; nbslash--) {
2212
+ *vptr++ = '.';
2213
+ *vptr++ = '.';
2214
+ *vptr++ = '/';
2215
}
2216
/*
2217
* Finish up with the end of the URI
2218
*/
2219
if (uptr != NULL) {
2220
- if ((vptr > val) && (len > 0) &&
2221
-     (uptr[0] == '/') && (vptr[-1] == '/')) {
2222
-     memcpy (vptr, uptr + 1, len - 1);
2223
-     vptr[len - 2] = 0;
2224
-    } else {
2225
-     memcpy (vptr, uptr, len);
2226
-     vptr[len - 1] = 0;
2227
-    }
2228
+ if ((vptr > val) && (len > 0) && (uptr[0] == '/') &&
2229
+ (vptr[-1] == '/')) {
2230
+ memcpy(vptr, uptr + 1, len - 1);
2231
+ vptr[len - 2] = 0;
2232
+ } else {
2233
+ memcpy(vptr, uptr, len);
2234
+ vptr[len - 1] = 0;
2235
+ }
2236
} else {
2237
-    vptr[len - 1] = 0;
2238
+ vptr[len - 1] = 0;
2239
}
2240
2241
/* escape the freshly-built path */
2242
vptr = val;
2243
-    /* exception characters from uri_to_string */
2244
+ /* exception characters from uri_to_string */
2245
val = uri_string_escape(vptr, "/;&=+$,");
2246
g_free(vptr);
2247
2248
@@ -XXX,XX +XXX,XX @@ done:
2249
if (remove_path != 0)
2250
ref->path = NULL;
2251
if (ref != NULL)
2252
-    uri_free (ref);
2253
+ uri_free(ref);
2254
if (bas != NULL)
2255
-    uri_free (bas);
2256
+ uri_free(bas);
2257
2258
return val;
2259
}
2260
@@ -XXX,XX +XXX,XX @@ done:
2261
* Utility functions to help parse and assemble query strings.
2262
*/
2263
2264
-struct QueryParams *
2265
-query_params_new (int init_alloc)
2266
+struct QueryParams *query_params_new(int init_alloc)
2267
{
2268
struct QueryParams *ps;
2269
2270
- if (init_alloc <= 0) init_alloc = 1;
2271
+ if (init_alloc <= 0)
2272
+ init_alloc = 1;
2273
2274
ps = g_new(QueryParams, 1);
2275
ps->n = 0;
2276
@@ -XXX,XX +XXX,XX @@ query_params_new (int init_alloc)
2277
/* Ensure there is space to store at least one more parameter
2278
* at the end of the set.
2279
*/
2280
-static int
2281
-query_params_append (struct QueryParams *ps,
2282
- const char *name, const char *value)
2283
+static int query_params_append(struct QueryParams *ps, const char *name,
2284
+ const char *value)
2285
{
2286
if (ps->n >= ps->alloc) {
2287
ps->p = g_renew(QueryParam, ps->p, ps->alloc * 2);
2288
@@ -XXX,XX +XXX,XX @@ query_params_append (struct QueryParams *ps,
2289
return 0;
567
return 0;
2290
}
568
}
2291
569
2292
-void
570
-static int check_host_key(BDRVSSHState *s, const char *host, int port,
2293
-query_params_free (struct QueryParams *ps)
571
- SshHostKeyCheck *hkc, Error **errp)
2294
+void query_params_free(struct QueryParams *ps)
572
+static int check_host_key(BDRVSSHState *s, SshHostKeyCheck *hkc, Error **errp)
2295
{
573
{
2296
int i;
574
SshHostKeyCheckMode mode;
2297
575
2298
for (i = 0; i < ps->n; ++i) {
576
@@ -XXX,XX +XXX,XX @@ static int check_host_key(BDRVSSHState *s, const char *host, int port,
2299
- g_free (ps->p[i].name);
577
case SSH_HOST_KEY_CHECK_MODE_HASH:
2300
- g_free (ps->p[i].value);
578
if (hkc->u.hash.type == SSH_HOST_KEY_CHECK_HASH_TYPE_MD5) {
2301
+ g_free(ps->p[i].name);
579
return check_host_key_hash(s, hkc->u.hash.hash,
2302
+ g_free(ps->p[i].value);
580
- LIBSSH2_HOSTKEY_HASH_MD5, 16, errp);
2303
}
581
+ SSH_PUBLICKEY_HASH_MD5, errp);
2304
- g_free (ps->p);
582
} else if (hkc->u.hash.type == SSH_HOST_KEY_CHECK_HASH_TYPE_SHA1) {
2305
- g_free (ps);
583
return check_host_key_hash(s, hkc->u.hash.hash,
2306
+ g_free(ps->p);
584
- LIBSSH2_HOSTKEY_HASH_SHA1, 20, errp);
2307
+ g_free(ps);
585
+ SSH_PUBLICKEY_HASH_SHA1, errp);
586
}
587
g_assert_not_reached();
588
break;
589
case SSH_HOST_KEY_CHECK_MODE_KNOWN_HOSTS:
590
- return check_host_key_knownhosts(s, host, port, errp);
591
+ return check_host_key_knownhosts(s, errp);
592
default:
593
g_assert_not_reached();
594
}
595
@@ -XXX,XX +XXX,XX @@ static int check_host_key(BDRVSSHState *s, const char *host, int port,
596
return -EINVAL;
2308
}
597
}
2309
598
2310
-struct QueryParams *
599
-static int authenticate(BDRVSSHState *s, const char *user, Error **errp)
2311
-query_params_parse (const char *query)
600
+static int authenticate(BDRVSSHState *s, Error **errp)
2312
+struct QueryParams *query_params_parse(const char *query)
2313
{
601
{
2314
struct QueryParams *ps;
602
int r, ret;
2315
const char *end, *eq;
603
- const char *userauthlist;
2316
604
- LIBSSH2_AGENT *agent = NULL;
2317
- ps = query_params_new (0);
605
- struct libssh2_agent_publickey *identity;
2318
- if (!query || query[0] == '\0') return ps;
606
- struct libssh2_agent_publickey *prev_identity = NULL;
2319
+ ps = query_params_new(0);
607
+ int method;
2320
+ if (!query || query[0] == '\0')
608
2321
+ return ps;
609
- userauthlist = libssh2_userauth_list(s->session, user, strlen(user));
2322
610
- if (strstr(userauthlist, "publickey") == NULL) {
2323
while (*query) {
611
+ /* Try to authenticate with the "none" method. */
2324
char *name = NULL, *value = NULL;
612
+ r = ssh_userauth_none(s->session, NULL);
2325
613
+ if (r == SSH_AUTH_ERROR) {
2326
/* Find the next separator, or end of the string. */
614
ret = -EPERM;
2327
- end = strchr (query, '&');
615
- error_setg(errp,
2328
+ end = strchr(query, '&');
616
- "remote server does not support \"publickey\" authentication");
2329
if (!end)
617
+ session_error_setg(errp, s, "failed to authenticate using none "
2330
- end = strchr (query, ';');
618
+ "authentication");
2331
+ end = strchr(query, ';');
619
goto out;
2332
if (!end)
620
- }
2333
- end = query + strlen (query);
621
-
2334
+ end = query + strlen(query);
622
- /* Connect to ssh-agent and try each identity in turn. */
2335
623
- agent = libssh2_agent_init(s->session);
2336
/* Find the first '=' character between here and end. */
624
- if (!agent) {
2337
- eq = strchr (query, '=');
625
- ret = -EINVAL;
2338
- if (eq && eq >= end) eq = NULL;
626
- session_error_setg(errp, s, "failed to initialize ssh-agent support");
2339
+ eq = strchr(query, '=');
627
- goto out;
2340
+ if (eq && eq >= end)
628
- }
2341
+ eq = NULL;
629
- if (libssh2_agent_connect(agent)) {
2342
630
- ret = -ECONNREFUSED;
2343
/* Empty section (eg. "&&"). */
631
- session_error_setg(errp, s, "failed to connect to ssh-agent");
2344
if (end == query)
632
- goto out;
2345
@@ -XXX,XX +XXX,XX @@ query_params_parse (const char *query)
633
- }
2346
* and consistent with CGI.pm we assume value is "".
634
- if (libssh2_agent_list_identities(agent)) {
2347
*/
635
- ret = -EINVAL;
2348
else if (!eq) {
636
- session_error_setg(errp, s,
2349
- name = uri_string_unescape (query, end - query, NULL);
637
- "failed requesting identities from ssh-agent");
2350
+ name = uri_string_unescape(query, end - query, NULL);
638
+ } else if (r == SSH_AUTH_SUCCESS) {
2351
value = NULL;
639
+ /* Authenticated! */
640
+ ret = 0;
641
goto out;
642
}
643
644
- for(;;) {
645
- r = libssh2_agent_get_identity(agent, &identity, prev_identity);
646
- if (r == 1) { /* end of list */
647
- break;
648
- }
649
- if (r < 0) {
650
+ method = ssh_userauth_list(s->session, NULL);
651
+ trace_ssh_auth_methods(method);
652
+
653
+ /*
654
+ * Try to authenticate with publickey, using the ssh-agent
655
+ * if available.
656
+ */
657
+ if (method & SSH_AUTH_METHOD_PUBLICKEY) {
658
+ r = ssh_userauth_publickey_auto(s->session, NULL, NULL);
659
+ if (r == SSH_AUTH_ERROR) {
660
ret = -EINVAL;
661
- session_error_setg(errp, s,
662
- "failed to obtain identity from ssh-agent");
663
+ session_error_setg(errp, s, "failed to authenticate using "
664
+ "publickey authentication");
665
goto out;
666
- }
667
- r = libssh2_agent_userauth(agent, user, identity);
668
- if (r == 0) {
669
+ } else if (r == SSH_AUTH_SUCCESS) {
670
/* Authenticated! */
671
ret = 0;
672
goto out;
2352
}
673
}
2353
/* Or if we have "name=" here (works around annoying
674
- /* Failed to authenticate with this identity, try the next one. */
2354
* problem when calling uri_string_unescape with len = 0).
675
- prev_identity = identity;
2355
*/
676
}
2356
- else if (eq+1 == end) {
677
2357
- name = uri_string_unescape (query, eq - query, NULL);
678
ret = -EPERM;
2358
+ else if (eq + 1 == end) {
679
@@ -XXX,XX +XXX,XX @@ static int authenticate(BDRVSSHState *s, const char *user, Error **errp)
2359
+ name = uri_string_unescape(query, eq - query, NULL);
680
"and the identities held by your ssh-agent");
2360
value = g_new0(char, 1);
681
682
out:
683
- if (agent != NULL) {
684
- /* Note: libssh2 implementation implicitly calls
685
- * libssh2_agent_disconnect if necessary.
686
- */
687
- libssh2_agent_free(agent);
688
- }
689
-
690
return ret;
691
}
692
693
@@ -XXX,XX +XXX,XX @@ static int connect_to_ssh(BDRVSSHState *s, BlockdevOptionsSsh *opts,
694
int ssh_flags, int creat_mode, Error **errp)
695
{
696
int r, ret;
697
- long port = 0;
698
+ unsigned int port = 0;
699
+ int new_sock = -1;
700
701
if (opts->has_user) {
702
s->user = g_strdup(opts->user);
703
@@ -XXX,XX +XXX,XX @@ static int connect_to_ssh(BDRVSSHState *s, BlockdevOptionsSsh *opts,
704
s->inet = opts->server;
705
opts->server = NULL;
706
707
- if (qemu_strtol(s->inet->port, NULL, 10, &port) < 0) {
708
+ if (qemu_strtoui(s->inet->port, NULL, 10, &port) < 0) {
709
error_setg(errp, "Use only numeric port value");
710
ret = -EINVAL;
711
goto err;
712
}
713
714
/* Open the socket and connect. */
715
- s->sock = inet_connect_saddr(s->inet, errp);
716
- if (s->sock < 0) {
717
+ new_sock = inet_connect_saddr(s->inet, errp);
718
+ if (new_sock < 0) {
719
ret = -EIO;
720
goto err;
721
}
722
723
+ /*
724
+ * Try to disable the Nagle algorithm on TCP sockets to reduce latency,
725
+ * but do not fail if it cannot be disabled.
726
+ */
727
+ r = socket_set_nodelay(new_sock);
728
+ if (r < 0) {
729
+ warn_report("can't set TCP_NODELAY for the ssh server %s: %s",
730
+ s->inet->host, strerror(errno));
731
+ }
732
+
733
/* Create SSH session. */
734
- s->session = libssh2_session_init();
735
+ s->session = ssh_new();
736
if (!s->session) {
737
ret = -EINVAL;
738
- session_error_setg(errp, s, "failed to initialize libssh2 session");
739
+ session_error_setg(errp, s, "failed to initialize libssh session");
740
goto err;
741
}
742
743
-#if TRACE_LIBSSH2 != 0
744
- libssh2_trace(s->session, TRACE_LIBSSH2);
745
-#endif
746
+ /*
747
+ * Make sure we are in blocking mode during the connection and
748
+ * authentication phases.
749
+ */
750
+ ssh_set_blocking(s->session, 1);
751
752
- r = libssh2_session_handshake(s->session, s->sock);
753
- if (r != 0) {
754
+ r = ssh_options_set(s->session, SSH_OPTIONS_USER, s->user);
755
+ if (r < 0) {
756
+ ret = -EINVAL;
757
+ session_error_setg(errp, s,
758
+ "failed to set the user in the libssh session");
759
+ goto err;
760
+ }
761
+
762
+ r = ssh_options_set(s->session, SSH_OPTIONS_HOST, s->inet->host);
763
+ if (r < 0) {
764
+ ret = -EINVAL;
765
+ session_error_setg(errp, s,
766
+ "failed to set the host in the libssh session");
767
+ goto err;
768
+ }
769
+
770
+ if (port > 0) {
771
+ r = ssh_options_set(s->session, SSH_OPTIONS_PORT, &port);
772
+ if (r < 0) {
773
+ ret = -EINVAL;
774
+ session_error_setg(errp, s,
775
+ "failed to set the port in the libssh session");
776
+ goto err;
777
+ }
778
+ }
779
+
780
+ r = ssh_options_set(s->session, SSH_OPTIONS_COMPRESSION, "none");
781
+ if (r < 0) {
782
+ ret = -EINVAL;
783
+ session_error_setg(errp, s,
784
+ "failed to disable the compression in the libssh "
785
+ "session");
786
+ goto err;
787
+ }
788
+
789
+ /* Read ~/.ssh/config. */
790
+ r = ssh_options_parse_config(s->session, NULL);
791
+ if (r < 0) {
792
+ ret = -EINVAL;
793
+ session_error_setg(errp, s, "failed to parse ~/.ssh/config");
794
+ goto err;
795
+ }
796
+
797
+ r = ssh_options_set(s->session, SSH_OPTIONS_FD, &new_sock);
798
+ if (r < 0) {
799
+ ret = -EINVAL;
800
+ session_error_setg(errp, s,
801
+ "failed to set the socket in the libssh session");
802
+ goto err;
803
+ }
804
+ /* libssh took ownership of the socket. */
805
+ s->sock = new_sock;
806
+ new_sock = -1;
807
+
808
+ /* Connect. */
809
+ r = ssh_connect(s->session);
810
+ if (r != SSH_OK) {
811
ret = -EINVAL;
812
session_error_setg(errp, s, "failed to establish SSH session");
813
goto err;
814
}
815
816
/* Check the remote host's key against known_hosts. */
817
- ret = check_host_key(s, s->inet->host, port, opts->host_key_check, errp);
818
+ ret = check_host_key(s, opts->host_key_check, errp);
819
if (ret < 0) {
820
goto err;
821
}
822
823
/* Authenticate. */
824
- ret = authenticate(s, s->user, errp);
825
+ ret = authenticate(s, errp);
826
if (ret < 0) {
827
goto err;
828
}
829
830
/* Start SFTP. */
831
- s->sftp = libssh2_sftp_init(s->session);
832
+ s->sftp = sftp_new(s->session);
833
if (!s->sftp) {
834
- session_error_setg(errp, s, "failed to initialize sftp handle");
835
+ session_error_setg(errp, s, "failed to create sftp handle");
836
+ ret = -EINVAL;
837
+ goto err;
838
+ }
839
+
840
+ r = sftp_init(s->sftp);
841
+ if (r < 0) {
842
+ sftp_error_setg(errp, s, "failed to initialize sftp handle");
843
ret = -EINVAL;
844
goto err;
845
}
846
847
/* Open the remote file. */
848
trace_ssh_connect_to_ssh(opts->path, ssh_flags, creat_mode);
849
- s->sftp_handle = libssh2_sftp_open(s->sftp, opts->path, ssh_flags,
850
- creat_mode);
851
+ s->sftp_handle = sftp_open(s->sftp, opts->path, ssh_flags, creat_mode);
852
if (!s->sftp_handle) {
853
- session_error_setg(errp, s, "failed to open remote file '%s'",
854
- opts->path);
855
+ sftp_error_setg(errp, s, "failed to open remote file '%s'",
856
+ opts->path);
857
ret = -EINVAL;
858
goto err;
859
}
860
861
- r = libssh2_sftp_fstat(s->sftp_handle, &s->attrs);
862
- if (r < 0) {
863
+ /* Make sure the SFTP file is handled in blocking mode. */
864
+ sftp_file_set_blocking(s->sftp_handle);
865
+
866
+ s->attrs = sftp_fstat(s->sftp_handle);
867
+ if (!s->attrs) {
868
sftp_error_setg(errp, s, "failed to read file attributes");
869
return -EINVAL;
870
}
871
@@ -XXX,XX +XXX,XX @@ static int connect_to_ssh(BDRVSSHState *s, BlockdevOptionsSsh *opts,
872
return 0;
873
874
err:
875
+ if (s->attrs) {
876
+ sftp_attributes_free(s->attrs);
877
+ }
878
+ s->attrs = NULL;
879
if (s->sftp_handle) {
880
- libssh2_sftp_close(s->sftp_handle);
881
+ sftp_close(s->sftp_handle);
882
}
883
s->sftp_handle = NULL;
884
if (s->sftp) {
885
- libssh2_sftp_shutdown(s->sftp);
886
+ sftp_free(s->sftp);
887
}
888
s->sftp = NULL;
889
if (s->session) {
890
- libssh2_session_disconnect(s->session,
891
- "from qemu ssh client: "
892
- "error opening connection");
893
- libssh2_session_free(s->session);
894
+ ssh_disconnect(s->session);
895
+ ssh_free(s->session);
896
}
897
s->session = NULL;
898
+ s->sock = -1;
899
+ if (new_sock >= 0) {
900
+ close(new_sock);
901
+ }
902
903
return ret;
904
}
905
@@ -XXX,XX +XXX,XX @@ static int ssh_file_open(BlockDriverState *bs, QDict *options, int bdrv_flags,
906
907
ssh_state_init(s);
908
909
- ssh_flags = LIBSSH2_FXF_READ;
910
+ ssh_flags = 0;
911
if (bdrv_flags & BDRV_O_RDWR) {
912
- ssh_flags |= LIBSSH2_FXF_WRITE;
913
+ ssh_flags |= O_RDWR;
914
+ } else {
915
+ ssh_flags |= O_RDONLY;
916
}
917
918
opts = ssh_parse_options(options, errp);
919
@@ -XXX,XX +XXX,XX @@ static int ssh_file_open(BlockDriverState *bs, QDict *options, int bdrv_flags,
920
}
921
922
/* Go non-blocking. */
923
- libssh2_session_set_blocking(s->session, 0);
924
+ ssh_set_blocking(s->session, 0);
925
926
qapi_free_BlockdevOptionsSsh(opts);
927
928
return 0;
929
930
err:
931
- if (s->sock >= 0) {
932
- close(s->sock);
933
- }
934
- s->sock = -1;
935
-
936
qapi_free_BlockdevOptionsSsh(opts);
937
938
return ret;
939
@@ -XXX,XX +XXX,XX @@ static int ssh_grow_file(BDRVSSHState *s, int64_t offset, Error **errp)
940
{
941
ssize_t ret;
942
char c[1] = { '\0' };
943
- int was_blocking = libssh2_session_get_blocking(s->session);
944
+ int was_blocking = ssh_is_blocking(s->session);
945
946
/* offset must be strictly greater than the current size so we do
947
* not overwrite anything */
948
- assert(offset > 0 && offset > s->attrs.filesize);
949
+ assert(offset > 0 && offset > s->attrs->size);
950
951
- libssh2_session_set_blocking(s->session, 1);
952
+ ssh_set_blocking(s->session, 1);
953
954
- libssh2_sftp_seek64(s->sftp_handle, offset - 1);
955
- ret = libssh2_sftp_write(s->sftp_handle, c, 1);
956
+ sftp_seek64(s->sftp_handle, offset - 1);
957
+ ret = sftp_write(s->sftp_handle, c, 1);
958
959
- libssh2_session_set_blocking(s->session, was_blocking);
960
+ ssh_set_blocking(s->session, was_blocking);
961
962
if (ret < 0) {
963
sftp_error_setg(errp, s, "Failed to grow file");
964
return -EIO;
965
}
966
967
- s->attrs.filesize = offset;
968
+ s->attrs->size = offset;
969
return 0;
970
}
971
972
@@ -XXX,XX +XXX,XX @@ static int ssh_co_create(BlockdevCreateOptions *options, Error **errp)
973
ssh_state_init(&s);
974
975
ret = connect_to_ssh(&s, opts->location,
976
- LIBSSH2_FXF_READ|LIBSSH2_FXF_WRITE|
977
- LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC,
978
+ O_RDWR | O_CREAT | O_TRUNC,
979
0644, errp);
980
if (ret < 0) {
981
goto fail;
982
@@ -XXX,XX +XXX,XX @@ static int ssh_has_zero_init(BlockDriverState *bs)
983
/* Assume false, unless we can positively prove it's true. */
984
int has_zero_init = 0;
985
986
- if (s->attrs.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) {
987
- if (s->attrs.permissions & LIBSSH2_SFTP_S_IFREG) {
988
- has_zero_init = 1;
989
- }
990
+ if (s->attrs->type == SSH_FILEXFER_TYPE_REGULAR) {
991
+ has_zero_init = 1;
992
}
993
994
return has_zero_init;
995
@@ -XXX,XX +XXX,XX @@ static coroutine_fn void co_yield(BDRVSSHState *s, BlockDriverState *bs)
996
.co = qemu_coroutine_self()
997
};
998
999
- r = libssh2_session_block_directions(s->session);
1000
+ r = ssh_get_poll_flags(s->session);
1001
1002
- if (r & LIBSSH2_SESSION_BLOCK_INBOUND) {
1003
+ if (r & SSH_READ_PENDING) {
1004
rd_handler = restart_coroutine;
1005
}
1006
- if (r & LIBSSH2_SESSION_BLOCK_OUTBOUND) {
1007
+ if (r & SSH_WRITE_PENDING) {
1008
wr_handler = restart_coroutine;
1009
}
1010
1011
@@ -XXX,XX +XXX,XX @@ static coroutine_fn void co_yield(BDRVSSHState *s, BlockDriverState *bs)
1012
trace_ssh_co_yield_back(s->sock);
1013
}
1014
1015
-/* SFTP has a function `libssh2_sftp_seek64' which seeks to a position
1016
- * in the remote file. Notice that it just updates a field in the
1017
- * sftp_handle structure, so there is no network traffic and it cannot
1018
- * fail.
1019
- *
1020
- * However, `libssh2_sftp_seek64' does have a catastrophic effect on
1021
- * performance since it causes the handle to throw away all in-flight
1022
- * reads and buffered readahead data. Therefore this function tries
1023
- * to be intelligent about when to call the underlying libssh2 function.
1024
- */
1025
-#define SSH_SEEK_WRITE 0
1026
-#define SSH_SEEK_READ 1
1027
-#define SSH_SEEK_FORCE 2
1028
-
1029
-static void ssh_seek(BDRVSSHState *s, int64_t offset, int flags)
1030
-{
1031
- bool op_read = (flags & SSH_SEEK_READ) != 0;
1032
- bool force = (flags & SSH_SEEK_FORCE) != 0;
1033
-
1034
- if (force || op_read != s->offset_op_read || offset != s->offset) {
1035
- trace_ssh_seek(offset);
1036
- libssh2_sftp_seek64(s->sftp_handle, offset);
1037
- s->offset = offset;
1038
- s->offset_op_read = op_read;
1039
- }
1040
-}
1041
-
1042
static coroutine_fn int ssh_read(BDRVSSHState *s, BlockDriverState *bs,
1043
int64_t offset, size_t size,
1044
QEMUIOVector *qiov)
1045
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int ssh_read(BDRVSSHState *s, BlockDriverState *bs,
1046
1047
trace_ssh_read(offset, size);
1048
1049
- ssh_seek(s, offset, SSH_SEEK_READ);
1050
+ trace_ssh_seek(offset);
1051
+ sftp_seek64(s->sftp_handle, offset);
1052
1053
/* This keeps track of the current iovec element ('i'), where we
1054
* will write to next ('buf'), and the end of the current iovec
1055
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int ssh_read(BDRVSSHState *s, BlockDriverState *bs,
1056
buf = i->iov_base;
1057
end_of_vec = i->iov_base + i->iov_len;
1058
1059
- /* libssh2 has a hard-coded limit of 2000 bytes per request,
1060
- * although it will also do readahead behind our backs. Therefore
1061
- * we may have to do repeated reads here until we have read 'size'
1062
- * bytes.
1063
- */
1064
for (got = 0; got < size; ) {
1065
+ size_t request_read_size;
1066
again:
1067
- trace_ssh_read_buf(buf, end_of_vec - buf);
1068
- r = libssh2_sftp_read(s->sftp_handle, buf, end_of_vec - buf);
1069
- trace_ssh_read_return(r);
1070
+ /*
1071
+ * The size of SFTP packets is limited to 32K bytes, so limit
1072
+ * the amount of data requested to 16K, as libssh currently
1073
+ * does not handle multiple requests on its own.
1074
+ */
1075
+ request_read_size = MIN(end_of_vec - buf, 16384);
1076
+ trace_ssh_read_buf(buf, end_of_vec - buf, request_read_size);
1077
+ r = sftp_read(s->sftp_handle, buf, request_read_size);
1078
+ trace_ssh_read_return(r, sftp_get_error(s->sftp));
1079
1080
- if (r == LIBSSH2_ERROR_EAGAIN || r == LIBSSH2_ERROR_TIMEOUT) {
1081
+ if (r == SSH_AGAIN) {
1082
co_yield(s, bs);
1083
goto again;
2361
}
1084
}
2362
/* If the '=' character is at the beginning then we have
1085
- if (r < 0) {
2363
@@ -XXX,XX +XXX,XX @@ query_params_parse (const char *query)
1086
- sftp_error_trace(s, "read");
2364
1087
- s->offset = -1;
2365
/* Otherwise it's "name=value". */
1088
- return -EIO;
2366
else {
1089
- }
2367
- name = uri_string_unescape (query, eq - query, NULL);
1090
- if (r == 0) {
2368
- value = uri_string_unescape (eq+1, end - (eq+1), NULL);
1091
+ if (r == SSH_EOF || (r == 0 && sftp_get_error(s->sftp) == SSH_FX_EOF)) {
2369
+ name = uri_string_unescape(query, eq - query, NULL);
1092
/* EOF: Short read so pad the buffer with zeroes and return it. */
2370
+ value = uri_string_unescape(eq + 1, end - (eq + 1), NULL);
1093
qemu_iovec_memset(qiov, got, 0, size - got);
1094
return 0;
2371
}
1095
}
2372
1096
+ if (r <= 0) {
2373
/* Append to the parameter set. */
1097
+ sftp_error_trace(s, "read");
2374
- query_params_append (ps, name, value);
1098
+ return -EIO;
2375
+ query_params_append(ps, name, value);
1099
+ }
2376
g_free(name);
1100
2377
g_free(value);
1101
got += r;
2378
1102
buf += r;
2379
next:
1103
- s->offset += r;
2380
query = end;
1104
if (buf >= end_of_vec && got < size) {
2381
- if (*query) query ++; /* skip '&' separator */
1105
i++;
2382
+ if (*query)
1106
buf = i->iov_base;
2383
+ query++; /* skip '&' separator */
1107
@@ -XXX,XX +XXX,XX @@ static int ssh_write(BDRVSSHState *s, BlockDriverState *bs,
2384
}
1108
2385
1109
trace_ssh_write(offset, size);
2386
return ps;
1110
1111
- ssh_seek(s, offset, SSH_SEEK_WRITE);
1112
+ trace_ssh_seek(offset);
1113
+ sftp_seek64(s->sftp_handle, offset);
1114
1115
/* This keeps track of the current iovec element ('i'), where we
1116
* will read from next ('buf'), and the end of the current iovec
1117
@@ -XXX,XX +XXX,XX @@ static int ssh_write(BDRVSSHState *s, BlockDriverState *bs,
1118
end_of_vec = i->iov_base + i->iov_len;
1119
1120
for (written = 0; written < size; ) {
1121
+ size_t request_write_size;
1122
again:
1123
- trace_ssh_write_buf(buf, end_of_vec - buf);
1124
- r = libssh2_sftp_write(s->sftp_handle, buf, end_of_vec - buf);
1125
- trace_ssh_write_return(r);
1126
+ /*
1127
+ * Avoid too large data packets, as libssh currently does not
1128
+ * handle multiple requests on its own.
1129
+ */
1130
+ request_write_size = MIN(end_of_vec - buf, 131072);
1131
+ trace_ssh_write_buf(buf, end_of_vec - buf, request_write_size);
1132
+ r = sftp_write(s->sftp_handle, buf, request_write_size);
1133
+ trace_ssh_write_return(r, sftp_get_error(s->sftp));
1134
1135
- if (r == LIBSSH2_ERROR_EAGAIN || r == LIBSSH2_ERROR_TIMEOUT) {
1136
+ if (r == SSH_AGAIN) {
1137
co_yield(s, bs);
1138
goto again;
1139
}
1140
if (r < 0) {
1141
sftp_error_trace(s, "write");
1142
- s->offset = -1;
1143
return -EIO;
1144
}
1145
- /* The libssh2 API is very unclear about this. A comment in
1146
- * the code says "nothing was acked, and no EAGAIN was
1147
- * received!" which apparently means that no data got sent
1148
- * out, and the underlying channel didn't return any EAGAIN
1149
- * indication. I think this is a bug in either libssh2 or
1150
- * OpenSSH (server-side). In any case, forcing a seek (to
1151
- * discard libssh2 internal buffers), and then trying again
1152
- * works for me.
1153
- */
1154
- if (r == 0) {
1155
- ssh_seek(s, offset + written, SSH_SEEK_WRITE|SSH_SEEK_FORCE);
1156
- co_yield(s, bs);
1157
- goto again;
1158
- }
1159
1160
written += r;
1161
buf += r;
1162
- s->offset += r;
1163
if (buf >= end_of_vec && written < size) {
1164
i++;
1165
buf = i->iov_base;
1166
end_of_vec = i->iov_base + i->iov_len;
1167
}
1168
1169
- if (offset + written > s->attrs.filesize)
1170
- s->attrs.filesize = offset + written;
1171
+ if (offset + written > s->attrs->size) {
1172
+ s->attrs->size = offset + written;
1173
+ }
1174
}
1175
1176
return 0;
1177
@@ -XXX,XX +XXX,XX @@ static void unsafe_flush_warning(BDRVSSHState *s, const char *what)
1178
}
1179
}
1180
1181
-#ifdef HAS_LIBSSH2_SFTP_FSYNC
1182
+#ifdef HAVE_LIBSSH_0_8
1183
1184
static coroutine_fn int ssh_flush(BDRVSSHState *s, BlockDriverState *bs)
1185
{
1186
int r;
1187
1188
trace_ssh_flush();
1189
+
1190
+ if (!sftp_extension_supported(s->sftp, "fsync@openssh.com", "1")) {
1191
+ unsafe_flush_warning(s, "OpenSSH >= 6.3");
1192
+ return 0;
1193
+ }
1194
again:
1195
- r = libssh2_sftp_fsync(s->sftp_handle);
1196
- if (r == LIBSSH2_ERROR_EAGAIN || r == LIBSSH2_ERROR_TIMEOUT) {
1197
+ r = sftp_fsync(s->sftp_handle);
1198
+ if (r == SSH_AGAIN) {
1199
co_yield(s, bs);
1200
goto again;
1201
}
1202
- if (r == LIBSSH2_ERROR_SFTP_PROTOCOL &&
1203
- libssh2_sftp_last_error(s->sftp) == LIBSSH2_FX_OP_UNSUPPORTED) {
1204
- unsafe_flush_warning(s, "OpenSSH >= 6.3");
1205
- return 0;
1206
- }
1207
if (r < 0) {
1208
sftp_error_trace(s, "fsync");
1209
return -EIO;
1210
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int ssh_co_flush(BlockDriverState *bs)
1211
return ret;
1212
}
1213
1214
-#else /* !HAS_LIBSSH2_SFTP_FSYNC */
1215
+#else /* !HAVE_LIBSSH_0_8 */
1216
1217
static coroutine_fn int ssh_co_flush(BlockDriverState *bs)
1218
{
1219
BDRVSSHState *s = bs->opaque;
1220
1221
- unsafe_flush_warning(s, "libssh2 >= 1.4.4");
1222
+ unsafe_flush_warning(s, "libssh >= 0.8.0");
1223
return 0;
1224
}
1225
1226
-#endif /* !HAS_LIBSSH2_SFTP_FSYNC */
1227
+#endif /* !HAVE_LIBSSH_0_8 */
1228
1229
static int64_t ssh_getlength(BlockDriverState *bs)
1230
{
1231
BDRVSSHState *s = bs->opaque;
1232
int64_t length;
1233
1234
- /* Note we cannot make a libssh2 call here. */
1235
- length = (int64_t) s->attrs.filesize;
1236
+ /* Note we cannot make a libssh call here. */
1237
+ length = (int64_t) s->attrs->size;
1238
trace_ssh_getlength(length);
1239
1240
return length;
1241
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn ssh_co_truncate(BlockDriverState *bs, int64_t offset,
1242
return -ENOTSUP;
1243
}
1244
1245
- if (offset < s->attrs.filesize) {
1246
+ if (offset < s->attrs->size) {
1247
error_setg(errp, "ssh driver does not support shrinking files");
1248
return -ENOTSUP;
1249
}
1250
1251
- if (offset == s->attrs.filesize) {
1252
+ if (offset == s->attrs->size) {
1253
return 0;
1254
}
1255
1256
@@ -XXX,XX +XXX,XX @@ static void bdrv_ssh_init(void)
1257
{
1258
int r;
1259
1260
- r = libssh2_init(0);
1261
+ r = ssh_init();
1262
if (r != 0) {
1263
- fprintf(stderr, "libssh2 initialization failed, %d\n", r);
1264
+ fprintf(stderr, "libssh initialization failed, %d\n", r);
1265
exit(EXIT_FAILURE);
1266
}
1267
1268
+#if TRACE_LIBSSH != 0
1269
+ ssh_set_log_level(TRACE_LIBSSH);
1270
+#endif
1271
+
1272
bdrv_register(&bdrv_ssh);
1273
}
1274
1275
diff --git a/.travis.yml b/.travis.yml
1276
index XXXXXXX..XXXXXXX 100644
1277
--- a/.travis.yml
1278
+++ b/.travis.yml
1279
@@ -XXX,XX +XXX,XX @@ addons:
1280
- libseccomp-dev
1281
- libspice-protocol-dev
1282
- libspice-server-dev
1283
- - libssh2-1-dev
1284
+ - libssh-dev
1285
- liburcu-dev
1286
- libusb-1.0-0-dev
1287
- libvte-2.91-dev
1288
@@ -XXX,XX +XXX,XX @@ matrix:
1289
- libseccomp-dev
1290
- libspice-protocol-dev
1291
- libspice-server-dev
1292
- - libssh2-1-dev
1293
+ - libssh-dev
1294
- liburcu-dev
1295
- libusb-1.0-0-dev
1296
- libvte-2.91-dev
1297
diff --git a/block/trace-events b/block/trace-events
1298
index XXXXXXX..XXXXXXX 100644
1299
--- a/block/trace-events
1300
+++ b/block/trace-events
1301
@@ -XXX,XX +XXX,XX @@ nbd_client_connect_success(const char *export_name) "export '%s'"
1302
# ssh.c
1303
ssh_restart_coroutine(void *co) "co=%p"
1304
ssh_flush(void) "fsync"
1305
-ssh_check_host_key_knownhosts(const char *key) "host key OK: %s"
1306
+ssh_check_host_key_knownhosts(void) "host key OK"
1307
ssh_connect_to_ssh(char *path, int flags, int mode) "opening file %s flags=0x%x creat_mode=0%o"
1308
ssh_co_yield(int sock, void *rd_handler, void *wr_handler) "s->sock=%d rd_handler=%p wr_handler=%p"
1309
ssh_co_yield_back(int sock) "s->sock=%d - back"
1310
ssh_getlength(int64_t length) "length=%" PRIi64
1311
ssh_co_create_opts(uint64_t size) "total_size=%" PRIu64
1312
ssh_read(int64_t offset, size_t size) "offset=%" PRIi64 " size=%zu"
1313
-ssh_read_buf(void *buf, size_t size) "sftp_read buf=%p size=%zu"
1314
-ssh_read_return(ssize_t ret) "sftp_read returned %zd"
1315
+ssh_read_buf(void *buf, size_t size, size_t actual_size) "sftp_read buf=%p size=%zu (actual size=%zu)"
1316
+ssh_read_return(ssize_t ret, int sftp_err) "sftp_read returned %zd (sftp error=%d)"
1317
ssh_write(int64_t offset, size_t size) "offset=%" PRIi64 " size=%zu"
1318
-ssh_write_buf(void *buf, size_t size) "sftp_write buf=%p size=%zu"
1319
-ssh_write_return(ssize_t ret) "sftp_write returned %zd"
1320
+ssh_write_buf(void *buf, size_t size, size_t actual_size) "sftp_write buf=%p size=%zu (actual size=%zu)"
1321
+ssh_write_return(ssize_t ret, int sftp_err) "sftp_write returned %zd (sftp error=%d)"
1322
ssh_seek(int64_t offset) "seeking to offset=%" PRIi64
1323
+ssh_auth_methods(int methods) "auth methods=0x%x"
1324
+ssh_server_status(int status) "server status=%d"
1325
1326
# curl.c
1327
curl_timer_cb(long timeout_ms) "timer callback timeout_ms %ld"
1328
@@ -XXX,XX +XXX,XX @@ sheepdog_snapshot_create(const char *sn_name, const char *id) "%s %s"
1329
sheepdog_snapshot_create_inode(const char *name, uint32_t snap, uint32_t vdi) "s->inode: name %s snap_id 0x%" PRIx32 " vdi 0x%" PRIx32
1330
1331
# ssh.c
1332
-sftp_error(const char *op, const char *ssh_err, int ssh_err_code, unsigned long sftp_err_code) "%s failed: %s (libssh2 error code: %d, sftp error code: %lu)"
1333
+sftp_error(const char *op, const char *ssh_err, int ssh_err_code, int sftp_err_code) "%s failed: %s (libssh error code: %d, sftp error code: %d)"
1334
diff --git a/docs/qemu-block-drivers.texi b/docs/qemu-block-drivers.texi
1335
index XXXXXXX..XXXXXXX 100644
1336
--- a/docs/qemu-block-drivers.texi
1337
+++ b/docs/qemu-block-drivers.texi
1338
@@ -XXX,XX +XXX,XX @@ print a warning when @code{fsync} is not supported:
1339
1340
warning: ssh server @code{ssh.example.com:22} does not support fsync
1341
1342
-With sufficiently new versions of libssh2 and OpenSSH, @code{fsync} is
1343
+With sufficiently new versions of libssh and OpenSSH, @code{fsync} is
1344
supported.
1345
1346
@node disk_images_nvme
1347
diff --git a/tests/docker/dockerfiles/debian-win32-cross.docker b/tests/docker/dockerfiles/debian-win32-cross.docker
1348
index XXXXXXX..XXXXXXX 100644
1349
--- a/tests/docker/dockerfiles/debian-win32-cross.docker
1350
+++ b/tests/docker/dockerfiles/debian-win32-cross.docker
1351
@@ -XXX,XX +XXX,XX @@ RUN DEBIAN_FRONTEND=noninteractive eatmydata \
1352
mxe-$TARGET-w64-mingw32.shared-curl \
1353
mxe-$TARGET-w64-mingw32.shared-glib \
1354
mxe-$TARGET-w64-mingw32.shared-libgcrypt \
1355
- mxe-$TARGET-w64-mingw32.shared-libssh2 \
1356
mxe-$TARGET-w64-mingw32.shared-libusb1 \
1357
mxe-$TARGET-w64-mingw32.shared-lzo \
1358
mxe-$TARGET-w64-mingw32.shared-nettle \
1359
diff --git a/tests/docker/dockerfiles/debian-win64-cross.docker b/tests/docker/dockerfiles/debian-win64-cross.docker
1360
index XXXXXXX..XXXXXXX 100644
1361
--- a/tests/docker/dockerfiles/debian-win64-cross.docker
1362
+++ b/tests/docker/dockerfiles/debian-win64-cross.docker
1363
@@ -XXX,XX +XXX,XX @@ RUN DEBIAN_FRONTEND=noninteractive eatmydata \
1364
mxe-$TARGET-w64-mingw32.shared-curl \
1365
mxe-$TARGET-w64-mingw32.shared-glib \
1366
mxe-$TARGET-w64-mingw32.shared-libgcrypt \
1367
- mxe-$TARGET-w64-mingw32.shared-libssh2 \
1368
mxe-$TARGET-w64-mingw32.shared-libusb1 \
1369
mxe-$TARGET-w64-mingw32.shared-lzo \
1370
mxe-$TARGET-w64-mingw32.shared-nettle \
1371
diff --git a/tests/docker/dockerfiles/fedora.docker b/tests/docker/dockerfiles/fedora.docker
1372
index XXXXXXX..XXXXXXX 100644
1373
--- a/tests/docker/dockerfiles/fedora.docker
1374
+++ b/tests/docker/dockerfiles/fedora.docker
1375
@@ -XXX,XX +XXX,XX @@ ENV PACKAGES \
1376
libpng-devel \
1377
librbd-devel \
1378
libseccomp-devel \
1379
- libssh2-devel \
1380
+ libssh-devel \
1381
libubsan \
1382
libusbx-devel \
1383
libxml2-devel \
1384
@@ -XXX,XX +XXX,XX @@ ENV PACKAGES \
1385
mingw32-gtk3 \
1386
mingw32-libjpeg-turbo \
1387
mingw32-libpng \
1388
- mingw32-libssh2 \
1389
mingw32-libtasn1 \
1390
mingw32-nettle \
1391
mingw32-pixman \
1392
@@ -XXX,XX +XXX,XX @@ ENV PACKAGES \
1393
mingw64-gtk3 \
1394
mingw64-libjpeg-turbo \
1395
mingw64-libpng \
1396
- mingw64-libssh2 \
1397
mingw64-libtasn1 \
1398
mingw64-nettle \
1399
mingw64-pixman \
1400
diff --git a/tests/docker/dockerfiles/ubuntu.docker b/tests/docker/dockerfiles/ubuntu.docker
1401
index XXXXXXX..XXXXXXX 100644
1402
--- a/tests/docker/dockerfiles/ubuntu.docker
1403
+++ b/tests/docker/dockerfiles/ubuntu.docker
1404
@@ -XXX,XX +XXX,XX @@ ENV PACKAGES flex bison \
1405
libsnappy-dev \
1406
libspice-protocol-dev \
1407
libspice-server-dev \
1408
- libssh2-1-dev \
1409
+ libssh-dev \
1410
libusb-1.0-0-dev \
1411
libusbredirhost-dev \
1412
libvdeplug-dev \
1413
diff --git a/tests/docker/dockerfiles/ubuntu1804.docker b/tests/docker/dockerfiles/ubuntu1804.docker
1414
index XXXXXXX..XXXXXXX 100644
1415
--- a/tests/docker/dockerfiles/ubuntu1804.docker
1416
+++ b/tests/docker/dockerfiles/ubuntu1804.docker
1417
@@ -XXX,XX +XXX,XX @@ ENV PACKAGES flex bison \
1418
libsnappy-dev \
1419
libspice-protocol-dev \
1420
libspice-server-dev \
1421
- libssh2-1-dev \
1422
+ libssh-dev \
1423
libusb-1.0-0-dev \
1424
libusbredirhost-dev \
1425
libvdeplug-dev \
1426
diff --git a/tests/qemu-iotests/207 b/tests/qemu-iotests/207
1427
index XXXXXXX..XXXXXXX 100755
1428
--- a/tests/qemu-iotests/207
1429
+++ b/tests/qemu-iotests/207
1430
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.img') as disk_path, \
1431
1432
iotests.img_info_log(remote_path)
1433
1434
- md5_key = subprocess.check_output(
1435
- 'ssh-keyscan -t rsa 127.0.0.1 2>/dev/null | grep -v "\\^#" | ' +
1436
- 'cut -d" " -f3 | base64 -d | md5sum -b | cut -d" " -f1',
1437
- shell=True).rstrip().decode('ascii')
1438
+ keys = subprocess.check_output(
1439
+ 'ssh-keyscan 127.0.0.1 2>/dev/null | grep -v "\\^#" | ' +
1440
+ 'cut -d" " -f3',
1441
+ shell=True).rstrip().decode('ascii').split('\n')
1442
+
1443
+ # Mappings of base64 representations to digests
1444
+ md5_keys = {}
1445
+ sha1_keys = {}
1446
+
1447
+ for key in keys:
1448
+ md5_keys[key] = subprocess.check_output(
1449
+ 'echo %s | base64 -d | md5sum -b | cut -d" " -f1' % key,
1450
+ shell=True).rstrip().decode('ascii')
1451
+
1452
+ sha1_keys[key] = subprocess.check_output(
1453
+ 'echo %s | base64 -d | sha1sum -b | cut -d" " -f1' % key,
1454
+ shell=True).rstrip().decode('ascii')
1455
1456
vm.launch()
1457
+
1458
+ # Find correct key first
1459
+ matching_key = None
1460
+ for key in keys:
1461
+ result = vm.qmp('blockdev-add',
1462
+ driver='ssh', node_name='node0', path=disk_path,
1463
+ server={
1464
+ 'host': '127.0.0.1',
1465
+ 'port': '22',
1466
+ }, host_key_check={
1467
+ 'mode': 'hash',
1468
+ 'type': 'md5',
1469
+ 'hash': md5_keys[key],
1470
+ })
1471
+
1472
+ if 'error' not in result:
1473
+ vm.qmp('blockdev-del', node_name='node0')
1474
+ matching_key = key
1475
+ break
1476
+
1477
+ if matching_key is None:
1478
+ vm.shutdown()
1479
+ iotests.notrun('Did not find a key that fits 127.0.0.1')
1480
+
1481
blockdev_create(vm, { 'driver': 'ssh',
1482
'location': {
1483
'path': disk_path,
1484
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.img') as disk_path, \
1485
'host-key-check': {
1486
'mode': 'hash',
1487
'type': 'md5',
1488
- 'hash': md5_key,
1489
+ 'hash': md5_keys[matching_key],
1490
}
1491
},
1492
'size': 8388608 })
1493
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.img') as disk_path, \
1494
1495
iotests.img_info_log(remote_path)
1496
1497
- sha1_key = subprocess.check_output(
1498
- 'ssh-keyscan -t rsa 127.0.0.1 2>/dev/null | grep -v "\\^#" | ' +
1499
- 'cut -d" " -f3 | base64 -d | sha1sum -b | cut -d" " -f1',
1500
- shell=True).rstrip().decode('ascii')
1501
-
1502
vm.launch()
1503
blockdev_create(vm, { 'driver': 'ssh',
1504
'location': {
1505
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.img') as disk_path, \
1506
'host-key-check': {
1507
'mode': 'hash',
1508
'type': 'sha1',
1509
- 'hash': sha1_key,
1510
+ 'hash': sha1_keys[matching_key],
1511
}
1512
},
1513
'size': 4194304 })
1514
diff --git a/tests/qemu-iotests/207.out b/tests/qemu-iotests/207.out
1515
index XXXXXXX..XXXXXXX 100644
1516
--- a/tests/qemu-iotests/207.out
1517
+++ b/tests/qemu-iotests/207.out
1518
@@ -XXX,XX +XXX,XX @@ virtual size: 4 MiB (4194304 bytes)
1519
1520
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"mode": "none"}, "path": "/this/is/not/an/existing/path", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 4194304}}}
1521
{"return": {}}
1522
-Job failed: failed to open remote file '/this/is/not/an/existing/path': Failed opening remote file (libssh2 error code: -31)
1523
+Job failed: failed to open remote file '/this/is/not/an/existing/path': SFTP server: No such file (libssh error code: 1, sftp error code: 2)
1524
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
1525
{"return": {}}
1526
2387
--
1527
--
2388
2.14.3
1528
2.21.0
2389
1529
2390
1530
diff view generated by jsdifflib
1
From: Fam Zheng <famz@redhat.com>
1
Tests should place their files into the test directory. This includes
2
Unix sockets. 205 currently fails to do so, which prevents it from
3
being run concurrently.
2
4
3
Signed-off-by: Fam Zheng <famz@redhat.com>
5
Signed-off-by: Max Reitz <mreitz@redhat.com>
4
Message-id: 20180226030326.20219-3-famz@redhat.com
6
Message-id: 20190618210238.9524-1-mreitz@redhat.com
5
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
7
Reviewed-by: Eric Blake <eblake@redhat.com>
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
6
---
9
---
7
README | 31 ++++++++++++++++++++++++++++++-
10
tests/qemu-iotests/205 | 2 +-
8
1 file changed, 30 insertions(+), 1 deletion(-)
11
1 file changed, 1 insertion(+), 1 deletion(-)
9
12
10
diff --git a/README b/README
13
diff --git a/tests/qemu-iotests/205 b/tests/qemu-iotests/205
11
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100755
12
--- a/README
15
--- a/tests/qemu-iotests/205
13
+++ b/README
16
+++ b/tests/qemu-iotests/205
14
@@ -XXX,XX +XXX,XX @@ The QEMU source code is maintained under the GIT version control system.
17
@@ -XXX,XX +XXX,XX @@ import iotests
15
18
import time
16
git clone git://git.qemu.org/qemu.git
19
from iotests import qemu_img_create, qemu_io, filter_qemu_io, QemuIoInteractive
17
20
18
-When submitting patches, the preferred approach is to use 'git
21
-nbd_sock = 'nbd_sock'
19
+When submitting patches, one common approach is to use 'git
22
+nbd_sock = os.path.join(iotests.test_dir, 'nbd_sock')
20
format-patch' and/or 'git send-email' to format & send the mail to the
23
nbd_uri = 'nbd+unix:///exp?socket=' + nbd_sock
21
qemu-devel@nongnu.org mailing list. All patches submitted must contain
24
disk = os.path.join(iotests.test_dir, 'disk')
22
a 'Signed-off-by' line from the author. Patches should follow the
23
@@ -XXX,XX +XXX,XX @@ The QEMU website is also maintained under source control.
24
git clone git://git.qemu.org/qemu-web.git
25
https://www.qemu.org/2017/02/04/the-new-qemu-website-is-up/
26
27
+A 'git-profile' utility was created to make above process less
28
+cumbersome, and is highly recommended for making regular contributions,
29
+or even just for sending consecutive patch series revisions. It also
30
+requires a working 'git send-email' setup, and by default doesn't
31
+automate everything, so you may want to go through the above steps
32
+manually for once.
33
+
34
+For installation instructions, please go to
35
+
36
+ https://github.com/stefanha/git-publish
37
+
38
+The workflow with 'git-publish' is:
39
+
40
+ $ git checkout master -b my-feature
41
+ $ # work on new commits, add your 'Signed-off-by' lines to each
42
+ $ git publish
43
+
44
+Your patch series will be sent and tagged as my-feature-v1 if you need to refer
45
+back to it in the future.
46
+
47
+Sending v2:
48
+
49
+ $ git checkout my-feature # same topic branch
50
+ $ # making changes to the commits (using 'git rebase', for example)
51
+ $ git publish
52
+
53
+Your patch series will be sent with 'v2' tag in the subject and the git tip
54
+will be tagged as my-feature-v2.
55
+
56
Bug reporting
57
=============
58
25
59
--
26
--
60
2.14.3
27
2.21.0
61
28
62
29
diff view generated by jsdifflib