Generator: Improve accuracy of a comment.
[libguestfs.git] / src / generator.ml
index 8c864f0..eb61fd1 100755 (executable)
@@ -25,9 +25,8 @@
  * daemon/<somefile>.c to write the implementation.
  *
  * After editing this file, run it (./src/generator.ml) to regenerate all the
  * daemon/<somefile>.c to write the implementation.
  *
  * After editing this file, run it (./src/generator.ml) to regenerate all the
- * output files. Note that if you are using a separate build directory you must
- * run generator.ml from your top level build directory. You must also have run
- * configure before generator.ml will run.
+ * output files.  Note that if you are using a separate build directory you
+ * must run generator.ml from the _source_ directory.
  *
  * IMPORTANT: This script should NOT print any warnings.  If it prints
  * warnings, you should treat them as errors.
  *
  * IMPORTANT: This script should NOT print any warnings.  If it prints
  * warnings, you should treat them as errors.
@@ -1371,7 +1370,9 @@ contains the filesystem.");
 This returns the list of currently mounted filesystems.  It returns
 the list of devices (eg. C</dev/sda1>, C</dev/VG/LV>).
 
 This returns the list of currently mounted filesystems.  It returns
 the list of devices (eg. C</dev/sda1>, C</dev/VG/LV>).
 
-Some internal mounts are not shown.");
+Some internal mounts are not shown.
+
+See also: C<guestfs_mountpoints>");
 
   ("umount_all", (RErr, []), 47, [FishAlias "unmount-all"],
    [InitBasicFS, Always, TestOutputList (
 
   ("umount_all", (RErr, []), 47, [FishAlias "unmount-all"],
    [InitBasicFS, Always, TestOutputList (
@@ -1718,8 +1719,8 @@ This uses the L<blockdev(8)> command.");
   ("upload", (RErr, [FileIn "filename"; String "remotefilename"]), 66, [],
    [InitBasicFS, Always, TestOutput (
       (* Pick a file from cwd which isn't likely to change. *)
   ("upload", (RErr, [FileIn "filename"; String "remotefilename"]), 66, [],
    [InitBasicFS, Always, TestOutput (
       (* Pick a file from cwd which isn't likely to change. *)
-    [["upload"; "../COPYING.LIB"; "/COPYING.LIB"];
-     ["checksum"; "md5"; "/COPYING.LIB"]], "e3eda01d9815f8d24aae2dbd89b68b06")],
+      [["upload"; "../COPYING.LIB"; "/COPYING.LIB"];
+       ["checksum"; "md5"; "/COPYING.LIB"]], "e3eda01d9815f8d24aae2dbd89b68b06")],
    "upload a file from the local machine",
    "\
 Upload local file C<filename> to C<remotefilename> on the
    "upload a file from the local machine",
    "\
 Upload local file C<filename> to C<remotefilename> on the
@@ -1732,10 +1733,10 @@ See also C<guestfs_download>.");
   ("download", (RErr, [String "remotefilename"; FileOut "filename"]), 67, [],
    [InitBasicFS, Always, TestOutput (
       (* Pick a file from cwd which isn't likely to change. *)
   ("download", (RErr, [String "remotefilename"; FileOut "filename"]), 67, [],
    [InitBasicFS, Always, TestOutput (
       (* Pick a file from cwd which isn't likely to change. *)
-    [["upload"; "../COPYING.LIB"; "/COPYING.LIB"];
-     ["download"; "/COPYING.LIB"; "testdownload.tmp"];
-     ["upload"; "testdownload.tmp"; "/upload"];
-     ["checksum"; "md5"; "/upload"]], "e3eda01d9815f8d24aae2dbd89b68b06")],
+      [["upload"; "../COPYING.LIB"; "/COPYING.LIB"];
+       ["download"; "/COPYING.LIB"; "testdownload.tmp"];
+       ["upload"; "testdownload.tmp"; "/upload"];
+       ["checksum"; "md5"; "/upload"]], "e3eda01d9815f8d24aae2dbd89b68b06")],
    "download a file to the local machine",
    "\
 Download file C<remotefilename> and save it as C<filename>
    "download a file to the local machine",
    "\
 Download file C<remotefilename> and save it as C<filename>
@@ -2357,19 +2358,19 @@ are activated or deactivated.");
 
   ("lvresize", (RErr, [String "device"; Int "mbytes"]), 105, [],
    [InitNone, Always, TestOutput (
 
   ("lvresize", (RErr, [String "device"; Int "mbytes"]), 105, [],
    [InitNone, Always, TestOutput (
-    [["sfdiskM"; "/dev/sda"; ","];
-     ["pvcreate"; "/dev/sda1"];
-     ["vgcreate"; "VG"; "/dev/sda1"];
-     ["lvcreate"; "LV"; "VG"; "10"];
-     ["mkfs"; "ext2"; "/dev/VG/LV"];
-     ["mount"; "/dev/VG/LV"; "/"];
-     ["write_file"; "/new"; "test content"; "0"];
-     ["umount"; "/"];
-     ["lvresize"; "/dev/VG/LV"; "20"];
-     ["e2fsck_f"; "/dev/VG/LV"];
-     ["resize2fs"; "/dev/VG/LV"];
-     ["mount"; "/dev/VG/LV"; "/"];
-     ["cat"; "/new"]], "test content")],
+      [["sfdiskM"; "/dev/sda"; ","];
+       ["pvcreate"; "/dev/sda1"];
+       ["vgcreate"; "VG"; "/dev/sda1"];
+       ["lvcreate"; "LV"; "VG"; "10"];
+       ["mkfs"; "ext2"; "/dev/VG/LV"];
+       ["mount"; "/dev/VG/LV"; "/"];
+       ["write_file"; "/new"; "test content"; "0"];
+       ["umount"; "/"];
+       ["lvresize"; "/dev/VG/LV"; "20"];
+       ["e2fsck_f"; "/dev/VG/LV"];
+       ["resize2fs"; "/dev/VG/LV"];
+       ["mount"; "/dev/VG/LV"; "/"];
+       ["cat"; "/new"]], "test content")],
    "resize an LVM logical volume",
    "\
 This resizes (expands or shrinks) an existing LVM logical
    "resize an LVM logical volume",
    "\
 This resizes (expands or shrinks) an existing LVM logical
@@ -2441,7 +2442,7 @@ This command is only needed because of C<guestfs_resize2fs>
 
   ("sleep", (RErr, [Int "secs"]), 109, [],
    [InitNone, Always, TestRun (
 
   ("sleep", (RErr, [Int "secs"]), 109, [],
    [InitNone, Always, TestRun (
-    [["sleep"; "1"]])],
+      [["sleep"; "1"]])],
    "sleep for some seconds",
    "\
 Sleep for C<secs> seconds.");
    "sleep for some seconds",
    "\
 Sleep for C<secs> seconds.");
@@ -2857,6 +2858,120 @@ were rarely if ever used anyway.
 
 See also C<guestfs_sfdisk> and the L<sfdisk(8)> manpage.");
 
 
 See also C<guestfs_sfdisk> and the L<sfdisk(8)> manpage.");
 
+  ("zfile", (RString "description", [String "method"; String "path"]), 140, [],
+   [],
+   "determine file type inside a compressed file",
+   "\
+This command runs C<file> after first decompressing C<path>
+using C<method>.
+
+C<method> must be one of C<gzip>, C<compress> or C<bzip2>.
+
+See also: C<guestfs_file>");
+
+  ("getxattrs", (RStructList ("xattrs", "xattr"), [String "path"]), 141, [],
+   [],
+   "list extended attributes of a file or directory",
+   "\
+This call lists the extended attributes of the file or directory
+C<path>.
+
+At the system call level, this is a combination of the
+L<listxattr(2)> and L<getxattr(2)> calls.
+
+See also: C<guestfs_lgetxattrs>, L<attr(5)>.");
+
+  ("lgetxattrs", (RStructList ("xattrs", "xattr"), [String "path"]), 142, [],
+   [],
+   "list extended attributes of a file or directory",
+   "\
+This is the same as C<guestfs_getxattrs>, but if C<path>
+is a symbolic link, then it returns the extended attributes
+of the link itself.");
+
+  ("setxattr", (RErr, [String "xattr";
+                      String "val"; Int "vallen"; (* will be BufferIn *)
+                      String "path"]), 143, [],
+   [],
+   "set extended attribute of a file or directory",
+   "\
+This call sets the extended attribute named C<xattr>
+of the file C<path> to the value C<val> (of length C<vallen>).
+The value is arbitrary 8 bit data.
+
+See also: C<guestfs_lsetxattr>, L<attr(5)>.");
+
+  ("lsetxattr", (RErr, [String "xattr";
+                       String "val"; Int "vallen"; (* will be BufferIn *)
+                       String "path"]), 144, [],
+   [],
+   "set extended attribute of a file or directory",
+   "\
+This is the same as C<guestfs_setxattr>, but if C<path>
+is a symbolic link, then it sets an extended attribute
+of the link itself.");
+
+  ("removexattr", (RErr, [String "xattr"; String "path"]), 145, [],
+   [],
+   "remove extended attribute of a file or directory",
+   "\
+This call removes the extended attribute named C<xattr>
+of the file C<path>.
+
+See also: C<guestfs_lremovexattr>, L<attr(5)>.");
+
+  ("lremovexattr", (RErr, [String "xattr"; String "path"]), 146, [],
+   [],
+   "remove extended attribute of a file or directory",
+   "\
+This is the same as C<guestfs_removexattr>, but if C<path>
+is a symbolic link, then it removes an extended attribute
+of the link itself.");
+
+  ("mountpoints", (RHashtable "mps", []), 147, [],
+   [],
+   "show mountpoints",
+   "\
+This call is similar to C<guestfs_mounts>.  That call returns
+a list of devices.  This one returns a hash table (map) of
+device name to directory where the device is mounted.");
+
+  ("mkmountpoint", (RErr, [String "path"]), 148, [],
+   [],
+   "create a mountpoint",
+   "\
+C<guestfs_mkmountpoint> and C<guestfs_rmmountpoint> are
+specialized calls that can be used to create extra mountpoints
+before mounting the first filesystem.
+
+These calls are I<only> necessary in some very limited circumstances,
+mainly the case where you want to mount a mix of unrelated and/or
+read-only filesystems together.
+
+For example, live CDs often contain a \"Russian doll\" nest of
+filesystems, an ISO outer layer, with a squashfs image inside, with
+an ext2/3 image inside that.  You can unpack this as follows
+in guestfish:
+
+ add-ro Fedora-11-i686-Live.iso
+ run
+ mkmountpoint /cd
+ mkmountpoint /squash
+ mkmountpoint /ext3
+ mount /dev/sda /cd
+ mount-loop /cd/LiveOS/squashfs.img /squash
+ mount-loop /squash/LiveOS/ext3fs.img /ext3
+
+The inner filesystem is now unpacked under the /ext3 mountpoint.");
+
+  ("rmmountpoint", (RErr, [String "path"]), 149, [],
+   [],
+   "remove a mountpoint",
+   "\
+This calls removes a mountpoint that was previously created
+with C<guestfs_mkmountpoint>.  See C<guestfs_mkmountpoint>
+for full details.");
+
 ]
 
 let all_functions = non_daemon_functions @ daemon_functions
 ]
 
 let all_functions = non_daemon_functions @ daemon_functions
@@ -2872,6 +2987,7 @@ let all_functions_sorted =
 type field =
   | FChar                      (* C 'char' (really, a 7 bit byte). *)
   | FString                    (* nul-terminated ASCII string. *)
 type field =
   | FChar                      (* C 'char' (really, a 7 bit byte). *)
   | FString                    (* nul-terminated ASCII string. *)
+  | FBuffer                    (* opaque buffer of bytes, (char *, int) pair *)
   | FUInt32
   | FInt32
   | FUInt64
   | FUInt32
   | FInt32
   | FUInt64
@@ -3010,6 +3126,12 @@ let structs = [
     "release", FInt64;
     "extra", FString;
   ];
     "release", FInt64;
     "extra", FString;
   ];
+
+  (* Extended attribute. *)
+  "xattr", [
+    "attrname", FString;
+    "attrval", FBuffer;
+  ];
 ] (* end of structs *)
 
 (* Ugh, Java has to be different ..
 ] (* end of structs *)
 
 (* Ugh, Java has to be different ..
@@ -3024,6 +3146,7 @@ let java_structs = [
   "statvfs", "StatVFS";
   "dirent", "Dirent";
   "version", "Version";
   "statvfs", "StatVFS";
   "dirent", "Dirent";
   "version", "Version";
+  "xattr", "XAttr";
 ]
 
 (* Used for testing language bindings. *)
 ]
 
 (* Used for testing language bindings. *)
@@ -3437,6 +3560,10 @@ and generate_structs_pod () =
        | 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, (FUInt64|FBytes) -> pr "   uint64_t %s;\n" name
        | name, FInt64 -> pr "   int64_t %s;\n" name
        | name, FString -> pr "   char *%s;\n" name
+       | name, FBuffer ->
+           pr "   /* The next two fields describe a byte array. */\n";
+           pr "   uint32_t %s_len;\n" name;
+           pr "   char *%s;\n" name
        | name, FUUID ->
            pr "   /* The next field is NOT nul-terminated, be careful when printing it: */\n";
            pr "   char %s[32];\n" name
        | name, FUUID ->
            pr "   /* The next field is NOT nul-terminated, be careful when printing it: */\n";
            pr "   char %s[32];\n" name
@@ -3480,6 +3607,7 @@ and generate_xdr () =
        List.iter (function
                   | name, FChar -> pr "  char %s;\n" name
                   | name, FString -> pr "  string %s<>;\n" name
        List.iter (function
                   | name, FChar -> pr "  char %s;\n" name
                   | name, FString -> pr "  string %s<>;\n" name
+                  | name, FBuffer -> pr "  opaque %s<>;\n" name
                   | name, FUUID -> pr "  opaque %s[32];\n" name
                   | name, (FInt32|FUInt32) -> pr "  int %s;\n" name
                   | name, (FInt64|FUInt64|FBytes) -> pr "  hyper %s;\n" name
                   | name, FUUID -> pr "  opaque %s[32];\n" name
                   | name, (FInt32|FUInt32) -> pr "  int %s;\n" name
                   | name, (FInt64|FUInt64|FBytes) -> pr "  hyper %s;\n" name
@@ -3641,6 +3769,9 @@ and generate_structs_h () =
        function
        | name, FChar -> pr "  char %s;\n" name
        | name, FString -> pr "  char *%s;\n" name
        function
        | name, FChar -> pr "  char %s;\n" name
        | name, FString -> pr "  char *%s;\n" name
+       | name, FBuffer ->
+           pr "  uint32_t %s_len;\n" name;
+           pr "  char *%s;\n" name
        | name, FUUID -> pr "  char %s[32]; /* this is NOT nul-terminated, be careful when printing */\n" name
        | name, FUInt32 -> pr "  uint32_t %s;\n" name
        | name, FInt32 -> pr "  int32_t %s;\n" name
        | name, FUUID -> pr "  char %s[32]; /* this is NOT nul-terminated, be careful when printing */\n" name
        | name, FUInt32 -> pr "  uint32_t %s;\n" name
        | name, FInt32 -> pr "  int32_t %s;\n" name
@@ -3726,7 +3857,7 @@ check_state (guestfs_h *g, const char *caller)
 {
   if (!guestfs_is_ready (g)) {
     if (guestfs_is_config (g))
 {
   if (!guestfs_is_ready (g)) {
     if (guestfs_is_config (g))
-      error (g, \"%%s: call launch() before using this function\",
+      error (g, \"%%s: call launch before using this function\\n(in guestfish, don't forget to use the 'run' command)\",
         caller);
     else if (guestfs_is_launching (g))
       error (g, \"%%s: call wait_ready() before using this function\",
         caller);
     else if (guestfs_is_launching (g))
       error (g, \"%%s: call wait_ready() before using this function\",
@@ -4258,7 +4389,7 @@ and generate_daemon_actions () =
                 pr "    fprintf (stderr, \"%%s: failed to parse float '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
                 pr "    return -1;\n";
                 pr "  }\n";
                 pr "    fprintf (stderr, \"%%s: failed to parse float '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
                 pr "    return -1;\n";
                 pr "  }\n";
-            | FInt32 | FUInt32 | FUInt64 | FChar ->
+            | FBuffer | FInt32 | FUInt32 | FUInt64 | FChar ->
                 assert false (* can never be an LVM column *)
            );
            pr "  tok = next;\n";
                 assert false (* can never be an LVM column *)
            );
            pr "  tok = next;\n";
@@ -5041,6 +5172,7 @@ and generate_fish_cmds () =
   pr "#include <stdlib.h>\n";
   pr "#include <string.h>\n";
   pr "#include <inttypes.h>\n";
   pr "#include <stdlib.h>\n";
   pr "#include <string.h>\n";
   pr "#include <inttypes.h>\n";
+  pr "#include <ctype.h>\n";
   pr "\n";
   pr "#include <guestfs.h>\n";
   pr "#include \"fish.h\"\n";
   pr "\n";
   pr "#include <guestfs.h>\n";
   pr "#include \"fish.h\"\n";
@@ -5118,7 +5250,7 @@ and generate_fish_cmds () =
   List.iter (
     fun (typ, cols) ->
       let needs_i =
   List.iter (
     fun (typ, cols) ->
       let needs_i =
-        List.exists (function (_, FUUID) -> true | _ -> false) cols in
+        List.exists (function (_, (FUUID|FBuffer)) -> true | _ -> false) cols in
 
       pr "static void print_%s (struct guestfs_%s *%s)\n" typ typ typ;
       pr "{\n";
 
       pr "static void print_%s (struct guestfs_%s *%s)\n" typ typ typ;
       pr "{\n";
@@ -5135,6 +5267,14 @@ and generate_fish_cmds () =
            pr "  for (i = 0; i < 32; ++i)\n";
            pr "    printf (\"%%c\", %s->%s[i]);\n" typ name;
            pr "  printf (\"\\n\");\n"
            pr "  for (i = 0; i < 32; ++i)\n";
            pr "    printf (\"%%c\", %s->%s[i]);\n" typ name;
            pr "  printf (\"\\n\");\n"
+       | name, FBuffer ->
+           pr "  printf (\"%s: \");\n" name;
+           pr "  for (i = 0; i < %s->%s_len; ++i)\n" typ name;
+           pr "    if (isprint (%s->%s[i]))\n" typ name;
+           pr "      printf (\"%%c\", %s->%s[i]);\n" typ name;
+           pr "    else\n";
+           pr "      printf (\"\\\\x%%02x\", %s->%s[i]);\n" typ name;
+           pr "  printf (\"\\n\");\n"
        | name, (FUInt64|FBytes) ->
            pr "  printf (\"%s: %%\" PRIu64 \"\\n\", %s->%s);\n" name typ name
        | name, FInt64 ->
        | name, (FUInt64|FBytes) ->
            pr "  printf (\"%s: %%\" PRIu64 \"\\n\", %s->%s);\n" name typ name
        | name, FInt64 ->
@@ -5650,6 +5790,10 @@ copy_table (char * const * argv)
          (match col with
           | name, FString ->
               pr "  v = caml_copy_string (%s->%s);\n" typ name
          (match col with
           | name, FString ->
               pr "  v = caml_copy_string (%s->%s);\n" typ name
+          | name, FBuffer ->
+              pr "  v = caml_alloc_string (%s->%s_len);\n" typ name;
+              pr "  memcpy (String_val (v), %s->%s, %s->%s_len);\n"
+                typ name typ name
           | name, FUUID ->
               pr "  v = caml_alloc_string (32);\n";
               pr "  memcpy (String_val (v), %s->%s, 32);\n" typ name
           | name, FUUID ->
               pr "  v = caml_alloc_string (32);\n";
               pr "  memcpy (String_val (v), %s->%s, 32);\n" typ name
@@ -5830,6 +5974,7 @@ and generate_ocaml_structure_decls () =
       List.iter (
        function
        | name, FString -> pr "  %s : string;\n" name
       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, (FBytes|FInt64|FUInt64) -> pr "  %s : int64;\n" name
        | name, (FInt32|FUInt32) -> pr "  %s : int32;\n" name
        | name, FUUID -> pr "  %s : string;\n" name
        | name, (FBytes|FInt64|FUInt64) -> pr "  %s : int64;\n" name
        | name, (FInt32|FUInt32) -> pr "  %s : int32;\n" name
@@ -6126,6 +6271,9 @@ and generate_perl_struct_list_code typ cols name style n do_cleanups =
     | name, FUUID ->
        pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 32), 0);\n"
          name (String.length name) n name
     | name, FUUID ->
        pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 32), 0);\n"
          name (String.length name) n name
+    | name, FBuffer ->
+       pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, %s->val[i].%s_len), 0);\n"
+         name (String.length name) n name n name
     | name, (FBytes|FUInt64) ->
        pr "        (void) hv_store (hv, \"%s\", %d, my_newSVull (%s->val[i].%s), 0);\n"
          name (String.length name) n name
     | name, (FBytes|FUInt64) ->
        pr "        (void) hv_store (hv, \"%s\", %d, my_newSVull (%s->val[i].%s), 0);\n"
          name (String.length name) n name
@@ -6165,6 +6313,9 @@ and generate_perl_struct_code typ cols name style n do_cleanups =
       | name, FString ->
          pr "      PUSHs (sv_2mortal (newSVpv (%s->%s, 0)));\n"
            n name
       | name, FString ->
          pr "      PUSHs (sv_2mortal (newSVpv (%s->%s, 0)));\n"
            n name
+      | name, FBuffer ->
+         pr "      PUSHs (sv_2mortal (newSVpv (%s->%s, %s->%s_len)));\n"
+           n name n name
       | name, FUUID ->
          pr "      PUSHs (sv_2mortal (newSVpv (%s->%s, 32)));\n"
            n name
       | name, FUUID ->
          pr "      PUSHs (sv_2mortal (newSVpv (%s->%s, 32)));\n"
            n name
@@ -6497,6 +6648,10 @@ py_guestfs_close (PyObject *self, PyObject *args)
            pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
            pr "                        PyString_FromString (%s->%s));\n"
              typ name
            pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
            pr "                        PyString_FromString (%s->%s));\n"
              typ name
+       | name, FBuffer ->
+           pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
+           pr "                        PyString_FromStringAndSize (%s->%s, %s->%s_len));\n"
+             typ name typ name
        | name, FUUID ->
            pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
            pr "                        PyString_FromStringAndSize (%s->%s, 32));\n"
        | name, FUUID ->
            pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
            pr "                        PyString_FromStringAndSize (%s->%s, 32));\n"
@@ -7040,6 +7195,8 @@ and generate_ruby_struct_code typ cols =
     function
     | name, FString ->
        pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new2 (r->%s));\n" name name
     function
     | name, FString ->
        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
     | name, FUUID ->
        pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new (r->%s, 32));\n" name name
     | name, (FBytes|FUInt64) ->
     | name, FUUID ->
        pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new (r->%s, 32));\n" name name
     | name, (FBytes|FUInt64) ->
@@ -7068,6 +7225,8 @@ and generate_ruby_struct_list_code typ cols =
     function
     | name, FString ->
        pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_str_new2 (r->val[i].%s));\n" name name
     function
     | name, FString ->
        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
     | name, FUUID ->
        pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_str_new (r->val[i].%s, 32));\n" name name
     | name, (FBytes|FUInt64) ->
     | name, FUUID ->
        pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_str_new (r->val[i].%s, 32));\n" name name
     | name, (FBytes|FUInt64) ->
@@ -7279,7 +7438,8 @@ public class %s {
   List.iter (
     function
     | name, FString
   List.iter (
     function
     | name, FString
-    | name, FUUID -> pr "  public String %s;\n" name
+    | name, FUUID
+    | name, FBuffer -> pr "  public String %s;\n" name
     | name, (FBytes|FUInt64|FInt64) -> pr "  public long %s;\n" name
     | name, (FUInt32|FInt32) -> pr "  public int %s;\n" name
     | name, FChar -> pr "  public char %s;\n" name
     | name, (FBytes|FUInt64|FInt64) -> pr "  public long %s;\n" name
     | name, (FUInt32|FInt32) -> pr "  public int %s;\n" name
     | name, FChar -> pr "  public char %s;\n" name
@@ -7543,6 +7703,15 @@ and generate_java_struct_return typ jtyp cols =
        pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
        pr "    (*env)->SetObjectField (env, jr, fl, (*env)->NewStringUTF (env, s));\n";
        pr "  }\n";
        pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
        pr "    (*env)->SetObjectField (env, jr, fl, (*env)->NewStringUTF (env, s));\n";
        pr "  }\n";
+    | name, FBuffer ->
+       pr "  {\n";
+       pr "    int len = r->%s_len;\n" name;
+       pr "    char s[len+1];\n";
+       pr "    memcpy (s, r->%s, len);\n" name;
+       pr "    s[len] = 0;\n";
+       pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
+       pr "    (*env)->SetObjectField (env, jr, fl, (*env)->NewStringUTF (env, s));\n";
+       pr "  }\n";
     | name, (FBytes|FUInt64|FInt64) ->
        pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n" name;
        pr "  (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
     | name, (FBytes|FUInt64|FInt64) ->
        pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n" name;
        pr "  (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
@@ -7577,6 +7746,15 @@ and generate_java_struct_list_return typ jtyp cols =
        pr "      fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
        pr "      (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, s));\n";
        pr "    }\n";
        pr "      fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
        pr "      (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, s));\n";
        pr "    }\n";
+    | name, FBuffer ->
+       pr "    {\n";
+       pr "      int len = r->val[i].%s_len;\n" name;
+       pr "      char s[len+1];\n";
+       pr "      memcpy (s, r->val[i].%s, len);\n" name;
+       pr "      s[len] = 0;\n";
+       pr "      fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
+       pr "      (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, s));\n";
+       pr "    }\n";
     | name, (FBytes|FUInt64|FInt64) ->
        pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n" name;
        pr "    (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
     | name, (FBytes|FUInt64|FInt64) ->
        pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n" name;
        pr "    (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
@@ -8214,7 +8392,7 @@ let output_to filename =
 let () =
   check_functions ();
 
 let () =
   check_functions ();
 
-  if not (Sys.file_exists "config.status") then (
+  if not (Sys.file_exists "HACKING") then (
     eprintf "\
 You are probably running this from the wrong directory.
 Run it from the top source directory using the command
     eprintf "\
 You are probably running this from the wrong directory.
 Run it from the top source directory using the command