examples/to-xml.c: Don't depend on Gnulib function.
[libguestfs.git] / src / generator.ml
index 1dd8b20..3249459 100755 (executable)
@@ -2488,7 +2488,7 @@ C<resize2fs> sometimes gives an error about this and sometimes not.
 In any case, it is always safe to call C<guestfs_e2fsck_f> before
 calling this function.");
 
-  ("find", (RStringList "names", [Pathname "directory"]), 107, [],
+  ("find", (RStringList "names", [Pathname "directory"]), 107, [ProtocolLimitWarning],
    [InitBasicFS, Always, TestOutputList (
       [["find"; "/"]], ["lost+found"]);
     InitBasicFS, Always, TestOutputList (
@@ -2525,7 +2525,9 @@ then the returned list from C<guestfs_find> C</tmp> would be
 If C<directory> is not a directory, then this command returns
 an error.
 
-The returned list is sorted.");
+The returned list is sorted.
+
+See also C<guestfs_find0>.");
 
   ("e2fsck_f", (RErr, [Device "device"]), 108, [],
    [], (* lvresize tests this *)
@@ -3610,6 +3612,109 @@ You can use this command to test the connection through to the daemon.
 
 See also C<guestfs_ping_daemon>.");
 
+  ("find0", (RErr, [Pathname "directory"; FileOut "files"]), 196, [],
+   [], (* There is a regression test for this. *)
+   "find all files and directories, returning NUL-separated list",
+   "\
+This command lists out all files and directories, recursively,
+starting at C<directory>, placing the resulting list in the
+external file called C<files>.
+
+This command works the same way as C<guestfs_find> with the
+following exceptions:
+
+=over 4
+
+=item *
+
+The resulting list is written to an external file.
+
+=item *
+
+Items (filenames) in the result are separated
+by C<\\0> characters.  See L<find(1)> option I<-print0>.
+
+=item *
+
+This command is not limited in the number of names that it
+can return.
+
+=item *
+
+The result list is not sorted.
+
+=back");
+
+  ("case_sensitive_path", (RString "rpath", [Pathname "path"]), 197, [],
+   [InitISOFS, Always, TestOutput (
+      [["case_sensitive_path"; "/DIRECTORY"]], "/directory");
+    InitISOFS, Always, TestOutput (
+      [["case_sensitive_path"; "/DIRECTORY/"]], "/directory");
+    InitISOFS, Always, TestOutput (
+      [["case_sensitive_path"; "/Known-1"]], "/known-1");
+    InitISOFS, Always, TestLastFail (
+      [["case_sensitive_path"; "/Known-1/"]]);
+    InitBasicFS, Always, TestOutput (
+      [["mkdir"; "/a"];
+       ["mkdir"; "/a/bbb"];
+       ["touch"; "/a/bbb/c"];
+       ["case_sensitive_path"; "/A/bbB/C"]], "/a/bbb/c");
+    InitBasicFS, Always, TestOutput (
+      [["mkdir"; "/a"];
+       ["mkdir"; "/a/bbb"];
+       ["touch"; "/a/bbb/c"];
+       ["case_sensitive_path"; "/A////bbB/C"]], "/a/bbb/c");
+    InitBasicFS, Always, TestLastFail (
+      [["mkdir"; "/a"];
+       ["mkdir"; "/a/bbb"];
+       ["touch"; "/a/bbb/c"];
+       ["case_sensitive_path"; "/A/bbb/../bbb/C"]])],
+   "return true path on case-insensitive filesystem",
+   "\
+This can be used to resolve case insensitive paths on
+a filesystem which is case sensitive.  The use case is
+to resolve paths which you have read from Windows configuration
+files or the Windows Registry, to the true path.
+
+The command handles a peculiarity of the Linux ntfs-3g
+filesystem driver (and probably others), which is that although
+the underlying filesystem is case-insensitive, the driver
+exports the filesystem to Linux as case-sensitive.
+
+One consequence of this is that special directories such
+as C<c:\\windows> may appear as C</WINDOWS> or C</windows>
+(or other things) depending on the precise details of how
+they were created.  In Windows itself this would not be
+a problem.
+
+Bug or feature?  You decide:
+L<http://www.tuxera.com/community/ntfs-3g-faq/#posixfilenames1>
+
+This function resolves the true case of each element in the
+path and returns the case-sensitive path.
+
+Thus C<guestfs_case_sensitive_path> (\"/Windows/System32\")
+might return C<\"/WINDOWS/system32\"> (the exact return value
+would depend on details of how the directories were originally
+created under Windows).
+
+I<Note>:
+This function does not handle drive names, backslashes etc.
+
+See also C<guestfs_realpath>.");
+
+  ("vfs_type", (RString "fstype", [Device "device"]), 198, [],
+   [InitBasicFS, Always, TestOutput (
+      [["vfs_type"; "/dev/sda1"]], "ext2")],
+   "get the Linux VFS type corresponding to a mounted device",
+   "\
+This command gets the block device type corresponding to
+a mounted device called C<device>.
+
+Usually the result is the name of the Linux VFS module that
+is used to mount this device (probably determined automatically
+if you used the C<guestfs_mount> call).");
+
 ]
 
 let all_functions = non_daemon_functions @ daemon_functions
@@ -3810,7 +3915,7 @@ type rstructs_used_t = RStructOnly | RStructListOnly | RStructAndList
  *    == there are functions returning both RStruct (_, structname)
  *                                      and RStructList (_, structname)
  *)
-let rstructs_used =
+let rstructs_used_by functions =
   (* ||| is a "logical OR" for rstructs_used_t *)
   let (|||) a b =
     match a, b with
@@ -3839,21 +3944,11 @@ let rstructs_used =
       | RStruct (_, structname) -> update structname RStructOnly
       | RStructList (_, structname) -> update structname RStructListOnly
       | _ -> ()
-  ) all_functions;
+  ) functions;
 
   (* return key->values as a list of (key,value) *)
   Hashtbl.fold (fun key value xs -> (key, value) :: xs) h []
 
-(* debug:
-let () =
-  List.iter (
-    function
-    | sn, RStructOnly -> printf "%s RStructOnly\n" sn
-    | sn, RStructListOnly -> printf "%s RStructListOnly\n" sn
-    | sn, RStructAndList -> printf "%s RStructAndList\n" sn
-  ) rstructs_used
-*)
-
 (* Used for testing language bindings. *)
 type callt =
   | CallString of string
@@ -4674,8 +4769,8 @@ check_state (guestfs_h *g, const char *caller)
 
     let needs_i =
       List.exists (function
-                  | StringList _ | DeviceList _ -> true
-                  | _ -> false) (snd style) in
+                   | StringList _ | DeviceList _ -> true
+                   | _ -> false) (snd style) in
     if needs_i then (
       pr "    int i;\n";
       pr "\n"
@@ -4690,24 +4785,24 @@ check_state (guestfs_h *g, const char *caller)
       | Dev_or_Path n
       | FileIn n
       | FileOut n ->
-         (* guestfish doesn't support string escaping, so neither do we *)
-         pr "    printf (\" \\\"%%s\\\"\", %s);\n" n
+          (* guestfish doesn't support string escaping, so neither do we *)
+          pr "    printf (\" \\\"%%s\\\"\", %s);\n" n
       | OptString n ->                 (* string option *)
-         pr "    if (%s) printf (\" \\\"%%s\\\"\", %s);\n" n n;
-         pr "    else printf (\" null\");\n"
+          pr "    if (%s) printf (\" \\\"%%s\\\"\", %s);\n" n n;
+          pr "    else printf (\" null\");\n"
       | StringList n
       | DeviceList n ->                        (* string list *)
-         pr "    putchar (' ');\n";
-         pr "    putchar ('\"');\n";
-         pr "    for (i = 0; %s[i]; ++i) {\n" n;
-         pr "      if (i > 0) putchar (' ');\n";
-         pr "      fputs (%s[i], stdout);\n" n;
-         pr "    }\n";
-         pr "    putchar ('\"');\n";
+          pr "    putchar (' ');\n";
+          pr "    putchar ('\"');\n";
+          pr "    for (i = 0; %s[i]; ++i) {\n" n;
+          pr "      if (i > 0) putchar (' ');\n";
+          pr "      fputs (%s[i], stdout);\n" n;
+          pr "    }\n";
+          pr "    putchar ('\"');\n";
       | Bool n ->                      (* boolean *)
-         pr "    fputs (%s ? \" true\" : \" false\", stdout);\n" n
+          pr "    fputs (%s ? \" true\" : \" false\", stdout);\n" n
       | Int n ->                       (* int *)
-         pr "    printf (\" %%d\", %s);\n" n
+          pr "    printf (\" %%d\", %s);\n" n
     ) (snd style);
     pr "    putchar ('\\n');\n";
     pr "  }\n";
@@ -4759,16 +4854,16 @@ check_state (guestfs_h *g, const char *caller)
       pr "  guestfs_message_header hdr;\n";
       pr "  guestfs_message_error err;\n";
       let has_ret =
-       match fst style with
-       | RErr -> false
-       | RConstString _ | RConstOptString _ ->
+        match fst style with
+        | RErr -> false
+        | RConstString _ | RConstOptString _ ->
             failwithf "RConstString|RConstOptString cannot be used by daemon functions"
-       | RInt _ | RInt64 _
-       | RBool _ | RString _ | RStringList _
-       | RStruct _ | RStructList _
-       | RHashtable _ | RBufferOut _ ->
+        | RInt _ | RInt64 _
+        | RBool _ | RString _ | RStringList _
+        | RStruct _ | RStructList _
+        | RHashtable _ | RBufferOut _ ->
             pr "  struct %s_ret ret;\n" name;
-           true in
+            true in
 
       pr "  int serial;\n";
       pr "  int r;\n";
@@ -4835,7 +4930,7 @@ check_state (guestfs_h *g, const char *caller)
       pr "\n";
       pr "  r = guestfs___recv (g, \"%s\", &hdr, &err,\n        " shortname;
       if not has_ret then
-       pr "NULL, NULL"
+        pr "NULL, NULL"
       else
         pr "(xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret" shortname;
       pr ");\n";
@@ -4956,11 +5051,11 @@ and generate_daemon_actions () =
   pr "#include <stdlib.h>\n";
   pr "#include <string.h>\n";
   pr "#include <inttypes.h>\n";
-  pr "#include <ctype.h>\n";
   pr "#include <rpc/types.h>\n";
   pr "#include <rpc/xdr.h>\n";
   pr "\n";
   pr "#include \"daemon.h\"\n";
+  pr "#include \"c-ctype.h\"\n";
   pr "#include \"../src/guestfs_protocol.h\"\n";
   pr "#include \"actions.h\"\n";
   pr "\n";
@@ -5186,7 +5281,7 @@ and generate_daemon_actions () =
         pr "    fprintf (stderr, \"%%s: failed: passed a NULL string\\n\", __func__);\n";
         pr "    return -1;\n";
         pr "  }\n";
-        pr "  if (!*str || isspace (*str)) {\n";
+        pr "  if (!*str || c_isspace (*str)) {\n";
         pr "    fprintf (stderr, \"%%s: failed: passed a empty string or one beginning with whitespace\\n\", __func__);\n";
         pr "    return -1;\n";
         pr "  }\n";
@@ -5288,7 +5383,7 @@ and generate_daemon_actions () =
         pr "      pend++;\n";
         pr "    }\n";
         pr "\n";
-        pr "    while (*p && isspace (*p))     /* Skip any leading whitespace. */\n";
+        pr "    while (*p && c_isspace (*p))   /* Skip any leading whitespace. */\n";
         pr "      p++;\n";
         pr "\n";
         pr "    if (!*p) {                     /* Empty line?  Skip it. */\n";
@@ -6073,9 +6168,9 @@ and generate_fish_cmds () =
   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 \"c-ctype.h\"\n";
   pr "#include \"fish.h\"\n";
   pr "\n";
 
@@ -6186,17 +6281,17 @@ and generate_fish_cmds () =
         | name, FString ->
             pr "  printf (\"%%s%s: %%s\\n\", indent, %s->%s);\n" name typ name
         | name, FUUID ->
-            pr "  printf (\"%s: \");\n" name;
+            pr "  printf (\"%%s%s: \", indent);\n" name;
             pr "  for (i = 0; i < 32; ++i)\n";
-            pr "    printf (\"%%s%%c\", indent, %s->%s[i]);\n" typ name;
+            pr "    printf (\"%%c\", %s->%s[i]);\n" typ name;
             pr "  printf (\"\\n\");\n"
         | name, FBuffer ->
             pr "  printf (\"%%s%s: \", indent);\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 (\"%%s%%c\", indent, %s->%s[i]);\n" typ name;
+            pr "    if (c_isprint (%s->%s[i]))\n" typ name;
+            pr "      printf (\"%%c\", %s->%s[i]);\n" typ name;
             pr "    else\n";
-            pr "      printf (\"%%s\\\\x%%02x\", indent, %s->%s[i]);\n" typ name;
+            pr "      printf (\"\\\\x%%02x\", %s->%s[i]);\n" typ name;
             pr "  printf (\"\\n\");\n"
         | name, (FUInt64|FBytes) ->
             pr "  printf (\"%%s%s: %%\" PRIu64 \"\\n\", indent, %s->%s);\n"
@@ -6229,19 +6324,19 @@ and generate_fish_cmds () =
         (* generate the function for typ *)
         emit_print_list_function typ
     | typ, _ -> () (* empty *)
-  ) rstructs_used;
+  ) (rstructs_used_by all_functions);
 
   (* Emit a print_TYPE function definition only if that function is used. *)
   List.iter (
     function
-    | typ, RStructOnly ->
+    | typ, (RStructOnly | RStructAndList) ->
         pr "static void print_%s (struct guestfs_%s *%s)\n" typ typ typ;
         pr "{\n";
         pr "  print_%s_indent (%s, \"\");\n" typ typ;
         pr "}\n";
         pr "\n";
     | typ, _ -> () (* empty *)
-  ) rstructs_used;
+  ) (rstructs_used_by all_functions);
 
   (* run_<action> actions *)
   List.iter (
@@ -6264,12 +6359,13 @@ and generate_fish_cmds () =
       );
       List.iter (
         function
-        | Pathname n
-        | Device n | Dev_or_Path n
+        | Device n
         | String n
         | OptString n
         | FileIn n
         | FileOut n -> pr "  const char *%s;\n" n
+        | Pathname n
+        | Dev_or_Path n -> pr "  char *%s;\n" n
         | StringList n | DeviceList n -> pr "  char **%s;\n" n
         | Bool n -> pr "  int %s;\n" n
         | Int n -> pr "  int %s;\n" n
@@ -6286,8 +6382,13 @@ and generate_fish_cmds () =
       iteri (
         fun i ->
           function
+          | Device name
+          | String name ->
+             pr "  %s = argv[%d];\n" name i
           | Pathname name
-          | Device name | Dev_or_Path name | String name -> pr "  %s = argv[%d];\n" name i
+          | Dev_or_Path name ->
+             pr "  %s = resolve_win_path (argv[%d]);\n" name i;
+             pr "  if (%s == NULL) return -1;\n" name
           | OptString name ->
               pr "  %s = strcmp (argv[%d], \"\") != 0 ? argv[%d] : NULL;\n"
                 name i i
@@ -6316,9 +6417,11 @@ and generate_fish_cmds () =
 
       List.iter (
         function
-        | Pathname name | Device name | Dev_or_Path name | String name
+        | Device name | String name
         | OptString name | FileIn name | FileOut name | Bool name
         | Int name -> ()
+        | Pathname name | Dev_or_Path name ->
+            pr "  free (%s);\n" name
         | StringList name | DeviceList name ->
             pr "  free_strings (%s);\n" name
       ) (snd style);
@@ -6829,7 +6932,7 @@ copy_table (char * const * argv)
         (* generate the function for typ *)
         emit_ocaml_copy_list_function typ
     | typ, _ -> () (* empty *)
-  ) rstructs_used;
+  ) (rstructs_used_by all_functions);
 
   (* The wrappers. *)
   List.iter (
@@ -7775,7 +7878,7 @@ py_guestfs_close (PyObject *self, PyObject *args)
         (* generate the function for typ *)
         emit_put_list_function typ
     | typ, _ -> () (* empty *)
-  ) rstructs_used;
+  ) (rstructs_used_by all_functions);
 
   (* Python wrapper functions. *)
   List.iter (