[augeas-devel] Windows registry files?

David Lutterkort lutter at redhat.com
Tue Oct 20 13:37:16 UTC 2009


On Mon, 2009-10-19 at 18:25 +0200, David Lutterkort wrote:
> On Mon, 2009-10-19 at 14:54 +0100, Richard W.M. Jones wrote:
> > Transfering this discussion from #augeas, does Augeas support Windows
> > Registry files?
> 
> Almost ;) Attached are a lens and corresponding test that works for your
> user.reg and system.reg. The software.reg fails for at least a couple of
> reasons:
> 
>       * The lens doesn't handle DOS line endings
>       * sofwtare.reg contains braindead entries like ""foo bar"
>         baz" (i.e., w/o quoting the inner double quotes in any way)
> 
> I'll look into fixing these up and getting the lens to work on the real
> w2k registries tomorrow.

Here another cut at it - this seems to be complete as far as I can tell.
The main changes from yesterday's version:

      * Accept DOS or Unix line endings
      * store individual entries 'foo=bar' as { "entry" { "key" =
        "foo" } { "value" = "bar" } } - this is necessary since keys in
        the file can contain '/' and can therefore not be used as the
        label of tree nodes. It makes the tree more bloated, but is
        unavoidable

To automate [1], this prints the current value of the path setting
(assuming wine.aug is in /tmp/lenses):

        augtool -I /tmp/lenses --noautoload <<EOF
        set /augeas/load/Reg/lens Wine.lns
        set /augeas/load/Reg/incl /tmp/reg/system.reg
        load
        match "/files/tmp/reg/system.reg/section[. = 'System\\CurrentControlSet\\Control\\Session Manager\\Environment']/entry[key = 'PATH']/value"
        EOF

and a similar snippet can be used to modify the value.

I'd like to commit the Wine lens as soon as somebody (Rich) tells me
that it works for them, too.

David
-------------- next part --------------
module Test_wine =

let s1 = "WINE REGISTRY Version 2
;; All keys relative to \\Machine

[Software\\Borland\\Database Engine\\Settings\\SYSTEM\\INIT] 1255960431
\"SHAREDMEMLOCATION\"=\"9000\"

[Software\\Classes\\.gif] 1255960430
@=\"giffile\"
\"Content Type\"=\"image/gif\"

[Software\\Classes\\CLSID\\{083863F1-70DE-11D0-BD40-00A0C911CE86}\\Instance\\{1B544C20-FD0B-11CE-8C63-00AA0044B51E}] 1255960430
\"CLSID\"=\"{1B544C20-FD0B-11CE-8C63-00AA0044B51E}\"
\"FilterData\"=hex:02,00,00,00,00,00,60,00,02,00,00,00,00,00,00,00,30,70,69,33,\
  9f,53,00,20,af,0b,a7,70,76,69,64,73,00,00,10,00,80,00,00,aa,00,38,9b,71,00,\
  00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
\"FriendlyName\"=\"AVI Splitter\"

[Software\\Classes\\CLSID\\{0AFACED1-E828-11D1-9187-B532F1E9575D}\\ShellFolder] 1255960429
\"Attributes\"=dword:60010000
\"CallForAttributes\"=dword:f0000000
"

test Wine.lns get s1 =
  { "registry" = "WINE REGISTRY" }
  { "version" = "2" }
  { "#comment" = "All keys relative to \Machine" }
  { }
  { "section" = "Software\Borland\Database Engine\Settings\SYSTEM\INIT"
    { "timestamp" = "1255960431" }
    { "entry"
      { "key" = "SHAREDMEMLOCATION" }
      { "value" = "9000" } }
    { } }
  { "section" = "Software\Classes\.gif"
    { "timestamp" = "1255960430" }
    { "anon" { "value" = "giffile" } }
    { "entry"
      { "key" = "Content Type" }
      { "value" = "image/gif" } }
    { } }
  { "section" = "Software\Classes\CLSID\{083863F1-70DE-11D0-BD40-00A0C911CE86}\Instance\{1B544C20-FD0B-11CE-8C63-00AA0044B51E}"
    { "timestamp" = "1255960430" }
    { "entry"
      { "key" = "CLSID" }
      { "value" = "{1B544C20-FD0B-11CE-8C63-00AA0044B51E}" } }
    { "entry"
      { "key" = "FilterData" }
      { "type" = "hex" }
      { "value" = "02,00,00,00,00,00,60,00,02,00,00,00,00,00,00,00,30,70,69,33,\
  9f,53,00,20,af,0b,a7,70,76,69,64,73,00,00,10,00,80,00,00,aa,00,38,9b,71,00,\
  00,00,00,00,00,00,00,00,00,00,00,00,00,00,00" } }
    { "entry"
      { "key" = "FriendlyName" }
      { "value" = "AVI Splitter" } }
    { } }
  { "section" = "Software\Classes\CLSID\{0AFACED1-E828-11D1-9187-B532F1E9575D}\ShellFolder"
    { "timestamp" = "1255960429" }
    { "entry"
      { "key" = "Attributes" }
      { "type" = "dword" }
      { "value" = "60010000" } }
    { "entry"
      { "key" = "CallForAttributes" }
      { "type" = "dword" }
      { "value" = "f0000000" } } }

(* The weird 'str(2)' type *)
let s2 = "[Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders] 1248768928
\"AppData\"=str(2):\"%USERPROFILE%\\Application Data\"
\"Cache\"=str(2):\"%USERPROFILE%\\Local Settings\\Temporary Internet Files\"
\"Cookies\"=str(2):\"%USERPROFILE%\\Cookies\"
\"Desktop\"=str(2):\"%USERPROFILE%\\Desktop\"
"

test Wine.section get s2 =
  { "section" =
    "Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders"
    { "timestamp" = "1248768928" }
    { "entry"
      { "key" = "AppData" }
      { "type" = "str(2)" }
      { "value" = "%USERPROFILE%\Application Data" } }
    { "entry"
      { "key" = "Cache" }
      { "type" = "str(2)" }
      { "value" = "%USERPROFILE%\Local Settings\Temporary Internet Files" } }
    { "entry"
      { "key" = "Cookies" }
      { "type" = "str(2)" }
      { "value" = "%USERPROFILE%\Cookies" } }
    { "entry"
      { "key" = "Desktop" }
      { "type" = "str(2)" }
      { "value" = "%USERPROFILE%\Desktop" } } }

(* Quoted doublequotes embedded in the string *)
let s3 = "[Software\\Classes\\CLSID\\Shell\\OpenHomePage\\Command] 1248768931
@=\"\\\"C:\\Program Files\\Internet Explorer\\iexplore.exe\\\"\"\n"

test Wine.section get s3 =
  { "section" = "Software\Classes\CLSID\Shell\OpenHomePage\Command"
    { "timestamp" = "1248768931" }
    { "anon"
      { "value" = "\\\"C:\Program Files\Internet Explorer\iexplore.exe\\\"" } } }

(* There's a str(7) type, too *)
let s4 = "[Software\\Microsoft\\Cryptography\\OID\\EncodingType 1\\CertDllVerifyRevocation\\DEFAULT] 1248768928
\"Dll\"=str(7):\"cryptnet.dll\0\"\n"

test Wine.section get s4 =
  { "section" = "Software\Microsoft\Cryptography\OID\EncodingType 1\CertDllVerifyRevocation\DEFAULT"
    { "timestamp" = "1248768928" }
    { "entry"
      { "key" = "Dll" }
      { "type" = "str(7)" }
      { "value" = "cryptnet.dll\0" } } }

(* The Windows Registry Editor header *)
test Wine.header get "Windows Registry Editor Version 5.00\n" =
  { "registry" = "Windows Registry Editor" }
  { "version" = "5.00" }

(* The type hex(7) *)
let s5 = "[HKEY_LOCAL_MACHINE\SOFTWARE\ADFS]
\"Patches\"=hex(7):25,00,77,00,69,00,6e,00,64,00,69,00,72,00,25,00,5c,00,61,00,\
  64,00,66,00,73,00,73,00,70,00,32,00,2e,00,6d,00,73,00,70,00,\
  00,00,00,00,f8
"
test Wine.section get s5 =
  { "section" = "HKEY_LOCAL_MACHINE\SOFTWARE\ADFS"
    { "entry"
      { "key" = "Patches" }
      { "type" = "hex(7)" }
      { "value" = "25,00,77,00,69,00,6e,00,64,00,69,00,72,00,25,00,5c,00,61,00,\
  64,00,66,00,73,00,73,00,70,00,32,00,2e,00,6d,00,73,00,70,00,\
  00,00,00,00,f8" } } }

(* Test DOS line endings *)
let s6 = "Windows Registry Editor Version 5.00\r\n\r
[HKEY_LOCAL_MACHINE\SOFTWARE\C07ft5Y\WinXP]\r
\"@\"=\"\"\r
\r
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes]\r\n"

test Wine.lns get s6 =
  { "registry" = "Windows Registry Editor" }
  { "version" = "5.00" }
  { }
  { "section" = "HKEY_LOCAL_MACHINE\SOFTWARE\C07ft5Y\WinXP"
    { "anon" { "value" = "" } }
    { } }
  { "section" = "HKEY_LOCAL_MACHINE\SOFTWARE\Classes" }

(* Keys can contain '/' *)
let s7 =
"\"application/vnd.ms-xpsdocument\"=\"{c18d5e87-12b4-46a3-ae40-67cf39bc6758}\"\n"

test Wine.entry get s7 =
  { "entry"
    { "key" = "application/vnd.ms-xpsdocument" }
    { "value" = "{c18d5e87-12b4-46a3-ae40-67cf39bc6758}" } }
-------------- next part --------------
(* Lens for the textual representation of Windows registry files, as used *)
(* by wine etc.                                                           *)
(* This is pretty quick and dirty, as it doesn't put a lot of finesse on  *)
(* splitting up values that have structure, e.g. hex arrays or            *)
(* collections of paths.                                                  *)
module Wine =

(* We handle Unix and DOS line endings, though we can only add one or the *)
(* other to new lines. Maybe provide a function to gather that from the   *)
(* current file ?                                                         *)
let eol = del /[ \t]*\r?\n/ "\n"
let comment = [ label "#comment" . del /[ \t]*;;[ \t]*/ ";; "
		         . store /([^ \t\r\n].*[^ \t\r\n]|[^ \t\r\n])/ . eol ]
let empty = [ eol ]
let dels = Util.del_str
let del_ws = Util.del_ws_spc

let header =
  [ label "registry" . store /[a-zA-Z0-9 \t]*[a-zA-Z0-9]/ ] .
    del /[ \t]*Version[ \t]*/ " Version " .
  [ label "version" . store /[0-9.]+/ ] . eol

let qstr =
  let re = /([^"\n]|\\\\.)*/ - /@|"@"/ in    (* " Relax, emacs *)
    dels "\"" . store re . dels "\""

let typed_val =
  ([ label "type" . store /dword|hex(\\([0-9]+\\))?/ ] . dels ":" .
    [ label "value" . store /[a-zA-Z0-9,()]+(\\\\\r?\n[ \t]*[a-zA-Z0-9,]+)*/])
  |([ label "type" . store /str\\([0-9]+\\)/ ] . dels ":" .
      dels "\"" . [ label "value" . store /[^"\n]*/ ] . dels "\"")   (* " Relax, emacs *)

let entry =
  let qkey = [ label "key" . qstr ] in
  let eq = del /[ \t]*=[ \t]*/ "=" in
  let qstore = [ label "value" . qstr ] in
  [ label "entry" . qkey . eq . (qstore|typed_val) . eol ]
  |[label "anon" . del /"?@"?/ "@" . eq . (qstore|typed_val) .eol ]

let section =
  let ts = [ label "timestamp" . store Rx.integer ] in
  [ label "section" . del /[ \t]*\\[/ "[" .
    store /[^]\n]+/ . dels "]" . (del_ws . ts)? . eol .
    (entry|empty|comment)* ]

let lns = header . (empty|comment)* . section*


More information about the augeas-devel mailing list