From 983159e5f0d31ae64dfc0a584c089699315196a6 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Wed, 16 Apr 2025 11:35:13 +0100 Subject: [PATCH] generator: Implement struct FDevice type This acts just like FString except that we do reverse device name translation on it. The only use is in the 'pvs-full' API where we will use it (in a subsequent commit) to reverse translate the pv_name field (a device name) before returning it from the daemon. Compare this to the 'pvs' API which also returns a list of device names, but using the generator's 'RStructList (RDevice,...)' return type, where RDevice is similarly reverse translated. Note in the library-side bindings, because the name has already been translated in the daemon, we just treat it exactly the same as FString. The vast majority of this patch is this mechanical change. (cherry picked from commit 0ff73a42c7f4f309fbab11ea2e89ee6f0501367d) (cherry picked from commit 4e27b259c166d87a57d133a79b8eed3b556288b8) --- generator/GObject.ml | 6 +++--- generator/OCaml.ml | 6 ++---- generator/XDR.ml | 2 +- generator/c.ml | 20 +++++++++----------- generator/csharp.ml | 2 +- generator/daemon.ml | 30 ++++++++++++++++++++++++++---- generator/erlang.ml | 2 +- generator/golang.ml | 4 ++-- generator/java.ml | 7 ++++--- generator/lua.ml | 2 +- generator/perl.ml | 4 ++-- generator/php.ml | 4 ++-- generator/python.ml | 2 +- generator/ruby.ml | 4 ++-- generator/rust.ml | 6 +++--- generator/types.ml | 1 + generator/types.mli | 1 + 17 files changed, 62 insertions(+), 41 deletions(-) diff --git a/generator/GObject.ml b/generator/GObject.ml index 6c74b31b8..e7462c0ed 100644 --- a/generator/GObject.ml +++ b/generator/GObject.ml @@ -206,7 +206,7 @@ let generate_gobject_struct_header filename typ cols () = pr " * @%s: An unsigned 64-bit integer\n" n | n, FInt64 -> pr " * @%s: A signed 64-bit integer\n" n - | n, FString -> + | n, (FString|FDevice) -> pr " * @%s: A NULL-terminated string\n" n | n, FBuffer -> pr " * @%s: A GByteArray\n" n @@ -231,7 +231,7 @@ let generate_gobject_struct_header filename typ cols () = pr " guint64 %s;\n" n | n, FInt64 -> pr " gint64 %s;\n" n - | n, FString -> + | n, (FString|FDevice) -> pr " gchar *%s;\n" n | n, FBuffer -> pr " GByteArray *%s;\n" n @@ -1228,7 +1228,7 @@ guestfs_session_close (GuestfsSession *session, GError **err) | n, FUUID -> pr "%smemcpy (%s%s, %s%s, sizeof (%s%s));\n" indent dst n src n dst n - | n, FString -> + | n, (FString|FDevice) -> pr "%sif (%s%s) %s%s = g_strdup (%s%s);\n" indent src n dst n src n | n, FBuffer -> diff --git a/generator/OCaml.ml b/generator/OCaml.ml index 1e6f603ab..4ef07e272 100644 --- a/generator/OCaml.ml +++ b/generator/OCaml.ml @@ -512,7 +512,7 @@ copy_table (char * const * argv) List.iteri ( fun i col -> (match col with - | name, FString -> + | name, (FString|FDevice) -> pr " v = caml_copy_string (%s->%s);\n" typ name | name, FBuffer -> pr " v = caml_alloc_initialized_string (%s->%s_len, %s->%s);\n" @@ -839,9 +839,7 @@ and generate_ocaml_structure_decls () = pr "type %s = {\n" typ; List.iter ( function - | name, FString -> pr " %s : string;\n" name - | name, FBuffer -> pr " %s : string;\n" name - | name, FUUID -> pr " %s : string;\n" name + | name, (FString|FDevice|FBuffer|FUUID) -> pr " %s : string;\n" name | name, (FBytes|FInt64|FUInt64) -> pr " %s : int64;\n" name | name, (FInt32|FUInt32) -> pr " %s : int32;\n" name | name, FChar -> pr " %s : char;\n" name diff --git a/generator/XDR.ml b/generator/XDR.ml index 566ba69e8..e71d97f5c 100644 --- a/generator/XDR.ml +++ b/generator/XDR.ml @@ -66,7 +66,7 @@ let generate_xdr () = pr "struct guestfs_int_%s {\n" typ; List.iter (function | name, FChar -> pr " char %s;\n" name - | name, FString -> pr " string %s<>;\n" name + | name, (FString|FDevice) -> pr " string %s<>;\n" name | name, FBuffer -> pr " opaque %s<>;\n" name | name, FUUID -> pr " opaque %s[32];\n" name | name, FInt32 -> pr " int %s;\n" name diff --git a/generator/c.ml b/generator/c.ml index 0391dd3dd..e850885e4 100644 --- a/generator/c.ml +++ b/generator/c.ml @@ -352,7 +352,7 @@ and generate_structs_pod () = | name, FInt32 -> pr " int32_t %s;\n" name | name, (FUInt64|FBytes) -> pr " uint64_t %s;\n" name | name, FInt64 -> pr " int64_t %s;\n" name - | name, FString -> pr " char *%s;\n" name + | name, (FString|FDevice) -> pr " char *%s;\n" name | name, FBuffer -> pr " /* The next two fields describe a byte array. */\n"; pr " uint32_t %s_len;\n" name; @@ -609,7 +609,7 @@ extern GUESTFS_DLL_PUBLIC void *guestfs_next_private (guestfs_h *g, const char * List.iter ( function | name, FChar -> pr " char %s;\n" name - | name, FString -> pr " char *%s;\n" name + | name, (FString|FDevice) -> pr " char *%s;\n" name | name, FBuffer -> pr " uint32_t %s_len;\n" name; pr " char *%s;\n" name @@ -926,7 +926,7 @@ and generate_client_structs_compare () = fun { s_name = typ; s_cols = cols } -> let has_nonnumeric_cols = let nonnumeric = function - | _,(FString|FUUID|FBuffer) -> true + | _,(FString|FDevice|FUUID|FBuffer) -> true | _,(FChar|FUInt32|FInt32|FUInt64|FBytes|FInt64|FOptPercent) -> false in List.exists nonnumeric cols in @@ -942,7 +942,7 @@ and generate_client_structs_compare () = ); List.iter ( function - | name, FString -> + | name, (FString|FDevice) -> pr " r = strcmp (s1->%s, s2->%s);\n" name name; pr " if (r != 0) return r;\n" | name, FBuffer -> @@ -1011,7 +1011,7 @@ and generate_client_structs_copy () = fun { s_name = typ; s_cols = cols } -> let has_boxed_cols = let boxed = function - | _,(FString|FBuffer) -> true + | _,(FString|FDevice|FBuffer) -> true | _,(FChar|FUUID|FUInt32|FInt32|FUInt64|FBytes|FInt64|FOptPercent) -> false in @@ -1024,8 +1024,7 @@ and generate_client_structs_copy () = pr "{\n"; List.iter ( function - | name, FString - | name, FBuffer -> pr " free (s->%s);\n" name + | name, (FString|FDevice|FBuffer) -> pr " free (s->%s);\n" name | _, FChar | _, FUUID | _, FUInt32 @@ -1048,8 +1047,7 @@ and generate_client_structs_copy () = pr "\n"; List.iter ( function - | name, FString - | name, FBuffer -> pr " out->%s = NULL;\n" name + | name, (FString|FDevice|FBuffer) -> pr " out->%s = NULL;\n" name | _, FChar | _, FUUID | _, FUInt32 @@ -1061,7 +1059,7 @@ and generate_client_structs_copy () = ) cols; List.iter ( function - | name, FString -> + | name, (FString|FDevice) -> pr " out->%s = strdup (inp->%s);\n" name name; pr " if (out->%s == NULL) goto error;\n" name | name, FBuffer -> @@ -1244,7 +1242,7 @@ and generate_client_structs_print_c () = ); List.iter ( function - | name, FString -> + | name, (FString|FDevice) -> pr " fprintf (dest, \"%%s%s: %%s%%s\", indent, %s->%s, linesep);\n" name typ name | name, FUUID -> diff --git a/generator/csharp.ml b/generator/csharp.ml index 43579df5e..6ab6c3c98 100644 --- a/generator/csharp.ml +++ b/generator/csharp.ml @@ -119,7 +119,7 @@ namespace Guestfs List.iter ( function | name, FChar -> pr " char %s;\n" name - | name, FString -> pr " string %s;\n" name + | name, (FString | FDevice) -> pr " string %s;\n" name | name, FBuffer -> pr " uint %s_len;\n" name; pr " string %s;\n" name diff --git a/generator/daemon.ml b/generator/daemon.ml index 78a2412d2..0218d3e50 100644 --- a/generator/daemon.ml +++ b/generator/daemon.ml @@ -447,15 +447,37 @@ let generate_daemon_stubs actions () = pr " ret.%s.%s_val = r;\n" n n; pr " reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n" name - | RStruct (n, _) -> + | RStruct (n, typ) -> + (* XXX RStruct containing an FDevice field would require + * reverse device name translation. That is not implemented. + * See also RStructList immediately below this. + *) + let cols = (Structs.lookup_struct typ).s_cols in + assert (not (List.exists + (function (_, FDevice) -> true | _ -> false) cols)); pr " struct guestfs_%s_ret ret;\n" name; pr " ret.%s = *r;\n" n; pr " reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n" name; pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n" name - | RStructList (n, _) -> + | RStructList (n, typ) -> pr " struct guestfs_%s_ret ret;\n" name; + let cols = (Structs.lookup_struct typ).s_cols in + List.iter ( + function + | (fname, FDevice) -> + pr " for (size_t i = 0; i < r->guestfs_int_%s_list_len; ++i) {\n" + typ; + pr " char *field = r->guestfs_int_%s_list_val[i].%s;\n" + typ fname; + pr " char *rr = reverse_device_name_translation (field);\n"; + pr " if (!rr) abort ();\n"; + pr " free (field);\n"; + pr " r->guestfs_int_%s_list_val[i].%s = rr;\n" typ fname; + pr " }\n"; + | _ -> () + ) cols; pr " ret.%s = *r;\n" n; pr " reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n" name; @@ -624,7 +646,7 @@ let generate_daemon_caml_stubs () = fun i -> pr " v = Field (retv, %d);\n" i; function - | n, (FString|FUUID) -> + | n, (FString|FDevice|FUUID) -> pr " ret->%s = strdup (String_val (v));\n" n; pr " if (ret->%s == NULL) return NULL;\n" n | n, FBuffer -> @@ -991,7 +1013,7 @@ let generate_daemon_lvm_tokenization () = pr " if (*p) next = p+1; else next = NULL;\n"; pr " *p = '\\0';\n"; (match coltype with - | FString -> + | FString | FDevice -> pr " r->%s = strdup (tok);\n" name; pr " if (r->%s == NULL) {\n" name; pr " perror (\"strdup\");\n"; diff --git a/generator/erlang.ml b/generator/erlang.ml index 65af75aaf..864b3ff04 100644 --- a/generator/erlang.ml +++ b/generator/erlang.ml @@ -286,7 +286,7 @@ and generate_erlang_structs () = List.iteri ( fun i col -> (match col with - | name, FString -> + | name, (FString|FDevice) -> pr " if (ei_x_encode_string (buff, %s->%s) != 0) return -1;\n" typ name | name, FBuffer -> pr " if (ei_x_encode_string_len (buff, %s->%s, %s->%s_len) != 0) return -1;\n" diff --git a/generator/golang.ml b/generator/golang.ml index 0d6a92367..a5b39f5df 100644 --- a/generator/golang.ml +++ b/generator/golang.ml @@ -248,7 +248,7 @@ func return_hashtable (argv **C.char) map[string]string { let n = String.capitalize_ascii n in match field with | FChar -> pr " %s byte\n" n - | FString -> pr " %s string\n" n + | FString | FDevice -> pr " %s string\n" n | FBuffer -> pr " %s []byte\n" n | FUInt32 -> pr " %s uint32\n" n | FInt32 -> pr " %s int32\n" n @@ -267,7 +267,7 @@ func return_hashtable (argv **C.char) map[string]string { let gon = String.capitalize_ascii n in match field with | FChar -> pr " r.%s = byte (c.%s)\n" gon n - | FString -> pr " r.%s = C.GoString (c.%s)\n" gon n + | FString | FDevice -> pr " r.%s = C.GoString (c.%s)\n" gon n | FBuffer -> pr " r.%s = C.GoBytes (unsafe.Pointer (c.%s), C.int (c.%s_len))\n" gon n n diff --git a/generator/java.ml b/generator/java.ml index afcddf90f..4b74203aa 100644 --- a/generator/java.ml +++ b/generator/java.ml @@ -560,6 +560,7 @@ public class %s { List.iter ( function | name, FString + | name, FDevice | name, FUUID | name, FBuffer -> pr " public String %s;\n" name | name, (FBytes|FUInt64|FInt64) -> pr " public long %s;\n" name @@ -947,7 +948,7 @@ and generate_java_struct_return typ jtyp cols = pr " jr = (*env)->AllocObject (env, cl);\n"; List.iter ( function - | name, FString -> + | name, (FString|FDevice) -> pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name; pr " (*env)->SetObjectField (env, jr, fl, (*env)->NewStringUTF (env, r->%s));\n" name; | name, FUUID -> @@ -997,7 +998,7 @@ and generate_java_struct_list_return typ jtyp cols = fun (name, ftyp) -> (* Get the field ID in 'fl'. *) let java_field_type = match ftyp with - | FString | FUUID | FBuffer -> "Ljava/lang/String;" + | FString | FDevice | FUUID | FBuffer -> "Ljava/lang/String;" | FBytes | FUInt64 | FInt64 -> "J" | FUInt32 | FInt32 -> "I" | FOptPercent -> "F" @@ -1007,7 +1008,7 @@ and generate_java_struct_list_return typ jtyp cols = (* Assign the value to this field. *) match ftyp with - | FString -> + | FString | FDevice -> pr " (*env)->SetObjectField (env, jfl, fl,\n"; pr " (*env)->NewStringUTF (env, r->val[i].%s));\n" name; | FUUID -> diff --git a/generator/lua.ml b/generator/lua.ml index 0d7e63be0..685645abf 100644 --- a/generator/lua.ml +++ b/generator/lua.ml @@ -824,7 +824,7 @@ push_event (lua_State *L, uint64_t event) (match field with | FChar -> pr " lua_pushlstring (L, &v->%s, 1);\n" n - | FString -> + | FString | FDevice -> pr " lua_pushstring (L, v->%s);\n" n | FBuffer -> pr " lua_pushlstring (L, v->%s, v->%s_len);\n" n n diff --git a/generator/perl.ml b/generator/perl.ml index 8b9834ef0..e0edc249b 100644 --- a/generator/perl.ml +++ b/generator/perl.ml @@ -607,7 +607,7 @@ and generate_perl_struct_list_code typ cols name style = pr " hv = newHV ();\n"; List.iter ( function - | name, FString -> + | name, (FString|FDevice) -> pr " (void) hv_store (hv, \"%s\", %d, newSVpv (r->val[i].%s, 0), 0);\n" name (String.length name) name | name, FUUID -> @@ -645,7 +645,7 @@ and generate_perl_struct_code typ cols name style = pr " PUSHs (sv_2mortal (newSVpv (\"%s\", 0)));\n" name; match col with - | name, FString -> + | name, (FString|FDevice) -> pr " PUSHs (sv_2mortal (newSVpv (r->%s, 0)));\n" name | name, FBuffer -> diff --git a/generator/php.ml b/generator/php.ml index 99ec66c74..5023e0c5a 100644 --- a/generator/php.ml +++ b/generator/php.ml @@ -616,7 +616,7 @@ and generate_php_struct_code typ cols = pr " array_init (return_value);\n"; List.iter ( function - | name, FString -> + | name, (FString|FDevice) -> pr " guestfs_add_assoc_string (return_value, \"%s\", r->%s, 1);\n" name name | name, FBuffer -> pr " guestfs_add_assoc_stringl (return_value, \"%s\", r->%s, r->%s_len, 1);\n" @@ -650,7 +650,7 @@ and generate_php_struct_list_code typ cols = pr " array_init (z_elem);\n"; List.iter ( function - | name, FString -> + | name, (FString|FDevice) -> pr " guestfs_add_assoc_string (z_elem, \"%s\", r->val[c].%s, 1);\n" name name | name, FBuffer -> diff --git a/generator/python.ml b/generator/python.ml index ad02ea939..5534e74a9 100644 --- a/generator/python.ml +++ b/generator/python.ml @@ -168,7 +168,7 @@ and generate_python_structs () = pr " return NULL;\n"; List.iter ( function - | name, FString -> + | name, (FString|FDevice) -> pr " value = guestfs_int_py_fromstring (%s->%s);\n" typ name; pr " if (value == NULL)\n"; pr " goto err;\n"; diff --git a/generator/ruby.ml b/generator/ruby.ml index be3238f60..ea5a31945 100644 --- a/generator/ruby.ml +++ b/generator/ruby.ml @@ -526,7 +526,7 @@ and generate_ruby_struct_code typ cols = pr " volatile VALUE rv = rb_hash_new ();\n"; List.iter ( function - | name, FString -> + | name, (FString|FDevice) -> pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new2 (r->%s));\n" name name | name, FBuffer -> pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new (r->%s, r->%s_len));\n" name name name @@ -556,7 +556,7 @@ and generate_ruby_struct_list_code typ cols = pr " volatile VALUE hv = rb_hash_new ();\n"; List.iter ( function - | name, FString -> + | name, (FString|FDevice) -> pr " rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_str_new2 (r->val[i].%s));\n" name name | name, FBuffer -> pr " rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_str_new (r->val[i].%s, r->val[i].%s_len));\n" name name name diff --git a/generator/rust.ml b/generator/rust.ml index 1f5cefa62..f4dcfd723 100644 --- a/generator/rust.ml +++ b/generator/rust.ml @@ -115,7 +115,7 @@ extern \"C\" { List.iter ( function | n, FChar -> pr " pub %s: i8,\n" n - | n, FString -> pr " pub %s: String,\n" n + | n, (FString|FDevice) -> pr " pub %s: String,\n" n | n, FBuffer -> pr " pub %s: Vec,\n" n | n, FUInt32 -> pr " pub %s: u32,\n" n | n, FInt32 -> pr " pub %s: i32,\n" n @@ -130,7 +130,7 @@ extern \"C\" { List.iter ( function | n, FChar -> pr " %s: c_char,\n" n - | n, FString -> pr " %s: *const c_char,\n" n + | n, (FString|FDevice) -> pr " %s: *const c_char,\n" n | n, FBuffer -> pr " %s_len: usize,\n" n; pr " %s: *const c_char,\n" n; @@ -154,7 +154,7 @@ extern \"C\" { match x with | n, FChar -> pr "%s: (*raw).%s as i8,\n" n n; - | n, FString -> + | n, (FString|FDevice) -> pr "%s: char_ptr_to_string((*raw).%s)?,\n" n n; | n, FBuffer -> pr "%s: slice::from_raw_parts((*raw).%s as *const u8, (*raw).%s_len).to_vec(),\n" n n n diff --git a/generator/types.ml b/generator/types.ml index d9b008850..c901aa731 100644 --- a/generator/types.ml +++ b/generator/types.ml @@ -215,6 +215,7 @@ let defaults = { name = ""; type field = | FChar (* C 'char' (really, a 7 bit byte). *) | FString (* nul-terminated ASCII string, NOT NULL. *) + | FDevice (* device name, needs reverse transl. *) | FBuffer (* opaque buffer of bytes, (char *, int) pair *) | FUInt32 | FInt32 diff --git a/generator/types.mli b/generator/types.mli index 0ce0d33b4..0a4752d5c 100644 --- a/generator/types.mli +++ b/generator/types.mli @@ -413,6 +413,7 @@ val defaults : action type field = | FChar (** C 'char' (really, a 7 bit byte). *) | FString (** nul-terminated ASCII string, NOT NULL. *) + | FDevice (** device name, needs reverse transl. *) | FBuffer (** opaque buffer of bytes, (char *, int) pair*) | FUInt32 | FInt32