source: trunk/python/pyregfi/__init__.py @ 224

Last change on this file since 224 was 224, checked in by tim, 13 years ago

added new regfi API function to help manage memory better
fixed reference loop problems in pyregfi

File size: 28.3 KB
Line 
1#!/usr/bin/env python
2
3## @package pyregfi
4# Python interface to the regfi library.
5#
6
7## @mainpage API Documentation
8#
9# The pyregfi module provides a Python interface to the @ref regfi Windows
10# registry library. 
11#
12# The library operates on registry hives, each of which is contained within a
13# single file.  To get started, one must first open the registry hive file with
14# the open() or file() Python built-in functions (or equivalent) and then pass
15# the resulting file object to pyregfi. For example:
16# @code
17# >>> import pyregfi
18# >>> fh = open('/mnt/win/c/WINDOWS/system32/config/system', 'rb')
19# >>> myHive = pyregfi.Hive(fh)
20# @endcode
21#
22# Using this Hive object, one can begin investigating what top-level keys
23# exist by starting with the root Key attribute:
24# @code
25# >>> for key in myHive.root.subkeys:
26# ...   print(key.name)
27# ControlSet001
28# ControlSet003
29# LastKnownGoodRecovery
30# MountedDevices
31# Select
32# Setup
33# WPA
34# @endcode
35#
36# From there, accessing subkeys and values by name is a simple matter of:
37# @code
38# >>> myKey = myHive.root.subkeys['Select']
39# >>> myValue = myKey.values['Current']
40# @endcode
41#
42# The data associated with a Value can be obtained through the fetch_data()
43# method:
44# @code
45# >>> print(myValue.fetch_data())
46# 1
47# @endcode
48#
49# While useful for simple exercises, using the subkeys object for deeply nested
50# paths is not efficient and doesn't make for particularly attractive code. 
51# Instead, a special-purpose HiveIterator class is provided for simplicity of
52# use and fast access to specific known paths:
53# @code
54# >>> myIter = pyregfi.HiveIterator(myHive)
55# >>> myIter.descend(['ControlSet001','Control','NetworkProvider','HwOrder'])
56# >>> myKey = myIter.current_key()
57# >>> print(myKey.values['ProviderOrder'].fetch_data())
58# RDPNP,LanmanWorkstation,WebClient
59# @endcode
60#
61# The first two lines above can be simplified in some "syntactic sugar" provided
62# by the Hive.subtree() method.  Also, as one might expect, the HiveIterator
63# also acts as an iterator, producing keys in a depth-first order.
64# For instance, to traverse all keys under the ControlSet003\\Services key,
65# printing their names as we go, we could do:
66# @code
67# >>> for key in Hive.subtree(['ControlSet003','Services']):
68# >>>   print(key.name)
69# Services
70# Abiosdsk
71# abp480n5
72# Parameters
73# PnpInterface
74# ACPI
75# [...]
76# @endcode
77#
78# Note that "Services" was printed first, since the subtree is traversed as a
79# "preordering depth-first" search starting with the HiveIterator's current_key(). 
80# As one might expect, traversals of subtrees stops when all elements in a
81# specific subtree (and none outside of it) have been traversed.
82#
83# For more information, peruse the various attributes and methods available on
84# the Hive, HiveIterator, Key, Value, and Security classes.
85#
86# @note @ref regfi is a read-only library by design and there
87# are no plans to implement write support.
88#
89# @note At present, pyregfi has been tested with Python versions 2.6 and 3.1
90#
91# @note Developers strive to make pyregfi thread-safe.
92#
93# @note Key and Value names are case-sensitive in regfi and pyregfi
94#
95import sys
96import time
97import weakref
98from pyregfi.structures import *
99
100import ctypes
101import ctypes.util
102
103## An enumeration of registry Value data types
104#
105# @note This is a static class, there is no need to instantiate it.
106#       Just access its attributes directly as DATA_TYPES.SZ, etc
107class DATA_TYPES(object):
108    ## None / Unknown
109    NONE                       =  0
110    ## String
111    SZ                         =  1
112    ## String with %...% expansions
113    EXPAND_SZ                  =  2
114    ## Binary buffer
115    BINARY                     =  3
116    ## 32 bit integer (little endian)
117    DWORD                      =  4 # DWORD, little endian
118    ## 32 bit integer (little endian)
119    DWORD_LE                   =  4
120    ## 32 bit integer (big endian)
121    DWORD_BE                   =  5 # DWORD, big endian
122    ## Symbolic link
123    LINK                       =  6
124    ## List of strings
125    MULTI_SZ                   =  7
126    ## Unknown structure
127    RESOURCE_LIST              =  8
128    ## Unknown structure
129    FULL_RESOURCE_DESCRIPTOR   =  9
130    ## Unknown structure
131    RESOURCE_REQUIREMENTS_LIST = 10
132    ## 64 bit integer
133    QWORD                      = 11 # 64-bit little endian
134
135
136def _buffer2bytearray(char_pointer, length):
137    if length == 0 or char_pointer == None:
138        return None
139   
140    ret_val = bytearray(length)
141    for i in range(0,length):
142        ret_val[i] = char_pointer[i][0]
143
144    return ret_val
145
146
147def _strlist2charss(str_list):
148    ret_val = []
149    for s in str_list:
150        ret_val.append(s.encode('utf-8', 'replace'))
151
152    ret_val = (ctypes.c_char_p*(len(str_list)+1))(*ret_val)
153    # Terminate the char** with a NULL pointer
154    ret_val[-1] = 0
155
156    return ret_val
157
158
159def _charss2strlist(chars_pointer):
160    ret_val = []
161    i = 0
162    s = chars_pointer[i]
163    while s != None:
164        ret_val.append(s.decode('utf-8', 'replace'))
165        i += 1
166        s = chars_pointer[i]
167
168    return ret_val
169
170
171## Retrieves messages produced by regfi during parsing and interpretation
172#
173# The regfi C library may generate log messages stored in a special thread-safe
174# global data structure.  These messages should be retrieved periodically or
175# after each major operation by callers to determine if any errors or warnings
176# should be reported to the user.  Failure to retrieve these could result in
177# excessive memory consumption.
178def GetLogMessages():
179    msgs = regfi.regfi_log_get_str()
180    if msgs == None:
181        return ''
182    return msgs.decode('utf-8')
183
184
185## Abstract class for most objects returned by the library
186class _StructureWrapper(object):
187    _hive = None
188    _base = None
189
190    def __init__(self, hive, base):
191        if not hive:
192            raise Exception("Could not create _StructureWrapper,"
193                            + " hive is NULL.  Current log:\n"
194                            + GetLogMessages())
195        if not base:
196            raise Exception("Could not create _StructureWrapper,"
197                            + " base is NULL.  Current log:\n"
198                            + GetLogMessages())
199        self._hive = hive
200        self._base = base
201
202
203    # Memory management for most regfi structures is taken care of here
204    def __del__(self):
205        regfi.regfi_free_record(self._base)
206
207
208    # Any attribute requests not explicitly defined in subclasses gets passed
209    # to the equivalent REGFI_* structure defined in structures.py
210    def __getattr__(self, name):
211        return getattr(self._base.contents, name)
212
213   
214    ## Test for equality
215    #
216    # Records returned by pyregfi may be compared with one another.  For example:
217    # @code
218    #  >>> key2 = key1.subkeys['child']
219    #  >>> key1 == key2
220    #  False
221    #  >>> key1 != key2
222    #  True
223    #  >>> key1 == key2.get_parent()
224    #  True
225    # @endcode
226    def __eq__(self, other):
227        return (type(self) == type(other)) and (self.offset == other.offset)
228
229
230    def __ne__(self, other):
231        return (not self.__eq__(other))
232
233
234class Key():
235    pass
236
237
238class Value():
239    pass
240
241
242## Registry security record and descriptor
243# XXX: Access to security descriptors not yet implemented
244class Security(_StructureWrapper):
245    pass
246
247## Abstract class for ValueList and SubkeyList
248class _GenericList(object):
249    _hive = None
250    _key_base = None
251    _length = None
252    _current = None
253
254    # implementation-specific functions for SubkeyList and ValueList
255    _fetch_num = None
256    _find_element = None
257    _get_element = None
258    _constructor = None
259
260    def __init__(self, key):
261        if not key:
262            raise Exception("Could not create _GenericList; key is NULL."
263                            + "Current log:\n" + GetLogMessages())
264       
265        if not regfi.regfi_reference_record(key._base):
266            raise Exception("Could not create _GenericList; memory error."
267                            + "Current log:\n" + GetLogMessages())
268        self._key_base = key._base
269        self._length = self._fetch_num(self._key_base)
270        self._hive = key._hive
271
272   
273    def __del__(self):
274        regfi.regfi_free_record(self._key_base)
275   
276
277    ## Length of list
278    def __len__(self):
279        return self._length
280
281
282    ## Retrieves a list element by name
283    #
284    # @return the first element whose name matches, or None if the element
285    #         could not be found
286    def __getitem__(self, name):
287        index = ctypes.c_uint32()
288        if isinstance(name, str):
289            name = name.encode('utf-8')
290
291        if name != None:
292            name = create_string_buffer(bytes(name))
293
294        if self._find_element(self._hive.file, self._key_base, 
295                              name, byref(index)):
296            return self._constructor(self._hive,
297                                     self._get_element(self._hive.file,
298                                                       self._key_base,
299                                                       index))
300        raise KeyError('')
301
302    def get(self, name, default):
303        try:
304            return self[name]
305        except KeyError:
306            return default
307   
308    def __iter__(self):
309        self._current = 0
310        return self
311   
312    def __next__(self):
313        if self._current >= self._length:
314            raise StopIteration('')
315
316        elem = self._get_element(self._hive.file, self._key_base,
317                                 ctypes.c_uint32(self._current))
318        self._current += 1
319        return self._constructor(self._hive, elem)
320   
321    # For Python 2.x
322    next = __next__
323
324
325## The list of subkeys associated with a Key
326#
327# This attribute is both iterable:
328# @code
329#   for k in myKey.subkeys:
330#     ...
331# @endcode
332# and accessible as a dictionary:
333# @code
334#   mySubkey = myKey.subkeys["keyName"]
335# @endcode
336#
337# @note SubkeyLists should never be accessed directly and only exist
338#       in association with a parent Key object.  Do not retain references to
339#       SubkeyLists.  Instead, access them via their parent Key at all times.
340class SubkeyList(_GenericList):
341    _fetch_num = regfi.regfi_fetch_num_subkeys
342    _find_element = regfi.regfi_find_subkey
343    _get_element = regfi.regfi_get_subkey
344
345
346## The list of values associated with a Key
347#
348# This attribute is both iterable:
349# @code
350#   for v in myKey.values:
351#     ...
352# @endcode
353# and accessible as a dictionary:
354# @code
355#   myValue = myKey.values["valueName"]
356# @endcode
357#
358# @note ValueLists should never be accessed directly and only exist
359#       in association with a parent Key object.  Do not retain references to
360#       ValueLists.  Instead, access them via their parent Key at all times.
361class ValueList(_GenericList):
362    _fetch_num = regfi.regfi_fetch_num_values
363    _find_element = regfi.regfi_find_value
364    _get_element = regfi.regfi_get_value
365
366
367## Registry key
368# These represent registry keys (@ref REGFI_NK records) and provide
369# access to their subkeys, values, and other metadata.
370#
371# @note Value instances may provide access to more than the attributes
372#       documented here.  However, undocumented attributes may change over time
373#       and are not officially supported.  If you need access to an attribute
374#       not shown here, see pyregfi.structures.
375class Key(_StructureWrapper):
376    ## A @ref ValueList object representing the list of Values
377    #  stored on this Key
378    values = None
379
380    ## A @ref SubkeyList object representing the list of subkeys
381    #  stored on this Key
382    subkeys = None
383
384    ## The raw Key name as an uninterpreted bytearray
385    name_raw = (b"...")
386   
387    ## The name of the Key as a (unicode) string
388    name = "..."
389   
390    ## The absolute file offset of the Key record's cell in the Hive file
391    offset = 0xCAFEBABE
392
393    ## This Key's last modified time represented as the number of seconds
394    #  since the UNIX epoch in UTC; similar to what time.time() returns
395    modified = 1300000000.123456
396
397    ## The NK record's flags field
398    flags = 0x10110001
399
400    def __init__(self, hive, base):
401        super(Key, self).__init__(hive, base)
402        self.values = ValueList(self)
403        self.subkeys = SubkeyList(self)
404
405    def __getattr__(self, name):
406        if name == "name":
407            ret_val = super(Key, self).__getattr__(name)
408
409            if ret_val == None:
410                ret_val = self.name_raw
411            else:
412                ret_val = ret_val.decode('utf-8', 'replace')
413               
414        elif name == "name_raw":
415            ret_val = super(Key, self).__getattr__(name)
416            length = super(Key, self).__getattr__('name_length')
417            ret_val = _buffer2bytearray(ret_val, length)
418       
419        elif name == "modified":
420            ret_val = regfi.regfi_nt2unix_time(byref(self._base.contents.mtime))
421
422        else:
423            ret_val = super(Key, self).__getattr__(name)
424
425        return ret_val
426
427
428    ## Retrieves the Security properties for this key
429    def fetch_security(self):
430        return Security(self._hive,
431                        regfi.regfi_fetch_sk(self._hive.file, self._base))
432
433
434    ## Retrieves the class name for this key
435    #
436    # Class names are typically stored as UTF-16LE strings, so these are decoded
437    # into proper python (unicode) strings.  However, if this fails, a bytearray
438    # is instead returned containing the raw buffer stored for the class name.
439    #
440    # @return The class name as a string or bytearray.  None if a class name
441    #         doesn't exist or an unrecoverable error occurred during retrieval.
442    def fetch_classname(self):
443        ret_val = None
444        cn_p = regfi.regfi_fetch_classname(self._hive.file, self._base)
445        if cn_p:
446            cn_struct = cn_p.contents
447            if cn_struct.interpreted:
448                ret_val = cn_struct.interpreted.decode('utf-8', 'replace')
449            else:
450                ret_val = _buffer2bytearray(cn_struct.raw,
451                                            cn_struct.size)
452            regfi.regfi_free_record(cn_p)
453
454        return ret_val
455
456
457    ## Retrieves this key's parent key
458    #
459    # @return The parent's Key instance or None if current key is root
460    #         (or an error occured)
461    def get_parent(self):
462        if self.is_root():
463            return None
464        parent_base = regfi.regfi_get_parentkey(self._hive.file, self._base)
465        if parent_base:
466            return Key(self._hive, parent_base)
467        return None
468
469    def is_root(self):
470        return (self._hive.root == self)
471
472
473## Registry value (metadata)
474#
475# These represent registry values (@ref REGFI_VK records) and provide
476# access to their associated data.
477#
478# @note Value instances may provide access to more than the attributes
479#       documented here.  However, undocumented attributes may change over time
480#       and are not officially supported.  If you need access to an attribute
481#       not shown here, see pyregfi.structures.
482class Value(_StructureWrapper):
483    ## The raw Value name as an uninterpreted bytearray
484    name_raw = (b"...")
485   
486    ## The name of the Value as a (unicode) string
487    name = "..."
488   
489    ## The absolute file offset of the Value record's cell in the Hive file
490    offset = 0xCAFEBABE
491
492    ## The length of data advertised in the VK record
493    data_size = 0xCAFEBABE
494
495    ## An integer which represents the data type for this Value's data
496    # Typically this value is one of 12 types defined in @ref DATA_TYPES,
497    # but in some cases (the SAM hive) it may be used for other purposes
498    type = DATA_TYPES.NONE
499
500    ## The VK record's flags field
501    flags = 0x10110001
502
503    ## Retrieves the Value's data according to advertised type
504    #
505    # Data is loaded from its cell(s) and then interpreted based on the data
506    # type recorded in the Value.  It is not uncommon for data to be stored with
507    # the wrong type or even with invalid types.  If you have difficulty
508    # obtaining desired data here, use @ref fetch_raw_data().
509    #
510    # @return The interpreted representation of the data as one of several
511    #         possible Python types, as listed below.  None if any failure
512    #         occurred during extraction or conversion.
513    #
514    # @retval string for SZ, EXPAND_SZ, and LINK
515    # @retval int for DWORD, DWORD_BE, and QWORD
516    # @retval list(string) for MULTI_SZ
517    # @retval bytearray for NONE, BINARY, RESOURCE_LIST,
518    #         FULL_RESOURCE_DESCRIPTOR, and RESOURCE_REQUIREMENTS_LIST
519    #
520    def fetch_data(self):
521        ret_val = None
522        data_p = regfi.regfi_fetch_data(self._hive.file, self._base)
523        if not data_p:
524            return None
525        data_struct = data_p.contents
526
527        if data_struct.interpreted_size == 0:
528            ret_val = None
529        elif data_struct.type in (DATA_TYPES.SZ, DATA_TYPES.EXPAND_SZ, DATA_TYPES.LINK):
530            # Unicode strings
531            ret_val = data_struct.interpreted.string.decode('utf-8', 'replace')
532        elif data_struct.type in (DATA_TYPES.DWORD, DATA_TYPES.DWORD_BE):
533            # 32 bit integers
534            ret_val = data_struct.interpreted.dword
535        elif data_struct.type == DATA_TYPES.QWORD:
536            # 64 bit integers
537            ret_val = data_struct.interpreted.qword
538        elif data_struct.type == DATA_TYPES.MULTI_SZ:
539            ret_val = _charss2strlist(data_struct.interpreted.multiple_string)
540        elif data_struct.type in (DATA_TYPES.NONE, DATA_TYPES.RESOURCE_LIST,
541                                  DATA_TYPES.FULL_RESOURCE_DESCRIPTOR,
542                                  DATA_TYPES.RESOURCE_REQUIREMENTS_LIST,
543                                  DATA_TYPES.BINARY):
544            ret_val = _buffer2bytearray(data_struct.interpreted.none,
545                                        data_struct.interpreted_size)
546
547        regfi.regfi_free_record(data_p)
548        return ret_val
549   
550
551    ## Retrieves raw representation of Value's data
552    #
553    # @return A bytearray containing the data
554    #
555    def fetch_raw_data(self):
556        ret_val = None
557        # XXX: should we load the data without interpretation instead?
558        data_p = regfi.regfi_fetch_data(self._hive.file, self._base)
559        if not data_p:
560            return None
561
562        data_struct = data_p.contents
563        ret_val = _buffer2bytearray(data_struct.raw,
564                                    data_struct.size)
565        regfi.regfi_free_record(data_p)
566        return ret_val
567
568
569    def __getattr__(self, name):
570        ret_val = super(Value, self).__getattr__(name)
571        if name == "name":
572            if ret_val == None:
573                ret_val = self.name_raw
574            else:
575                ret_val = ret_val.decode('utf-8', 'replace')
576
577        elif name == "name_raw":
578            length = super(Value, self).__getattr__('name_length')
579            ret_val = _buffer2bytearray(ret_val, length)
580
581        return ret_val
582
583
584# Avoids chicken/egg class definitions.
585# Also makes for convenient code reuse in these lists' parent classes.
586SubkeyList._constructor = Key
587ValueList._constructor = Value
588
589
590
591## Represents a single registry hive (file)
592class Hive():
593    file = None
594    raw_file = None
595    _root = None
596
597    ## The root Key of this Hive
598    root = None
599
600    ## This Hives's last modified time represented as the number of seconds
601    #  since the UNIX epoch in UTC; similar to what time.time() returns
602    modified = 1300000000.123456
603
604    ## First sequence number
605    sequence1 = 12345678
606
607    ## Second sequence number
608    sequence2 = 12345678
609
610    ## Major version
611    major_version = 1
612
613    ## Minor version
614    minor_version = 5
615
616    # XXX: Possibly add a second or factory function which opens a
617    #      hive file for you
618
619    ## Constructor
620    #
621    # @param fh A Python file object.  The constructor first looks for a valid
622    #           fileno attribute on this object and uses it if possible. 
623    #           Otherwise, the seek and read methods are used for file
624    #           access.
625    #
626    # @note Supplied file must be seekable
627    def __init__(self, fh):
628        try:
629            # The fileno method may not exist, or it may throw an exception
630            # when called if the file isn't backed with a descriptor.
631            if hasattr(fh, 'fileno'):
632                self.file = regfi.regfi_alloc(fh.fileno(), REGFI_ENCODING_UTF8)
633                return
634        except:
635            pass
636       
637        self.raw_file = structures.REGFI_RAW_FILE()
638        self.raw_file.fh = fh
639        self.raw_file.seek = seek_cb_type(self.raw_file.cb_seek)
640        self.raw_file.read = read_cb_type(self.raw_file.cb_read)
641        self.file = regfi.regfi_alloc_cb(self.raw_file, REGFI_ENCODING_UTF8)
642
643
644    def __getattr__(self, name):
645        if name == "root":
646            # XXX: This creates reference loops.  Need to cache better inside regfi
647            #if self._root == None:
648            #    self._root = Key(self, regfi.regfi_get_rootkey(self.file))
649            #return self._root
650            return Key(self, regfi.regfi_get_rootkey(self.file))
651
652        elif name == "modified":
653            return regfi.regfi_nt2unix_time(byref(self._base.contents.mtime))
654
655        return getattr(self.file.contents, name)
656
657   
658    def __del__(self):
659        regfi.regfi_free(self.file)
660        if self.raw_file != None:
661            self.raw_file = None
662
663
664    def __iter__(self):
665        return HiveIterator(self)
666
667
668    ## Creates a @ref HiveIterator initialized at the specified path in
669    #  the hive.
670    #
671    # @param path A list of Key names which represent an absolute path within
672    #             the Hive
673    #
674    # @return A @ref HiveIterator which is positioned at the specified path.
675    #
676    # @exception Exception If the path could not be found/traversed
677    def subtree(self, path):
678        hi = HiveIterator(self)
679        hi.descend(path)
680        return hi
681
682
683## A special purpose iterator for registry hives
684#
685# Iterating over an object of this type causes all keys in a specific
686# hive subtree to be returned in a depth-first manner. These iterators
687# are typically created using the @ref Hive.subtree() function on a @ref Hive
688# object.
689#
690# HiveIterators can also be used to manually traverse up and down a
691# registry hive as they retain information about the current position in
692# the hive, along with which iteration state for subkeys and values for
693# every parent key.  See the @ref up and @ref down methods for more
694# information.
695class HiveIterator():
696    _hive = None
697    _iter = None
698    _iteration_root = None
699
700    def __init__(self, hive):
701        self._iter = regfi.regfi_iterator_new(hive.file, REGFI_ENCODING_UTF8)
702        if self._iter == None:
703            raise Exception("Could not create iterator.  Current log:\n"
704                            + GetLogMessages())
705        self._hive = hive
706       
707    def __getattr__(self, name):
708        return getattr(self.file.contents, name)
709
710    def __del__(self):   
711        regfi.regfi_iterator_free(self._iter)
712
713    def __iter__(self):
714        self._iteration_root = None
715        return self
716
717    def __next__(self):
718        if self._iteration_root == None:
719            self._iteration_root = self.current_key()
720        elif not regfi.regfi_iterator_down(self._iter):
721            up_ret = regfi.regfi_iterator_up(self._iter)
722            while (up_ret and
723                   not regfi.regfi_iterator_next_subkey(self._iter)):
724                if self._iteration_root == self.current_key():
725                    self._iteration_root = None
726                    raise StopIteration('')
727                up_ret = regfi.regfi_iterator_up(self._iter)
728
729            if not up_ret:
730                self._iteration_root = None
731                raise StopIteration('')
732           
733            # XXX: Use non-generic exception
734            if not regfi.regfi_iterator_down(self._iter):
735                raise Exception('Error traversing iterator downward.'+
736                                ' Current log:\n'+ GetLogMessages())
737
738        regfi.regfi_iterator_first_subkey(self._iter)
739        return self.current_key()
740
741    # For Python 2.x
742    next = __next__
743
744    # XXX: Should add sanity checks on some of these traversal functions
745    #      to throw exceptions if a traversal/retrieval *should* have worked
746    #      but failed for some reason.
747
748    ## Descends the iterator to a subkey
749    #
750    # Descends the iterator one level to the current subkey, or a subkey
751    # specified by name.
752    #
753    # @param subkey_name If specified, locates specified subkey by name
754    #                    (via find_subkey()) and descends to it.
755    #
756    # @return True if successful, False otherwise
757    def down(self, subkey_name=None):
758        if subkey_name == None:
759            return regfi.regfi_iterator_down(self._iter)
760        else:
761            if name != None:
762                name = name.encode('utf-8')
763            return (regfi.regfi_iterator_find_subkey(self._iter, name) 
764                    and regfi.regfi_iterator_down(self._iter))
765
766
767    ## Causes the iterator to ascend to the current Key's parent
768    #
769    # @return True if successful, False otherwise
770    #
771    # @note The state of current subkeys and values at this level in the tree
772    #       is lost as a side effect.  That is, if you go up() and then back
773    #       down() again, current_subkey() and current_value() will return
774    #       default selections.
775    def up(self):
776        return regfi.regfi_iterator_up(self._iter)
777
778
779    ## Selects first subkey of current key
780    #
781    # @return A Key instance for the first subkey. 
782    #         None on error or if the current key has no subkeys.
783    def first_subkey(self):
784        if regfi.regfi_iterator_first_subkey(self._iter):
785            return self.current_subkey()
786        return None
787
788
789    ## Selects first value of current Key
790    #
791    # @return A Value instance for the first value. 
792    #         None on error or if the current key has no values.
793    def first_value(self):
794        if regfi.regfi_iterator_first_value(self._iter):
795            return self.current_value()
796        return None
797
798
799    ## Selects the next subkey in the current Key's list
800    #
801    # @return A Key instance for the next subkey.
802    #         None if there are no remaining subkeys or an error occurred.
803    def next_subkey(self):
804        if regfi.regfi_iterator_next_subkey(self._iter):
805            return self.current_subkey()
806        return None
807
808
809    ## Selects the next value in the current Key's list
810   
811    # @return A Value instance for the next value.
812    #         None if there are no remaining values or an error occurred.
813    def next_value(self):
814        if regfi.regfi_iterator_next_value(self._iter):
815            return self.current_value()
816        return None
817
818
819    ## Selects the first subkey which has the specified name
820    #
821    # @return A Key instance for the selected key.
822    #         None if it could not be located or an error occurred.
823    def find_subkey(self, name):
824        if name != None:
825            name = name.encode('utf-8')
826        if regfi.regfi_iterator_find_subkey(self._iter, name):
827            return self.current_subkey()
828        return None
829
830
831    ## Selects the first value which has the specified name
832    #
833    # @return A Value instance for the selected value.
834    #         None if it could not be located or an error occurred.
835    def find_value(self, name):
836        if name != None:
837            name = name.encode('utf-8')
838        if regfi.regfi_iterator_find_value(self._iter, name):
839            return self.current_value()
840        return None
841
842    ## Retrieves the currently selected subkey
843    #
844    # @return A Key instance of the current subkey
845    def current_subkey(self):
846        return Key(self._hive, regfi.regfi_iterator_cur_subkey(self._iter))
847
848    ## Retrieves the currently selected value
849    #
850    # @return A Value instance of the current value
851    def current_value(self):
852        return Value(self._hive, regfi.regfi_iterator_cur_value(self._iter))
853
854    ## Retrieves the current key
855    #
856    # @return A Key instance of the current position of the iterator
857    def current_key(self):
858        return Key(self._hive, regfi.regfi_iterator_cur_key(self._iter))
859
860
861    ## Traverse downward multiple levels
862    #
863    # This is more efficient than calling down() multiple times
864    #
865    # @param path A list of Key names which represent the path to descend
866    #
867    # @exception Exception If path could not be located
868    def descend(self, path):
869        cpath = _strlist2charss(path)
870
871        # XXX: Use non-generic exception
872        if not regfi.regfi_iterator_walk_path(self._iter, cpath):
873            raise Exception('Could not locate path.\n'+GetLogMessages())
874
875
876# Freeing symbols defined for the sake of documentation
877del Value.name,Value.name_raw,Value.offset,Value.data_size,Value.type,Value.flags
878del Key.name,Key.name_raw,Key.offset,Key.modified,Key.flags
879del Hive.root,Hive.modified,Hive.sequence1,Hive.sequence2,Hive.major_version,Hive.minor_version
Note: See TracBrowser for help on using the repository browser.