[Patch] Allow access to /proc/registry/HKEY_PERFORMANCE_DATA

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

[Patch] Allow access to /proc/registry/HKEY_PERFORMANCE_DATA

Christian Franke
The command 'ls /proc/registry/HKEY_PERFORMANCE_DATA' returns garbage,
because the registry functions don't work or work different for this
(pseudo-)key.

This patch fixes the directory listing and allows access to the raw
binary counter data, e.g.

All Global values, except "Costly" values:
xxd /proc/registry/HKEY_PERFORMANCE_DATA/Global

Prozessor time:
xxd /proc/registry/HKEY_PERFORMANCE_DATA/6

The directory listing is fixed, all lists of numbers are accepted as
file names.
The actual counter numbers listed in the key
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib
are not considered yet.

2008-12-19  Christian Franke  <[hidden email]>

        * fhandler_registry.cc (perf_data_files): New table.
        (PERF_DATA_FILE_COUNT): New constant.
        (fhandler_registry::exists): Add check for HKEY_PERFORMANCE_DATA
        value names.
        (fhandler_registry::fstat): For HKEY_PERFORMANCE_DATA, return
        default values only.
        (fhandler_registry::readdir): For HKEY_PERFORMANCE_DATA, list
        names from perf_data_files only.
        (fhandler_registry::fill_filebuf): Use larger buffer to speed up
        access to HKEY_PERFORMANCE_DATA values.  Remove check for possible
        subkey.  Add RegCloseKey ().
        (open_key): Replace goto by break, remove label.  Do not try to
        open subkey of HKEY_PERFORMANCE_DATA.  Add missing RegCloseKey ()
        after open subkey error.



Christian





diff --git a/winsup/cygwin/fhandler_registry.cc b/winsup/cygwin/fhandler_registry.cc
index 9efb2d1..c3c2264 100644
--- a/winsup/cygwin/fhandler_registry.cc
+++ b/winsup/cygwin/fhandler_registry.cc
@@ -75,6 +75,22 @@ static const char *special_dot_files[] =
 static const int SPECIAL_DOT_FILE_COUNT =
   (sizeof (special_dot_files) / sizeof (const char *)) - 1;
 
+/* Value names for HKEY_PERFORMANCE_DATA.
+ *
+ * CAUTION: Never call RegQueryValueEx (HKEY_PERFORMANCE_DATA, "Add", ...).
+ * It WRITES data and may destroy the perfc009.dat file.  Same applies to
+ * name prefixes "Ad" and "A".
+ */
+static const char * const perf_data_files[] =
+{
+  "@",
+  "Costly",
+  "Global"
+};
+
+static const int PERF_DATA_FILE_COUNT =
+  sizeof (perf_data_files) / sizeof (perf_data_files[0]);
+
 static HKEY open_key (const char *name, REGSAM access, DWORD wow64, bool isValue);
 
 /* Return true if char must be encoded.
@@ -273,6 +289,24 @@ fhandler_registry::exists ()
   if (hKey == (HKEY) INVALID_HANDLE_VALUE)
     return 0;
 
+  if (hKey == HKEY_PERFORMANCE_DATA)
+    {
+      /* RegEnumValue () returns garbage for this key.
+         RegQueryValueEx () returns a PERF_DATA_BLOCK even
+         if a value does not contain any counter objects.
+         So allow access to the generic names and to
+         (blank separated) lists of counter numbers.
+         Never allow access to "Add", see above comment.  */
+      for (int i = 0; i < PERF_DATA_FILE_COUNT && file_type == 0; i++)
+ {
+  if (strcasematch (perf_data_files[i], file))
+    file_type = -1;
+ }
+      if (file_type == 0 && !file[strspn (file, " 0123456789")])
+ file_type = -1;
+      goto out;
+    }
+
   if (!val_only && dec_file[0])
     {
       while (ERROR_SUCCESS ==
@@ -376,7 +410,11 @@ fhandler_registry::fstat (struct __stat64 *buf)
  open_key (path, STANDARD_RIGHTS_READ | KEY_QUERY_VALUE, wow64,
   (file_type < 0) ? true : false);
 
-      if (hKey != (HKEY) INVALID_HANDLE_VALUE)
+      if (hKey == HKEY_PERFORMANCE_DATA)
+ /* RegQueryInfoKey () always returns write time 0,
+   RegQueryValueEx () does not return required buffer size.  */
+ ;
+      else if (hKey != (HKEY) INVALID_HANDLE_VALUE)
  {
   FILETIME ftLastWriteTime;
   DWORD subkey_count;
@@ -474,6 +512,18 @@ fhandler_registry::readdir (DIR *dir, dirent *de)
       res = 0;
       goto out;
     }
+  if ((HKEY) dir->__handle == HKEY_PERFORMANCE_DATA)
+    {
+      /* RegEnumValue () returns garbage for this key,
+         simulate only a minimal listing of the generic names.  */
+      if (dir->__d_position >= SPECIAL_DOT_FILE_COUNT + PERF_DATA_FILE_COUNT)
+ goto out;
+      strcpy (de->d_name, perf_data_files[dir->__d_position - SPECIAL_DOT_FILE_COUNT]);
+      dir->__d_position++;
+      res = 0;
+      goto out;
+    }
+
 retry:
   if (dir->__d_position & REG_ENUM_VALUES_MASK)
     /* For the moment, the type of key is ignored here. when write access is added,
@@ -782,23 +832,21 @@ fhandler_registry::fill_filebuf ()
       bufalloc = 0;
       do
  {
-  bufalloc += 1000;
+  bufalloc += 16 * 1024;
   filebuf = (char *) crealloc_abort (filebuf, bufalloc);
   size = bufalloc;
   error = RegQueryValueEx (handle, value_name, NULL, &type,
    (BYTE *) filebuf, &size);
   if (error != ERROR_SUCCESS && error != ERROR_MORE_DATA)
     {
-      if (error != ERROR_FILE_NOT_FOUND)
- {
-  seterrno_from_win_error (__FILE__, __LINE__, error);
-  return true;
- }
-      goto value_not_found;
+      seterrno_from_win_error (__FILE__, __LINE__, error);
+      return false;
     }
  }
       while (error == ERROR_MORE_DATA);
       filesize = size;
+      /* RegQueryValueEx () opens HKEY_PERFORMANCE_DATA.  */
+      RegCloseKey (handle);
     }
   return true;
 value_not_found:
@@ -851,9 +899,9 @@ open_key (const char *name, REGSAM access, DWORD wow64, bool isValue)
       if (*name)
  name++;
       if (*name == 0 && isValue == true)
- goto out;
+ break;
 
-      if (val_only || !component[0])
+      if (val_only || !component[0] || hKey == HKEY_PERFORMANCE_DATA)
  {
   set_errno (ENOENT);
   if (parentOpened)
@@ -874,14 +922,14 @@ open_key (const char *name, REGSAM access, DWORD wow64, bool isValue)
     REG_OPTION_BACKUP_RESTORE,
     effective_access | wow64, NULL,
     &hKey, NULL);
+  if (parentOpened)
+    RegCloseKey (hParentKey);
   if (error != ERROR_SUCCESS)
     {
       hKey = (HKEY) INVALID_HANDLE_VALUE;
       seterrno_from_win_error (__FILE__, __LINE__, error);
       return hKey;
     }
-  if (parentOpened)
-    RegCloseKey (hParentKey);
   hParentKey = hKey;
   parentOpened = true;
  }
@@ -895,7 +943,6 @@ open_key (const char *name, REGSAM access, DWORD wow64, bool isValue)
   hParentKey = hKey;
  }
     }
-out:
   return hKey;
 }
 
Reply | Threaded
Open this post in threaded view
|

Re: [Patch] Allow access to /proc/registry/HKEY_PERFORMANCE_DATA

Corinna Vinschen-2
On Dec 19 14:58, Christian Franke wrote:

> * fhandler_registry.cc (perf_data_files): New table.
> (PERF_DATA_FILE_COUNT): New constant.
> (fhandler_registry::exists): Add check for HKEY_PERFORMANCE_DATA
> value names.
> (fhandler_registry::fstat): For HKEY_PERFORMANCE_DATA, return
> default values only.
> (fhandler_registry::readdir): For HKEY_PERFORMANCE_DATA, list
> names from perf_data_files only.
> (fhandler_registry::fill_filebuf): Use larger buffer to speed up
> access to HKEY_PERFORMANCE_DATA values.  Remove check for possible
> subkey.  Add RegCloseKey ().
> (open_key): Replace goto by break, remove label.  Do not try to
> open subkey of HKEY_PERFORMANCE_DATA.  Add missing RegCloseKey ()
> after open subkey error.

Looks good.  Works fine AFAICS.  Applied.


Thanks,
Corinna


--
Corinna Vinschen                  Please, send mails regarding Cygwin to
Cygwin Project Co-Leader          cygwin AT cygwin DOT com
Red Hat
Reply | Threaded
Open this post in threaded view
|

Re: [Patch] Allow access to /proc/registry/HKEY_PERFORMANCE_DATA

Chris January-2
In reply to this post by Christian Franke
On Fri, Dec 19, 2008 at 1:58 PM, Christian Franke  wrote:
>        (fhandler_registry::fill_filebuf): Use larger buffer to speed up
>        access to HKEY_PERFORMANCE_DATA values.  Remove check for possible
>        subkey.  Add RegCloseKey ().

+      /* RegQueryValueEx () opens HKEY_PERFORMANCE_DATA.  */
+      RegCloseKey (handle);

I'm slightly puzzled by this change. handle is usually closed in
fhandler_register::close. If you close it here then won't CloseHandle
be called with an invalid handle in that method?

Chris
Reply | Threaded
Open this post in threaded view
|

Re: [Patch] Allow access to /proc/registry/HKEY_PERFORMANCE_DATA

Christian Franke
Chris January wrote:

> On Fri, Dec 19, 2008 at 1:58 PM, Christian Franke  wrote:
>  
>>        (fhandler_registry::fill_filebuf): Use larger buffer to speed up
>>        access to HKEY_PERFORMANCE_DATA values.  Remove check for possible
>>        subkey.  Add RegCloseKey ().
>>    
>
> +      /* RegQueryValueEx () opens HKEY_PERFORMANCE_DATA.  */
> +      RegCloseKey (handle);
>
> I'm slightly puzzled by this change. handle is usually closed in
> fhandler_register::close. If you close it here then won't CloseHandle
> be called with an invalid handle in that method?
>
>  

fhandler_registry::close() closes only handles < HKEY_CLASSES_ROOT.
Normally, it is not necessary to close predefined keys.

HKEY_PERFORMANCE_DATA is an exception: It has no subkeys and access to a
value opens the predefined key. Therefore, the key is closed immediately
after value access. Doing this in close() would require to pass a new
'key_is_open' flag from fill_filebuf().

Christian