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 0ff73a42c7)
(cherry picked from commit 4e27b259c1)
This commit is contained in:
Richard W.M. Jones
2025-04-16 11:35:13 +01:00
parent 0de9a79780
commit 983159e5f0
17 changed files with 62 additions and 41 deletions

View File

@@ -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 ->

View File

@@ -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

View File

@@ -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

View File

@@ -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 ->

View File

@@ -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

View File

@@ -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";

View File

@@ -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"

View File

@@ -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

View File

@@ -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 ->

View File

@@ -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

View File

@@ -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 ->

View File

@@ -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 ->

View File

@@ -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";

View File

@@ -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

View File

@@ -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<u8>,\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

View File

@@ -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

View File

@@ -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