3 * Copyright (C) 2009-2011 Red Hat Inc.
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 (* This script generates language bindings and some documentation for
23 * After editing this file, run it (./generator/generator.ml) to
24 * regenerate all the output files. 'make' will rerun this
25 * automatically when necessary. Note that if you are using a separate
26 * build directory you must run generator.ml from the _source_
29 * IMPORTANT: This script should NOT print any warnings. If it prints
30 * warnings, you should treat them as errors.
32 * OCaml tips: (1) In emacs, install tuareg-mode to display and format
33 * OCaml code correctly. 'vim' comes with a good OCaml editing mode by
34 * default. (2) Read the resources at http://ocaml-tutorial.org/
43 type style = ret * args
45 | RErr (* 0 = ok, -1 = error *)
46 | RErrDispose (* Disposes handle, see hivex_close. *)
47 | RHive (* Returns a hive_h or NULL. *)
48 | RSize (* Returns size_t or 0. *)
49 | RNode (* Returns hive_node_h or 0. *)
50 | RNodeNotFound (* See hivex_node_get_child. *)
51 | RNodeList (* Returns hive_node_h* or NULL. *)
52 | RValue (* Returns hive_value_h or 0. *)
53 | RValueList (* Returns hive_value_h* or NULL. *)
54 | RString (* Returns char* or NULL. *)
55 | RStringList (* Returns char** or NULL. *)
56 | RLenType (* See hivex_value_type. *)
57 | RLenTypeVal (* See hivex_value_value. *)
58 | RInt32 (* Returns int32. *)
59 | RInt64 (* Returns int64. *)
61 and args = argt list (* List of parameters. *)
63 and argt = (* Note, cannot be NULL/0 unless it
64 says so explicitly below. *)
66 | ANode of string (* hive_node_h *)
67 | AValue of string (* hive_value_h *)
68 | AString of string (* char* *)
69 | AStringNullable of string (* char* (can be NULL) *)
70 | AOpenFlags (* HIVEX_OPEN_* flags list. *)
71 | AUnusedFlags (* Flags arg that is always 0 *)
72 | ASetValues (* See hivex_node_set_values. *)
73 | ASetValue (* See hivex_node_set_value. *)
76 * https://secure.wikimedia.org/wikipedia/en/wiki/Windows_Registry#Keys_and_values
78 * It's unfortunate that in our original C binding we strayed away from
79 * the names that Windows uses (eg. REG_SZ for strings). We include
80 * both our names and the Windows names.
84 "Just a key without a value";
86 "A Windows string (encoding is unknown, but often UTF16-LE)";
87 2, "expand_string", "EXPAND_SZ",
88 "A Windows string that contains %env% (environment variable expansion)";
89 3, "binary", "BINARY",
92 "DWORD (32 bit integer), little endian";
93 5, "dword_be", "DWORD_BIG_ENDIAN",
94 "DWORD (32 bit integer), big endian";
96 "Symbolic link to another part of the registry tree";
97 7, "multiple_strings", "MULTI_SZ",
98 "Multiple Windows strings. See http://blogs.msdn.com/oldnewthing/archive/2009/10/08/9904646.aspx";
99 8, "resource_list", "RESOURCE_LIST",
101 9, "full_resource_description", "FULL_RESOURCE_DESCRIPTOR",
102 "Resource descriptor";
103 10, "resource_requirements_list", "RESOURCE_REQUIREMENTS_LIST",
104 "Resouce requirements list";
105 11, "qword", "QWORD",
106 "QWORD (64 bit integer), unspecified endianness but usually little endian"
108 let max_hive_type = 11
110 (* Open flags (bitmask passed to AOpenFlags) *)
112 1, "VERBOSE", "Verbose messages";
113 2, "DEBUG", "Debug messages";
114 4, "WRITE", "Enable writes to the hive";
119 "open", (RHive, [AString "filename"; AOpenFlags]),
122 Opens the hive named C<filename> for reading.
124 Flags is an ORed list of the open flags (or C<0> if you don't
125 want to pass any flags). These flags are defined:
129 =item HIVEX_OPEN_VERBOSE
133 =item HIVEX_OPEN_DEBUG
135 Very verbose messages, suitable for debugging problems in the library
138 This is also selected if the C<HIVEX_DEBUG> environment variable
141 =item HIVEX_OPEN_WRITE
143 Open the hive for writing. If omitted, the hive is read-only.
145 See L<hivex(3)/WRITING TO HIVE FILES>.
149 "close", (RErrDispose, [AHive]),
150 "close a hive handle",
152 Close a hive handle and free all associated resources.
154 Note that any uncommitted writes are I<not> committed by this call,
155 but instead are lost. See L<hivex(3)/WRITING TO HIVE FILES>.";
157 "root", (RNode, [AHive]),
158 "return the root node of the hive",
160 Return root node of the hive. All valid hives must contain a root node.";
162 "last_modified", (RInt64, [AHive]),
163 "return the modification time from the header of the hive",
165 Return the modification time from the header of the hive.
167 The returned value is a Windows filetime.
168 To convert this to a Unix C<time_t> see:
169 L<http://stackoverflow.com/questions/6161776/convert-windows-filetime-to-second-in-unix-linux/6161842#6161842>";
171 "node_name", (RString, [AHive; ANode "node"]),
172 "return the name of the node",
174 Return the name of the node.
176 Note that the name of the root node is a dummy, such as
177 C<$$$PROTO.HIV> (other names are possible: it seems to depend on the
178 tool or program that created the hive in the first place). You can
179 only know the \"real\" name of the root node by knowing which registry
180 file this hive originally comes from, which is knowledge that is
181 outside the scope of this library.";
183 "node_timestamp", (RInt64, [AHive; ANode "node"]),
184 "return the modification time of the node",
186 Return the modification time of the node.
188 The returned value is a Windows filetime.
189 To convert this to a Unix C<time_t> see:
190 L<http://stackoverflow.com/questions/6161776/convert-windows-filetime-to-second-in-unix-linux/6161842#6161842>";
192 "node_children", (RNodeList, [AHive; ANode "node"]),
193 "return children of node",
195 Return an array of nodes which are the subkeys
196 (children) of C<node>.";
198 "node_get_child", (RNodeNotFound, [AHive; ANode "node"; AString "name"]),
199 "return named child of node",
201 Return the child of node with the name C<name>, if it exists.
203 The name is matched case insensitively.";
205 "node_parent", (RNode, [AHive; ANode "node"]),
206 "return the parent of node",
208 Return the parent of C<node>.
210 The parent pointer of the root node in registry files that we
211 have examined seems to be invalid, and so this function will
212 return an error if called on the root node.";
214 "node_values", (RValueList, [AHive; ANode "node"]),
215 "return (key, value) pairs attached to a node",
217 Return the array of (key, value) pairs attached to this node.";
219 "node_get_value", (RValue, [AHive; ANode "node"; AString "key"]),
220 "return named key at node",
222 Return the value attached to this node which has the name C<key>,
225 The key name is matched case insensitively.
227 Note that to get the default key, you should pass the empty
228 string C<\"\"> here. The default key is often written C<\"@\">, but
229 inside hives that has no meaning and won't give you the
232 "value_key_len", (RSize, [AHive; AValue "val"]),
233 "return the length of a value's key",
235 Return the length of the key (name) of a (key, value) pair. The
236 length can legitimately be 0, so errno is the necesary mechanism
239 In the context of Windows Registries, a zero-length name means
240 that this value is the default key for this node in the tree.
241 This is usually written as C<\"@\">.";
243 "value_key", (RString, [AHive; AValue "val"]),
244 "return the key of a (key, value) pair",
246 Return the key (name) of a (key, value) pair. The name
247 is reencoded as UTF-8 and returned as a string.
249 The string should be freed by the caller when it is no longer needed.
251 Note that this function can return a zero-length string. In the
252 context of Windows Registries, this means that this value is the
253 default key for this node in the tree. This is usually written
256 "value_type", (RLenType, [AHive; AValue "val"]),
257 "return data length and data type of a value",
259 Return the data length and data type of the value in this (key, value)
260 pair. See also C<hivex_value_value> which returns all this
261 information, and the value itself. Also, C<hivex_value_*> functions
262 below which can be used to return the value in a more useful form when
263 you know the type in advance.";
265 "node_struct_length", (RSize, [AHive; ANode "node"]),
266 "return the length of a node",
268 Return the length of the node data structure.";
270 "value_struct_length", (RSize, [AHive; AValue "val"]),
271 "return the length of a value data structure",
273 Return the length of the value data structure.";
275 "value_value", (RLenTypeVal, [AHive; AValue "val"]),
276 "return data length, data type and data of a value",
278 Return the value of this (key, value) pair. The value should
279 be interpreted according to its type (see C<hive_type>).";
281 "value_string", (RString, [AHive; AValue "val"]),
282 "return value as a string",
284 If this value is a string, return the string reencoded as UTF-8
285 (as a C string). This only works for values which have type
286 C<hive_t_string>, C<hive_t_expand_string> or C<hive_t_link>.";
288 "value_multiple_strings", (RStringList, [AHive; AValue "val"]),
289 "return value as multiple strings",
291 If this value is a multiple-string, return the strings reencoded
292 as UTF-8 (in C, as a NULL-terminated array of C strings, in other
293 language bindings, as a list of strings). This only
294 works for values which have type C<hive_t_multiple_strings>.";
296 "value_dword", (RInt32, [AHive; AValue "val"]),
297 "return value as a DWORD",
299 If this value is a DWORD (Windows int32), return it. This only works
300 for values which have type C<hive_t_dword> or C<hive_t_dword_be>.";
302 "value_qword", (RInt64, [AHive; AValue "val"]),
303 "return value as a QWORD",
305 If this value is a QWORD (Windows int64), return it. This only
306 works for values which have type C<hive_t_qword>.";
308 "commit", (RErr, [AHive; AStringNullable "filename"; AUnusedFlags]),
309 "commit (write) changes to file",
311 Commit (write) any changes which have been made.
313 C<filename> is the new file to write. If C<filename> is null/undefined
314 then we overwrite the original file (ie. the file name that was passed to
317 Note this does not close the hive handle. You can perform further
318 operations on the hive after committing, including making more
319 modifications. If you no longer wish to use the hive, then you
320 should close the handle after committing.";
322 "node_add_child", (RNode, [AHive; ANode "parent"; AString "name"]),
325 Add a new child node named C<name> to the existing node C<parent>.
326 The new child initially has no subnodes and contains no keys or
327 values. The sk-record (security descriptor) is inherited from
330 The parent must not have an existing child called C<name>, so if you
331 want to overwrite an existing child, call C<hivex_node_delete_child>
334 "node_delete_child", (RErr, [AHive; ANode "node"]),
337 Delete the node C<node>. All values at the node and all subnodes are
338 deleted (recursively). The C<node> handle and the handles of all
339 subnodes become invalid. You cannot delete the root node.";
341 "node_set_values", (RErr, [AHive; ANode "node"; ASetValues; AUnusedFlags]),
342 "set (key, value) pairs at a node",
344 This call can be used to set all the (key, value) pairs
347 C<node> is the node to modify.";
349 "node_set_value", (RErr, [AHive; ANode "node"; ASetValue; AUnusedFlags]),
350 "set a single (key, value) pair at a given node",
352 This call can be used to replace a single C<(key, value)> pair
353 stored in C<node>. If the key does not already exist, then a
354 new key is added. Key matching is case insensitive.
356 C<node> is the node to modify.";
360 * Note we don't want to use any external OCaml libraries which
361 * makes this a bit harder than it should be.
363 module StringMap = Map.Make (String)
365 let failwithf fs = ksprintf failwith fs
367 let unique = let i = ref 0 in fun () -> incr i; !i
369 let replace_char s c1 c2 =
370 let s2 = String.copy s in
372 for i = 0 to String.length s2 - 1 do
373 if String.unsafe_get s2 i = c1 then (
374 String.unsafe_set s2 i c2;
378 if not !r then s else s2
382 (* || c = '\f' *) || c = '\n' || c = '\r' || c = '\t' (* || c = '\v' *)
384 let triml ?(test = isspace) str =
386 let n = ref (String.length str) in
387 while !n > 0 && test str.[!i]; do
392 else String.sub str !i !n
394 let trimr ?(test = isspace) str =
395 let n = ref (String.length str) in
396 while !n > 0 && test str.[!n-1]; do
399 if !n = String.length str then str
400 else String.sub str 0 !n
402 let trim ?(test = isspace) str =
403 trimr ~test (triml ~test str)
405 (* Used to memoize the result of pod2text. *)
406 let pod2text_memo_filename = "generator/.pod2text.data.version.2"
407 let pod2text_memo : ((int option * bool * bool * string * string), string list) Hashtbl.t =
409 let chan = open_in pod2text_memo_filename in
410 let v = input_value chan in
414 _ -> Hashtbl.create 13
415 let pod2text_memo_updated () =
416 let chan = open_out pod2text_memo_filename in
417 output_value chan pod2text_memo;
420 (* Useful if you need the longdesc POD text as plain text. Returns a
423 * Because this is very slow (the slowest part of autogeneration),
424 * we memoize the results.
426 let pod2text ?width ?(trim = true) ?(discard = true) name longdesc =
427 let key = width, trim, discard, name, longdesc in
428 try Hashtbl.find pod2text_memo key
430 let filename, chan = Filename.open_temp_file "gen" ".tmp" in
431 fprintf chan "=head1 %s\n\n%s\n" name longdesc;
436 sprintf "pod2text -w %d %s" width (Filename.quote filename)
438 sprintf "pod2text %s" (Filename.quote filename) in
439 let chan = open_process_in cmd in
440 let lines = ref [] in
442 let line = input_line chan in
443 if i = 1 && discard then (* discard the first line of output *)
446 let line = if trim then triml line else line in
447 lines := line :: !lines;
450 let lines = try loop 1 with End_of_file -> List.rev !lines in
452 (match close_process_in chan with
455 failwithf "pod2text: process exited with non-zero status (%d)" i
456 | WSIGNALED i | WSTOPPED i ->
457 failwithf "pod2text: process signalled or stopped by signal %d" i
459 Hashtbl.add pod2text_memo key lines;
460 pod2text_memo_updated ();
464 let len = String.length s in
465 let sublen = String.length sub in
467 if i <= len-sublen then (
470 if s.[i+j] = sub.[j] then loop2 (j+1)
476 if r = -1 then loop (i+1) else r
482 let rec replace_str s s1 s2 =
483 let len = String.length s in
484 let sublen = String.length s1 in
488 let s' = String.sub s 0 i in
489 let s'' = String.sub s (i+sublen) (len-i-sublen) in
490 s' ^ s2 ^ replace_str s'' s1 s2
493 let rec string_split sep str =
494 let len = String.length str in
495 let seplen = String.length sep in
496 let i = find str sep in
499 let s' = String.sub str 0 i in
500 let s'' = String.sub str (i+seplen) (len-i-seplen) in
501 s' :: string_split sep s''
504 let files_equal n1 n2 =
505 let cmd = sprintf "cmp -s %s %s" (Filename.quote n1) (Filename.quote n2) in
506 match Sys.command cmd with
509 | i -> failwithf "%s: failed with error code %d" cmd i
511 let rec filter_map f = function
515 | Some y -> y :: filter_map f xs
516 | None -> filter_map f xs
518 let rec find_map f = function
519 | [] -> raise Not_found
523 | None -> find_map f xs
526 let rec loop i = function
528 | x :: xs -> f i x; loop (i+1) xs
533 let rec loop i = function
535 | x :: xs -> let r = f i x in r :: loop (i+1) xs
539 let count_chars c str =
541 for i = 0 to String.length str - 1 do
542 if c = String.unsafe_get str i then incr count
546 let name_of_argt = function
548 | ANode n | AValue n | AString n | AStringNullable n -> n
549 | AOpenFlags | AUnusedFlags -> "flags"
550 | ASetValues -> "values"
553 (* Check function names etc. for consistency. *)
554 let check_functions () =
555 let contains_uppercase str =
556 let len = String.length str in
558 if i >= len then false
561 if c >= 'A' && c <= 'Z' then true
568 (* Check function names. *)
570 fun (name, _, _, _) ->
571 if String.length name >= 7 && String.sub name 0 7 = "hivex" then
572 failwithf "function name %s does not need 'hivex' prefix" name;
574 failwithf "function name is empty";
575 if name.[0] < 'a' || name.[0] > 'z' then
576 failwithf "function name %s must start with lowercase a-z" name;
577 if String.contains name '-' then
578 failwithf "function name %s should not contain '-', use '_' instead."
582 (* Check function parameter/return names. *)
584 fun (name, style, _, _) ->
585 let check_arg_ret_name n =
586 if contains_uppercase n then
587 failwithf "%s param/ret %s should not contain uppercase chars"
589 if String.contains n '-' || String.contains n '_' then
590 failwithf "%s param/ret %s should not contain '-' or '_'"
593 failwithf "%s has a param/ret called 'value', which causes conflicts in the OCaml bindings, use something like 'val' or a more descriptive name" name;
594 if n = "int" || n = "char" || n = "short" || n = "long" then
595 failwithf "%s has a param/ret which conflicts with a C type (eg. 'int', 'char' etc.)" name;
596 if n = "i" || n = "n" then
597 failwithf "%s has a param/ret called 'i' or 'n', which will cause some conflicts in the generated code" name;
598 if n = "argv" || n = "args" then
599 failwithf "%s has a param/ret called 'argv' or 'args', which will cause some conflicts in the generated code" name;
601 (* List Haskell, OCaml and C keywords here.
602 * http://www.haskell.org/haskellwiki/Keywords
603 * http://caml.inria.fr/pub/docs/manual-ocaml/lex.html#operator-char
604 * http://en.wikipedia.org/wiki/C_syntax#Reserved_keywords
605 * Formatted via: cat c haskell ocaml|sort -u|grep -vE '_|^val$' \
606 * |perl -pe 's/(.+)/"$1";/'|fmt -70
607 * Omitting _-containing words, since they're handled above.
608 * Omitting the OCaml reserved word, "val", is ok,
609 * and saves us from renaming several parameters.
612 "and"; "as"; "asr"; "assert"; "auto"; "begin"; "break"; "case";
613 "char"; "class"; "const"; "constraint"; "continue"; "data";
614 "default"; "deriving"; "do"; "done"; "double"; "downto"; "else";
615 "end"; "enum"; "exception"; "extern"; "external"; "false"; "float";
616 "for"; "forall"; "foreign"; "fun"; "function"; "functor"; "goto";
617 "hiding"; "if"; "import"; "in"; "include"; "infix"; "infixl";
618 "infixr"; "inherit"; "initializer"; "inline"; "instance"; "int";
620 "land"; "lazy"; "let"; "long"; "lor"; "lsl"; "lsr"; "lxor";
621 "match"; "mdo"; "method"; "mod"; "module"; "mutable"; "new";
622 "newtype"; "object"; "of"; "open"; "or"; "private"; "qualified";
623 "rec"; "register"; "restrict"; "return"; "short"; "sig"; "signed";
624 "sizeof"; "static"; "struct"; "switch"; "then"; "to"; "true"; "try";
625 "type"; "typedef"; "union"; "unsigned"; "virtual"; "void";
626 "volatile"; "when"; "where"; "while";
628 if List.mem n reserved then
629 failwithf "%s has param/ret using reserved word %s" name n;
632 List.iter (fun arg -> check_arg_ret_name (name_of_argt arg)) (snd style)
635 (* Check short descriptions. *)
637 fun (name, _, shortdesc, _) ->
638 if shortdesc.[0] <> Char.lowercase shortdesc.[0] then
639 failwithf "short description of %s should begin with lowercase." name;
640 let c = shortdesc.[String.length shortdesc-1] in
641 if c = '\n' || c = '.' then
642 failwithf "short description of %s should not end with . or \\n." name
645 (* Check long dscriptions. *)
647 fun (name, _, _, longdesc) ->
648 if longdesc.[String.length longdesc-1] = '\n' then
649 failwithf "long description of %s should not end with \\n." name
652 (* 'pr' prints to the current output file. *)
653 let chan = ref Pervasives.stdout
658 let i = count_chars '\n' str in
660 output_string !chan str
663 let copyright_years =
664 let this_year = 1900 + (localtime (time ())).tm_year in
665 if this_year > 2009 then sprintf "2009-%04d" this_year else "2009"
667 (* Generate a header block in a number of standard styles. *)
669 | CStyle | CPlusPlusStyle | HashStyle | OCamlStyle | HaskellStyle
671 type license = GPLv2plus | LGPLv2plus | GPLv2 | LGPLv2
673 let generate_header ?(extra_inputs = []) comment license =
674 let inputs = "generator/generator.ml" :: extra_inputs in
675 let c = match comment with
676 | CStyle -> pr "/* "; " *"
677 | CPlusPlusStyle -> pr "// "; "//"
678 | HashStyle -> pr "# "; "#"
679 | OCamlStyle -> pr "(* "; " *"
680 | HaskellStyle -> pr "{- "; " "
681 | PODCommentStyle -> pr "=begin comment\n\n "; "" in
682 pr "hivex generated file\n";
683 pr "%s WARNING: THIS FILE IS GENERATED FROM:\n" c;
684 List.iter (pr "%s %s\n" c) inputs;
685 pr "%s ANY CHANGES YOU MAKE TO THIS FILE WILL BE LOST.\n" c;
687 pr "%s Copyright (C) %s Red Hat Inc.\n" c copyright_years;
688 pr "%s Derived from code by Petter Nordahl-Hagen under a compatible license:\n" c;
689 pr "%s Copyright (c) 1997-2007 Petter Nordahl-Hagen.\n" c;
690 pr "%s Derived from code by Markus Stephany under a compatible license:\n" c;
691 pr "%s Copyright (c)2000-2004, Markus Stephany.\n" c;
695 pr "%s This program is free software; you can redistribute it and/or modify\n" c;
696 pr "%s it under the terms of the GNU General Public License as published by\n" c;
697 pr "%s the Free Software Foundation; either version 2 of the License, or\n" c;
698 pr "%s (at your option) any later version.\n" c;
700 pr "%s This program is distributed in the hope that it will be useful,\n" c;
701 pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
702 pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" c;
703 pr "%s GNU General Public License for more details.\n" c;
705 pr "%s You should have received a copy of the GNU General Public License along\n" c;
706 pr "%s with this program; if not, write to the Free Software Foundation, Inc.,\n" c;
707 pr "%s 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n" c;
710 pr "%s This library is free software; you can redistribute it and/or\n" c;
711 pr "%s modify it under the terms of the GNU Lesser General Public\n" c;
712 pr "%s License as published by the Free Software Foundation; either\n" c;
713 pr "%s version 2 of the License, or (at your option) any later version.\n" c;
715 pr "%s This library is distributed in the hope that it will be useful,\n" c;
716 pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
717 pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n" c;
718 pr "%s Lesser General Public License for more details.\n" c;
720 pr "%s You should have received a copy of the GNU Lesser General Public\n" c;
721 pr "%s License along with this library; if not, write to the Free Software\n" c;
722 pr "%s Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n" c;
725 pr "%s This program is free software; you can redistribute it and/or modify\n" c;
726 pr "%s it under the terms of the GNU General Public License as published by\n" c;
727 pr "%s the Free Software Foundation; version 2 of the License only.\n" c;
729 pr "%s This program is distributed in the hope that it will be useful,\n" c;
730 pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
731 pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" c;
732 pr "%s GNU General Public License for more details.\n" c;
734 pr "%s You should have received a copy of the GNU General Public License along\n" c;
735 pr "%s with this program; if not, write to the Free Software Foundation, Inc.,\n" c;
736 pr "%s 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n" c;
739 pr "%s This library is free software; you can redistribute it and/or\n" c;
740 pr "%s modify it under the terms of the GNU Lesser General Public\n" c;
741 pr "%s License as published by the Free Software Foundation;\n" c;
742 pr "%s version 2.1 of the License only.\n" c;
744 pr "%s This library is distributed in the hope that it will be useful,\n" c;
745 pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
746 pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n" c;
747 pr "%s Lesser General Public License for more details.\n" c;
749 pr "%s You should have received a copy of the GNU Lesser General Public\n" c;
750 pr "%s License along with this library; if not, write to the Free Software\n" c;
751 pr "%s Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n" c;
754 | CStyle -> pr " */\n"
757 | OCamlStyle -> pr " *)\n"
758 | HaskellStyle -> pr "-}\n"
759 | PODCommentStyle -> pr "\n=end comment\n"
763 (* Start of main code generation functions below this line. *)
765 let rec generate_c_header () =
766 generate_header CStyle LGPLv2;
779 /* NOTE: This API is documented in the man page hivex(3). */
782 typedef struct hive_h hive_h;
784 /* Nodes and values. */
785 typedef size_t hive_node_h;
786 typedef size_t hive_value_h;
790 # define HIVEX_NO_KEY ENOKEY
792 # define HIVEX_NO_KEY ENOENT
795 /* Pre-defined types. */
799 fun (t, old_style, new_style, description) ->
800 pr " /* %s */\n" description;
801 pr " hive_t_REG_%s,\n" new_style;
802 pr "#define hive_t_%s hive_t_REG_%s\n" old_style new_style;
808 typedef enum hive_type hive_type;
810 /* Bitmask of flags passed to hivex_open. */
813 fun (v, flag, description) ->
814 pr " /* %s */\n" description;
815 pr "#define HIVEX_OPEN_%-10s %d\n" flag v;
820 /* Array of (key, value) pairs passed to hivex_node_set_values. */
821 struct hive_set_value {
827 typedef struct hive_set_value hive_set_value;
831 pr "/* Functions. */\n";
833 (* Function declarations. *)
835 fun (shortname, style, _, _) ->
836 let name = "hivex_" ^ shortname in
837 generate_c_prototype ~extern:true name style
840 (* The visitor pattern. *)
842 /* Visit all nodes. This is specific to the C API and is not made
843 * available to other languages. This is because of the complexity
844 * of binding callbacks in other languages, but also because other
845 * languages make it much simpler to iterate over a tree.
847 struct hivex_visitor {
848 int (*node_start) (hive_h *, void *opaque, hive_node_h, const char *name);
849 int (*node_end) (hive_h *, void *opaque, hive_node_h, const char *name);
850 int (*value_string) (hive_h *, void *opaque, hive_node_h, hive_value_h, hive_type t, size_t len, const char *key, const char *str);
851 int (*value_multiple_strings) (hive_h *, void *opaque, hive_node_h, hive_value_h, hive_type t, size_t len, const char *key, char **argv);
852 int (*value_string_invalid_utf16) (hive_h *, void *opaque, hive_node_h, hive_value_h, hive_type t, size_t len, const char *key, const char *str);
853 int (*value_dword) (hive_h *, void *opaque, hive_node_h, hive_value_h, hive_type t, size_t len, const char *key, int32_t);
854 int (*value_qword) (hive_h *, void *opaque, hive_node_h, hive_value_h, hive_type t, size_t len, const char *key, int64_t);
855 int (*value_binary) (hive_h *, void *opaque, hive_node_h, hive_value_h, hive_type t, size_t len, const char *key, const char *value);
856 int (*value_none) (hive_h *, void *opaque, hive_node_h, hive_value_h, hive_type t, size_t len, const char *key, const char *value);
857 int (*value_other) (hive_h *, void *opaque, hive_node_h, hive_value_h, hive_type t, size_t len, const char *key, const char *value);
858 int (*value_any) (hive_h *, void *opaque, hive_node_h, hive_value_h, hive_type t, size_t len, const char *key, const char *value);
861 #define HIVEX_VISIT_SKIP_BAD 1
863 extern int hivex_visit (hive_h *h, const struct hivex_visitor *visitor, size_t len, void *opaque, int flags);
864 extern int hivex_visit_node (hive_h *h, hive_node_h node, const struct hivex_visitor *visitor, size_t len, void *opaque, int flags);
868 (* Finish the header file. *)
874 #endif /* HIVEX_H_ */
877 and generate_c_prototype ?(extern = false) name style =
878 if extern then pr "extern ";
879 (match fst style with
881 | RErrDispose -> pr "int "
882 | RHive -> pr "hive_h *"
883 | RSize -> pr "size_t "
884 | RNode -> pr "hive_node_h "
885 | RNodeNotFound -> pr "hive_node_h "
886 | RNodeList -> pr "hive_node_h *"
887 | RValue -> pr "hive_value_h "
888 | RValueList -> pr "hive_value_h *"
889 | RString -> pr "char *"
890 | RStringList -> pr "char **"
891 | RLenType -> pr "int "
892 | RLenTypeVal -> pr "char *"
893 | RInt32 -> pr "int32_t "
894 | RInt64 -> pr "int64_t "
897 let comma = ref false in
900 if !comma then pr ", "; comma := true;
902 | AHive -> pr "hive_h *h"
903 | ANode n -> pr "hive_node_h %s" n
904 | AValue n -> pr "hive_value_h %s" n
905 | AString n | AStringNullable n -> pr "const char *%s" n
906 | AOpenFlags | AUnusedFlags -> pr "int flags"
907 | ASetValues -> pr "size_t nr_values, const hive_set_value *values"
908 | ASetValue -> pr "const hive_set_value *val"
910 (match fst style with
911 | RLenType | RLenTypeVal -> pr ", hive_type *t, size_t *len"
916 and generate_c_pod () =
917 generate_header PODCommentStyle GPLv2;
924 hivex - Windows Registry \"hive\" extraction library
932 fun (shortname, style, _, _) ->
933 let name = "hivex_" ^ shortname in
935 generate_c_prototype ~extern:false name style;
940 Link with I<-lhivex>.
944 Hivex is a library for extracting the contents of Windows Registry
945 \"hive\" files. It is designed to be secure against buggy or malicious
948 Unlike other tools in this area, it doesn't use the textual .REG
949 format, because parsing that is as much trouble as parsing the
950 original binary format. Instead it makes the file available
951 through a C API, and then wraps this API in higher level scripting
954 There is a separate program to export the hive as XML
955 (see L<hivexml(1)>), or to navigate the file (see L<hivexsh(1)>).
956 There is also a Perl script to export and merge the
957 file as a textual .REG (regedit) file, see L<hivexregedit(1)>.
959 If you just want to export or modify the Registry of a Windows
960 virtual machine, you should look at L<virt-win-reg(1)>.
962 Hivex is also comes with language bindings for
963 OCaml, Perl, Python and Ruby.
969 This handle describes an open hive file.
971 =head2 C<hive_node_h>
973 This is a node handle, an integer but opaque outside the library.
974 Valid node handles cannot be 0. The library returns 0 in some
975 situations to indicate an error.
979 The enum below describes the possible types for the value(s)
980 stored at each node. Note that you should not trust the
981 type field in a Windows Registry, as it very often has no
982 relationship to reality. Some applications use their own
983 types. The encoding of strings is not specified. Some
984 programs store everything (including strings) in binary blobs.
989 fun (t, _, new_style, description) ->
990 pr " /* %s */\n" description;
991 pr " hive_t_REG_%s = %d,\n" new_style t
996 =head2 C<hive_value_h>
998 This is a value handle, an integer but opaque outside the library.
999 Valid value handles cannot be 0. The library returns 0 in some
1000 situations to indicate an error.
1002 =head2 C<hive_set_value>
1004 The typedef C<hive_set_value> is used in conjunction with the
1005 C<hivex_node_set_values> call described below.
1007 struct hive_set_value {
1008 char *key; /* key - a UTF-8 encoded ASCIIZ string */
1009 hive_type t; /* type of value field */
1010 size_t len; /* length of value field in bytes */
1011 char *value; /* value field */
1013 typedef struct hive_set_value hive_set_value;
1015 To set the default value for a node, you have to pass C<key = \"\">.
1017 Note that the C<value> field is just treated as a list of bytes, and
1018 is stored directly in the hive. The caller has to ensure correct
1019 encoding and endianness, for example converting dwords to little
1022 The correct type and encoding for values depends on the node and key
1023 in the registry, the version of Windows, and sometimes even changes
1024 between versions of Windows for the same key. We don't document it
1025 here. Often it's not documented at all.
1031 fun (shortname, style, _, longdesc) ->
1032 let name = "hivex_" ^ shortname in
1033 pr "=head2 %s\n" name;
1035 generate_c_prototype ~extern:false name style;
1040 if List.mem AUnusedFlags (snd style) then
1041 pr "The flags parameter is unused. Always pass 0.\n\n";
1043 if List.mem ASetValues (snd style) then
1044 pr "C<values> is an array of (key, value) pairs. There
1045 should be C<nr_values> elements in this array.
1047 Any existing values stored at the node are discarded, and their
1048 C<hive_value_h> handles become invalid. Thus you can remove all
1049 values stored at C<node> by passing C<nr_values = 0>.\n\n";
1051 if List.mem ASetValue (snd style) then
1052 pr "C<value> is a single (key, value) pair.
1054 Existing C<hive_value_h> handles become invalid.\n\n";
1056 (match fst style with
1059 Returns 0 on success.
1060 On error this returns -1 and sets errno.\n\n"
1063 Returns 0 on success.
1064 On error this returns -1 and sets errno.
1066 This function frees the hive handle (even if it returns an error).
1067 The hive handle must not be used again after calling this function.\n\n"
1070 Returns a new hive handle.
1071 On error this returns NULL and sets errno.\n\n"
1075 On error this returns 0 and sets errno.\n\n"
1078 Returns a node handle.
1079 On error this returns 0 and sets errno.\n\n"
1082 Returns a node handle.
1083 If the node was not found, this returns 0 without setting errno.
1084 On error this returns 0 and sets errno.\n\n"
1087 Returns a 0-terminated array of nodes.
1088 The array must be freed by the caller when it is no longer needed.
1089 On error this returns NULL and sets errno.\n\n"
1092 Returns a value handle.
1093 On error this returns 0 and sets errno.\n\n"
1096 Returns a 0-terminated array of values.
1097 The array must be freed by the caller when it is no longer needed.
1098 On error this returns NULL and sets errno.\n\n"
1102 The string must be freed by the caller when it is no longer needed.
1103 On error this returns NULL and sets errno.\n\n"
1106 Returns a NULL-terminated array of C strings.
1107 The strings and the array must all be freed by the caller when
1108 they are no longer needed.
1109 On error this returns NULL and sets errno.\n\n"
1112 Returns 0 on success.
1113 On error this returns -1 and sets errno.\n\n"
1116 The value is returned as an array of bytes (of length C<len>).
1117 The value must be freed by the caller when it is no longer needed.
1118 On error this returns NULL and sets errno.\n\n"
1119 | RInt32 | RInt64 -> ()
1124 =head1 WRITING TO HIVE FILES
1126 The hivex library supports making limited modifications to hive files.
1127 We have tried to implement this very conservatively in order to reduce
1128 the chance of corrupting your registry. However you should be careful
1129 and take back-ups, since Microsoft has never documented the hive
1130 format, and so it is possible there are nuances in the
1131 reverse-engineered format that we do not understand.
1133 To be able to modify a hive, you must pass the C<HIVEX_OPEN_WRITE>
1134 flag to C<hivex_open>, otherwise any write operation will return with
1137 The write operations shown below do not modify the on-disk file
1138 immediately. You must call C<hivex_commit> in order to write the
1139 changes to disk. If you call C<hivex_close> without committing then
1140 any writes are discarded.
1142 Hive files internally consist of a \"memory dump\" of binary blocks
1143 (like the C heap), and some of these blocks can be unused. The hivex
1144 library never reuses these unused blocks. Instead, to ensure
1145 robustness in the face of the partially understood on-disk format,
1146 hivex only allocates new blocks after the end of the file, and makes
1147 minimal modifications to existing structures in the file to point to
1148 these new blocks. This makes hivex slightly less disk-efficient than
1149 it could be, but disk is cheap, and registry modifications tend to be
1152 When deleting nodes, it is possible that this library may leave
1153 unreachable live blocks in the hive. This is because certain parts of
1154 the hive disk format such as security (sk) records and big data (db)
1155 records and classname fields are not well understood (and not
1156 documented at all) and we play it safe by not attempting to modify
1157 them. Apart from wasting a little bit of disk space, it is not
1158 thought that unreachable blocks are a problem.
1160 =head2 WRITE OPERATIONS WHICH ARE NOT SUPPORTED
1166 Changing the root node.
1170 Creating a new hive file from scratch. This is impossible at present
1171 because not all fields in the header are understood. In the hivex
1172 source tree is a file called C<images/minimal> which could be used as
1173 the basis for a new hive (but I<caveat emptor>).
1177 Modifying or deleting single values at a node.
1181 Modifying security key (sk) records or classnames.
1182 Previously we did not understand these records. However now they
1183 are well-understood and we could add support if it was required
1184 (but nothing much really uses them).
1188 =head1 VISITING ALL NODES
1190 The visitor pattern is useful if you want to visit all nodes
1191 in the tree or all nodes below a certain point in the tree.
1193 First you set up your own C<struct hivex_visitor> with your
1196 Each of these callback functions should return 0 on success or -1
1197 on error. If any callback returns -1, then the entire visit
1198 terminates immediately. If you don't need a callback function at
1199 all, set the function pointer to NULL.
1201 struct hivex_visitor {
1202 int (*node_start) (hive_h *, void *opaque, hive_node_h, const char *name);
1203 int (*node_end) (hive_h *, void *opaque, hive_node_h, const char *name);
1204 int (*value_string) (hive_h *, void *opaque, hive_node_h, hive_value_h,
1205 hive_type t, size_t len, const char *key, const char *str);
1206 int (*value_multiple_strings) (hive_h *, void *opaque, hive_node_h,
1207 hive_value_h, hive_type t, size_t len, const char *key, char **argv);
1208 int (*value_string_invalid_utf16) (hive_h *, void *opaque, hive_node_h,
1209 hive_value_h, hive_type t, size_t len, const char *key,
1211 int (*value_dword) (hive_h *, void *opaque, hive_node_h, hive_value_h,
1212 hive_type t, size_t len, const char *key, int32_t);
1213 int (*value_qword) (hive_h *, void *opaque, hive_node_h, hive_value_h,
1214 hive_type t, size_t len, const char *key, int64_t);
1215 int (*value_binary) (hive_h *, void *opaque, hive_node_h, hive_value_h,
1216 hive_type t, size_t len, const char *key, const char *value);
1217 int (*value_none) (hive_h *, void *opaque, hive_node_h, hive_value_h,
1218 hive_type t, size_t len, const char *key, const char *value);
1219 int (*value_other) (hive_h *, void *opaque, hive_node_h, hive_value_h,
1220 hive_type t, size_t len, const char *key, const char *value);
1221 /* If value_any callback is not NULL, then the other value_*
1222 * callbacks are not used, and value_any is called on all values.
1224 int (*value_any) (hive_h *, void *opaque, hive_node_h, hive_value_h,
1225 hive_type t, size_t len, const char *key, const char *value);
1232 int hivex_visit (hive_h *h, const struct hivex_visitor *visitor, size_t len, void *opaque, int flags);
1234 Visit all the nodes recursively in the hive C<h>.
1236 C<visitor> should be a C<hivex_visitor> structure with callback
1237 fields filled in as required (unwanted callbacks can be set to
1238 NULL). C<len> must be the length of the 'visitor' struct (you
1239 should pass C<sizeof (struct hivex_visitor)> for this).
1241 This returns 0 if the whole recursive visit was completed
1242 successfully. On error this returns -1. If one of the callback
1243 functions returned an error than we don't touch errno. If the
1244 error was generated internally then we set errno.
1246 You can skip bad registry entries by setting C<flag> to
1247 C<HIVEX_VISIT_SKIP_BAD>. If this flag is not set, then a bad registry
1248 causes the function to return an error immediately.
1250 This function is robust if the registry contains cycles or
1251 pointers which are invalid or outside the registry. It detects
1252 these cases and returns an error.
1254 =item hivex_visit_node
1256 int hivex_visit_node (hive_h *h, hive_node_h node, const struct hivex_visitor *visitor, size_t len, void *opaque);
1258 Same as C<hivex_visit> but instead of starting out at the root, this
1263 =head1 THE STRUCTURE OF THE WINDOWS REGISTRY
1265 Note: To understand the relationship between hives and the common
1266 Windows Registry keys (like C<HKEY_LOCAL_MACHINE>) please see the
1267 Wikipedia page on the Windows Registry.
1269 The Windows Registry is split across various binary files, each
1270 file being known as a \"hive\". This library only handles a single
1271 hive file at a time.
1273 Hives are n-ary trees with a single root. Each node in the tree
1276 Each node in the tree (including non-leaf nodes) may have an
1277 arbitrary list of (key, value) pairs attached to it. It may
1278 be the case that one of these pairs has an empty key. This
1279 is referred to as the default key for the node.
1281 The (key, value) pairs are the place where the useful data is
1282 stored in the registry. The key is always a string (possibly the
1283 empty string for the default key). The value is a typed object
1284 (eg. string, int32, binary, etc.).
1286 =head2 RELATIONSHIP TO .REG FILES
1288 The hivex C library does not care about or deal with Windows .REG
1289 files. Instead we push this complexity up to the Perl
1290 L<Win::Hivex(3)> library and the Perl programs
1291 L<hivexregedit(1)> and L<virt-win-reg(1)>.
1292 Nevertheless it is useful to look at the relationship between the
1293 Registry and .REG files because they are so common.
1295 A .REG file is a textual representation of the registry, or part of the
1296 registry. The actual registry hives that Windows uses are binary
1297 files. There are a number of Windows and Linux tools that let you
1298 generate .REG files, or merge .REG files back into the registry hives.
1299 Notable amongst them is Microsoft's REGEDIT program (formerly known as
1302 A typical .REG file will contain many sections looking like this:
1304 [HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes\\Stack]
1305 \"@\"=\"Generic Stack\"
1306 \"TileInfo\"=\"prop:System.FileCount\"
1307 \"TilePath\"=str(2):\"%%systemroot%%\\\\system32\"
1308 \"ThumbnailCutoff\"=dword:00000000
1309 \"FriendlyTypeName\"=hex(2):40,00,25,00,53,00,79,00,73,00,74,00,65,00,6d,00,52,00,6f,00,\\
1310 6f,00,74,00,25,00,5c,00,53,00,79,00,73,00,74,00,65,00,6d,00,\\
1311 33,00,32,00,5c,00,73,00,65,00,61,00,72,00,63,00,68,00,66,00,\\
1312 6f,00,6c,00,64,00,65,00,72,00,2e,00,64,00,6c,00,6c,00,2c,00,\\
1313 2d,00,39,00,30,00,32,00,38,00,00,00,d8
1315 Taking this one piece at a time:
1317 [HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes\\Stack]
1319 This is the path to this node in the registry tree. The first part,
1320 C<HKEY_LOCAL_MACHINE\\SOFTWARE> means that this comes from a hive
1321 file called C<C:\\WINDOWS\\SYSTEM32\\CONFIG\\SOFTWARE>.
1322 C<\\Classes\\Stack> is the real path part,
1323 starting at the root node of the C<SOFTWARE> hive.
1325 Below the node name is a list of zero or more key-value pairs. Any
1326 interior or leaf node in the registry may have key-value pairs
1329 \"@\"=\"Generic Stack\"
1331 This is the \"default key\". In reality (ie. inside the binary hive)
1332 the key string is the empty string. In .REG files this is written as
1333 C<@> but this has no meaning either in the hives themselves or in this
1334 library. The value is a string (type 1 - see C<enum hive_type>
1337 \"TileInfo\"=\"prop:System.FileCount\"
1339 This is a regular (key, value) pair, with the value being a type 1
1340 string. Note that inside the binary file the string is likely to be
1341 UTF-16LE encoded. This library converts to and from UTF-8 strings
1342 transparently in some cases.
1344 \"TilePath\"=str(2):\"%%systemroot%%\\\\system32\"
1346 The value in this case has type 2 (expanded string) meaning that some
1347 %%...%% variables get expanded by Windows. (This library doesn't know
1348 or care about variable expansion).
1350 \"ThumbnailCutoff\"=dword:00000000
1352 The value in this case is a dword (type 4).
1354 \"FriendlyTypeName\"=hex(2):40,00,....
1356 This value is an expanded string (type 2) represented in the .REG file
1357 as a series of hex bytes. In this case the string appears to be a
1360 =head1 NOTE ON THE USE OF ERRNO
1362 Many functions in this library set errno to indicate errors. These
1363 are the values of errno you may encounter (this list is not
1370 Corrupt or unsupported Registry file format.
1378 Passed an invalid argument to the function.
1382 Followed a Registry pointer which goes outside
1383 the registry or outside a registry block.
1387 Registry contains cycles.
1391 Field in the registry out of range.
1395 Registry key already exists.
1399 Tried to write to a registry which is not opened for writing.
1403 =head1 ENVIRONMENT VARIABLES
1409 Setting HIVEX_DEBUG=1 will enable very verbose messages. This is
1410 useful for debugging problems with the library itself.
1423 L<http://libguestfs.org/>,
1426 L<http://en.wikipedia.org/wiki/Windows_Registry>.
1430 Richard W.M. Jones (C<rjones at redhat dot com>)
1434 Copyright (C) 2009-2010 Red Hat Inc.
1436 Derived from code by Petter Nordahl-Hagen under a compatible license:
1437 Copyright (C) 1997-2007 Petter Nordahl-Hagen.
1439 Derived from code by Markus Stephany under a compatible license:
1440 Copyright (C) 2000-2004 Markus Stephany.
1442 This library is free software; you can redistribute it and/or
1443 modify it under the terms of the GNU Lesser General Public
1444 License as published by the Free Software Foundation;
1445 version 2.1 of the License only.
1447 This library is distributed in the hope that it will be useful,
1448 but WITHOUT ANY WARRANTY; without even the implied warranty of
1449 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1450 Lesser General Public License for more details.
1453 (* Generate the linker script which controls the visibility of
1454 * symbols in the public ABI and ensures no other symbols get
1455 * exported accidentally.
1457 and generate_linker_script () =
1458 generate_header HashStyle GPLv2plus;
1466 List.map (fun (name, _, _, _) -> "hivex_" ^ name)
1468 let globals = List.sort compare (globals @ functions) in
1472 List.iter (pr " %s;\n") globals;
1479 and generate_ocaml_interface () =
1480 generate_header OCamlStyle LGPLv2plus;
1484 (** A [hive_h] hive file handle. *)
1488 (** Nodes and values. *)
1490 exception Error of string * Unix.error * string
1491 (** Error raised by a function.
1493 The first parameter is the name of the function which raised the error.
1494 The second parameter is the errno (see the [Unix] module). The third
1495 parameter is a human-readable string corresponding to the errno.
1497 See hivex(3) for a partial list of interesting errno values that
1498 can be generated by the library. *)
1499 exception Handle_closed of string
1500 (** This exception is raised if you call a function on a closed handle. *)
1506 fun (t, _, new_style, description) ->
1508 pr " | REG_%s (** %s *)\n" new_style description
1512 | REG_UNKNOWN of int32 (** unknown type *)
1513 (** Hive type field. *)
1519 fun (v, flag, description) ->
1520 assert (1 lsl i = v);
1521 pr " | OPEN_%s (** %s *)\n" flag description
1525 (** Open flags for {!open_file} call. *)
1532 (** (key, value) pair passed (as an array) to {!node_set_values}. *)
1536 fun (name, style, shortdesc, _) ->
1538 generate_ocaml_prototype name style;
1539 pr "(** %s *)\n" shortdesc
1542 and generate_ocaml_implementation () =
1543 generate_header OCamlStyle LGPLv2plus;
1550 exception Error of string * Unix.error * string
1551 exception Handle_closed of string
1553 (* Give the exceptions names, so they can be raised from the C code. *)
1555 Callback.register_exception \"ocaml_hivex_error\"
1556 (Error (\"\", Unix.EUNKNOWNERR 0, \"\"));
1557 Callback.register_exception \"ocaml_hivex_closed\" (Handle_closed \"\")
1563 fun (t, _, new_style, _) ->
1565 pr " | REG_%s\n" new_style
1569 | REG_UNKNOWN of int32
1575 fun (v, flag, description) ->
1576 assert (1 lsl i = v);
1577 pr " | OPEN_%s (** %s *)\n" flag description
1591 fun (name, style, _, _) ->
1592 generate_ocaml_prototype ~is_external:true name style
1595 and generate_ocaml_prototype ?(is_external = false) name style =
1596 let ocaml_name = if name = "open" then "open_file" else name in
1598 if is_external then pr "external " else pr "val ";
1599 pr "%s : " ocaml_name;
1602 | AHive -> pr "t -> "
1603 | ANode _ -> pr "node -> "
1604 | AValue _ -> pr "value -> "
1605 | AString _ -> pr "string -> "
1606 | AStringNullable _ -> pr "string option -> "
1607 | AOpenFlags -> pr "open_flag list -> "
1608 | AUnusedFlags -> ()
1609 | ASetValues -> pr "set_value array -> "
1610 | ASetValue -> pr "set_value -> "
1612 (match fst style with
1613 | RErr -> pr "unit" (* all errors are turned into exceptions *)
1614 | RErrDispose -> pr "unit"
1616 | RSize -> pr "int64"
1617 | RNode -> pr "node"
1618 | RNodeNotFound -> pr "node"
1619 | RNodeList -> pr "node array"
1620 | RValue -> pr "value"
1621 | RValueList -> pr "value array"
1622 | RString -> pr "string"
1623 | RStringList -> pr "string array"
1624 | RLenType -> pr "hive_type * int"
1625 | RLenTypeVal -> pr "hive_type * string"
1626 | RInt32 -> pr "int32"
1627 | RInt64 -> pr "int64"
1630 pr " = \"ocaml_hivex_%s\"" name;
1633 and generate_ocaml_c () =
1634 generate_header CStyle LGPLv2plus;
1645 #include <caml/config.h>
1646 #include <caml/alloc.h>
1647 #include <caml/callback.h>
1648 #include <caml/custom.h>
1649 #include <caml/fail.h>
1650 #include <caml/memory.h>
1651 #include <caml/mlvalues.h>
1652 #include <caml/signals.h>
1654 #ifdef HAVE_CAML_UNIXSUPPORT_H
1655 #include <caml/unixsupport.h>
1657 extern value unix_error_of_code (int errcode);
1660 #ifndef HAVE_CAML_RAISE_WITH_ARGS
1662 caml_raise_with_args (value tag, int nargs, value args[])
1665 CAMLxparamN (args, nargs);
1669 bucket = caml_alloc_small (1 + nargs, 0);
1670 Field(bucket, 0) = tag;
1671 for (i = 0; i < nargs; i++) Field(bucket, 1 + i) = args[i];
1679 #define Hiveh_val(v) (*((hive_h **)Data_custom_val(v)))
1680 static value Val_hiveh (hive_h *);
1681 static int HiveOpenFlags_val (value);
1682 static hive_set_value *HiveSetValue_val (value);
1683 static hive_set_value *HiveSetValues_val (value);
1684 static hive_type HiveType_val (value);
1685 static value Val_hive_type (hive_type);
1686 static value copy_int_array (size_t *);
1687 static value copy_type_len (size_t, hive_type);
1688 static value copy_type_value (const char *, size_t, hive_type);
1689 static void raise_error (const char *) Noreturn;
1690 static void raise_closed (const char *) Noreturn;
1696 fun (name, style, _, _) ->
1697 pr "/* Automatically generated wrapper for function\n";
1698 pr " * "; generate_ocaml_prototype name style;
1704 | ASetValues -> ["nrvalues"; "values"]
1705 | AUnusedFlags -> ["0"]
1706 | arg -> [name_of_argt arg]) (snd style) in
1708 match fst style with
1709 | RLenType | RLenTypeVal -> c_params @ [["&t"; "&len"]]
1711 let c_params = List.concat c_params in
1714 filter_map (function
1715 | AUnusedFlags -> None
1716 | arg -> Some (name_of_argt arg ^ "v")) (snd style) in
1718 pr "/* Emit prototype to appease gcc's -Wmissing-prototypes. */\n";
1719 pr "CAMLprim value ocaml_hivex_%s (value %s" name (List.hd params);
1720 List.iter (pr ", value %s") (List.tl params); pr ");\n";
1723 pr "CAMLprim value\n";
1724 pr "ocaml_hivex_%s (value %s" name (List.hd params);
1725 List.iter (pr ", value %s") (List.tl params);
1729 pr " CAMLparam%d (%s);\n"
1730 (List.length params) (String.concat ", " params);
1731 pr " CAMLlocal1 (rv);\n";
1737 pr " hive_h *h = Hiveh_val (hv);\n";
1738 pr " if (h == NULL)\n";
1739 pr " raise_closed (\"%s\");\n" name
1741 pr " hive_node_h %s = Int_val (%sv);\n" n n
1743 pr " hive_value_h %s = Int_val (%sv);\n" n n
1745 pr " const char *%s = String_val (%sv);\n" n n
1746 | AStringNullable n ->
1747 pr " const char *%s =\n" n;
1748 pr " %sv != Val_int (0) ? String_val (Field (%sv, 0)) : NULL;\n"
1751 pr " int flags = HiveOpenFlags_val (flagsv);\n"
1752 | AUnusedFlags -> ()
1754 pr " int nrvalues = Wosize_val (valuesv);\n";
1755 pr " hive_set_value *values = HiveSetValues_val (valuesv);\n"
1757 pr " hive_set_value *val = HiveSetValue_val (valv);\n"
1762 match fst style with
1763 | RErr -> pr " int r;\n"; "-1"
1764 | RErrDispose -> pr " int r;\n"; "-1"
1765 | RHive -> pr " hive_h *r;\n"; "NULL"
1766 | RSize -> pr " size_t r;\n"; "0"
1767 | RNode -> pr " hive_node_h r;\n"; "0"
1770 pr " hive_node_h r;\n";
1772 | RNodeList -> pr " hive_node_h *r;\n"; "NULL"
1773 | RValue -> pr " hive_value_h r;\n"; "0"
1774 | RValueList -> pr " hive_value_h *r;\n"; "NULL"
1775 | RString -> pr " char *r;\n"; "NULL"
1776 | RStringList -> pr " char **r;\n"; "NULL"
1779 pr " size_t len;\n";
1780 pr " hive_type t;\n";
1784 pr " size_t len;\n";
1785 pr " hive_type t;\n";
1794 "-1 && errno != 0" in
1796 (* The libguestfs OCaml bindings call enter_blocking_section
1797 * here. However I don't think that is safe, because we are
1798 * holding pointers to caml strings during the call, and these
1799 * could be moved or freed by other threads. In any case, there
1800 * is very little reason to enter_blocking_section for any hivex
1801 * call, so don't do it. XXX
1803 (*pr " caml_enter_blocking_section ();\n";*)
1804 pr " r = hivex_%s (%s" name (List.hd c_params);
1805 List.iter (pr ", %s") (List.tl c_params);
1807 (*pr " caml_leave_blocking_section ();\n";*)
1810 (* Dispose of the hive handle (even if hivex_close returns error). *)
1811 (match fst style with
1813 pr " /* So we don't double-free in the finalizer. */\n";
1814 pr " Hiveh_val (hv) = NULL;\n";
1821 | AHive | ANode _ | AValue _ | AString _ | AStringNullable _
1822 | AOpenFlags | AUnusedFlags -> ()
1824 pr " free (values);\n";
1827 pr " free (val);\n";
1831 (* Check for errors. *)
1832 pr " if (r == %s)\n" error_code;
1833 pr " raise_error (\"%s\");\n" name;
1836 (match fst style with
1837 | RErr -> pr " rv = Val_unit;\n"
1838 | RErrDispose -> pr " rv = Val_unit;\n"
1839 | RHive -> pr " rv = Val_hiveh (r);\n"
1840 | RSize -> pr " rv = caml_copy_int64 (r);\n"
1841 | RNode -> pr " rv = Val_int (r);\n"
1843 pr " if (r == 0)\n";
1844 pr " caml_raise_not_found ();\n";
1846 pr " rv = Val_int (r);\n"
1848 pr " rv = copy_int_array (r);\n";
1850 | RValue -> pr " rv = Val_int (r);\n"
1852 pr " rv = copy_int_array (r);\n";
1855 pr " rv = caml_copy_string (r);\n";
1858 pr " rv = caml_copy_string_array ((const char **) r);\n";
1859 pr " for (int i = 0; r[i] != NULL; ++i) free (r[i]);\n";
1861 | RLenType -> pr " rv = copy_type_len (len, t);\n"
1863 pr " rv = copy_type_value (r, len, t);\n";
1865 | RInt32 -> pr " rv = caml_copy_int32 (r);\n"
1866 | RInt64 -> pr " rv = caml_copy_int64 (r);\n"
1869 pr " CAMLreturn (rv);\n";
1877 HiveOpenFlags_val (value v)
1882 while (v != Val_int (0)) {
1884 flags |= 1 << Int_val (v2);
1891 static hive_set_value *
1892 HiveSetValue_val (value v)
1894 hive_set_value *val = malloc (sizeof (hive_set_value));
1896 val->key = String_val (Field (v, 0));
1897 val->t = HiveType_val (Field (v, 1));
1898 val->len = caml_string_length (Field (v, 2));
1899 val->value = String_val (Field (v, 2));
1904 static hive_set_value *
1905 HiveSetValues_val (value v)
1907 size_t nr_values = Wosize_val (v);
1908 hive_set_value *values = malloc (nr_values * sizeof (hive_set_value));
1912 for (i = 0; i < nr_values; ++i) {
1914 values[i].key = String_val (Field (v2, 0));
1915 values[i].t = HiveType_val (Field (v2, 1));
1916 values[i].len = caml_string_length (Field (v2, 2));
1917 values[i].value = String_val (Field (v2, 2));
1924 HiveType_val (value v)
1927 return Int_val (v); /* REG_NONE etc. */
1929 return Int32_val (Field (v, 0)); /* REG_UNKNOWN of int32 */
1933 Val_hive_type (hive_type t)
1939 CAMLreturn (Val_int (t));
1941 rv = caml_alloc (1, 0); /* REG_UNKNOWN of int32 */
1942 v = caml_copy_int32 (t);
1943 caml_modify (&Field (rv, 0), v);
1949 copy_int_array (size_t *xs)
1955 for (nr = 0; xs[nr] != 0; ++nr)
1958 CAMLreturn (Atom (0));
1960 rv = caml_alloc (nr, 0);
1961 for (i = 0; i < nr; ++i) {
1962 v = Val_int (xs[i]);
1963 Store_field (rv, i, v); /* Safe because v is not a block. */
1970 copy_type_len (size_t len, hive_type t)
1975 rv = caml_alloc (2, 0);
1976 v = Val_hive_type (t);
1977 Store_field (rv, 0, v);
1979 Store_field (rv, 1, v);
1984 copy_type_value (const char *r, size_t len, hive_type t)
1989 rv = caml_alloc (2, 0);
1990 v = Val_hive_type (t);
1991 Store_field (rv, 0, v);
1992 v = caml_alloc_string (len);
1993 memcpy (String_val (v), r, len);
1994 caml_modify (&Field (rv, 1), v);
1998 /* Raise exceptions. */
2000 raise_error (const char *function)
2002 /* Save errno early in case it gets trashed. */
2006 CAMLlocal3 (v1, v2, v3);
2008 v1 = caml_copy_string (function);
2009 v2 = unix_error_of_code (err);
2010 v3 = caml_copy_string (strerror (err));
2011 value vvv[] = { v1, v2, v3 };
2012 caml_raise_with_args (*caml_named_value (\"ocaml_hivex_error\"), 3, vvv);
2018 raise_closed (const char *function)
2023 v = caml_copy_string (function);
2024 caml_raise_with_arg (*caml_named_value (\"ocaml_hivex_closed\"), v);
2029 /* Allocate handles and deal with finalization. */
2031 hivex_finalize (value hv)
2033 hive_h *h = Hiveh_val (hv);
2034 if (h) hivex_close (h);
2037 static struct custom_operations hivex_custom_operations = {
2038 (char *) \"hivex_custom_operations\",
2040 custom_compare_default,
2041 custom_hash_default,
2042 custom_serialize_default,
2043 custom_deserialize_default
2047 Val_hiveh (hive_h *h)
2052 rv = caml_alloc_custom (&hivex_custom_operations,
2053 sizeof (hive_h *), 0, 1);
2060 and generate_perl_pm () =
2061 generate_header HashStyle LGPLv2plus;
2068 Win::Hivex - Perl bindings for reading and writing Windows Registry hive files
2074 $h = Win::Hivex->open ('SOFTWARE');
2075 $root_node = $h->root ();
2076 print $h->node_name ($root_node);
2080 The C<Win::Hivex> module provides a Perl XS binding to the
2081 L<hivex(3)> API for reading and writing Windows Registry binary
2086 All errors turn into calls to C<croak> (see L<Carp(3)>).
2100 XSLoader::load ('Win::Hivex');
2104 $h = Win::Hivex->open ($filename,";
2108 pr "\n [%s => 1,]" (String.lowercase flag)
2113 Open a Windows Registry binary hive file.
2115 The C<verbose> and C<debug> flags enable different levels of
2118 The C<write> flag is required if you will be modifying the
2119 hive file (see L<hivex(3)/WRITING TO HIVE FILES>).
2121 This function returns a hive handle. The hive handle is
2122 closed automatically when its reference count drops to 0.
2128 my $class = ref ($proto) || $proto;
2129 my $filename = shift;
2136 fun (n, flag, description) ->
2137 pr " # %s\n" description;
2138 pr " $flags += %d if $flags{%s};\n" n (String.lowercase flag)
2143 my $self = Win::Hivex::_open ($filename, $flags);
2144 bless $self, $class;
2151 fun (name, style, _, longdesc) ->
2152 (* The close call isn't explicit in Perl: handles are closed
2153 * when their reference count drops to 0.
2155 * The open call is coded specially in Perl.
2157 * Therefore we don't generate prototypes for these two calls:
2159 if fst style <> RErrDispose && List.hd (snd style) = AHive then (
2160 let longdesc = replace_str longdesc "C<hivex_" "C<" in
2161 pr "=item %s\n\n " name;
2162 generate_perl_prototype name style;
2164 pr "%s\n\n" longdesc;
2166 (match fst style with
2178 This returns a size.\n\n"
2181 This returns a node handle.\n\n"
2184 This returns a node handle, or C<undef> if the node was not found.\n\n"
2187 This returns a list of node handles.\n\n"
2190 This returns a value handle.\n\n"
2193 This returns a list of value handles.\n\n"
2196 if List.mem ASetValues (snd style) then
2197 pr "C<@values> is an array of (keys, value) pairs.
2198 Each element should be a hashref containing C<key>, C<t> (type)
2201 Any existing values stored at the node are discarded, and their
2202 C<value> handles become invalid. Thus you can remove all
2203 values stored at C<node> by passing C<@values = []>.\n\n"
2216 Copyright (C) %s Red Hat Inc.
2220 Please see the file COPYING.LIB for the full license.
2226 L<http://libguestfs.org>,
2232 and generate_perl_prototype name style =
2234 (match fst style with
2237 | RHive -> pr "$h = "
2238 | RSize -> pr "$size = "
2240 | RNodeNotFound -> pr "$node = "
2241 | RNodeList -> pr "@nodes = "
2242 | RValue -> pr "$value = "
2243 | RValueList -> pr "@values = "
2244 | RString -> pr "$string = "
2245 | RStringList -> pr "@strings = "
2246 | RLenType -> pr "($type, $len) = "
2247 | RLenTypeVal -> pr "($type, $data) = "
2248 | RInt32 -> pr "$int32 = "
2249 | RInt64 -> pr "$int64 = "
2252 let args = List.tl (snd style) in
2254 (* AUnusedFlags is dropped in the bindings. *)
2255 let args = List.filter ((<>) AUnusedFlags) args in
2259 let comma = ref false in
2262 if !comma then pr ", "; comma := true;
2267 | AString n -> pr "$%s" n
2268 | AStringNullable n -> pr "[$%s|undef]" n
2269 | AOpenFlags -> pr "[flags]"
2270 | AUnusedFlags -> assert false
2271 | ASetValues -> pr "\\@values"
2272 | ASetValue -> pr "$val"
2277 and generate_perl_xs () =
2278 generate_header CStyle LGPLv2plus;
2281 #include \"EXTERN.h\"
2287 #include <inttypes.h>
2290 my_newSVll(long long val) {
2291 #ifdef USE_64_BIT_ALL
2292 return newSViv(val);
2296 len = snprintf(buf, 100, \"%%\" PRId64, val);
2297 return newSVpv(buf, len);
2303 my_newSVull(unsigned long long val) {
2304 #ifdef USE_64_BIT_ALL
2305 return newSVuv(val);
2309 len = snprintf(buf, 100, \"%%\" PRIu64, val);
2310 return newSVpv(buf, len);
2316 /* http://www.perlmonks.org/?node_id=680842 */
2318 XS_unpack_charPtrPtr (SV *arg) {
2323 if (!arg || !SvOK (arg) || !SvROK (arg) || SvTYPE (SvRV (arg)) != SVt_PVAV)
2324 croak (\"array reference expected\");
2326 av = (AV *)SvRV (arg);
2327 ret = malloc ((av_len (av) + 1 + 1) * sizeof (char *));
2329 croak (\"malloc failed\");
2331 for (i = 0; i <= av_len (av); i++) {
2332 SV **elem = av_fetch (av, i, 0);
2334 if (!elem || !*elem)
2335 croak (\"missing element in list\");
2337 ret[i] = SvPV_nolen (*elem);
2346 /* Handle set_values parameter. */
2347 typedef struct pl_set_values {
2349 hive_set_value *values;
2352 static pl_set_values
2353 unpack_pl_set_values (SV *sv)
2359 if (!sv || !SvOK (sv) || !SvROK (sv) || SvTYPE (SvRV (sv)) != SVt_PVAV)
2360 croak (\"array reference expected\");
2362 av = (AV *)SvRV(sv);
2363 ret.nr_values = av_len (av) + 1;
2364 ret.values = malloc (ret.nr_values * sizeof (hive_set_value));
2366 croak (\"malloc failed\");
2368 for (i = 0; i <= av_len (av); i++) {
2369 SV **hvp = av_fetch (av, i, 0);
2371 if (!hvp || !*hvp || !SvROK (*hvp) || SvTYPE (SvRV (*hvp)) != SVt_PVHV)
2372 croak (\"missing element in list or not a hash ref\");
2374 HV *hv = (HV *)SvRV(*hvp);
2377 svp = hv_fetch (hv, \"key\", 3, 0);
2379 croak (\"missing 'key' in hash\");
2380 ret.values[i].key = SvPV_nolen (*svp);
2382 svp = hv_fetch (hv, \"t\", 1, 0);
2384 croak (\"missing 't' in hash\");
2385 ret.values[i].t = SvIV (*svp);
2387 svp = hv_fetch (hv, \"value\", 5, 0);
2389 croak (\"missing 'value' in hash\");
2390 ret.values[i].value = SvPV (*svp, ret.values[i].len);
2396 static hive_set_value *
2397 unpack_set_value (SV *sv)
2399 hive_set_value *ret;
2401 if (!sv || !SvROK (sv) || SvTYPE (SvRV (sv)) != SVt_PVHV)
2402 croak (\"not a hash ref\");
2404 ret = malloc (sizeof (hive_set_value));
2406 croak (\"malloc failed\");
2408 HV *hv = (HV *)SvRV(sv);
2411 svp = hv_fetch (hv, \"key\", 3, 0);
2413 croak (\"missing 'key' in hash\");
2414 ret->key = SvPV_nolen (*svp);
2416 svp = hv_fetch (hv, \"t\", 1, 0);
2418 croak (\"missing 't' in hash\");
2419 ret->t = SvIV (*svp);
2421 svp = hv_fetch (hv, \"value\", 5, 0);
2423 croak (\"missing 'value' in hash\");
2424 ret->value = SvPV (*svp, ret->len);
2429 MODULE = Win::Hivex PACKAGE = Win::Hivex
2434 _open (filename, flags)
2438 RETVAL = hivex_open (filename, flags);
2440 croak (\"hivex_open: %%s: %%s\", filename, strerror (errno));
2448 if (hivex_close (h) == -1)
2449 croak (\"hivex_close: %%s\", strerror (errno));
2454 fun (name, style, _, longdesc) ->
2455 (* The close and open calls are handled specially above. *)
2456 if fst style <> RErrDispose && List.hd (snd style) = AHive then (
2457 (match fst style with
2458 | RErr -> pr "void\n"
2459 | RErrDispose -> failwith "perl bindings cannot handle a call which disposes of the handle"
2460 | RHive -> failwith "perl bindings cannot handle a call which returns a handle"
2465 | RString -> pr "SV *\n"
2470 | RLenTypeVal -> pr "void\n"
2471 | RInt32 -> pr "SV *\n"
2472 | RInt64 -> pr "SV *\n"
2475 (* Call and arguments. *)
2477 filter_map (function
2478 | AUnusedFlags -> None
2479 | arg -> Some (name_of_argt arg)) (snd style) in
2483 | AUnusedFlags -> "0"
2484 | ASetValues -> "values.nr_values, values.values"
2485 | arg -> name_of_argt arg) (snd style) in
2487 pr "%s (%s)\n" name (String.concat ", " perl_params);
2498 | AStringNullable n ->
2499 (* http://www.perlmonks.org/?node_id=554277 *)
2500 pr " char *%s = SvOK(ST(%d)) ? SvPV_nolen(ST(%d)) : NULL;\n" n i i
2503 | AUnusedFlags -> ()
2505 pr " pl_set_values values = unpack_pl_set_values (ST(%d));\n" i
2507 pr " hive_set_value *val = unpack_set_value (ST(%d));\n" i
2514 pr " free (values.values);\n"
2517 | AHive | ANode _ | AValue _ | AString _ | AStringNullable _
2518 | AOpenFlags | AUnusedFlags -> ()
2523 (match fst style with
2528 pr " r = hivex_%s (%s);\n"
2529 name (String.concat ", " c_params);
2531 pr " if (r == -1)\n";
2532 pr " croak (\"%%s: %%s\", \"%s\", strerror (errno));\n"
2535 | RErrDispose -> assert false
2536 | RHive -> assert false
2542 pr " /* hive_node_h = hive_value_h = size_t so we cheat\n";
2543 pr " here to simplify the generator */\n";
2546 pr " r = hivex_%s (%s);\n"
2547 name (String.concat ", " c_params);
2549 pr " if (r == 0)\n";
2550 pr " croak (\"%%s: %%s\", \"%s\", strerror (errno));\n"
2552 pr " RETVAL = newSViv (r);\n";
2558 pr " hive_node_h r;\n";
2561 pr " r = hivex_%s (%s);\n"
2562 name (String.concat ", " c_params);
2564 pr " if (r == 0 && errno != 0)\n";
2565 pr " croak (\"%%s: %%s\", \"%s\", strerror (errno));\n"
2567 pr " if (r == 0)\n";
2568 pr " RETVAL = &PL_sv_undef;\n";
2570 pr " RETVAL = newSViv (r);\n";
2578 pr " r = hivex_%s (%s);\n"
2579 name (String.concat ", " c_params);
2581 pr " if (r == NULL)\n";
2582 pr " croak (\"%%s: %%s\", \"%s\", strerror (errno));\n"
2584 pr " RETVAL = newSVpv (r, 0);\n";
2595 pr " r = hivex_%s (%s);\n"
2596 name (String.concat ", " c_params);
2598 pr " if (r == NULL)\n";
2599 pr " croak (\"%%s: %%s\", \"%s\", strerror (errno));\n"
2601 pr " for (n = 0; r[n] != 0; ++n) /**/;\n";
2602 pr " EXTEND (SP, n);\n";
2603 pr " for (i = 0; i < n; ++i)\n";
2604 pr " PUSHs (sv_2mortal (newSViv (r[i])));\n";
2612 pr " r = hivex_%s (%s);\n"
2613 name (String.concat ", " c_params);
2615 pr " if (r == NULL)\n";
2616 pr " croak (\"%%s: %%s\", \"%s\", strerror (errno));\n"
2618 pr " for (n = 0; r[n] != NULL; ++n) /**/;\n";
2619 pr " EXTEND (SP, n);\n";
2620 pr " for (i = 0; i < n; ++i) {\n";
2621 pr " PUSHs (sv_2mortal (newSVpv (r[i], 0)));\n";
2622 pr " free (r[i]);\n";
2629 pr " size_t len;\n";
2630 pr " hive_type type;\n";
2632 pr " r = hivex_%s (%s, &type, &len);\n"
2633 name (String.concat ", " c_params);
2635 pr " if (r == -1)\n";
2636 pr " croak (\"%%s: %%s\", \"%s\", strerror (errno));\n"
2638 pr " EXTEND (SP, 2);\n";
2639 pr " PUSHs (sv_2mortal (newSViv (type)));\n";
2640 pr " PUSHs (sv_2mortal (newSViv (len)));\n";
2645 pr " size_t len;\n";
2646 pr " hive_type type;\n";
2648 pr " r = hivex_%s (%s, &type, &len);\n"
2649 name (String.concat ", " c_params);
2651 pr " if (r == NULL)\n";
2652 pr " croak (\"%%s: %%s\", \"%s\", strerror (errno));\n"
2654 pr " EXTEND (SP, 2);\n";
2655 pr " PUSHs (sv_2mortal (newSViv (type)));\n";
2656 pr " PUSHs (sv_2mortal (newSVpvn (r, len)));\n";
2664 pr " r = hivex_%s (%s);\n"
2665 name (String.concat ", " c_params);
2667 pr " if (r == -1 && errno != 0)\n";
2668 pr " croak (\"%%s: %%s\", \"%s\", strerror (errno));\n"
2670 pr " RETVAL = newSViv (r);\n";
2679 pr " r = hivex_%s (%s);\n"
2680 name (String.concat ", " c_params);
2682 pr " if (r == -1 && errno != 0)\n";
2683 pr " croak (\"%%s: %%s\", \"%s\", strerror (errno));\n"
2685 pr " RETVAL = my_newSVll (r);\n";
2693 and generate_python_c () =
2694 generate_header CStyle LGPLv2plus;
2699 #define PY_SSIZE_T_CLEAN 1
2702 #if PY_VERSION_HEX < 0x02050000
2703 typedef int Py_ssize_t;
2704 #define PY_SSIZE_T_MAX INT_MAX
2705 #define PY_SSIZE_T_MIN INT_MIN
2712 #include \"hivex.h\"
2714 #ifndef HAVE_PYCAPSULE_NEW
2722 get_handle (PyObject *obj)
2725 assert (obj != Py_None);
2726 #ifndef HAVE_PYCAPSULE_NEW
2727 return ((Pyhivex_Object *) obj)->h;
2729 return (hive_h *) PyCapsule_GetPointer(obj, \"hive_h\");
2734 put_handle (hive_h *h)
2737 #ifndef HAVE_PYCAPSULE_NEW
2739 PyCObject_FromVoidPtrAndDesc ((void *) h, (char *) \"hive_h\", NULL);
2741 return PyCapsule_New ((void *) h, \"hive_h\", NULL);
2745 /* This returns pointers into the Python objects, which should
2749 get_value (PyObject *v, hive_set_value *ret)
2752 #ifndef HAVE_PYSTRING_ASSTRING
2756 obj = PyDict_GetItemString (v, \"key\");
2758 PyErr_SetString (PyExc_RuntimeError, \"no 'key' element in dictionary\");
2761 #ifdef HAVE_PYSTRING_ASSTRING
2762 ret->key = PyString_AsString (obj);
2764 bytes = PyUnicode_AsUTF8String (obj);
2765 ret->key = PyBytes_AS_STRING (bytes);
2768 obj = PyDict_GetItemString (v, \"t\");
2770 PyErr_SetString (PyExc_RuntimeError, \"no 't' element in dictionary\");
2773 ret->t = PyLong_AsLong (obj);
2775 obj = PyDict_GetItemString (v, \"value\");
2777 PyErr_SetString (PyExc_RuntimeError, \"no 'value' element in dictionary\");
2780 #ifdef HAVE_PYSTRING_ASSTRING
2781 ret->value = PyString_AsString (obj);
2782 ret->len = PyString_Size (obj);
2784 bytes = PyUnicode_AsUTF8String (obj);
2785 ret->value = PyBytes_AS_STRING (bytes);
2786 ret->len = PyBytes_GET_SIZE (bytes);
2792 typedef struct py_set_values {
2794 hive_set_value *values;
2798 get_values (PyObject *v, py_set_values *ret)
2803 if (!PyList_Check (v)) {
2804 PyErr_SetString (PyExc_RuntimeError, \"expecting a list parameter\");
2808 slen = PyList_Size (v);
2810 PyErr_SetString (PyExc_RuntimeError, \"get_string_list: PyList_Size failure\");
2813 len = (size_t) slen;
2814 ret->nr_values = len;
2815 ret->values = malloc (len * sizeof (hive_set_value));
2817 PyErr_SetString (PyExc_RuntimeError, strerror (errno));
2821 for (i = 0; i < len; ++i) {
2822 if (get_value (PyList_GetItem (v, i), &(ret->values[i])) == -1) {
2832 put_string_list (char * const * const argv)
2837 for (argc = 0; argv[argc] != NULL; ++argc)
2840 list = PyList_New (argc);
2841 for (i = 0; i < argc; ++i) {
2842 #ifdef HAVE_PYSTRING_ASSTRING
2843 PyList_SetItem (list, i, PyString_FromString (argv[i]));
2845 PyList_SetItem (list, i, PyUnicode_FromString (argv[i]));
2853 free_strings (char **argv)
2857 for (argc = 0; argv[argc] != NULL; ++argc)
2862 /* Since hive_node_t is the same as hive_value_t this also works for values. */
2864 put_node_list (hive_node_h *nodes)
2869 for (argc = 0; nodes[argc] != 0; ++argc)
2872 list = PyList_New (argc);
2873 for (i = 0; i < argc; ++i)
2874 PyList_SetItem (list, i, PyLong_FromLongLong ((long) nodes[i]));
2880 put_len_type (size_t len, hive_type t)
2882 PyObject *r = PyTuple_New (2);
2883 PyTuple_SetItem (r, 0, PyLong_FromLong ((long) t));
2884 PyTuple_SetItem (r, 1, PyLong_FromLongLong ((long) len));
2889 put_val_type (char *val, size_t len, hive_type t)
2891 PyObject *r = PyTuple_New (2);
2892 PyTuple_SetItem (r, 0, PyLong_FromLong ((long) t));
2893 #ifdef HAVE_PYSTRING_ASSTRING
2894 PyTuple_SetItem (r, 1, PyString_FromStringAndSize (val, len));
2896 PyTuple_SetItem (r, 1, PyBytes_FromStringAndSize (val, len));
2903 (* Generate functions. *)
2905 fun (name, style, _, longdesc) ->
2906 pr "static PyObject *\n";
2907 pr "py_hivex_%s (PyObject *self, PyObject *args)\n" name;
2909 pr " PyObject *py_r;\n";
2912 match fst style with
2913 | RErr -> pr " int r;\n"; "-1"
2914 | RErrDispose -> pr " int r;\n"; "-1"
2915 | RHive -> pr " hive_h *r;\n"; "NULL"
2916 | RSize -> pr " size_t r;\n"; "0"
2917 | RNode -> pr " hive_node_h r;\n"; "0"
2920 pr " hive_node_h r;\n";
2922 | RNodeList -> pr " hive_node_h *r;\n"; "NULL"
2923 | RValue -> pr " hive_value_h r;\n"; "0"
2924 | RValueList -> pr " hive_value_h *r;\n"; "NULL"
2925 | RString -> pr " char *r;\n"; "NULL"
2926 | RStringList -> pr " char **r;\n"; "NULL"
2929 pr " size_t len;\n";
2930 pr " hive_type t;\n";
2934 pr " size_t len;\n";
2935 pr " hive_type t;\n";
2944 "-1 && errno != 0" in
2946 (* Call and arguments. *)
2949 | AUnusedFlags -> "0"
2950 | ASetValues -> "values.nr_values, values.values"
2951 | ASetValue -> "&val"
2952 | arg -> name_of_argt arg) (snd style) in
2954 match fst style with
2955 | RLenType | RLenTypeVal -> c_params @ ["&t"; "&len"]
2962 pr " PyObject *py_h;\n"
2967 | AStringNullable n ->
2971 | AUnusedFlags -> ()
2973 pr " py_set_values values;\n";
2974 pr " PyObject *py_values;\n"
2976 pr " hive_set_value val;\n";
2977 pr " PyObject *py_val;\n"
2982 (* Convert the required parameters. *)
2983 pr " if (!PyArg_ParseTuple (args, (char *) \"";
2993 | AStringNullable n ->
2997 | AUnusedFlags -> ()
3003 pr ":hivex_%s\"" name;
3013 | AStringNullable n ->
3017 | AUnusedFlags -> ()
3025 pr " return NULL;\n";
3027 (* Convert some Python argument types to C. *)
3031 pr " h = get_handle (py_h);\n"
3037 | AUnusedFlags -> ()
3039 pr " if (get_values (py_values, &values) == -1)\n";
3040 pr " return NULL;\n"
3042 pr " if (get_value (py_val, &val) == -1)\n";
3043 pr " return NULL;\n"
3046 (* Call the C function. *)
3047 pr " r = hivex_%s (%s);\n" name (String.concat ", " c_params);
3049 (* Free up arguments. *)
3052 | AHive | ANode _ | AValue _
3053 | AString _ | AStringNullable _
3054 | AOpenFlags | AUnusedFlags -> ()
3056 pr " free (values.values);\n"
3060 (* Check for errors from C library. *)
3061 pr " if (r == %s) {\n" error_code;
3062 pr " PyErr_SetString (PyExc_RuntimeError,\n";
3063 pr " strerror (errno));\n";
3064 pr " return NULL;\n";
3068 (* Convert return value to Python. *)
3069 (match fst style with
3072 pr " Py_INCREF (Py_None);\n";
3073 pr " py_r = Py_None;\n"
3075 pr " py_r = put_handle (r);\n"
3078 pr " py_r = PyLong_FromLongLong (r);\n"
3081 pr " py_r = PyLong_FromLongLong (r);\n";
3083 pr " Py_INCREF (Py_None);\n";
3084 pr " py_r = Py_None;\n";
3088 pr " py_r = put_node_list (r);\n";
3091 pr " py_r = PyLong_FromLongLong (r);\n"
3093 pr "#ifdef HAVE_PYSTRING_ASSTRING\n";
3094 pr " py_r = PyString_FromString (r);\n";
3096 pr " py_r = PyUnicode_FromString (r);\n";
3100 pr " py_r = put_string_list (r);\n";
3101 pr " free_strings (r);\n"
3103 pr " py_r = put_len_type (len, t);\n"
3105 pr " py_r = put_val_type (r, len, t);\n";
3108 pr " py_r = PyLong_FromLong ((long) r);\n"
3110 pr " py_r = PyLong_FromLongLong (r);\n"
3112 pr " return py_r;\n";
3117 (* Table of functions. *)
3118 pr "static PyMethodDef methods[] = {\n";
3120 fun (name, _, _, _) ->
3121 pr " { (char *) \"%s\", py_hivex_%s, METH_VARARGS, NULL },\n"
3124 pr " { NULL, NULL, 0, NULL }\n";
3128 (* Init function. *)
3130 #if PY_MAJOR_VERSION >= 3
3131 static struct PyModuleDef moduledef = {
3132 PyModuleDef_HEAD_INIT,
3133 \"libhivexmod\", /* m_name */
3134 \"hivex module\", /* m_doc */
3136 methods, /* m_methods */
3137 NULL, /* m_reload */
3138 NULL, /* m_traverse */
3149 #if PY_MAJOR_VERSION >= 3
3150 m = PyModule_Create (&moduledef);
3152 m = Py_InitModule ((char *) \"libhivexmod\", methods);
3155 return m; /* m might be NULL if module init failed */
3158 #if PY_MAJOR_VERSION >= 3
3160 PyInit_libhivexmod (void)
3162 return moduleinit ();
3166 initlibhivexmod (void)
3168 (void) moduleinit ();
3173 and generate_python_py () =
3174 generate_header HashStyle LGPLv2plus;
3177 \"\"\"Python bindings for hivex
3180 h = hivex.Hivex (filename)
3182 The hivex module provides Python bindings to the hivex API for
3183 examining and modifying Windows Registry 'hive' files.
3185 Read the hivex(3) man page to find out how to use the API.
3191 \"\"\"Instances of this class are hivex API handles.\"\"\"
3193 def __init__ (self, filename";
3196 fun (_, flag, _) -> pr ", %s = False" (String.lowercase flag)
3200 \"\"\"Create a new hivex handle.\"\"\"
3205 fun (n, flag, description) ->
3206 pr " # %s\n" description;
3207 pr " if %s: flags += %d\n" (String.lowercase flag) n
3210 pr " self._o = libhivexmod.open (filename, flags)
3213 libhivexmod.close (self._o)
3218 fun (name, style, shortdesc, _) ->
3219 (* The close and open calls are handled specially above. *)
3220 if fst style <> RErrDispose && List.hd (snd style) = AHive then (
3221 let args = List.tl (snd style) in
3222 let args = List.filter (
3223 function AOpenFlags | AUnusedFlags -> false
3227 pr " def %s (self" name;
3228 List.iter (fun arg -> pr ", %s" (name_of_argt arg)) args;
3230 pr " \"\"\"%s\"\"\"\n" shortdesc;
3231 pr " return libhivexmod.%s (self._o" name;
3236 | AHive -> assert false
3237 | ANode n | AValue n
3238 | AString n | AStringNullable n -> pr "%s" n
3240 | AUnusedFlags -> assert false
3241 | ASetValues -> pr "values"
3242 | ASetValue -> pr "val"
3249 and generate_ruby_c () =
3250 generate_header CStyle LGPLv2plus;
3259 #include \"hivex.h\"
3261 #include \"extconf.h\"
3263 /* For Ruby < 1.9 */
3265 #define RARRAY_LEN(r) (RARRAY((r))->len)
3269 #define RSTRING_LEN(r) (RSTRING((r))->len)
3273 #define RSTRING_PTR(r) (RSTRING((r))->ptr)
3276 static VALUE m_hivex; /* hivex module */
3277 static VALUE c_hivex; /* hive_h handle */
3278 static VALUE e_Error; /* used for all errors */
3281 ruby_hivex_free (void *hvp)
3290 get_value (VALUE valv, hive_set_value *val)
3292 VALUE key = rb_hash_lookup (valv, ID2SYM (rb_intern (\"key\")));
3293 VALUE type = rb_hash_lookup (valv, ID2SYM (rb_intern (\"type\")));
3294 VALUE value = rb_hash_lookup (valv, ID2SYM (rb_intern (\"value\")));
3296 val->key = StringValueCStr (key);
3297 val->t = NUM2ULL (type);
3298 val->len = RSTRING_LEN (value);
3299 val->value = RSTRING_PTR (value);
3302 static hive_set_value *
3303 get_values (VALUE valuesv, size_t *nr_values)
3306 hive_set_value *ret;
3308 *nr_values = RARRAY_LEN (valuesv);
3309 ret = malloc (sizeof (*ret) * *nr_values);
3313 for (i = 0; i < *nr_values; ++i) {
3314 VALUE v = rb_ary_entry (valuesv, i);
3315 get_value (v, &ret[i]);
3324 fun (name, (ret, args), shortdesc, longdesc) ->
3326 (* Generate rdoc. *)
3327 let doc = replace_str longdesc "C<hivex_" "C<h." in
3328 let doc = pod2text ~width:60 name doc in
3329 let doc = String.concat "\n * " doc in
3330 let doc = trim doc in
3334 | AHive :: args -> "h." ^ name, args
3335 | args -> "Hivex::" ^ name, args in
3336 let args = filter_map (
3338 | AUnusedFlags -> None
3339 | args -> Some (name_of_argt args)
3341 let args = String.concat ", " args in
3345 | RErr | RErrDispose -> "nil"
3346 | RHive -> "Hivex::Hivex"
3347 | RSize | RNode | RNodeNotFound -> "integer"
3348 | RNodeList -> "list"
3349 | RValue -> "integer"
3350 | RValueList -> "list"
3351 | RString -> "string"
3352 | RStringList -> "list"
3353 | RLenType -> "hash"
3354 | RLenTypeVal -> "hash"
3355 | RInt32 -> "integer"
3356 | RInt64 -> "integer" in
3367 * (For the C API documentation for this function, see
3368 * +hivex_%s+[http://libguestfs.org/hivex.3.html#hivex_%s]).
3370 " call args ret shortdesc doc name name in
3372 (* Generate the function. *)
3373 pr "static VALUE\n";
3374 pr "ruby_hivex_%s (" name;
3377 (* If the first argument is not AHive, then this is a module-level
3378 * function, and Ruby passes an implicit module argument which we
3379 * must ignore. Otherwise the first argument is the hive handle.
3383 | AHive :: args -> pr "VALUE hv"; args
3384 | args -> pr "VALUE modulev"; args in
3387 | AUnusedFlags -> ()
3389 pr ", VALUE %sv" (name_of_argt arg)
3399 pr " Data_Get_Struct (hv, hive_h, h);\n";
3401 pr " rb_raise (rb_eArgError, \"%%s: used handle after closing it\",\n";
3402 pr " \"%s\");\n" name;
3404 pr " hive_node_h %s = NUM2ULL (%sv);\n" n n
3406 pr " hive_value_h %s = NUM2ULL (%sv);\n" n n
3408 pr " const char *%s = StringValueCStr (%sv);\n" n n;
3409 | AStringNullable n ->
3410 pr " const char *%s =\n" n;
3411 pr " !NIL_P (%sv) ? StringValueCStr (%sv) : NULL;\n" n n
3413 pr " int flags = 0;\n";
3416 pr " if (RTEST (rb_hash_lookup (flagsv, ID2SYM (rb_intern (\"%s\")))))\n"
3417 (String.lowercase flag);
3418 pr " flags += %d;\n" n
3420 | AUnusedFlags -> ()
3422 pr " size_t nr_values;\n";
3423 pr " hive_set_value *values;\n";
3424 pr " values = get_values (valuesv, &nr_values);\n"
3426 pr " hive_set_value val;\n";
3427 pr " get_value (valv, &val);\n"
3433 | RErr -> pr " int r;\n"; "-1"
3434 | RErrDispose -> pr " int r;\n"; "-1"
3435 | RHive -> pr " hive_h *r;\n"; "NULL"
3436 | RSize -> pr " size_t r;\n"; "0"
3437 | RNode -> pr " hive_node_h r;\n"; "0"
3440 pr " hive_node_h r;\n";
3442 | RNodeList -> pr " hive_node_h *r;\n"; "NULL"
3443 | RValue -> pr " hive_value_h r;\n"; "0"
3444 | RValueList -> pr " hive_value_h *r;\n"; "NULL"
3445 | RString -> pr " char *r;\n"; "NULL"
3446 | RStringList -> pr " char **r;\n"; "NULL"
3449 pr " size_t len;\n";
3450 pr " hive_type t;\n";
3454 pr " size_t len;\n";
3455 pr " hive_type t;\n";
3464 "-1 && errno != 0" in
3469 | ASetValues -> ["nr_values"; "values"]
3470 | ASetValue -> ["&val"]
3471 | AUnusedFlags -> ["0"]
3472 | arg -> [name_of_argt arg]) args in
3475 | RLenType | RLenTypeVal -> c_params @ [["&t"; "&len"]]
3477 let c_params = List.concat c_params in
3479 pr " r = hivex_%s (%s" name (List.hd c_params);
3480 List.iter (pr ", %s") (List.tl c_params);
3484 (* Dispose of the hive handle (even if hivex_close returns error). *)
3487 pr " /* So we don't double-free in the finalizer. */\n";
3488 pr " DATA_PTR (hv) = NULL;\n";
3501 | AUnusedFlags -> ()
3503 pr " free (values);\n"
3507 (* Check for errors from C library. *)
3508 pr " if (r == %s)\n" error_code;
3509 pr " rb_raise (e_Error, \"%%s\", strerror (errno));\n";
3513 | RErr | RErrDispose ->
3514 pr " return Qnil;\n"
3516 pr " return Data_Wrap_Struct (c_hivex, NULL, ruby_hivex_free, r);\n"
3521 pr " return ULL2NUM (r);\n"
3523 pr " return INT2NUM (r);\n"
3526 pr " return ULL2NUM (r);\n";
3528 pr " return Qnil;\n"
3531 pr " size_t i, len = 0;\n";
3532 pr " for (i = 0; r[i] != 0; ++i) len++;\n";
3533 pr " VALUE rv = rb_ary_new2 (len);\n";
3534 pr " for (i = 0; r[i] != 0; ++i)\n";
3535 pr " rb_ary_push (rv, ULL2NUM (r[i]));\n";
3539 pr " VALUE rv = rb_str_new2 (r);\n";
3543 pr " size_t i, len = 0;\n";
3544 pr " for (i = 0; r[i] != NULL; ++i) len++;\n";
3545 pr " VALUE rv = rb_ary_new2 (len);\n";
3546 pr " for (i = 0; r[i] != NULL; ++i) {\n";
3547 pr " rb_ary_push (rv, rb_str_new2 (r[i]));\n";
3548 pr " free (r[i]);\n";
3553 pr " VALUE rv = rb_hash_new ();\n";
3554 pr " rb_hash_aset (rv, ID2SYM (rb_intern (\"len\")), INT2NUM (len));\n";
3555 pr " rb_hash_aset (rv, ID2SYM (rb_intern (\"type\")), INT2NUM (t));\n";
3558 pr " VALUE rv = rb_hash_new ();\n";
3559 pr " rb_hash_aset (rv, ID2SYM (rb_intern (\"len\")), INT2NUM (len));\n";
3560 pr " rb_hash_aset (rv, ID2SYM (rb_intern (\"type\")), INT2NUM (t));\n";
3561 pr " rb_hash_aset (rv, ID2SYM (rb_intern (\"value\")), rb_str_new (r, len));\n";
3571 /* Initialize the module. */
3574 m_hivex = rb_define_module (\"Hivex\");
3575 c_hivex = rb_define_class_under (m_hivex, \"Hivex\", rb_cObject);
3576 e_Error = rb_define_class_under (m_hivex, \"Error\", rb_eStandardError);
3578 /* XXX How to pass arguments? */
3580 #ifdef HAVE_RB_DEFINE_ALLOC_FUNC
3581 rb_define_alloc_func (c_hivex, ruby_hivex_open);
3589 fun (name, (_, args), _, _) ->
3590 let args = List.filter (
3592 | AUnusedFlags -> false
3595 let nr_args = List.length args in
3598 pr " rb_define_method (c_hivex, \"%s\",\n" name;
3599 pr " ruby_hivex_%s, %d);\n" name (nr_args-1)
3600 | args -> (* class function *)
3601 pr " rb_define_module_function (m_hivex, \"%s\",\n" name;
3602 pr " ruby_hivex_%s, %d);\n" name nr_args
3607 let output_to filename k =
3608 let filename_new = filename ^ ".new" in
3609 chan := open_out filename_new;
3612 chan := Pervasives.stdout;
3614 (* Is the new file different from the current file? *)
3615 if Sys.file_exists filename && files_equal filename filename_new then
3616 unlink filename_new (* same, so skip it *)
3618 (* different, overwrite old one *)
3619 (try chmod filename 0o644 with Unix_error _ -> ());
3620 rename filename_new filename;
3621 chmod filename 0o444;
3622 printf "written %s\n%!" filename;
3625 let perror msg = function
3626 | Unix_error (err, _, _) ->
3627 eprintf "%s: %s\n" msg (error_message err)
3629 eprintf "%s: %s\n" msg (Printexc.to_string exn)
3634 try openfile "configure.ac" [O_RDWR] 0
3636 | Unix_error (ENOENT, _, _) ->
3638 You are probably running this from the wrong directory.
3639 Run it from the top source directory using the command
3640 generator/generator.ml
3644 perror "open: configure.ac" exn;
3647 (* Acquire a lock so parallel builds won't try to run the generator
3648 * twice at the same time. Subsequent builds will wait for the first
3649 * one to finish. Note the lock is released implicitly when the
3652 (try lockf lock_fd F_LOCK 1
3654 perror "lock: configure.ac" exn;
3659 output_to "lib/hivex.h" generate_c_header;
3660 output_to "lib/hivex.pod" generate_c_pod;
3662 output_to "lib/hivex.syms" generate_linker_script;
3664 output_to "ocaml/hivex.mli" generate_ocaml_interface;
3665 output_to "ocaml/hivex.ml" generate_ocaml_implementation;
3666 output_to "ocaml/hivex_c.c" generate_ocaml_c;
3668 output_to "perl/lib/Win/Hivex.pm" generate_perl_pm;
3669 output_to "perl/Hivex.xs" generate_perl_xs;
3671 output_to "python/hivex.py" generate_python_py;
3672 output_to "python/hivex-py.c" generate_python_c;
3674 output_to "ruby/ext/hivex/_hivex.c" generate_ruby_c;
3676 (* Always generate this file last, and unconditionally. It's used
3677 * by the Makefile to know when we must re-run the generator.
3679 let chan = open_out "generator/stamp-generator" in
3683 printf "generated %d lines of code\n" !lines