diff --git a/0001-lib-uri.c-Replace-nbd-user-with-tls-username.patch b/0001-lib-uri.c-Replace-nbd-user-with-tls-username.patch new file mode 100644 index 0000000..807da84 --- /dev/null +++ b/0001-lib-uri.c-Replace-nbd-user-with-tls-username.patch @@ -0,0 +1,114 @@ +From 1f2ba448ffd703d3e19016fdc52bc181fb902346 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Sun, 24 Aug 2025 13:58:33 +0100 +Subject: [PATCH] lib/uri.c: Replace nbd-user with tls-username + +Commit f9df1ba621 added a new nbd-user parameter which let you +override the TLS username. It was misnamed, and should have been +called tls-username, both to reflect its actual use and to fit in with +the other tls-* parameters, so let's rename it. + +Renaming it also allows simplifying the loop which checks for other +query parameters. + +Updates: commit f9df1ba621cffc3ef74fdb27650c9258b0abd3fc +--- + generator/API.ml | 16 ++++++++-------- + lib/uri.c | 25 ++++++++++++------------- + 2 files changed, 20 insertions(+), 21 deletions(-) + +diff --git a/generator/API.ml b/generator/API.ml +index ab135004..c434e3e6 100644 +--- a/generator/API.ml ++++ b/generator/API.ml +@@ -2075,14 +2075,6 @@ For SSH transport, this specifies the port used to connect to + the NBD server, but the port in the authority field is used for + the SSH connection. + +-=item BC +- +-Override the username from the authority part of the URI. +- +-For SSH transport, this specifies the user for connecting to +-the NBD server, but the user in the authority field is used +-for the SSH connection. +- + =item BF + + Specifies the Unix domain socket to connect on. +@@ -2103,6 +2095,14 @@ this is not allowed by default - see next section. + + Set the TLS hostname. See L. + ++=item BC ++ ++Override the username from the authority part of the URI. ++ ++For SSH transport, this specifies the TLS username for connecting to ++the NBD server, but the user in the authority field is used ++for the SSH connection. ++ + =item B + + Do not verify the server certificate. See L. +diff --git a/lib/uri.c b/lib/uri.c +index e110bc34..45ba531c 100644 +--- a/lib/uri.c ++++ b/lib/uri.c +@@ -350,7 +350,7 @@ nbd_unlocked_aio_connect_uri (struct nbd_handle *h, const char *raw_uri) + uri_query_list queries = empty_vector; + int i, r; + int ret = -1; +- const char *nbd_user = NULL, *nbd_port = NULL; ++ const char *nbd_port = NULL; + const char *tls_username = NULL; + const char *unixsocket = NULL; + +@@ -489,9 +489,12 @@ nbd_unlocked_aio_connect_uri (struct nbd_handle *h, const char *raw_uri) + if (tls && nbd_unlocked_set_tls (h, LIBNBD_TLS_REQUIRE) == -1) + goto cleanup; + +- /* Look for some tls-* parameters. */ ++ /* Look for some other query parameters. */ + for (i = 0; i < queries.len; i++) { +- if (strcasecmp (queries.ptr[i].name, "tls-certificates") == 0) { ++ if (strcasecmp (queries.ptr[i].name, "nbd-port") == 0) { ++ nbd_port = queries.ptr[i].value; ++ } ++ else if (strcasecmp (queries.ptr[i].name, "tls-certificates") == 0) { + if (! h->uri_allow_local_file) { + set_error (EPERM, + "local file access (tls-certificates) is not allowed, " +@@ -515,6 +518,9 @@ nbd_unlocked_aio_connect_uri (struct nbd_handle *h, const char *raw_uri) + if (nbd_unlocked_set_tls_hostname (h, queries.ptr[i].value) == -1) + goto cleanup; + } ++ else if (strcasecmp (queries.ptr[i].name, "tls-username") == 0) { ++ tls_username = queries.ptr[i].value; /* set below */ ++ } + else if (strcasecmp (queries.ptr[i].name, "tls-verify-peer") == 0) { + int v = parse_bool ("tls-verify-peer", queries.ptr[i].value); + if (v == -1) +@@ -524,16 +530,9 @@ nbd_unlocked_aio_connect_uri (struct nbd_handle *h, const char *raw_uri) + } + } + +- /* NBD user and port overrides.. */ +- for (i = 0; i < queries.len; i++) { +- if (strcasecmp (queries.ptr[i].name, "nbd-user") == 0) +- nbd_user = queries.ptr[i].value; +- else if (strcasecmp (queries.ptr[i].name, "nbd-port") == 0) +- nbd_port = queries.ptr[i].value; +- } +- +- /* Set the TLS username. Always prefer nbd-user. */ +- tls_username = nbd_user ? : (uri->user ? : NULL); ++ /* Set the TLS username. Always prefer tls-username parameter. */ ++ if (!tls_username) ++ tls_username = uri->user; + if (tls_username && nbd_unlocked_set_tls_username (h, tls_username) == -1) + goto cleanup; + +-- +2.47.1 + diff --git a/0001-rust-Allow-cargo-build-target-RUST_TARGET-to-be-set.patch b/0001-rust-Allow-cargo-build-target-RUST_TARGET-to-be-set.patch deleted file mode 100644 index 47b8f9a..0000000 --- a/0001-rust-Allow-cargo-build-target-RUST_TARGET-to-be-set.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 1455311720b64b51a75fbc9f4da3e4a43551df53 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Tue, 22 Apr 2025 17:30:02 +0100 -Subject: [PATCH] rust: Allow cargo build --target $RUST_TARGET to be set - -(cherry picked from commit 6bfae4e22aad0d21a326ea2418dbc0d59718e14e) ---- - configure.ac | 2 ++ - rust/Makefile.am | 6 ++++-- - 2 files changed, 6 insertions(+), 2 deletions(-) - -diff --git a/configure.ac b/configure.ac -index 5feb6dbc..40d4f79f 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -751,6 +751,8 @@ AS_IF([test "x$enable_rust" != "xno"],[ - CARGO=no - ]) - ]) -+ AC_ARG_VAR([RUST_TARGET], -+ [if set, cargo build uses --target $RUST_TARGET]) - ],[CARGO=no]) - AM_CONDITIONAL([HAVE_RUST],[test "x$CARGO" != "xno"]) - -diff --git a/rust/Makefile.am b/rust/Makefile.am -index a7700d69..29c29bd9 100644 ---- a/rust/Makefile.am -+++ b/rust/Makefile.am -@@ -98,15 +98,17 @@ libnbd-sys/libnbd_version: Makefile - $(abs_top_builddir)/run echo $(VERSION) > libnbd-sys/libnbd_version.t - mv libnbd-sys/libnbd_version.t libnbd-sys/libnbd_version - -+RUST_TARGET_PARAM := $(if $(RUST_TARGET),--target $(RUST_TARGET)) -+ - target/debug/liblibnbd.rlib: $(source_files) -- $(abs_top_builddir)/run $(CARGO) build -+ $(abs_top_builddir)/run $(CARGO) build $(RUST_TARGET_PARAM) - - target/doc/libnbd/index.html: $(source_files) - $(abs_top_builddir)/run $(CARGO) doc - - # This will actually build all the examples: - target/debug/examples/get-size: $(source_files) -- $(abs_top_builddir)/run $(CARGO) build --examples -+ $(abs_top_builddir)/run $(CARGO) build $(RUST_TARGET_PARAM) --examples - - if HAVE_POD - --- -2.47.1 - diff --git a/0002-tests-Add-a-test-of-tls-username-in-NBD-URIs.patch b/0002-tests-Add-a-test-of-tls-username-in-NBD-URIs.patch new file mode 100644 index 0000000..87d5b58 --- /dev/null +++ b/0002-tests-Add-a-test-of-tls-username-in-NBD-URIs.patch @@ -0,0 +1,66 @@ +From 2a5c694f7370773cb51e0d344ea8da91cbe8518e Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Sun, 24 Aug 2025 16:32:18 +0100 +Subject: [PATCH] tests: Add a test of tls-username in NBD URIs + +This (or the previously added nbd-user) was not tested. +--- + .gitignore | 1 + + tests/Makefile.am | 18 ++++++++++++++++++ + 2 files changed, 19 insertions(+) + +diff --git a/.gitignore b/.gitignore +index bbe3967f..a373fc29 100644 +--- a/.gitignore ++++ b/.gitignore +@@ -230,6 +230,7 @@ Makefile.in + /tests/connect-uri-nbds-unix-tls-hostname + /tests/connect-uri-nbds-unix-tls-verify-peer-false + /tests/connect-uri-nbds-unix-psk ++/tests/connect-uri-nbds-unix-psk-tls-username + /tests/debug + /tests/debug-environment + /tests/dlopen +diff --git a/tests/Makefile.am b/tests/Makefile.am +index 8aca4c7d..e3b74a1d 100644 +--- a/tests/Makefile.am ++++ b/tests/Makefile.am +@@ -904,10 +904,12 @@ if HAVE_PSKTOOL + check_PROGRAMS += \ + connect-uri-nbds-psk \ + connect-uri-nbds-unix-psk \ ++ connect-uri-nbds-unix-psk-tls-username \ + $(NULL) + TESTS += \ + connect-uri-nbds-psk \ + connect-uri-nbds-unix-psk \ ++ connect-uri-nbds-unix-psk-tls-username \ + $(NULL) + + connect_uri_nbds_psk_SOURCES = \ +@@ -936,6 +938,22 @@ connect_uri_nbds_unix_psk_CPPFLAGS = \ + $(NULL) + connect_uri_nbds_unix_psk_LDADD = $(top_builddir)/lib/libnbd.la + ++connect_uri_nbds_unix_psk_tls_username_SOURCES = \ ++ connect-uri.c \ ++ requires.c requires.h pick-a-port.c pick-a-port.h \ ++ $(NULL) ++connect_uri_nbds_unix_psk_tls_username_CPPFLAGS = \ ++ $(AM_CPPFLAGS) \ ++ -DDEFINE_STR_AS_UNIX_SOCKET=1 \ ++ -DSERVER_PARAMS='"-U", str, "--tls=require", "--tls-verify-peer", "--tls-psk=keys.psk"' \ ++ -DREQUIRES="requires_nbdkit_tls_verify_peer ();" \ ++ -DURI='"nbds+unix://NOTUSED@/?tls-psk-file=keys.psk&socket=%s&tls-username=alice", str' \ ++ -DSKIP_GET_URI=1 \ ++ $(NULL) ++connect_uri_nbds_unix_psk_tls_username_LDADD = \ ++ $(top_builddir)/lib/libnbd.la \ ++ $(NULL) ++ + endif HAVE_PSKTOOL + + endif HAVE_GNUTLS +-- +2.47.1 + diff --git a/0003-docs-Document-which-NBD-URI-features-are-non-standar.patch b/0003-docs-Document-which-NBD-URI-features-are-non-standar.patch new file mode 100644 index 0000000..ac9d812 --- /dev/null +++ b/0003-docs-Document-which-NBD-URI-features-are-non-standar.patch @@ -0,0 +1,91 @@ +From 2bd353ef0e124c11b79eb3ed15eff5c8a9738086 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Sun, 24 Aug 2025 16:27:50 +0100 +Subject: [PATCH] docs: Document which NBD URI features are non-standard + +Also which version of libnbd implemented each feature (unless the +feature has basically been around since the beginning). +--- + generator/API.ml | 24 +++++++++++++++++++++++- + 1 file changed, 23 insertions(+), 1 deletion(-) + +diff --git a/generator/API.ml b/generator/API.ml +index c434e3e6..3ebc1912 100644 +--- a/generator/API.ml ++++ b/generator/API.ml +@@ -1992,6 +1992,16 @@ to an NBD server listening on port 10809. + + =back + ++=head2 NBD URI standard ++ ++L ++documents the NBD URI standard. ++ ++In the documentation below, I indicates features ++supported in libnbd which are not a part of the NBD URI standard, ++meaning that other NBD URI parsers might not support them or might ++implement things differently. ++ + =head2 URI scheme + + The scheme is the part before the first C<:>. The following schemes +@@ -2019,6 +2029,8 @@ respectively. The C parameter is required. + + =item C + ++I ++ + Connect over the C transport, without or with + TLS respectively. You can use L to + see if this build of libnbd supports C. +@@ -2027,7 +2039,7 @@ see if this build of libnbd supports C. + + =item C + +-I ++I 1.22> + + Tunnel NBD over a Secure Shell connection. This requires + that L is installed locally, and that L (from the +@@ -2069,6 +2081,8 @@ Finally the query part of the URI can contain: + + =item BC + ++I 1.24> ++ + Override the port number from the authority part of the URI. + + For SSH transport, this specifies the port used to connect to +@@ -2083,20 +2097,28 @@ for C<+ssh>, and must not be present for the other transports. + + =item BF + ++I 1.10> ++ + Set the certificates directory. See L. + Note this is not allowed by default - see next section. + + =item BF + ++I ++ + Set the PSK file. See L. Note + this is not allowed by default - see next section. + + =item BC + ++I 1.22> ++ + Set the TLS hostname. See L. + + =item BC + ++I 1.24> ++ + Override the username from the authority part of the URI. + + For SSH transport, this specifies the TLS username for connecting to +-- +2.47.1 + diff --git a/0003-maint-Spelling-fixes.patch b/0003-maint-Spelling-fixes.patch deleted file mode 100644 index 2fc86aa..0000000 --- a/0003-maint-Spelling-fixes.patch +++ /dev/null @@ -1,318 +0,0 @@ -From 3714f8912d9d1a56866df7309c4e9f0e6e60f809 Mon Sep 17 00:00:00 2001 -From: Eric Blake -Date: Thu, 24 Apr 2025 08:30:00 -0500 -Subject: [PATCH] maint: Spelling fixes - -As detected by: - -$ git ls-files | xargs codespell -L Tage - -Signed-off-by: Eric Blake -(cherry picked from commit 17513dabee51b2bbbe878b06aafc50e6e2ba28de) ---- - copy/file-ops.c | 2 +- - docs/libnbd-release-notes-1.18.pod | 2 +- - docs/libnbd.pod | 4 ++-- - examples/copy-libev.c | 12 ++++++------ - golang/aio_buffer.go | 2 +- - golang/callbacks.go | 2 +- - golang/examples/aio_copy/aio_copy.go | 4 ++-- - golang/libnbd_020_aio_buffer_test.go | 2 +- - golang/libnbd_590_aio_copy_test.go | 2 +- - golang/make-dist.sh | 2 +- - info/main.c | 8 ++++---- - interop/interop.c | 2 +- - ocaml/examples/asynch_copy.ml | 2 +- - ocaml/tests/test_590_aio_copy.ml | 2 +- - rust/cargo_test/README.md | 6 +++--- - rust/tests/test_log/mod.rs | 2 +- - tests/closure-lifetimes.c | 2 +- - 17 files changed, 29 insertions(+), 29 deletions(-) - -diff --git a/copy/file-ops.c b/copy/file-ops.c -index 491a4553..b3b04f5d 100644 ---- a/copy/file-ops.c -+++ b/copy/file-ops.c -@@ -82,7 +82,7 @@ struct rw_file { - bool seek_hole_supported; - int sector_size; - -- /* We try to use the most eficient zeroing first. If an efficent zero -+ /* We try to use the most efficient zeroing first. If an efficient zero - * method is not available, we disable the flag so next time we use - * the working method. - */ -diff --git a/docs/libnbd-release-notes-1.18.pod b/docs/libnbd-release-notes-1.18.pod -index 836ebe19..dc284bf4 100644 ---- a/docs/libnbd-release-notes-1.18.pod -+++ b/docs/libnbd-release-notes-1.18.pod -@@ -145,7 +145,7 @@ Consistently wrap source code at 80 columns (Laszlo Ersek). - - Debug messages no longer print the very verbose state transitions - inside the state machine as these are not usually useful. You can --reenable this by defining C<-DLIBNBD_STATE_VERBOSE=1> at compile time. -+re-enable this by defining C<-DLIBNBD_STATE_VERBOSE=1> at compile time. - - Completion C<.callback> methods are now always called exactly once, - and documentation is clearer on when this happens (Eric Blake). -diff --git a/docs/libnbd.pod b/docs/libnbd.pod -index 796a6f03..a7039210 100644 ---- a/docs/libnbd.pod -+++ b/docs/libnbd.pod -@@ -936,7 +936,7 @@ it would cause deadlock. - - =head2 Completion callbacks - --All of the asychronous commands have an optional completion callback -+All of the asynchronous commands have an optional completion callback - function that is used if the call to the asynchronous API reports - success. The completion callback is invoked when the submitted - command is eventually marked complete, after any mid-command callbacks -@@ -976,7 +976,7 @@ callback will still be valid (corresponding to the current portion of - the server's reply), and the overall command will still fail (at the - completion callback or L for an - asynchronous command, or as the result of the overall synchronous --command). Returing C<-1> from a mid-command callback does not prevent -+command). Returning C<-1> from a mid-command callback does not prevent - that callback from being reached again, if the server sends more - mid-command replies that warrant another use of that callback. A - mid-command callback may be reached more times than expected if the -diff --git a/examples/copy-libev.c b/examples/copy-libev.c -index e8e3cda2..6c91c55d 100644 ---- a/examples/copy-libev.c -+++ b/examples/copy-libev.c -@@ -3,7 +3,7 @@ - * - * http://pod.tst.eu/http://cvs.schmorp.de/libev/ev.pod - * -- * To build it you need the libev-devel pacakge. -+ * To build it you need the libev-devel package. - * - * To run it: - * -@@ -32,7 +32,7 @@ - - #include - --/* These values depend on the enviroment tested. -+/* These values depend on the environment tested. - * - * For shared storage using direct I/O: - * -@@ -76,8 +76,8 @@ enum request_state { - IDLE, /* Not used yet. */ - EXTENTS, /* Getting extents from source. */ - READ, /* Read from source. */ -- WRITE, /* Write to destiation. */ -- ZERO, /* Write zeroes to destiation. */ -+ WRITE, /* Write to destination. */ -+ ZERO, /* Write zeroes to destination. */ - SLEEP /* Waiting for extents completion. */ - }; - -@@ -631,12 +631,12 @@ main (int argc, char *argv[]) - - debug = getenv ("COPY_LIBEV_DEBUG") != NULL; - -- /* Configure soruce to report extents. */ -+ /* Configure source to report extents. */ - - if (nbd_add_meta_context (src.nbd, LIBNBD_CONTEXT_BASE_ALLOCATION)) - FAIL ("Cannot add base:allocation: %s", nbd_get_error ()); - -- /* Connecting is fast, so use the syncronous API. */ -+ /* Connecting is fast, so use the synchronous API. */ - - if (nbd_connect_uri (src.nbd, argv[1])) - FAIL ("Cannot connect to source: %s", nbd_get_error ()); -diff --git a/golang/aio_buffer.go b/golang/aio_buffer.go -index 3ddfce94..ff00e0a4 100644 ---- a/golang/aio_buffer.go -+++ b/golang/aio_buffer.go -@@ -80,7 +80,7 @@ func (b *AioBuffer) Bytes() []byte { - - // Slice creates a slice backed by the underlying C array. The slice can be - // used to access or modify the contents of the underlying array. The slice --// must not be used after caling Free(). -+// must not be used after calling Free(). - func (b *AioBuffer) Slice() []byte { - if b.P == nil { - panic("Using AioBuffer after Free()") -diff --git a/golang/callbacks.go b/golang/callbacks.go -index ac53572c..f9b4958a 100644 ---- a/golang/callbacks.go -+++ b/golang/callbacks.go -@@ -36,7 +36,7 @@ - // - Create an exported Golang function whose job will be to retrieve - // the context and execute the callback in it - // (connErrCallback). Such a function should receive a callback ID --// and will use it to retrive the context. -+// and will use it to retrieve the context. - // - // - Create a CGO function similar to the above function but with the - // appropriate signature to be registered as a callback in C code -diff --git a/golang/examples/aio_copy/aio_copy.go b/golang/examples/aio_copy/aio_copy.go -index 1de115b1..62756a97 100644 ---- a/golang/examples/aio_copy/aio_copy.go -+++ b/golang/examples/aio_copy/aio_copy.go -@@ -62,8 +62,8 @@ - ) - - // command keeps state of single AioPread call while the read is handled by --// libnbd, until the command reach the front of the queue and can be writen to --// the output. -+// libnbd, until the command reach the front of the queue and can be written -+// to the output. - type command struct { - buf libnbd.AioBuffer - ready bool -diff --git a/golang/libnbd_020_aio_buffer_test.go b/golang/libnbd_020_aio_buffer_test.go -index 5e63e27c..8addc350 100644 ---- a/golang/libnbd_020_aio_buffer_test.go -+++ b/golang/libnbd_020_aio_buffer_test.go -@@ -75,7 +75,7 @@ func TestAioBuffer(t *testing.T) { - t.Fatalf("Expected %v, got %v", zeroes, buf2.Bytes()) - } - -- /* Crated a zeroed buffer. */ -+ /* Create a zeroed buffer. */ - buf3 := MakeAioBufferZero(uint(32)) - defer buf.Free() - -diff --git a/golang/libnbd_590_aio_copy_test.go b/golang/libnbd_590_aio_copy_test.go -index 6ae0cc63..410c8f45 100644 ---- a/golang/libnbd_590_aio_copy_test.go -+++ b/golang/libnbd_590_aio_copy_test.go -@@ -86,7 +86,7 @@ func write_completed(buf AioBuffer) int { - return 1 - } - --/* Copy between two libnbd handles using aynchronous I/O (AIO). */ -+/* Copy between two libnbd handles using asynchronous I/O (AIO). */ - func asynch_copy(t *testing.T, src *Libnbd, dst *Libnbd) { - size, _ := dst.GetSize() - -diff --git a/golang/make-dist.sh b/golang/make-dist.sh -index e6c126c3..03cfc6a2 100755 ---- a/golang/make-dist.sh -+++ b/golang/make-dist.sh -@@ -112,7 +112,7 @@ echo "$info" > $v_dir/$version.info - cp go.mod $v_dir/$version.mod - mv $version.zip $v_dir - --# Create the list file by amending the curent file on the server. -+# Create the list file by amending the current file on the server. - list_url=https://download.libguestfs.org/libnbd/golang/libguestfs.org/libnbd/@v/list - curl --silent --show-error "$list_url" | sort > $v_dir/list - grep -q "$version" $v_dir/list || echo "$version" >> $v_dir/list -diff --git a/info/main.c b/info/main.c -index 1ee9e329..f7da425f 100644 ---- a/info/main.c -+++ b/info/main.c -@@ -130,7 +130,7 @@ main (int argc, char *argv[]) - { "can", required_argument, NULL, CAN_OPTION }, - { "cannot", required_argument, NULL, CANNOT_OPTION }, - { "can-not", required_argument, NULL, CANNOT_OPTION }, -- { "cant", required_argument, NULL, CANNOT_OPTION }, -+ { "can""t", required_argument, NULL, CANNOT_OPTION }, - { "color", no_argument, NULL, COLOUR_OPTION }, - { "colors", no_argument, NULL, COLOUR_OPTION }, - { "colour", no_argument, NULL, COLOUR_OPTION }, -@@ -144,15 +144,15 @@ main (int argc, char *argv[]) - { "has", required_argument, NULL, CAN_OPTION }, - { "hasnot", required_argument, NULL, CANNOT_OPTION }, - { "has-not", required_argument, NULL, CANNOT_OPTION }, -- { "hasnt", required_argument, NULL, CANNOT_OPTION }, -+ { "hasn""t", required_argument, NULL, CANNOT_OPTION }, - { "have", required_argument, NULL, CAN_OPTION }, -- { "havent", required_argument, NULL, CANNOT_OPTION }, -+ { "haven""t", required_argument, NULL, CANNOT_OPTION }, - { "havenot", required_argument, NULL, CANNOT_OPTION }, - { "have-not", required_argument, NULL, CANNOT_OPTION }, - { "is", required_argument, NULL, CAN_OPTION }, - { "isnot", required_argument, NULL, CANNOT_OPTION }, - { "is-not", required_argument, NULL, CANNOT_OPTION }, -- { "isnt", required_argument, NULL, CANNOT_OPTION }, -+ { "isn""t", required_argument, NULL, CANNOT_OPTION }, - { "json", no_argument, NULL, JSON_OPTION }, - { "list", no_argument, NULL, 'L' }, - { "long-options", no_argument, NULL, LONG_OPTIONS }, -diff --git a/interop/interop.c b/interop/interop.c -index 1ea0216e..841b7c9d 100644 ---- a/interop/interop.c -+++ b/interop/interop.c -@@ -131,7 +131,7 @@ main (int argc, char *argv[]) - * need to have our own log handler. - * - * Also the log levels are quite random. Level 2 doesn't show the -- * negotiated cyphersuite, but level 3+ shows excessive detail. -+ * negotiated ciphersuite, but level 3+ shows excessive detail. - */ - gnutls_global_set_log_level (2); - gnutls_global_set_log_function (tls_log); -diff --git a/ocaml/examples/asynch_copy.ml b/ocaml/examples/asynch_copy.ml -index 7132f573..8962a09e 100644 ---- a/ocaml/examples/asynch_copy.ml -+++ b/ocaml/examples/asynch_copy.ml -@@ -10,7 +10,7 @@ let max_reads_in_flight = 16 - let dir_is_read dir = dir land (Int32.to_int NBD.aio_direction_read) <> 0 - let dir_is_write dir = dir land (Int32.to_int NBD.aio_direction_write) <> 0 - --(* Copy between two libnbd handles using aynchronous I/O (AIO). *) -+(* Copy between two libnbd handles using asynchronous I/O (AIO). *) - let asynch_copy src dst = - let size = NBD.get_size dst in - -diff --git a/ocaml/tests/test_590_aio_copy.ml b/ocaml/tests/test_590_aio_copy.ml -index 25105e07..b5fb5cd6 100644 ---- a/ocaml/tests/test_590_aio_copy.ml -+++ b/ocaml/tests/test_590_aio_copy.ml -@@ -34,7 +34,7 @@ let bytes_written = ref 0 - let dir_is_read dir = dir land (Int32.to_int NBD.aio_direction_read) <> 0 - let dir_is_write dir = dir land (Int32.to_int NBD.aio_direction_write) <> 0 - --(* Copy between two libnbd handles using aynchronous I/O (AIO). *) -+(* Copy between two libnbd handles using asynchronous I/O (AIO). *) - let asynch_copy src dst = - let size = NBD.get_size dst in - -diff --git a/rust/cargo_test/README.md b/rust/cargo_test/README.md -index f80646b9..039cdb3e 100644 ---- a/rust/cargo_test/README.md -+++ b/rust/cargo_test/README.md -@@ -1,3 +1,3 @@ --The solely purpose of this directory is to serve as a test crate for checking if Cargo is useable. --`cargo test`, `cargo doc` and `cargo fmt` are run in the Autoconf script in this directory. If any of the commands failes, --Cargo is assumed not to be useable and the Rust bindings will be disabled. -+The sole purpose of this directory is to serve as a test crate for checking if Cargo is usable. -+`cargo test`, `cargo doc` and `cargo fmt` are run in the Autoconf script in this directory. If any of the commands fails, -+Cargo is assumed not to be usable and the Rust bindings will be disabled. -diff --git a/rust/tests/test_log/mod.rs b/rust/tests/test_log/mod.rs -index 8dbcd79f..d3fe98eb 100644 ---- a/rust/tests/test_log/mod.rs -+++ b/rust/tests/test_log/mod.rs -@@ -49,7 +49,7 @@ impl DebugLogger { - } - } - -- /// Check wether a specific message has been logged. -+ /// Check whether a specific message has been logged. - pub fn contains(&self, msg: &str) -> bool { - self.entries.lock().unwrap().iter().any(|(_, x)| x == msg) - } -diff --git a/tests/closure-lifetimes.c b/tests/closure-lifetimes.c -index b9d9ce14..d6625095 100644 ---- a/tests/closure-lifetimes.c -+++ b/tests/closure-lifetimes.c -@@ -156,7 +156,7 @@ main (int argc, char *argv[]) - completion_callback, 0); - if (cookie == -1) NBD_ERROR; - /* read_cb_called is indeterminate at this point, as state machine -- * progress may vary based on task schduling and network speed factors. -+ * progress may vary based on task scheduling and network speed factors. - */ - assert (completion_cb_called == 0); - assert (read_cb_freed == 0); --- -2.47.1 - diff --git a/0004-docs-Minor-copyediting-to-export-name-documentation.patch b/0004-docs-Minor-copyediting-to-export-name-documentation.patch new file mode 100644 index 0000000..43b37fd --- /dev/null +++ b/0004-docs-Minor-copyediting-to-export-name-documentation.patch @@ -0,0 +1,64 @@ +From a518da9fdc54e3652f67d92d266106017145c62b Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Sun, 24 Aug 2025 18:54:47 +0100 +Subject: [PATCH] docs: Minor copyediting to export name documentation + +--- + generator/API.ml | 24 ++++++++++++++++-------- + 1 file changed, 16 insertions(+), 8 deletions(-) + +diff --git a/generator/API.ml b/generator/API.ml +index 3ebc1912..3ab3aacb 100644 +--- a/generator/API.ml ++++ b/generator/API.ml +@@ -478,15 +478,19 @@ handle with this information."; + permitted_states = [ Created; Negotiating ]; + shortdesc = "set the export name"; + longdesc = "\ +-For servers which require an export name or can serve different +-content on different exports, set the C to +-connect to. The default is the empty string C<\"\">. ++Some NBD servers can serve multiple disk images (\"exports\"). ++The export is picked by the client, by requesting an export name ++during the negotiation phase. The default export is the ++empty string C<\"\">. + ++Some NBD servers ignore this and serve the same content regardless. + This is only relevant when connecting to servers using the + newstyle protocol as the oldstyle protocol did not support +-export names. The NBD protocol limits export names to +-4096 bytes, but servers may not support the full length. +-The encoding of export names is always UTF-8. ++export names. ++ ++The NBD protocol limits export names to 4096 bytes, but servers ++may not support the full length. The encoding of export names ++is always UTF-8. + + When option mode is not in use, the export name must be set + before beginning a connection. However, when L +@@ -498,7 +502,9 @@ be used to learn details about an export before connecting. + + This call may be skipped if using L to connect + to a URI that includes an export name."; +- see_also = [Link "get_export_name"; Link "connect_uri"; ++ see_also = [Link "get_export_name"; ++ Link "get_canonical_export_name"; ++ Link "connect_uri"; + Link "set_opt_mode"; Link "opt_go"; Link "opt_list"; + Link "opt_info"]; + }; +@@ -603,7 +609,9 @@ C<\"\">). + Some servers are unlikely to report a canonical name unless the + client specifically hinted about wanting it, via L."; + example = Some "examples/server-flags.c"; +- see_also = [Link "set_full_info"; Link "get_export_name"; ++ see_also = [Link "set_full_info"; ++ Link "set_export_name"; ++ Link "get_export_name"; + Link "opt_info"]; + }; + +-- +2.47.1 + diff --git a/0004-generator-Avoid-const-correctness-warnings-in-golang.patch b/0004-generator-Avoid-const-correctness-warnings-in-golang.patch deleted file mode 100644 index 8e5014b..0000000 --- a/0004-generator-Avoid-const-correctness-warnings-in-golang.patch +++ /dev/null @@ -1,89 +0,0 @@ -From 3d7cc461d78451cda566d6994a30ae8e1e789575 Mon Sep 17 00:00:00 2001 -From: Eric Blake -Date: Sat, 31 May 2025 07:37:28 -0500 -Subject: [PATCH] generator: Avoid const-correctness warnings in golang - -Hack the generator to add the necessary casts to discard const in a -way that shuts up the warnings from compiling wrappers.go. - -Signed-off-by: Eric Blake -(cherry picked from commit a909e74f902bb9d1e8a4ab87ae5ccf76d4675787) ---- - generator/C.ml | 10 ++++++---- - generator/C.mli | 2 +- - generator/GoLang.ml | 4 ++-- - 3 files changed, 9 insertions(+), 7 deletions(-) - -diff --git a/generator/C.ml b/generator/C.ml -index ad08437c..50d22306 100644 ---- a/generator/C.ml -+++ b/generator/C.ml -@@ -286,16 +286,16 @@ let print_fndecl ?wrap ?closure_style name args optargs ret = - pr "\n LIBNBD_ATTRIBUTE_NONNULL (%s);\n" (String.concat ", " nns) - - let rec print_cbarg_list ?(wrap = false) ?maxcol ?types ?(parens = true) -- cbargs = -+ ?(noconst = false) cbargs = - if parens then pr "("; - if wrap then - pr_wrap ?maxcol ',' -- (fun () -> print_cbarg_list' ?types cbargs) -+ (fun () -> print_cbarg_list' ?types noconst cbargs) - else -- print_cbarg_list' ?types cbargs; -+ print_cbarg_list' ?types noconst cbargs; - if parens then pr ")" - --and print_cbarg_list' ?(types = true) cbargs = -+and print_cbarg_list' ?(types = true) noconst cbargs = - if types then pr "void *"; - pr "user_data"; - -@@ -316,6 +316,7 @@ and print_cbarg_list' ?(types = true) cbargs = - | CBArrayAndLen _ -> assert false - | CBBytesIn (n, len) -> - if types then pr "const void *"; -+ if noconst then pr "(void *)"; - pr "%s, " n; - if types then pr "size_t "; - pr "%s" len -@@ -331,6 +332,7 @@ and print_cbarg_list' ?(types = true) cbargs = - | CBMutable arg -> assert false - | CBString n -> - if types then pr "const char *"; -+ if noconst then pr "(char *)"; - pr "%s" n - | CBUInt n -> - if types then pr "unsigned "; -diff --git a/generator/C.mli b/generator/C.mli -index a4b31351..75d77276 100644 ---- a/generator/C.mli -+++ b/generator/C.mli -@@ -34,7 +34,7 @@ val print_arg_list : ?wrap:bool -> ?maxcol:int -> - ?closure_style:closure_style -> - API.arg list -> API.optarg list -> unit - val print_cbarg_list : ?wrap:bool -> ?maxcol:int -> -- ?types:bool -> ?parens:bool -> -+ ?types:bool -> ?parens:bool -> ?noconst:bool -> - API.cbarg list -> unit - val print_call : ?wrap:bool -> ?maxcol:int -> - ?closure_style:closure_style -> -diff --git a/generator/GoLang.ml b/generator/GoLang.ml -index 3fe7cd53..1505a598 100644 ---- a/generator/GoLang.ml -+++ b/generator/GoLang.ml -@@ -159,9 +159,9 @@ let print_callback_wrapper { cbname; cbargs } = - C.print_cbarg_list ~wrap:true cbargs; - pr "\n"; - pr "{\n"; -- pr " // golang isn't const-correct, there will be warnings here:\n"; -+ pr " // golang isn't const-correct, casts avoid warnings here:\n"; - pr " return %s_callback ((long *)" cbname; -- C.print_cbarg_list ~types:false ~parens:false cbargs; -+ C.print_cbarg_list ~types:false ~parens:false ~noconst:true cbargs; - pr ");\n"; - pr "}\n"; - pr "\n"; --- -2.47.1 - diff --git a/0005-info-Tolerate-nbdkit-slop-on-large-extents.patch b/0005-info-Tolerate-nbdkit-slop-on-large-extents.patch deleted file mode 100644 index 02472a5..0000000 --- a/0005-info-Tolerate-nbdkit-slop-on-large-extents.patch +++ /dev/null @@ -1,114 +0,0 @@ -From 5fef22179c1ce7e032a773733073349d90aab155 Mon Sep 17 00:00:00 2001 -From: Eric Blake -Date: Sat, 31 May 2025 08:24:37 -0500 -Subject: [PATCH] info: Tolerate nbdkit slop on large extents - -The NBD spec currently requires servers to send aligned block extents -back if the client and server agreed to a minimum block size; but -nbdkit 1.42 has an issue where the server recognizes that a plugin -reporting an aligned extent of exactly 4G is too large for a 32-bit -block status response, and truncates it early but to an unaligned -offset (such a truncation is to an offset larger than the client's -request size). Although I'm also submitting a parallel patch to the -NBD spec to relax things on this front, and to nbdkit 1.44 to report -aligned offsets in the first place, it is still worth teaching nbdinfo -to work around this shortcoming of existing nbdkit releases. The -added test fails when applied in isolation without the corresponding -map.c changes and run against nbdkit 1.42. - -Signed-off-by: Eric Blake -(cherry picked from commit 7dc75f2542a003c7429f1af93b7ecbaef00b567c) ---- - info/Makefile.am | 1 + - info/info-map-large-extent.sh | 42 +++++++++++++++++++++++++++++++++++ - info/map.c | 12 +++++++++- - 3 files changed, 54 insertions(+), 1 deletion(-) - create mode 100755 info/info-map-large-extent.sh - -diff --git a/info/Makefile.am b/info/Makefile.am -index 21cf3f46..697bb2b6 100644 ---- a/info/Makefile.am -+++ b/info/Makefile.am -@@ -49,6 +49,7 @@ info_sh_files = \ - info-map-base-allocation-large.sh \ - info-map-base-allocation-weird.sh \ - info-map-base-allocation-zero.sh \ -+ info-map-large-extent.sh \ - info-map-qemu-dirty-bitmap.sh \ - info-map-qemu-allocation-depth.sh \ - info-map-totals.sh \ -diff --git a/info/info-map-large-extent.sh b/info/info-map-large-extent.sh -new file mode 100755 -index 00000000..91867275 ---- /dev/null -+++ b/info/info-map-large-extent.sh -@@ -0,0 +1,42 @@ -+#!/usr/bin/env bash -+# nbd client library in userspace -+# Copyright Red Hat -+# -+# This library is free software; you can redistribute it and/or -+# modify it under the terms of the GNU Lesser General Public -+# License as published by the Free Software Foundation; either -+# version 2 of the License, or (at your option) any later version. -+# -+# This library is distributed in the hope that it will be useful, -+# but WITHOUT ANY WARRANTY; without even the implied warranty of -+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+# Lesser General Public License for more details. -+# -+# You should have received a copy of the GNU Lesser General Public -+# License along with this library; if not, write to the Free Software -+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -+ -+. ../tests/functions.sh -+ -+set -e -+set -x -+ -+requires $NBDKIT --version -+requires $NBDKIT -U - --filter=blocksize-policy data 1 --run 'test "$uri" != ""' -+ -+out=info-map-large-extent.out -+cleanup_fn rm -f $out -+rm -f $out -+ -+# nbdkit < 1.44 had a bug where 4G large extents would truncate larger than -+# the aligned request; whether or not nbdkit is fixed, we can work around it. -+$NBDKIT -U - data data='@4294967296 1 @^512' \ -+ --filter=blocksize-policy blocksize-minimum=512 \ -+ --run '$VG nbdinfo --map "$uri"' > $out -+ -+cat $out -+ -+diff -u - $out < max_len) { -+ entries.ptr[i].length = max_len; -+ entries.len = i + 1; -+ } - offset += entries.ptr[i].length; -+ } - } - - if (!totals) --- -2.47.1 - diff --git a/0006-todo-Remove-a-couple-of-minor-features-that-have-bee.patch b/0006-todo-Remove-a-couple-of-minor-features-that-have-bee.patch deleted file mode 100644 index c5674be..0000000 --- a/0006-todo-Remove-a-couple-of-minor-features-that-have-bee.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 2a8dbd3840c7b01e7c544035749d3fde893923ed Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Sat, 12 Jul 2025 18:12:42 +0100 -Subject: [PATCH] todo: Remove a couple of minor features that have been - implemented - -Rust was implemented in 2023. - -nbdcopy implemented page cache efficient operations. - -(cherry picked from commit fe284d59fa0e5a85a4abac418efb8b79d81cdbb5) ---- - TODO | 6 ------ - 1 file changed, 6 deletions(-) - -diff --git a/TODO b/TODO -index e140b4fd..426b0384 100644 ---- a/TODO -+++ b/TODO -@@ -1,10 +1,6 @@ - Explore if nbd_aio_notify_error is needed for faster response if - server goes away. - --Bindings in other languages. -- - Latest attempt at adding Rust: -- https://www.redhat.com/archives/libguestfs/2019-August/msg00416.html -- - Example code integrating with ppoll, pollfd, APR pollset (and others?). - - NBD resize extension. -@@ -32,8 +28,6 @@ nbdcopy: - - Synchronous loop should be adjusted to take into account - the NBD preferred block size, as was done for multi-thread loop. - - Benchmark. -- - Better page cache usage, see nbdkit-file-plugin options -- fadvise=sequential cache=none. - - Consider io_uring if there are performance bottlenecks. - - Configurable retries in response to read or write failures. - --- -2.47.1 - diff --git a/0007-ublk-Remove-unused-EXPECTED_VERSION.patch b/0007-ublk-Remove-unused-EXPECTED_VERSION.patch deleted file mode 100644 index 00ea8e0..0000000 --- a/0007-ublk-Remove-unused-EXPECTED_VERSION.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 5717b3a12ed7df158abf89fc79d030c415c1a113 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Wed, 16 Jul 2025 12:31:33 +0100 -Subject: [PATCH] ublk: Remove unused EXPECTED_VERSION - -Probably we should test nbdublk --version. As we do not, this -variable was not used. - -(cherry picked from commit 01f5d93d43f7eab0444c87d9d99e2ecea9bf9d44) ---- - ublk/Makefile.am | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/ublk/Makefile.am b/ublk/Makefile.am -index 667d7d0c..e06e4396 100644 ---- a/ublk/Makefile.am -+++ b/ublk/Makefile.am -@@ -24,7 +24,6 @@ EXTRA_DIST = \ - TESTS_ENVIRONMENT = \ - LIBNBD_DEBUG=1 \ - $(MALLOC_CHECKS) \ -- EXPECTED_VERSION=$(VERSION) \ - $(NULL) - LOG_COMPILER = $(top_builddir)/run - TESTS = --- -2.47.1 - diff --git a/0008-copy-Add-blkhash-option.patch b/0008-copy-Add-blkhash-option.patch deleted file mode 100644 index 9397cc6..0000000 --- a/0008-copy-Add-blkhash-option.patch +++ /dev/null @@ -1,1111 +0,0 @@ -From 028271bfaa85afeb6f74cb754655efe463e1b884 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Sat, 29 Mar 2025 11:46:52 +0000 -Subject: [PATCH] copy: Add --blkhash option - -This option calculates the blkhash (similar to checksum) of the file -as it is copied. Blkhash is described here: - - https://gitlab.com/nirs/blkhash - -and in more detail in this paper: - - Soffer, N. and Waisbard, E. (2024). An Efficient Hash Function - Construction for Sparse Data. In Proceedings of the 21st - International Conference on Security and Cryptography - SECRYPT; - ISBN 978-989-758-709-2; ISSN 2184-7711, SciTePress, pages - 698-703. DOI: 10.5220/0012764500003767. - -Thanks: Nir Soffer -(cherry picked from commit c6ed852f71fb25e1de8093631c5cfc1c7135d571) ---- - copy/Makefile.am | 12 + - copy/blkhash.c | 490 ++++++++++++++++++++++++++++++++++ - copy/copy-blkhash-known.sh | 83 ++++++ - copy/copy-blkhash-pattern.sh | 49 ++++ - copy/copy-blkhash-randfile.sh | 45 ++++ - copy/main.c | 81 +++++- - copy/multi-thread-copying.c | 12 +- - copy/nbdcopy.h | 12 + - copy/nbdcopy.pod | 55 +++- - copy/synch-copying.c | 3 + - 10 files changed, 836 insertions(+), 6 deletions(-) - create mode 100644 copy/blkhash.c - create mode 100755 copy/copy-blkhash-known.sh - create mode 100755 copy/copy-blkhash-pattern.sh - create mode 100755 copy/copy-blkhash-randfile.sh - -diff --git a/copy/Makefile.am b/copy/Makefile.am -index 0ca76450..c7e37058 100644 ---- a/copy/Makefile.am -+++ b/copy/Makefile.am -@@ -22,6 +22,9 @@ EXTRA_DIST = \ - copy-allocated-synch.sh \ - copy-allocated-destination-zero-asynch.sh \ - copy-allocated-destination-zero-synch.sh \ -+ copy-blkhash-known.sh \ -+ copy-blkhash-pattern.sh \ -+ copy-blkhash-randfile.sh \ - copy-block-to-nbd.sh \ - copy-destination-zero-asynch.sh \ - copy-destination-zero-synch.sh \ -@@ -72,6 +75,7 @@ TESTS = - - nbdcopy_SOURCES = \ - nbdcopy.h \ -+ blkhash.c \ - file-ops.c \ - main.c \ - multi-thread-copying.c \ -@@ -89,8 +93,10 @@ nbdcopy_CPPFLAGS = \ - nbdcopy_CFLAGS = \ - $(WARNINGS_CFLAGS) \ - $(PTHREAD_CFLAGS) \ -+ $(GNUTLS_CFLAGS) \ - $(NULL) - nbdcopy_LDADD = \ -+ $(GNUTLS_LIBS) \ - $(PTHREAD_LIBS) \ - $(top_builddir)/common/utils/libutils.la \ - $(top_builddir)/lib/libnbd.la \ -@@ -164,6 +170,12 @@ TESTS += \ - endif - - if HAVE_GNUTLS -+TESTS += \ -+ copy-blkhash-known.sh \ -+ copy-blkhash-pattern.sh \ -+ copy-blkhash-randfile.sh \ -+ $(NULL) -+ - if HAVE_PSKTOOL - TESTS += copy-tls.sh - endif -diff --git a/copy/blkhash.c b/copy/blkhash.c -new file mode 100644 -index 00000000..622d8a39 ---- /dev/null -+++ b/copy/blkhash.c -@@ -0,0 +1,490 @@ -+/* NBD client library in userspace. -+ * Copyright Red Hat -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#ifdef HAVE_GNUTLS -+#include -+#include -+#endif -+ -+#include -+ -+#include "byte-swapping.h" -+#include "ispowerof2.h" -+#include "iszero.h" -+#include "minmax.h" -+#include "rounding.h" -+#include "vector.h" -+ -+#include "nbdcopy.h" -+ -+#ifdef HAVE_GNUTLS -+ -+/* We will have one of these structs per blkhash block. */ -+struct block { -+ /* unknown => We haven't seen this block yet. 'ptr' is NULL. -+ * -+ * zero => The block is all zeroes. 'ptr' is NULL. -+ * -+ * data => The block is all data, and we have seen the whole block, -+ * and the hash has been computed. 'ptr' points to the computed -+ * hash. 'n' is unused. -+ * -+ * incomplete => Part of the block was seen. 'ptr' points to the -+ * data block, waiting to be completed. 'n' is the number of bytes -+ * seen so far. We will compute the hash and turn this into a -+ * 'data' or 'zero' block, either when we have seen all bytes of -+ * this block, or at the end. -+ * -+ * Note that this code assumes that we are called exactly once for a -+ * range in the disk image. -+ */ -+ enum { block_unknown = 0, block_zero, block_data, block_incomplete } type; -+ void *ptr; -+ size_t n; -+}; -+ -+DEFINE_VECTOR_TYPE(blocks, struct block); -+static blocks block_vec; -+ -+static void -+free_struct_block (struct block b) -+{ -+ free (b.ptr); -+} -+ -+/* Since nbdcopy is multi-threaded, we need to use locks to protect -+ * access to shared resources. But also because computing digests is -+ * very compute intensive, we must allow those to run in parallel as -+ * much as possible. Therefore the locking is carefully chosen to -+ * protect critical resources while allowing (most) hashing to happen -+ * in parallel. -+ * -+ * 'bv_lock' protects access to 'block_vec', and is needed whenever -+ * the vector might be extended. -+ * -+ * It's safe to hash complete blocks without acquiring any lock (since -+ * we should only be called once per complete block). However -+ * 'incomplete_lock' must be acquired whenever we deal with incomplete -+ * blocks as we might be called in parallel for those. -+ */ -+static pthread_mutex_t bv_lock = PTHREAD_MUTEX_INITIALIZER; -+static pthread_mutex_t incomplete_lock = PTHREAD_MUTEX_INITIALIZER; -+ -+/* Length of the digests of this algorithm in bytes. */ -+static size_t alg_len; -+ -+void -+init_blkhash (void) -+{ -+ if (blkhash_alg == GNUTLS_DIG_UNKNOWN) return; -+ -+ assert (is_power_of_2 (blkhash_size)); -+ -+ alg_len = gnutls_hash_get_len (blkhash_alg); -+ -+ /* If we know the source size in advance, reserve the block vector. -+ * We don't always know this (src->size == -1), eg. if reading from -+ * a pipe. If the size is exactly zero we don't need to reserve -+ * anything. -+ */ -+ if (src->size > 0) { -+ if (blocks_reserve_exactly (&block_vec, -+ DIV_ROUND_UP (src->size, blkhash_size)) == -1) { -+ perror ("nbdcopy: realloc"); -+ exit (EXIT_FAILURE); -+ } -+ } -+} -+ -+/* Single block update functions. */ -+static struct block -+get_block (uint64_t blknum) -+{ -+ struct block b; -+ -+ pthread_mutex_lock (&bv_lock); -+ -+ /* Grow the underlying storage if needed. */ -+ if (block_vec.cap <= blknum) { -+ if (blocks_reserve (&block_vec, blknum - block_vec.cap + 1) == -1) { -+ perror ("nbdcopy: realloc"); -+ exit (EXIT_FAILURE); -+ } -+ } -+ -+ /* Initialize new blocks if needed. */ -+ if (block_vec.len <= blknum) { -+ size_t i; -+ for (i = block_vec.len; i <= blknum; ++i) { -+ block_vec.ptr[i].type = block_unknown; -+ block_vec.ptr[i].ptr = NULL; -+ block_vec.ptr[i].n = 0; -+ } -+ block_vec.len = blknum+1; -+ } -+ -+ b = block_vec.ptr[blknum]; -+ -+ pthread_mutex_unlock (&bv_lock); -+ -+ return b; -+} -+ -+static void -+put_block (uint64_t blknum, struct block b) -+{ -+ pthread_mutex_lock (&bv_lock); -+ block_vec.ptr[blknum] = b; -+ pthread_mutex_unlock (&bv_lock); -+} -+ -+/* Compute the hash of a single block of data and return it. This is -+ * normally a full block of size blkhash_size, but may be a smaller -+ * block at the end of the file. -+ */ -+static void * -+compute_one_block_hash (const void *buf, size_t len) -+{ -+ gnutls_hash_hd_t dig; -+ int r; -+ void *digest; -+ -+ /* Create the digest handle. */ -+ r = gnutls_hash_init (&dig, blkhash_alg); -+ if (r < 0) { -+ fprintf (stderr, "nbdcopy: gnutls_hash_init: %s\n", gnutls_strerror (r)); -+ exit (EXIT_FAILURE); -+ } -+ -+ /* Allocate space for the result. */ -+ digest = malloc (alg_len); -+ if (digest == NULL) { -+ perror ("nbdcopy: malloc"); -+ exit (EXIT_FAILURE); -+ } -+ -+ r = gnutls_hash (dig, buf, len); -+ if (r < 0) { -+ fprintf (stderr, "nbdcopy: gnutls_hash: %s\n", gnutls_strerror (r)); -+ exit (EXIT_FAILURE); -+ } -+ -+ gnutls_hash_deinit (dig, digest); -+ return digest; /* caller must free */ -+} -+ -+/* We have received a complete block. Compute the hash for this -+ * block. If buf == NULL, sets the block to zero. Note this function -+ * assumes we can only be called once per complete block, so locking -+ * is unnecessary (apart from inside the calls to get/put_block). -+ */ -+static void -+set_complete_block (uint64_t blknum, const char *buf) -+{ -+ struct block b = get_block (blknum); -+ void *p; -+ -+ /* Assert that we haven't seen this block before. */ -+ assert (b.type == block_unknown); -+ -+ if (buf) { -+ b.type = block_data; -+ -+ /* Compute the hash of the whole block now. */ -+ p = compute_one_block_hash (buf, blkhash_size); -+ b.ptr = p; -+ } -+ else { -+ b.type = block_zero; -+ /* Hash is computed for all zero blocks in one go at the end. */ -+ } -+ -+ put_block (blknum, b); -+} -+ -+static void finish_block (struct block *b); -+ -+/* We have received a partial block. Store or update what we have. -+ * If this completes the block, then do what is needed. If buf == -+ * NULL, this is a partial zero instead. -+ */ -+static void -+set_incomplete_block (uint64_t blknum, -+ uint64_t blkoffs, uint64_t len, -+ const char *buf) -+{ -+ /* We must acquire the incomplete_lock here, see locking comment above. */ -+ pthread_mutex_lock (&incomplete_lock); -+ -+ struct block b = get_block (blknum); -+ -+ switch (b.type) { -+ case block_data: -+ case block_zero: -+ /* We shouldn't have seen the complete block before. */ -+ abort (); -+ -+ case block_unknown: -+ /* Allocate the block. */ -+ b.ptr = calloc (1, blkhash_size); -+ if (b.ptr == NULL) { -+ perror ("nbdcopy: calloc"); -+ exit (EXIT_FAILURE); -+ } -+ b.n = 0; -+ b.type = block_incomplete; -+ -+ /*FALLTHROUGH*/ -+ case block_incomplete: -+ if (buf) -+ /* Add the partial data to the block. */ -+ memcpy ((char *)b.ptr + blkoffs, buf, len); -+ else -+ /* Add the partial zeroes to the block. */ -+ memset ((char *)b.ptr + blkoffs, 0, len); -+ b.n += len; -+ -+ /* If the block is now complete, finish it off. */ -+ if (b.n == blkhash_size) -+ finish_block (&b); -+ -+ put_block (blknum, b); -+ } -+ -+ pthread_mutex_unlock (&incomplete_lock); -+} -+ -+static void -+finish_block (struct block *b) -+{ -+ void *p; -+ -+ assert (b->type == block_incomplete); -+ -+ if (b->n == blkhash_size && is_zero (b->ptr, blkhash_size)) { -+ b->type = block_zero; -+ free (b->ptr); -+ b->ptr = NULL; -+ } -+ else { -+ b->type = block_data; -+ /* Compute the hash of the block. */ -+ p = compute_one_block_hash (b->ptr, b->n); -+ free (b->ptr); -+ b->ptr = p; -+ } -+} -+ -+/* Called from either synch-copying.c or multi-thread-copying.c to -+ * update the hash with some data (or zero if buf == NULL). -+ */ -+void -+update_blkhash (const char *buf, uint64_t offset, size_t len) -+{ -+ uint64_t blknum, blkoffs; -+ -+ if (blkhash_alg == GNUTLS_DIG_UNKNOWN) return; -+ -+ if (verbose) { -+ fprintf (stderr, "blkhash: %s " -+ "[0x%" PRIx64 " - 0x%" PRIx64 "] (length %zu)\n", -+ buf ? "data" : "zero", -+ offset, offset+len, len); -+ } -+ -+ /* Iterate over the blocks. */ -+ blknum = offset / blkhash_size; -+ blkoffs = offset % blkhash_size; -+ -+ /* Unaligned head */ -+ if (blkoffs) { -+ uint64_t n = MIN (blkhash_size - blkoffs, len); -+ set_incomplete_block (blknum, blkoffs, n, buf); -+ if (buf) buf += n; -+ len -= n; -+ offset += n; -+ blknum++; -+ } -+ -+ /* Aligned body */ -+ while (len >= blkhash_size) { -+ set_complete_block (blknum, buf); -+ if (buf) buf += blkhash_size; -+ len -= blkhash_size; -+ offset += blkhash_size; -+ blknum++; -+ } -+ -+ /* Unaligned tail */ -+ if (len) { -+ set_incomplete_block (blknum, 0, len, buf); -+ } -+} -+ -+/* Called after copying to finish and print the resulting blkhash. */ -+void -+finish_blkhash (uint64_t total_size) -+{ -+ gnutls_hash_hd_t dig; -+ size_t i; -+ struct block *b; -+ void *zero_block; -+ void *zero_digest; -+ int r; -+ const uint64_t total_size_le = htole64 (total_size); -+ unsigned char *final_digest; -+ FILE *fp; -+ -+ if (blkhash_alg == GNUTLS_DIG_UNKNOWN) return; -+ -+ if (verbose) { -+ fprintf (stderr, "blkhash: total size 0x%" PRIx64 "\n", total_size); -+ fprintf (stderr, "blkhash: number of blocks %zu\n", block_vec.len); -+ } -+ -+ /* If the last block is incomplete, finish it. */ -+ if (block_vec.len > 0) { -+ b = &block_vec.ptr[block_vec.len-1]; -+ if (b->type == block_incomplete) -+ finish_block (b); -+ } -+ -+ /* There must be no other unknown or incomplete blocks left. */ -+ for (i = 0; i < block_vec.len; ++i) { -+ b = &block_vec.ptr[i]; -+ assert (b->type != block_unknown); -+ assert (b->type != block_incomplete); -+ } -+ -+ /* Calculate the hash of a zero block. */ -+ zero_block = calloc (1, blkhash_size); -+ if (zero_block == NULL) { -+ perror ("nbdcopy: calloc"); -+ exit (EXIT_FAILURE); -+ } -+ zero_digest = compute_one_block_hash (zero_block, blkhash_size); -+ free (zero_block); -+ -+ /* Now compute the blkhash. */ -+ r = gnutls_hash_init (&dig, blkhash_alg); -+ if (r < 0) { -+ fprintf (stderr, "nbdcopy: gnutls_hash_init: %s\n", gnutls_strerror (r)); -+ exit (EXIT_FAILURE); -+ } -+ -+ for (i = 0; i < block_vec.len; ++i) { -+ b = &block_vec.ptr[i]; -+ -+ switch (b->type) { -+ case block_unknown: -+ case block_incomplete: -+ abort (); /* see assertion above */ -+ -+ case block_data: -+ /* Mix in the block digest. */ -+ r = gnutls_hash (dig, b->ptr, alg_len); -+ if (r < 0) { -+ fprintf (stderr, "nbdcopy: gnutls_hash: %s\n", gnutls_strerror (r)); -+ exit (EXIT_FAILURE); -+ } -+ break; -+ -+ case block_zero: -+ /* Block is zero, mix in the zero digest. */ -+ r = gnutls_hash (dig, zero_digest, alg_len); -+ if (r < 0) { -+ fprintf (stderr, "nbdcopy: gnutls_hash: %s\n", gnutls_strerror (r)); -+ exit (EXIT_FAILURE); -+ } -+ break; -+ } -+ } -+ -+ free (zero_digest); -+ -+ /* Append the length at the end. */ -+ r = gnutls_hash (dig, &total_size_le, sizeof total_size_le); -+ if (r < 0) { -+ fprintf (stderr, "nbdcopy: gnutls_hash: %s\n", gnutls_strerror (r)); -+ exit (EXIT_FAILURE); -+ } -+ -+ /* Get the final digest. */ -+ final_digest = malloc (alg_len); -+ if (final_digest == NULL) { -+ perror ("nbdcopy: malloc"); -+ exit (EXIT_FAILURE); -+ } -+ -+ gnutls_hash_deinit (dig, final_digest); -+ -+ /* Print the final digest. */ -+ if (blkhash_file != NULL) { -+ fp = fopen (blkhash_file, "w"); -+ if (fp == NULL) { -+ perror (blkhash_file); -+ exit (EXIT_FAILURE); -+ } -+ } -+ else { -+ fp = stdout; -+ } -+ for (i = 0; i < alg_len; ++i) -+ fprintf (fp, "%02x", final_digest[i]); -+ fprintf (fp, "\n"); -+ fflush (fp); -+ if (blkhash_file != NULL) -+ fclose (fp); -+ -+ free (final_digest); -+ -+ /* Free the hashes and vector. */ -+ blocks_iter (&block_vec, free_struct_block); -+ blocks_reset (&block_vec); -+} -+ -+#else /* !HAVE_GNUTLS */ -+ -+void -+init_blkhash (void) -+{ -+ /* nothing */ -+} -+ -+void -+update_blkhash (const char *buf, uint64_t offset, size_t len) -+{ -+ /* nothing */ -+} -+ -+void -+finish_blkhash (uint64_t total_size) -+{ -+ /* nothing */ -+} -+ -+#endif /* !HAVE_GNUTLS */ -diff --git a/copy/copy-blkhash-known.sh b/copy/copy-blkhash-known.sh -new file mode 100755 -index 00000000..ca398eac ---- /dev/null -+++ b/copy/copy-blkhash-known.sh -@@ -0,0 +1,83 @@ -+#!/usr/bin/env bash -+# nbd client library in userspace -+# Copyright Red Hat -+# -+# This library is free software; you can redistribute it and/or -+# modify it under the terms of the GNU Lesser General Public -+# License as published by the Free Software Foundation; either -+# version 2 of the License, or (at your option) any later version. -+# -+# This library is distributed in the hope that it will be useful, -+# but WITHOUT ANY WARRANTY; without even the implied warranty of -+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+# Lesser General Public License for more details. -+# -+# You should have received a copy of the GNU Lesser General Public -+# License along with this library; if not, write to the Free Software -+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -+ -+# Test --blkhash option. -+ -+. ../tests/functions.sh -+ -+set -e -+set -x -+ -+requires $NBDKIT --exit-with-parent --version -+requires $NBDKIT --exit-with-parent data --version -+ -+hashfile=copy-blkhash-known.hash -+cleanup_fn rm -f $hashfile -+rm -f $hashfile -+ -+do_test () { -+ data="$1" -+ hash="$2" -+ expected="$3" -+ -+ export hash hashfile -+ $NBDKIT -U - data "$data" \ -+ --run 'nbdcopy --blkhash=$hash --blkhash-file=$hashfile \ -+ "$uri" null:' -+ cat $hashfile -+ test "$expected" = "$(cat $hashfile)" -+} -+ -+# Instances of the data plugin and the corresponding hash that we -+# previously cross-checked against blkhash's test/blkhash.py -+ -+do_test "" \ -+ sha256 \ -+ af5570f5a1810b7af78caf4bc70a660f0df51e42baf91d4de5b2328de0e83dfc -+ -+do_test '"hello"' \ -+ md5 \ -+ f741ac9ce55f5325906bb14e9c05d467 -+ -+do_test '"hello"' \ -+ sha256 \ -+ 337355feb53a5309d5aba92796223c2c84ffab930e706c01fef573a2722545e6 -+ -+do_test '"hello"' \ -+ sha512 \ -+ eca04a593cf12ec4132993da709048e25a2f1be3526e132fb521ec9d41f023ec4018b3fd07b014a33e36bb5fa145b36991f431e62f9e1a93bebea6c9565682c1 -+ -+do_test '"hello"' \ -+ md5/4 \ -+ 8262896de34125dec173722c920e8bd0 -+ -+do_test '"hello" @1048576 "goodbye"' \ -+ sha256 \ -+ 61b8f3a8cea76e16eeff7ce27f1b7711c1f1e437f5038cec17773772a4bded28 -+ -+do_test '"12345678"*512*256' \ -+ md5 \ -+ 84fc21ac2f49ac283ff399378d834d1a -+ -+do_test '"12345678"*512*256' \ -+ sha256 \ -+ cbb388edd25e567b85f504c7b345497f9fb4f6bbf4e39768809184b9f9e678f8 -+ -+do_test '"12345678"*512*256' \ -+ sha512/512k \ -+ 379f7eb1628058c7abbc4c96941ac972074815ea9ef4aca95eefb2b4f9c29f64023fff8d966e9fddf08d07bdba548e75298917f10268fdf9ba636c2321a2214e -diff --git a/copy/copy-blkhash-pattern.sh b/copy/copy-blkhash-pattern.sh -new file mode 100755 -index 00000000..f135f54d ---- /dev/null -+++ b/copy/copy-blkhash-pattern.sh -@@ -0,0 +1,49 @@ -+#!/usr/bin/env bash -+# nbd client library in userspace -+# Copyright Red Hat -+# -+# This library is free software; you can redistribute it and/or -+# modify it under the terms of the GNU Lesser General Public -+# License as published by the Free Software Foundation; either -+# version 2 of the License, or (at your option) any later version. -+# -+# This library is distributed in the hope that it will be useful, -+# but WITHOUT ANY WARRANTY; without even the implied warranty of -+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+# Lesser General Public License for more details. -+# -+# You should have received a copy of the GNU Lesser General Public -+# License along with this library; if not, write to the Free Software -+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -+ -+# Test --blkhash option against a large plugin with known content. -+ -+. ../tests/functions.sh -+ -+set -e -+set -x -+ -+requires $NBDKIT --exit-with-parent --version -+requires $NBDKIT --exit-with-parent pattern --version -+ -+hashfile_sha256=copy-blkhash-pattern.hash256 -+hashfile_sha512=copy-blkhash-pattern.hash512 -+cleanup_fn rm -f $hashfile_sha256 $hashfile_sha512 -+rm -f $hashfile_sha256 $hashfile_sha512 -+ -+export hashfile_sha256 hashfile_sha512 -+ -+expected_sha256=6750a1c3d78e46eaffb0d094624825dea88f0c7098b2424fce776c0748442649 -+expected_sha512=aef2905a223b2b9b565374ce9671bcb434fc944b0a108c8b5b98769d830b6c61b9567de177791a092514675c3a3e0740758c6a5a171ae71d844c60315f07e334 -+ -+$NBDKIT -U - pattern 1G \ -+ --run ' -+ nbdcopy --blkhash --blkhash-file=$hashfile_sha256 "$uri" null: && -+ nbdcopy --blkhash=sha512/512k --blkhash-file=$hashfile_sha512 \ -+ "$uri" null: -+' -+cat $hashfile_sha256 -+test "$expected_sha256" = "$(cat $hashfile_sha256)" -+ -+cat $hashfile_sha512 -+test "$expected_sha512" = "$(cat $hashfile_sha512)" -diff --git a/copy/copy-blkhash-randfile.sh b/copy/copy-blkhash-randfile.sh -new file mode 100755 -index 00000000..029237c4 ---- /dev/null -+++ b/copy/copy-blkhash-randfile.sh -@@ -0,0 +1,45 @@ -+#!/usr/bin/env bash -+# nbd client library in userspace -+# Copyright Red Hat -+# -+# This library is free software; you can redistribute it and/or -+# modify it under the terms of the GNU Lesser General Public -+# License as published by the Free Software Foundation; either -+# version 2 of the License, or (at your option) any later version. -+# -+# This library is distributed in the hope that it will be useful, -+# but WITHOUT ANY WARRANTY; without even the implied warranty of -+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+# Lesser General Public License for more details. -+# -+# You should have received a copy of the GNU Lesser General Public -+# License along with this library; if not, write to the Free Software -+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -+ -+# Test --blkhash option. -+ -+. ../tests/functions.sh -+ -+set -e -+set -x -+ -+requires $DD --version -+requires $DD oflag=seek_bytes - #include - #include -+#include - - #ifdef HAVE_SYS_IOCTL_H - #include - #endif - --#include -+#ifdef HAVE_GNUTLS -+#include -+#endif - - #include - -@@ -48,6 +51,11 @@ - #include "nbdcopy.h" - - bool allocated; /* --allocated flag */ -+#ifdef HAVE_GNUTLS /* --blkhash */ -+gnutls_digest_algorithm_t blkhash_alg = GNUTLS_DIG_UNKNOWN; -+#endif -+unsigned blkhash_size = 65536; -+const char *blkhash_file; /* --blkhash-file (NULL = stdout) */ - unsigned connections = 4; /* --connections */ - bool target_is_zero; /* --target-is-zero flag */ - bool extents = true; /* ! --no-extents flag */ -@@ -76,7 +84,8 @@ usage (FILE *fp, int exitcode) - "\n" - "Copy to and from an NBD server:\n" - "\n" --" nbdcopy [--allocated] [-C N|--connections=N]\n" -+" nbdcopy [--allocated] [--blkhash=DIGEST] [--blkhash-file=FILENAME]\n" -+" [-C N|--connections=N]\n" - " [--destination-is-zero|--target-is-zero] [--flush]\n" - " [--no-extents] [-p|--progress|--progress=FD]\n" - " [--queue-size=N] [--request-size=N] [-R N|--requests=N]\n" -@@ -113,6 +122,8 @@ main (int argc, char *argv[]) - LONG_OPTIONS, - SHORT_OPTIONS, - ALLOCATED_OPTION, -+ BLKHASH_OPTION, -+ BLKHASH_FILE_OPTION, - TARGET_IS_ZERO_OPTION, - FLUSH_OPTION, - NO_EXTENTS_OPTION, -@@ -125,6 +136,8 @@ main (int argc, char *argv[]) - { "help", no_argument, NULL, HELP_OPTION }, - { "long-options", no_argument, NULL, LONG_OPTIONS }, - { "allocated", no_argument, NULL, ALLOCATED_OPTION }, -+ { "blkhash", optional_argument, NULL, BLKHASH_OPTION }, -+ { "blkhash-file", required_argument, NULL, BLKHASH_FILE_OPTION }, - { "connections", required_argument, NULL, 'C' }, - { "destination-is-zero", no_argument, NULL, TARGET_IS_ZERO_OPTION }, - { "flush", no_argument, NULL, FLUSH_OPTION }, -@@ -179,6 +192,64 @@ main (int argc, char *argv[]) - allocated = true; - break; - -+ case BLKHASH_OPTION: -+#ifdef HAVE_GNUTLS -+ if (optarg == NULL || optarg[0] == '\0') { -+ blkhash_alg = GNUTLS_DIG_SHA256; -+ blkhash_size = 65536; -+ } -+ else { -+ i = strcspn (optarg, "/"); -+ if (i == 3 && strncasecmp (optarg, "md5", i) == 0) -+ blkhash_alg = GNUTLS_DIG_MD5; -+ else if (i == 4 && strncasecmp (optarg, "sha1", i) == 0) -+ blkhash_alg = GNUTLS_DIG_SHA1; -+ else if (i == 6 && strncasecmp (optarg, "sha256", i) == 0) -+ blkhash_alg = GNUTLS_DIG_SHA256; -+ else if (i == 6 && strncasecmp (optarg, "sha512", i) == 0) -+ blkhash_alg = GNUTLS_DIG_SHA512; -+ else { -+ fprintf (stderr, "%s: %s: unknown digest algorithm '%s'\n", -+ prog, "--blkhash", optarg); -+ exit (EXIT_FAILURE); -+ } -+ if (optarg[i] == '/') { -+ i64 = human_size_parse (&optarg[i+1], &error, &pstr); -+ if (i64 == -1) { -+ fprintf (stderr, "%s: %s: %s: %s\n", -+ prog, "--blkhash", error, pstr); -+ exit (EXIT_FAILURE); -+ } -+ if (! is_power_of_2 (blkhash_size)) { -+ fprintf (stderr, "%s: %s is not a power of two: %s\n", -+ prog, "--blkhash", &optarg[i+1]); -+ exit (EXIT_FAILURE); -+ } -+ if (i64 > UINT_MAX) { -+ fprintf (stderr, "%s: %s is too large: %s\n", -+ prog, "--blkhash", &optarg[i+1]); -+ exit (EXIT_FAILURE); -+ } -+ blkhash_size = i64; -+ } -+ } -+ break; -+#else -+ fprintf (stderr, "%s: %s: option not supported in this build\n", -+ prog, "--blkhash"); -+ exit (EXIT_FAILURE); -+#endif -+ -+ case BLKHASH_FILE_OPTION: -+#ifdef HAVE_GNUTLS -+ blkhash_file = optarg; -+ break; -+#else -+ fprintf (stderr, "%s: %s: option not supported in this build\n", -+ prog, "--blkhash-file"); -+ exit (EXIT_FAILURE); -+#endif -+ - case TARGET_IS_ZERO_OPTION: - target_is_zero = true; - break; -@@ -369,6 +440,9 @@ main (int argc, char *argv[]) - exit (EXIT_FAILURE); - } - -+ /* Initialize the blkhash function (if used). */ -+ init_blkhash (); -+ - /* If multi-conn is not supported, force connections to 1. */ - if (! src->ops->can_multi_conn (src) || ! dst->ops->can_multi_conn (dst)) - connections = 1; -@@ -482,6 +556,9 @@ main (int argc, char *argv[]) - /* We should always know the total size copied here. */ - assert (src->size >= 0); - -+ /* Finish and print the blkhash. */ -+ finish_blkhash (src->size); -+ - /* Shut down the source side. */ - src->ops->close (src); - -diff --git a/copy/multi-thread-copying.c b/copy/multi-thread-copying.c -index a75fb265..89588e6e 100644 ---- a/copy/multi-thread-copying.c -+++ b/copy/multi-thread-copying.c -@@ -265,8 +265,10 @@ worker_thread (void *wp) - * THREAD_WORK_SIZE, so there is no danger of overflowing - * size_t. - */ -- command = create_command (zeroing_start, offset-zeroing_start, -- true, w); -+ uint64_t zeroing_len = offset - zeroing_start; -+ -+ update_blkhash (NULL, zeroing_start, zeroing_len); -+ command = create_command (zeroing_start, zeroing_len, true, w); - fill_dst_range_with_zeroes (command); - is_zeroing = false; - } -@@ -297,6 +299,9 @@ worker_thread (void *wp) - * THREAD_WORK_SIZE, so there is no danger of overflowing - * size_t. - */ -+ uint64_t zeroing_len = offset - zeroing_start; -+ -+ update_blkhash (NULL, zeroing_start, zeroing_len); - command = create_command (zeroing_start, offset - zeroing_start, - true, w); - fill_dst_range_with_zeroes (command); -@@ -505,6 +510,9 @@ finished_read (void *vp, int *error) - exit (EXIT_FAILURE); - } - -+ update_blkhash (slice_ptr (command->slice), command->offset, -+ command->slice.len); -+ - if (allocated || sparse_size == 0) { - /* If sparseness detection (see below) is turned off then we write - * the whole command. -diff --git a/copy/nbdcopy.h b/copy/nbdcopy.h -index 7c54463d..91289c32 100644 ---- a/copy/nbdcopy.h -+++ b/copy/nbdcopy.h -@@ -25,6 +25,10 @@ - #include - #include - -+#ifdef HAVE_GNUTLS -+#include -+#endif -+ - #include - - #include "vector.h" -@@ -228,6 +232,11 @@ extern void asynch_notify_read_write_not_supported (struct rw *rw, - size_t index); - - extern bool allocated; -+#ifdef HAVE_GNUTLS -+extern gnutls_digest_algorithm_t blkhash_alg; -+#endif -+extern unsigned blkhash_size; -+extern const char *blkhash_file; - extern unsigned connections; - extern bool target_is_zero; - extern bool extents; -@@ -247,5 +256,8 @@ extern const char *prog; - extern void progress_bar (off_t pos, int64_t size); - extern void synch_copying (void); - extern void multi_thread_copying (void); -+extern void init_blkhash (void); -+extern void update_blkhash (const char *buf, uint64_t offset, size_t len); -+extern void finish_blkhash (uint64_t total_size); - - #endif /* NBDCOPY_H */ -diff --git a/copy/nbdcopy.pod b/copy/nbdcopy.pod -index 940e37ad..3efe2b1b 100644 ---- a/copy/nbdcopy.pod -+++ b/copy/nbdcopy.pod -@@ -4,7 +4,8 @@ nbdcopy - copy to and from an NBD server - - =head1 SYNOPSIS - -- nbdcopy [--allocated] [-C N|--connections=N] -+ nbdcopy [--allocated] [--blkhash=DIGEST] [--blkhash-file=FILE] -+ [-C N|--connections=N] - [--destination-is-zero|--target-is-zero] [--flush] - [--no-extents] [-p|--progress|--progress=FD] - [--queue-size=N] [--request-size=N] [-R N|--requests=N] -@@ -50,6 +51,11 @@ option this will print a progress bar. - - Copy a full disk from one NBD server to another. - -+=head2 nbdcopy nbd://server1 nbd://server2 --blkhash -+ -+Copy a full disk from one NBD server to another, computing the blkhash -+(similar to a checksum) of the disk and printing that. -+ - =head2 nbdcopy -- [ qemu-nbd -r -f qcow2 https://example.com/disk.qcow2 ] - - - Run L as a subprocess to open URL -@@ -106,6 +112,49 @@ I<--no-extents>), or by detecting runs of zeroes (see I<-S>). If you - use I<--allocated> then nbdcopy creates a fully allocated, non-sparse - output on the destination. - -+=item B<--blkhash> -+ -+=item B<--blkhash=md5> -+ -+=item B<--blkhash=md5/>SIZE -+ -+=item B<--blkhash=sha1> -+ -+=item B<--blkhash=sha1/>SIZE -+ -+=item B<--blkhash=sha256> -+ -+=item B<--blkhash=sha256/>SIZE -+ -+=item B<--blkhash=sha512> -+ -+=item B<--blkhash=sha512/>SIZE -+ -+Compute the blkhash of the disk image during the copy and print it at -+the end. Blkhash (L) is an algorithm -+similar to a checksum except that it can be computed in parallel. -+Note that it is not compatible with programs like L or -+L. Using this option will make nbdcopy slower. -+ -+You can choose the digest function from C, C, C -+(recommended), or C. You can also choose the block size, the -+default being C<64k> (recommended). -+ -+The I<--blkhash> option without parameters selects sha256/64k. -+ -+To compute the blkhash of a file without copying it, you can do: -+ -+ nbdcopy --blkhash -- disk.raw null: -+ -+or if the format is qcow2: -+ -+ nbdcopy --blkhash -- [ qemu-nbd -f qcow2 disk.qcow2 ] null: -+ -+=item B<--blkhash-file=>FILE -+ -+If I<--blkhash> is selected, choose where to print the blkhash to. -+The default is stdout. -+ - =item B<-C> N - - =item B<--connections=>N -@@ -306,7 +355,9 @@ L, - L, - L, - L, --L. -+L, -+L, -+L. - - =head1 AUTHORS - -diff --git a/copy/synch-copying.c b/copy/synch-copying.c -index 5d21423d..09f05be2 100644 ---- a/copy/synch-copying.c -+++ b/copy/synch-copying.c -@@ -83,6 +83,7 @@ synch_copying (void) - size_t r; - - while ((r = src->ops->synch_read (src, buf, request_size, offset)) > 0) { -+ update_blkhash ((const char *) buf, offset, request_size); - dst->ops->synch_write (dst, buf, r, offset); - offset += r; - progress_bar (offset, src->size); -@@ -116,6 +117,7 @@ synch_copying (void) - assert (exts.ptr[i].length <= count); - - if (exts.ptr[i].zero) { -+ update_blkhash (NULL, offset, exts.ptr[i].length); - fill_dst_range_with_zeroes(offset, exts.ptr[i].length, buf); - offset += exts.ptr[i].length; - } -@@ -130,6 +132,7 @@ synch_copying (void) - exit (EXIT_FAILURE); - } - -+ update_blkhash ((const char *) buf, offset, r); - dst->ops->synch_write (dst, buf, r, offset); - offset += r; - progress_bar (offset, src->size); --- -2.47.1 - diff --git a/0009-copy-Fix-crash-when-blkhash-size-is-not-a-power-of-2.patch b/0009-copy-Fix-crash-when-blkhash-size-is-not-a-power-of-2.patch deleted file mode 100644 index a1b8f8b..0000000 --- a/0009-copy-Fix-crash-when-blkhash-size-is-not-a-power-of-2.patch +++ /dev/null @@ -1,33 +0,0 @@ -From d19e6eb145d93c827c5acf1b4c009ff27749a205 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Mon, 7 Apr 2025 11:35:25 +0100 -Subject: [PATCH] copy: Fix crash when blkhash size is not a power of 2 - -nbdcopy: blkhash.c:105: init_blkhash: Assertion `is_power_of_2 (blkhash_size)' failed. - -The check for this was wrong, resulting in a later assertion failure -instead of an error message. - -Reported-by: Vera Wu -Fixes: https://issues.redhat.com/browse/RHEL-85513 -(cherry picked from commit 6c6e0822c854e423d79bef87caf1c20c5bdb5eb5) ---- - copy/main.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/copy/main.c b/copy/main.c -index 8f943b30..9afb627c 100644 ---- a/copy/main.c -+++ b/copy/main.c -@@ -220,7 +220,7 @@ main (int argc, char *argv[]) - prog, "--blkhash", error, pstr); - exit (EXIT_FAILURE); - } -- if (! is_power_of_2 (blkhash_size)) { -+ if (! is_power_of_2 (i64)) { - fprintf (stderr, "%s: %s is not a power of two: %s\n", - prog, "--blkhash", &optarg[i+1]); - exit (EXIT_FAILURE); --- -2.47.1 - diff --git a/0010-copy-Define-block_type-outside-of-block-struct.patch b/0010-copy-Define-block_type-outside-of-block-struct.patch deleted file mode 100644 index 7b53b40..0000000 --- a/0010-copy-Define-block_type-outside-of-block-struct.patch +++ /dev/null @@ -1,66 +0,0 @@ -From f48db2429c5aa5f56018baa18c2aa37f756975ef Mon Sep 17 00:00:00 2001 -From: Nir Soffer -Date: Sun, 13 Apr 2025 14:51:09 +0000 -Subject: [PATCH] copy: Define block_type outside of block struct - -This make the code easier to follow and maintain. - -(cherry picked from commit dc5f0e6c79e7aa03ba634b71d4780f6d7d039cdd) ---- - copy/blkhash.c | 38 ++++++++++++++++++++------------------ - 1 file changed, 20 insertions(+), 18 deletions(-) - -diff --git a/copy/blkhash.c b/copy/blkhash.c -index 622d8a39..526db4d2 100644 ---- a/copy/blkhash.c -+++ b/copy/blkhash.c -@@ -43,26 +43,28 @@ - - #ifdef HAVE_GNUTLS - -+/* unknown => We haven't seen this block yet. 'ptr' is NULL. -+ * -+ * zero => The block is all zeroes. 'ptr' is NULL. -+ * -+ * data => The block is all data, and we have seen the whole block, -+ * and the hash has been computed. 'ptr' points to the computed -+ * hash. 'n' is unused. -+ * -+ * incomplete => Part of the block was seen. 'ptr' points to the -+ * data block, waiting to be completed. 'n' is the number of bytes -+ * seen so far. We will compute the hash and turn this into a -+ * 'data' or 'zero' block, either when we have seen all bytes of -+ * this block, or at the end. -+ * -+ * Note that this code assumes that we are called exactly once for a -+ * range in the disk image. -+ */ -+enum block_type { block_unknown = 0, block_zero, block_data, block_incomplete }; -+ - /* We will have one of these structs per blkhash block. */ - struct block { -- /* unknown => We haven't seen this block yet. 'ptr' is NULL. -- * -- * zero => The block is all zeroes. 'ptr' is NULL. -- * -- * data => The block is all data, and we have seen the whole block, -- * and the hash has been computed. 'ptr' points to the computed -- * hash. 'n' is unused. -- * -- * incomplete => Part of the block was seen. 'ptr' points to the -- * data block, waiting to be completed. 'n' is the number of bytes -- * seen so far. We will compute the hash and turn this into a -- * 'data' or 'zero' block, either when we have seen all bytes of -- * this block, or at the end. -- * -- * Note that this code assumes that we are called exactly once for a -- * range in the disk image. -- */ -- enum { block_unknown = 0, block_zero, block_data, block_incomplete } type; -+ enum block_type type; - void *ptr; - size_t n; - }; --- -2.47.1 - diff --git a/0011-copy-Shrink-struct-block.patch b/0011-copy-Shrink-struct-block.patch deleted file mode 100644 index f3a3397..0000000 --- a/0011-copy-Shrink-struct-block.patch +++ /dev/null @@ -1,78 +0,0 @@ -From 361ae3810398d0d5c3550267b0470ba235d94c32 Mon Sep 17 00:00:00 2001 -From: Nir Soffer -Date: Sun, 13 Apr 2025 14:54:31 +0000 -Subject: [PATCH] copy: Shrink struct block - -Change n to uint32_t since block size bigger than 4g does not make -sense. Move the type field to the end to shrink struct size from 24 -bytes to 16. - -This minimizes memory usage and improves locality. For example we can -have 4 blocks in a single cache line instead of 2.5. - -Testing shows up to 8% improvement in time and 33% in maximum resident -set size with 1000g empty image. With images full of zeros or images -full of non-zero bytes we see lower memory usage but no difference in -time. - -| size | content | tool | source | version | memory | time | -|--------|---------|------------|--------|---------|----------|----------| -| 1000g | hole | nbdcopy | file | before | 644716k | 3.33s | -| 1000g | hole | nbdcopy | file | after | 516716k | 3.10s | -| 1000g | hole | nbdcopy | nbd | before | 388844k | 1.13s | -| 1000g | hole | nbdcopy | nbd | after | 260716k | 1.04s | -| 1000g | hole | blksum | nbd | - | 10792k | 0.29s | -| 1000g | hole | sha256sum | file | - | *2796k | *445.00s | -|--------|---------|------------|--------|---------|----------|----------| -| 10g | zero | nbdcopy | file | before | 20236k | 1.33s | -| 10g | zero | nbdcopy | file | after | 18796k | 1.32s | -| 10g | zero | nbdcopy | nbd | before | 32648k | 8.21s | -| 10g | zero | nbdcopy | nbd | after | 31416k | 8.23s | -| 10g | zero | nbdcopy | pipe | before | 19052k | 4.56s | -| 10g | zero | nbdcopy | pipe | after | 17772k | 4.56s | -| 10g | zero | blksum | nbd | - | 13948k | 3.90s | -| 10g | zero | blksum | pipe | - | 10340k | 0.55s | -| 10g | zero | sha256sum | file | - | 2796k | 4.45s | -|--------|---------|------------|--------|---------|----------|----------| -| 10g | data | nbdcopy | file | before | 20224k | 1.28s | -| 10g | data | nbdcopy | file | after | 19036k | 1.26s | -| 10g | data | nbdcopy | nbd | before | 32792k | 8.02s | -| 10g | data | nbdcopy | nbd | after | 31512k | 8.02s | -| 10g | data | nbdcopy | pipe | before | 19052k | 4.56s | -| 10g | data | nbdcopy | pipe | after | 17772k | 4.57s | -| 10g | data | blksum | nbd | - | 13888k | 3.88s | -| 10g | data | blksum | pipe | - | 12512k | 1.10s | -| 10g | data | sha256sum | file | - | 2788k | 4.49s | - -* estimated based on 10g image - -Measured using: - - /usr/bin/time -f "memory=%Mk time=%es" ./nbdcopy --blkhash ... - -Tested on Fedora 41 VM on MacBook Pro M2 Max. - -(cherry picked from commit f3e1b5fe8423558b49a2b829c0fe13f601b475f2) ---- - copy/blkhash.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/copy/blkhash.c b/copy/blkhash.c -index 526db4d2..41253ec8 100644 ---- a/copy/blkhash.c -+++ b/copy/blkhash.c -@@ -64,9 +64,9 @@ enum block_type { block_unknown = 0, block_zero, block_data, block_incomplete }; - - /* We will have one of these structs per blkhash block. */ - struct block { -- enum block_type type; - void *ptr; -- size_t n; -+ uint32_t n; -+ enum block_type type; - }; - - DEFINE_VECTOR_TYPE(blocks, struct block); --- -2.47.1 - diff --git a/0012-copy-Enable-zero-optimization-for-allocated-extents.patch b/0012-copy-Enable-zero-optimization-for-allocated-extents.patch deleted file mode 100644 index 686063f..0000000 --- a/0012-copy-Enable-zero-optimization-for-allocated-extents.patch +++ /dev/null @@ -1,65 +0,0 @@ -From d57d58ba193674bef225f0e7094b0efbaa47f680 Mon Sep 17 00:00:00 2001 -From: Nir Soffer -Date: Sun, 13 Apr 2025 23:39:15 +0000 -Subject: [PATCH] copy: Enable zero optimization for allocated extents - -We optimized zero extents but computed the hash for all data blocks, -including data blocks full of zeros. Detecting a zero block is 20-100 -times faster than computing a hash, depending on the machine and the -hash algorithm. - -When adding a completed block, detect zero blocks and mark the block as -zero block, saving the computation of the hash and the allocation of the -digest buffer. - -This optimization is already implemented for incomplete blocks. - -Testing shows that computing a hash for image full of zeros is up to 7.4 -times faster, and memory usage is up to 40% lower. - -| size | content | tool | source | version | memory | time | -|--------|---------|------------|--------|---------|----------|----------| -| 10g | zero | nbdcopy | file | before | 20236k | 1.33s | -| 10g | zero | nbdcopy | file | after | 13212k | 0.33s | -| 10g | zero | nbdcopy | nbd | before | 32648k | 8.21s | -| 10g | zero | nbdcopy | nbd | after | 24996k | 3.32s | -| 10g | zero | nbdcopy | pipe | before | 19052k | 4.56s | -| 10g | zero | nbdcopy | pipe | after | 11244k | 0.61s | -| 10g | zero | blksum | nbd | - | 13948k | 3.90s | -| 10g | zero | blksum | pipe | - | 10340k | 0.55s | -| 10g | zero | sha256sum | file | - | 2796k | 4.45s | -|--------|---------|------------|--------|---------|----------|----------| -| 10g | data | nbdcopy | file | before | 20224k | 1.28s | -| 10g | data | nbdcopy | file | after | 20400k | 1.28s | -| 10g | data | nbdcopy | nbd | before | 32792k | 8.02s | -| 10g | data | nbdcopy | nbd | after | 32536k | 8.01s | -| 10g | data | nbdcopy | pipe | before | 19052k | 4.56s | -| 10g | data | nbdcopy | pipe | after | 19048k | 4.55s | -| 10g | data | blksum | nbd | - | 13888k | 3.88s | -| 10g | data | blksum | pipe | - | 12512k | 1.10s | -| 10g | data | sha256sum | file | - | 2788k | 4.49s | - -(cherry picked from commit efbe283f9fcfc8b4e57370f71356b1bfe7ffd0a4) ---- - copy/blkhash.c | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -diff --git a/copy/blkhash.c b/copy/blkhash.c -index 41253ec8..92ffafbd 100644 ---- a/copy/blkhash.c -+++ b/copy/blkhash.c -@@ -213,7 +213,10 @@ set_complete_block (uint64_t blknum, const char *buf) - /* Assert that we haven't seen this block before. */ - assert (b.type == block_unknown); - -- if (buf) { -+ /* Detecting a zero block is 20-100 times faster than computing a hash -+ * depending on the machine and the algorithm. -+ */ -+ if (buf && !is_zero (buf, blkhash_size)) { - b.type = block_data; - - /* Compute the hash of the whole block now. */ --- -2.47.1 - diff --git a/0013-copy-Fix-corrupted-hash-on-incomplete-read.patch b/0013-copy-Fix-corrupted-hash-on-incomplete-read.patch deleted file mode 100644 index 56e25cb..0000000 --- a/0013-copy-Fix-corrupted-hash-on-incomplete-read.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 4db52aea6b2c92e7dd199d5ce00f74d107f7f2f3 Mon Sep 17 00:00:00 2001 -From: Nir Soffer -Date: Mon, 14 Apr 2025 21:40:16 +0000 -Subject: [PATCH] copy: Fix corrupted hash on incomplete read - -When using synchronous read with unknown file size, if the read was -shorter than request size, we updated the hash with the complete buffer, -inserting leftover bytes from the previous read into the hash. - -I'm not sure if there is validation for source size and number of blocks -in the blocks vector, so this can generate a corrupted hash silently. - -We probably need to validate later that the image size matches the size -of the hashed data. - -I could not reproduce a corrupted hash, the issue discovered by reading -the code. - -(cherry picked from commit 49cd9fbc0022c0ae5bc5d0b9dd48219dfb92b2f7) ---- - copy/synch-copying.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/copy/synch-copying.c b/copy/synch-copying.c -index 09f05be2..2aa67df6 100644 ---- a/copy/synch-copying.c -+++ b/copy/synch-copying.c -@@ -83,7 +83,7 @@ synch_copying (void) - size_t r; - - while ((r = src->ops->synch_read (src, buf, request_size, offset)) > 0) { -- update_blkhash ((const char *) buf, offset, request_size); -+ update_blkhash ((const char *) buf, offset, r); - dst->ops->synch_write (dst, buf, r, offset); - offset += r; - progress_bar (offset, src->size); --- -2.47.1 - diff --git a/0014-build-Add-.-configure-with-extra.patch b/0014-build-Add-.-configure-with-extra.patch deleted file mode 100644 index 5e4e3ba..0000000 --- a/0014-build-Add-.-configure-with-extra.patch +++ /dev/null @@ -1,76 +0,0 @@ -From 327d819d8e8161c31da903e8171a89db97862951 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Wed, 16 Jul 2025 12:24:12 +0100 -Subject: [PATCH] build: Add ./configure --with-extra="..." - -This is intended for downstream packagers to use, to provide extra -information about the version of the downstream package (such as the -RPM ENVR). This helps when identifying bugs, especially in packges -which have extensive backports (such as the RHEL packages). This is -the same as the equivalent option in nbdkit. - -In Fedora we intend to use this in the spec file: - - ./configure --with-extra='%{name}-%{version}-%{release}' - -resulting in an extra version string something like "libnbd-1.23.4-1.fc43". - -(cherry picked from commit a04cda6938a9f60b26cb9aa6d55a0b4ef4d0fe76) ---- - README.md | 13 +++++++++++++ - configure.ac | 15 +++++++++++++++ - 2 files changed, 28 insertions(+) - -diff --git a/README.md b/README.md -index 0f6bcdd4..385c0e58 100644 ---- a/README.md -+++ b/README.md -@@ -163,6 +163,19 @@ ### Download tarballs - http://libguestfs.org/download/libnbd - - -+### Downstream packagers -+ -+If you are packaging libnbd, use: -+ -+``` -+./configure --with-extra='...' -+``` -+ -+providing extra information about the distribution, and/or -+distro-specific versions. It helps us with troubleshooting bug -+reports. (Also, talk to us!) -+ -+ - ## Developers - - Install the valgrind program and development headers. -diff --git a/configure.ac b/configure.ac -index 40d4f79f..6fc4342e 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -18,6 +18,21 @@ - AC_INIT([libnbd],[1.22.2]) - - AC_CONFIG_MACRO_DIR([m4]) -+ -+dnl Extra string, a freeform string defined by downstream packagers. -+dnl eg. If you are packaging libnbd for Linux distro X 1.1, you could -+dnl ./configure --with-extra="X release 1.1" -+AC_ARG_WITH([extra], -+ [AS_HELP_STRING([--with-extra=...], -+ [extra version information (for use by packagers)])], -+ [LIBNBD_VERSION_EXTRA="$withval"], -+ [LIBNBD_VERSION_EXTRA=] -+) -+AC_DEFINE_UNQUOTED([LIBNBD_VERSION_EXTRA], ["$LIBNBD_VERSION_EXTRA"], -+ [Extra version information (for use by packagers)]) -+ -+AC_MSG_NOTICE([libnbd version $PACKAGE_VERSION ($LIBNBD_VERSION_EXTRA)]) -+ - m4_ifdef([AC_USE_SYSTEM_EXTENSIONS],[], - [m4_define([AC_USE_SYSTEM_EXTENSIONS],[])]) - AC_USE_SYSTEM_EXTENSIONS --- -2.47.1 - diff --git a/0015-lib-New-API-nbd_get_version_extra.patch b/0015-lib-New-API-nbd_get_version_extra.patch deleted file mode 100644 index e0a07fd..0000000 --- a/0015-lib-New-API-nbd_get_version_extra.patch +++ /dev/null @@ -1,107 +0,0 @@ -From e17980b7bc91eb74d2cccfcc4dc89e4dcead5609 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Wed, 16 Jul 2025 12:26:29 +0100 -Subject: [PATCH] lib: New API: nbd_get_version_extra - -This new API gets the ./configure --with-extra="..." string, usually -the empty string (for upstream builds) or the package NVR (for -downstream builds). - -This commit also adds a test. - -(cherry picked from commit 0b7e0831912c9efcd601b4738756a0aeb948df79) ---- - generator/API.ml | 26 ++++++++++++++++++++++++-- - lib/handle.c | 6 ++++++ - tests/get-version.c | 7 +++++++ - 3 files changed, 37 insertions(+), 2 deletions(-) - -diff --git a/generator/API.ml b/generator/API.ml -index 8ee1843a..b1932dfa 100644 ---- a/generator/API.ml -+++ b/generator/API.ml -@@ -4172,7 +4172,7 @@ versions."; - longdesc = "\ - Returns the name of the library, always C<\"libnbd\"> unless - the library was modified with another name at compile time."; -- see_also = [Link "get_version"]; -+ see_also = [Link "get_version"; Link "get_version_extra"]; - }; - - "get_version", { -@@ -4220,7 +4220,26 @@ The release number is incremented for each release along a particular - branch. - - =back"; -- see_also = [Link "get_package_name"]; -+ see_also = [Link "get_package_name"; Link "get_version_extra"]; -+ }; -+ -+ "get_version_extra", { -+ default_call with -+ args = []; ret = RStaticString; is_locked = false; may_set_error = false; -+ shortdesc = "return the extra version of the library"; -+ longdesc = "\ -+Return the extra version of libnbd. This is a freeform string -+which is set at package build time using: -+ -+ ./configure --with-extra=\"...\" -+ -+and it intended to be used by downstream packagers (eg. Linux distributions) -+to convey extra version information, such as the precise version of -+the libnbd RPM, C<.deb> etc. -+ -+The string may be C<\"\">, indicating that no extra version information -+is available, or that this is an upstream build of libnbd."; -+ see_also = [Link "get_package_name"; Link "get_version_extra"]; - }; - - "kill_subprocess", { -@@ -4515,6 +4534,9 @@ let first_version = [ - "is_uri", (1, 22); - "get_subprocess_pid", (1, 22); - -+ (* Added in 1.23.x development cycle, will be stable and supported in 1.24 *) -+ "get_version_extra", (1, 24); -+ - (* These calls are proposed for a future version of libnbd, but - * have not been added to any released version so far. - "get_tls_certificates", (1, ??); -diff --git a/lib/handle.c b/lib/handle.c -index a263cc4c..ec64d601 100644 ---- a/lib/handle.c -+++ b/lib/handle.c -@@ -566,6 +566,12 @@ nbd_unlocked_get_version (struct nbd_handle *h) - return PACKAGE_VERSION; - } - -+const char * -+nbd_unlocked_get_version_extra (struct nbd_handle *h) -+{ -+ return LIBNBD_VERSION_EXTRA; -+} -+ - int - nbd_unlocked_kill_subprocess (struct nbd_handle *h, int signum) - { -diff --git a/tests/get-version.c b/tests/get-version.c -index b8dc5338..c195e5f5 100644 ---- a/tests/get-version.c -+++ b/tests/get-version.c -@@ -53,6 +53,13 @@ main (int argc, char *argv[]) - } - assert (strcmp (s, PACKAGE_VERSION) == 0); - -+ s = nbd_get_version_extra (nbd); -+ if (s == NULL) { -+ fprintf (stderr, "%s\n", nbd_get_error ()); -+ exit (EXIT_FAILURE); -+ } -+ assert (strcmp (s, LIBNBD_VERSION_EXTRA) == 0); -+ - nbd_close (nbd); - exit (EXIT_SUCCESS); - } --- -2.47.1 - diff --git a/0016-tools-Add-extra-version-information-in-the-output-of.patch b/0016-tools-Add-extra-version-information-in-the-output-of.patch deleted file mode 100644 index e2b4631..0000000 --- a/0016-tools-Add-extra-version-information-in-the-output-of.patch +++ /dev/null @@ -1,268 +0,0 @@ -From 625a79d4eea074d8f83dc590118605d88bd9676a Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Wed, 16 Jul 2025 12:27:21 +0100 -Subject: [PATCH] tools: Add extra version information in the output of - --version - -In tools like nbdcopy, add the extra version information, if present -to the output of commands like 'nbdcopy --version'. - -For example in a downstream build you might see: - - $ nbdcopy --version - nbdcopy 1.23.4 (libnbd-1.23.4-1.fc43) - libnbd 1.23.4 (libnbd-1.23.4-1.fc43) - -In upstream builds or builds not using the new ./configure --with-extra -option, the output is unchanged. - -(cherry picked from commit 441eadf352e387aaba687bf424cc46424507bf18) ---- - common/utils/version.c | 13 +++++++++++-- - copy/test-version.sh | 31 ++++++++++++++++--------------- - dump/test-version.sh | 31 ++++++++++++++++--------------- - fuse/test-version.sh | 31 ++++++++++++++++--------------- - info/test-version.sh | 31 ++++++++++++++++--------------- - sh/test-version.sh | 31 ++++++++++++++++--------------- - 6 files changed, 91 insertions(+), 77 deletions(-) - -diff --git a/common/utils/version.c b/common/utils/version.c -index 554d3056..135c0c75 100644 ---- a/common/utils/version.c -+++ b/common/utils/version.c -@@ -20,6 +20,7 @@ - - #include - #include -+#include - - #include "libnbd.h" - #include "version.h" -@@ -30,9 +31,13 @@ display_version (const char *program_name) - struct nbd_handle *nbd; - const char *package_name = NULL; - const char *version = NULL; -+ const char *version_extra = NULL; - - /* The program name and the version of the binary. */ -- printf ("%s %s\n", program_name, PACKAGE_VERSION); -+ printf ("%s %s", program_name, PACKAGE_VERSION); -+ if (strcmp (LIBNBD_VERSION_EXTRA, "") != 0) -+ printf (" (%s)", LIBNBD_VERSION_EXTRA); -+ printf ("\n"); - - /* Flush to make sure it is printed, even if the code below crashes - * for any reason. -@@ -46,9 +51,13 @@ display_version (const char *program_name) - if (nbd) { - package_name = nbd_get_package_name (nbd); - version = nbd_get_version (nbd); -+ version_extra = nbd_get_version_extra (nbd); - } - if (version) { -- printf ("%s %s\n", package_name ? package_name : PACKAGE_NAME, version); -+ printf ("%s %s", package_name ? package_name : PACKAGE_NAME, version); -+ if (strcmp (version_extra, "") != 0) -+ printf (" (%s)", version_extra); -+ printf ("\n"); - fflush (stdout); - } - nbd_close (nbd); -diff --git a/copy/test-version.sh b/copy/test-version.sh -index f3bd30d4..0738f109 100755 ---- a/copy/test-version.sh -+++ b/copy/test-version.sh -@@ -16,18 +16,19 @@ - # License along with this library; if not, write to the Free Software - # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - --# Test that nbdcopy --version looks sane. -- --fail=0 --output=$($VG nbdcopy --version) --if [ $? != 0 ]; then -- echo "$0: unexpected exit status" -- fail=1 --fi --if [ "$output" != "nbdcopy $EXPECTED_VERSION --libnbd $EXPECTED_VERSION" ]; then -- echo "$0: unexpected output" -- fail=1 --fi --echo "$output" --exit $fail -+# Test that --version looks sane. -+ -+. ../tests/functions.sh -+set -e -+set -x -+ -+tool=nbdcopy -+ -+output=test-$tool.out -+cleanup_fn rm -f $output -+ -+$VG $tool --version > $output -+cat $output -+ -+grep "$tool $EXPECTED_VERSION" $output -+grep "libnbd $EXPECTED_VERSION" $output -diff --git a/dump/test-version.sh b/dump/test-version.sh -index 2ef32e05..8adc0e19 100755 ---- a/dump/test-version.sh -+++ b/dump/test-version.sh -@@ -16,18 +16,19 @@ - # License along with this library; if not, write to the Free Software - # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - --# Test that nbddump --version looks sane. -- --fail=0 --output=$($VG nbddump --version) --if [ $? != 0 ]; then -- echo "$0: unexpected exit status" -- fail=1 --fi --if [ "$output" != "nbddump $EXPECTED_VERSION --libnbd $EXPECTED_VERSION" ]; then -- echo "$0: unexpected output" -- fail=1 --fi --echo "$output" --exit $fail -+# Test that --version looks sane. -+ -+. ../tests/functions.sh -+set -e -+set -x -+ -+tool=nbddump -+ -+output=test-$tool.out -+cleanup_fn rm -f $output -+ -+$VG $tool --version > $output -+cat $output -+ -+grep "$tool $EXPECTED_VERSION" $output -+grep "libnbd $EXPECTED_VERSION" $output -diff --git a/fuse/test-version.sh b/fuse/test-version.sh -index 7b3e9929..18924b1f 100755 ---- a/fuse/test-version.sh -+++ b/fuse/test-version.sh -@@ -16,18 +16,19 @@ - # License along with this library; if not, write to the Free Software - # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - --# Test that nbdfuse --version looks sane. -- --fail=0 --output=$($VG nbdfuse --version) --if [ $? != 0 ]; then -- echo "$0: unexpected exit status" -- fail=1 --fi --if [ "$output" != "nbdfuse $EXPECTED_VERSION --libnbd $EXPECTED_VERSION" ]; then -- echo "$0: unexpected output" -- fail=1 --fi --echo "$output" --exit $fail -+# Test that --version looks sane. -+ -+. ../tests/functions.sh -+set -e -+set -x -+ -+tool=nbdfuse -+ -+output=test-$tool.out -+cleanup_fn rm -f $output -+ -+$VG $tool --version > $output -+cat $output -+ -+grep "$tool $EXPECTED_VERSION" $output -+grep "libnbd $EXPECTED_VERSION" $output -diff --git a/info/test-version.sh b/info/test-version.sh -index 0125479e..35b1eec7 100755 ---- a/info/test-version.sh -+++ b/info/test-version.sh -@@ -16,18 +16,19 @@ - # License along with this library; if not, write to the Free Software - # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - --# Test that nbdinfo --version looks sane. -- --fail=0 --output=$($VG nbdinfo --version) --if [ $? != 0 ]; then -- echo "$0: unexpected exit status" -- fail=1 --fi --if [ "$output" != "nbdinfo $EXPECTED_VERSION --libnbd $EXPECTED_VERSION" ]; then -- echo "$0: unexpected output" -- fail=1 --fi --echo "$output" --exit $fail -+# Test that --version looks sane. -+ -+. ../tests/functions.sh -+set -e -+set -x -+ -+tool=nbdinfo -+ -+output=test-$tool.out -+cleanup_fn rm -f $output -+ -+$VG $tool --version > $output -+cat $output -+ -+grep "$tool $EXPECTED_VERSION" $output -+grep "libnbd $EXPECTED_VERSION" $output -diff --git a/sh/test-version.sh b/sh/test-version.sh -index ef730ea2..5caba42c 100755 ---- a/sh/test-version.sh -+++ b/sh/test-version.sh -@@ -16,18 +16,19 @@ - # License along with this library; if not, write to the Free Software - # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - --# Test that nbdsh --version looks sane. -- --fail=0 --output=$($VG nbdsh --version) --if [ $? != 0 ]; then -- echo "$0: unexpected exit status" -- fail=1 --fi --if [ "$output" != "nbdsh $EXPECTED_VERSION --libnbd $EXPECTED_VERSION" ]; then -- echo "$0: unexpected output" -- fail=1 --fi --echo "$output" --exit $fail -+# Test that --version looks sane. -+ -+. ../tests/functions.sh -+set -e -+set -x -+ -+tool=nbdsh -+ -+output=test-$tool.out -+cleanup_fn rm -f $output -+ -+$VG $tool --version > $output -+cat $output -+ -+grep "$tool $EXPECTED_VERSION" $output -+grep "libnbd $EXPECTED_VERSION" $output --- -2.47.1 - diff --git a/copy-patches.sh b/copy-patches.sh index ba47329..83f126a 100755 --- a/copy-patches.sh +++ b/copy-patches.sh @@ -6,7 +6,7 @@ set -e # directory. Use it like this: # ./copy-patches.sh -rhel_version=10.1 +rhel_version=10.2 # Check we're in the right directory. if [ ! -f libnbd.spec ]; then diff --git a/libnbd.spec b/libnbd.spec index 7eda2e8..f160ac5 100644 --- a/libnbd.spec +++ b/libnbd.spec @@ -17,11 +17,11 @@ %global verify_tarball_signature 1 # The source directory. -%global source_directory 1.22-stable +%global source_directory 1.23-development Name: libnbd -Version: 1.22.2 -Release: 2%{?dist} +Version: 1.23.7 +Release: 1%{?dist} Summary: NBD client library in userspace License: LGPL-2.0-or-later AND BSD-3-Clause @@ -38,25 +38,13 @@ Source2: libguestfs.keyring Source3: copy-patches.sh # Patches are stored in the upstream repository: -# https://gitlab.com/nbdkit/libnbd/-/commits/rhel-10.1/ +# https://gitlab.com/nbdkit/libnbd/-/commits/rhel-10.2/ # Patches. -Patch0001: 0001-rust-Allow-cargo-build-target-RUST_TARGET-to-be-set.patch -#Patch0002: 0002-ci-Disable-cross-builds-of-Rust.patch -Patch0003: 0003-maint-Spelling-fixes.patch -Patch0004: 0004-generator-Avoid-const-correctness-warnings-in-golang.patch -Patch0005: 0005-info-Tolerate-nbdkit-slop-on-large-extents.patch -Patch0006: 0006-todo-Remove-a-couple-of-minor-features-that-have-bee.patch -Patch0007: 0007-ublk-Remove-unused-EXPECTED_VERSION.patch -Patch0008: 0008-copy-Add-blkhash-option.patch -Patch0009: 0009-copy-Fix-crash-when-blkhash-size-is-not-a-power-of-2.patch -Patch0010: 0010-copy-Define-block_type-outside-of-block-struct.patch -Patch0011: 0011-copy-Shrink-struct-block.patch -Patch0012: 0012-copy-Enable-zero-optimization-for-allocated-extents.patch -Patch0013: 0013-copy-Fix-corrupted-hash-on-incomplete-read.patch -Patch0014: 0014-build-Add-.-configure-with-extra.patch -Patch0015: 0015-lib-New-API-nbd_get_version_extra.patch -Patch0016: 0016-tools-Add-extra-version-information-in-the-output-of.patch +Patch0001: 0001-lib-uri.c-Replace-nbd-user-with-tls-username.patch +Patch0002: 0002-tests-Add-a-test-of-tls-username-in-NBD-URIs.patch +Patch0003: 0003-docs-Document-which-NBD-URI-features-are-non-standar.patch +Patch0004: 0004-docs-Minor-copyediting-to-export-name-documentation.patch %if 0%{verify_tarball_signature} BuildRequires: gnupg2 @@ -96,6 +84,9 @@ BuildRequires: glib2-devel # For bash-completion. BuildRequires: bash-completion +%if !0%{?rhel} +BuildRequires: bash-completion-devel +%endif # Only for running the test suite. BuildRequires: coreutils @@ -371,6 +362,7 @@ make %{?_smp_mflags} check || { %{python3_sitearch}/__pycache__/nbd*.py* %{_bindir}/nbdsh %{_mandir}/man1/nbdsh.1* +%{_mandir}/man3/libnbd-python.3* %files -n nbdfuse @@ -386,6 +378,17 @@ make %{?_smp_mflags} check || { %files bash-completion +%if !0%{?rhel} +%dir %{bash_completions_dir} +%{bash_completions_dir}/nbdcopy +%{bash_completions_dir}/nbddump +%{bash_completions_dir}/nbdfuse +%{bash_completions_dir}/nbdinfo +%{bash_completions_dir}/nbdsh +%if 0%{?have_ublk} +%{bash_completions_dir}/nbdublk +%endif +%else %dir %{_datadir}/bash-completion/completions %{_datadir}/bash-completion/completions/nbdcopy %{_datadir}/bash-completion/completions/nbddump @@ -395,9 +398,14 @@ make %{?_smp_mflags} check || { %if 0%{?have_ublk} %{_datadir}/bash-completion/completions/nbdublk %endif +%endif %changelog +* Fri Aug 29 2025 Richard W.M. Jones - 1.23.7-1 +- Rebase to libnbd 1.23.7 + resolves: RHEL-111243 + * Wed Jul 16 2025 Richard W.M. Jones - 1.22.2-2 - Rebase to libnbd 1.22.2 - Synch spec file with Fedora Rawhide. diff --git a/sources b/sources index 381c18a..f40889c 100644 --- a/sources +++ b/sources @@ -1,2 +1,2 @@ -SHA512 (libnbd-1.22.2.tar.gz) = 5ece4cdc41cafefbe27ddaeafc2b6b390b0cf25f38f80c1b10ec2e17ee1dcda92964891faf4abca4c8aa5827c9eec6e0b38162871e8c72b2af8e769287cd603d -SHA512 (libnbd-1.22.2.tar.gz.sig) = 0b0d6cd4e5b900aef73820f53dc87e3d7dbd80a056efbb8c6236750c91fc570b529a3bddcbb446ebbb517f279daf90d6fa7e9ffca16901b5568ac395c1b6eda2 +SHA512 (libnbd-1.23.7.tar.gz) = a09a3e273829f17f5ba4b7f723afe31704ecd415f08056b308afd064358816548248cf943060acbe308ad581d4a8d236668606907bfc27f49021238a75897fc6 +SHA512 (libnbd-1.23.7.tar.gz.sig) = 67025852dfcea27a6c91c1fdec8245488699d85db25cdeedb339148d1cb3ae3f9102abd54513cc334345beb7b96180b4be80ec6b9aad628a6f4b14d458b62e03