s3-includes: only include system/filesys.h when needed.
[ab/samba.git/.git] / source3 / registry / reg_perfcount.c
1 /* 
2  *  Unix SMB/CIFS implementation.
3  *  Virtual Windows Registry Layer
4  *
5  *  Copyright (C) Marcin Krzysztof Porwit    2005,
6  *  Copyright (C) Gerald (Jerry) Carter      2005.
7  *  
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 3 of the License, or
11  *  (at your option) any later version.
12  *  
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *  
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
20  */
21
22 #include "includes.h"
23 #include "system/filesys.h"
24 #include "../librpc/gen_ndr/perfcount.h"
25 #include "registry.h"
26 #include "reg_perfcount.h"
27
28 #undef DBGC_CLASS
29 #define DBGC_CLASS DBGC_REGISTRY
30
31 #define PERFCOUNT_MAX_LEN 256
32
33 #define PERFCOUNTDIR    "perfmon"
34 #define NAMES_DB        "names.tdb"
35 #define DATA_DB         "data.tdb"
36
37 struct PERF_OBJECT_TYPE *_reg_perfcount_find_obj(struct PERF_DATA_BLOCK *block, int objind);
38
39 /*********************************************************************
40 *********************************************************************/
41
42 static char *counters_directory(const char *dbname)
43 {
44         char *path = NULL;
45         char *ret = NULL;
46         TALLOC_CTX *ctx = talloc_tos();
47
48         path = state_path(PERFCOUNTDIR);
49         if (!directory_exist(path)) {
50                 mkdir(path, 0755);
51         }
52
53         path = talloc_asprintf(ctx, "%s/%s", PERFCOUNTDIR, dbname);
54         if (!path) {
55                 return NULL;
56         }
57
58         ret = talloc_strdup(ctx, state_path(path));
59         TALLOC_FREE(path);
60         return ret;
61 }
62
63 /*********************************************************************
64 *********************************************************************/
65
66 uint32 reg_perfcount_get_base_index(void)
67 {
68         const char *fname = counters_directory( NAMES_DB );
69         TDB_CONTEXT *names;
70         TDB_DATA kbuf, dbuf;
71         char key[] = "1";
72         uint32 retval = 0;
73         char buf[PERFCOUNT_MAX_LEN];
74
75         names = tdb_open_log(fname, 0, TDB_DEFAULT, O_RDONLY, 0444);
76
77         if ( !names ) {
78                 DEBUG(1, ("reg_perfcount_get_base_index: unable to open [%s].\n", fname));
79                 return 0;
80         }    
81         /* needs to read the value of key "1" from the counter_names.tdb file, as that is
82            where the total number of counters is stored. We're assuming no holes in the
83            enumeration.
84            The format for the counter_names.tdb file is:
85            key        value
86            1          num_counters
87            2          perf_counter1
88            3          perf_counter1_help
89            4          perf_counter2
90            5          perf_counter2_help
91            even_num   perf_counter<even_num>
92            even_num+1 perf_counter<even_num>_help
93            and so on.
94            So last_counter becomes num_counters*2, and last_help will be last_counter+1 */
95         kbuf = string_tdb_data(key);
96         dbuf = tdb_fetch(names, kbuf);
97         if(dbuf.dptr == NULL)
98         {
99                 DEBUG(1, ("reg_perfcount_get_base_index: failed to find key \'1\' in [%s].\n", fname));
100                 tdb_close(names);
101                 return 0;
102         }
103         else
104         {
105                 tdb_close(names);
106                 memset(buf, 0, PERFCOUNT_MAX_LEN);
107                 memcpy(buf, dbuf.dptr, dbuf.dsize);
108                 retval = (uint32)atoi(buf);
109                 SAFE_FREE(dbuf.dptr);
110                 return retval;
111         }
112         return 0;
113 }
114
115 /*********************************************************************
116 *********************************************************************/
117
118 uint32 reg_perfcount_get_last_counter(uint32 base_index)
119 {
120         uint32 retval;
121
122         if(base_index == 0)
123                 retval = 0;
124         else
125                 retval = base_index * 2;
126
127         return retval;
128 }
129
130 /*********************************************************************
131 *********************************************************************/
132
133 uint32 reg_perfcount_get_last_help(uint32 last_counter)
134 {
135         uint32 retval;
136
137         if(last_counter == 0)
138                 retval = 0;
139         else
140                 retval = last_counter + 1;
141
142         return retval;
143 }
144
145
146 /*********************************************************************
147 *********************************************************************/
148
149 static uint32 _reg_perfcount_multi_sz_from_tdb(TDB_CONTEXT *tdb, 
150                                                int keyval,
151                                                char **retbuf,
152                                                uint32 buffer_size)
153 {
154         TDB_DATA kbuf, dbuf;
155         char temp[256];
156         char *buf1 = *retbuf;
157         uint32 working_size = 0;
158         DATA_BLOB name_index, name;
159
160         memset(temp, 0, sizeof(temp));
161         snprintf(temp, sizeof(temp), "%d", keyval);
162         kbuf = string_tdb_data(temp);
163         dbuf = tdb_fetch(tdb, kbuf);
164         if(dbuf.dptr == NULL)
165         {
166                 /* If a key isn't there, just bypass it -- this really shouldn't 
167                    happen unless someone's mucking around with the tdb */
168                 DEBUG(3, ("_reg_perfcount_multi_sz_from_tdb: failed to find key [%s] in [%s].\n",
169                           temp, tdb_name(tdb)));
170                 return buffer_size;
171         }
172         /* First encode the name_index */
173         working_size = (kbuf.dsize + 1)*sizeof(uint16);
174         buf1 = (char *)SMB_REALLOC(buf1, buffer_size + working_size);
175         if(!buf1) {
176                 buffer_size = 0;
177                 return buffer_size;
178         }
179         push_reg_sz(talloc_tos(), &name_index, (const char *)kbuf.dptr);
180         memcpy(buf1+buffer_size, (char *)name_index.data, working_size);
181         buffer_size += working_size;
182         /* Now encode the actual name */
183         working_size = (dbuf.dsize + 1)*sizeof(uint16);
184         buf1 = (char *)SMB_REALLOC(buf1, buffer_size + working_size);
185         if(!buf1) {
186                 buffer_size = 0;
187                 return buffer_size;
188         }
189         memset(temp, 0, sizeof(temp));
190         memcpy(temp, dbuf.dptr, dbuf.dsize);
191         SAFE_FREE(dbuf.dptr);
192         push_reg_sz(talloc_tos(), &name, temp);
193         memcpy(buf1+buffer_size, (char *)name.data, working_size);
194         buffer_size += working_size;
195
196         *retbuf = buf1;
197
198         return buffer_size;
199 }
200
201 /*********************************************************************
202 *********************************************************************/
203
204 uint32 reg_perfcount_get_counter_help(uint32 base_index, char **retbuf)
205 {
206         char *buf1 = NULL;
207         uint32 buffer_size = 0;
208         TDB_CONTEXT *names;
209         const char *fname = counters_directory( NAMES_DB );
210         int i;
211
212         if(base_index == 0)
213                 return 0;
214
215         names = tdb_open_log(fname, 0, TDB_DEFAULT, O_RDONLY, 0444);
216
217         if(names == NULL)
218         {
219                 DEBUG(1, ("reg_perfcount_get_counter_help: unable to open [%s].\n", fname));
220                 return 0;
221         }    
222
223         for(i = 1; i <= base_index; i++)
224         {
225                 buffer_size = _reg_perfcount_multi_sz_from_tdb(names, (i*2)+1, retbuf, buffer_size);
226         }
227         tdb_close(names);
228
229         /* Now terminate the MULTI_SZ with a double unicode NULL */
230         buf1 = *retbuf;
231         buf1 = (char *)SMB_REALLOC(buf1, buffer_size + 2);
232         if(!buf1) {
233                 buffer_size = 0;
234         } else {
235                 buf1[buffer_size++] = '\0';
236                 buf1[buffer_size++] = '\0';
237         }
238
239         *retbuf = buf1;
240
241         return buffer_size;
242 }
243
244 /*********************************************************************
245 *********************************************************************/
246
247 uint32 reg_perfcount_get_counter_names(uint32 base_index, char **retbuf)
248 {
249         char *buf1 = NULL;
250         uint32 buffer_size = 0;
251         TDB_CONTEXT *names;
252         const char *fname = counters_directory( NAMES_DB );
253         int i;
254
255         if(base_index == 0)
256                 return 0;
257
258         names = tdb_open_log(fname, 0, TDB_DEFAULT, O_RDONLY, 0444);
259
260         if(names == NULL)
261         {
262                 DEBUG(1, ("reg_perfcount_get_counter_names: unable to open [%s].\n", fname));
263                 return 0;
264         }    
265
266         buffer_size = _reg_perfcount_multi_sz_from_tdb(names, 1, retbuf, buffer_size);
267
268         for(i = 1; i <= base_index; i++)
269         {
270                 buffer_size = _reg_perfcount_multi_sz_from_tdb(names, i*2, retbuf, buffer_size);
271         }
272         tdb_close(names);
273
274         /* Now terminate the MULTI_SZ with a double unicode NULL */
275         buf1 = *retbuf;
276         buf1 = (char *)SMB_REALLOC(buf1, buffer_size + 2);
277         if(!buf1) {
278                 buffer_size = 0;
279         } else {
280                 buf1[buffer_size++] = '\0';
281                 buf1[buffer_size++] = '\0';
282         }
283
284         *retbuf=buf1;
285
286         return buffer_size;
287 }
288
289 /*********************************************************************
290 *********************************************************************/
291
292 static void _reg_perfcount_make_key(TDB_DATA *key,
293                                     char *buf,
294                                     int buflen,
295                                     int key_part1,
296                                     const char *key_part2)
297 {
298         memset(buf, 0, buflen);
299         if(key_part2 != NULL)
300                 snprintf(buf, buflen,"%d%s", key_part1, key_part2);
301         else 
302                 snprintf(buf, buflen, "%d", key_part1);
303
304         *key = string_tdb_data(buf);
305
306         return;
307 }
308
309 /*********************************************************************
310 *********************************************************************/
311
312 static bool _reg_perfcount_isparent(TDB_DATA data)
313 {
314         if(data.dsize > 0)
315         {
316                 if(data.dptr[0] == 'p')
317                         return True;
318                 else
319                         return False;
320         }
321         return False;
322 }
323
324 /*********************************************************************
325 *********************************************************************/
326
327 static bool _reg_perfcount_ischild(TDB_DATA data)
328 {
329         if(data.dsize > 0)
330         {
331                 if(data.dptr[0] == 'c')
332                         return True;
333                 else
334                         return False;
335         }
336         return False;
337 }
338
339 /*********************************************************************
340 *********************************************************************/
341
342 static uint32 _reg_perfcount_get_numinst(int objInd, TDB_CONTEXT *names)
343 {
344         TDB_DATA key, data;
345         char buf[PERFCOUNT_MAX_LEN];
346
347         _reg_perfcount_make_key(&key, buf, PERFCOUNT_MAX_LEN, objInd, "inst");
348         data = tdb_fetch(names, key);
349
350         if(data.dptr == NULL)
351                 return (uint32)PERF_NO_INSTANCES;
352
353         memset(buf, 0, PERFCOUNT_MAX_LEN);
354         memcpy(buf, data.dptr, data.dsize);
355         SAFE_FREE(data.dptr);
356         return (uint32)atoi(buf);
357 }
358
359 /*********************************************************************
360 *********************************************************************/
361
362 static bool _reg_perfcount_add_instance(struct PERF_OBJECT_TYPE *obj,
363                                         TALLOC_CTX *mem_ctx,
364                                         int instInd,
365                                         TDB_CONTEXT *names);
366
367 static bool _reg_perfcount_add_object(struct PERF_DATA_BLOCK *block,
368                                       TALLOC_CTX *mem_ctx,
369                                       int num,
370                                       TDB_DATA data,
371                                       TDB_CONTEXT *names)
372 {
373         int i;
374         bool success = True;
375         struct PERF_OBJECT_TYPE *obj;
376
377         block->objects = (struct PERF_OBJECT_TYPE *)TALLOC_REALLOC_ARRAY(mem_ctx,
378                                                                   block->objects,
379                                                                   struct PERF_OBJECT_TYPE,
380                                                                   block->NumObjectTypes+1);
381         if(block->objects == NULL)
382                 return False;
383         obj = &(block->objects[block->NumObjectTypes]);
384         memset((void *)&(block->objects[block->NumObjectTypes]), 0, sizeof(struct PERF_OBJECT_TYPE));
385         block->objects[block->NumObjectTypes].ObjectNameTitleIndex = num;
386         block->objects[block->NumObjectTypes].ObjectNameTitlePointer = 0;
387         block->objects[block->NumObjectTypes].ObjectHelpTitleIndex = num+1;
388         block->objects[block->NumObjectTypes].ObjectHelpTitlePointer = 0;
389         block->objects[block->NumObjectTypes].NumCounters = 0;
390         block->objects[block->NumObjectTypes].DefaultCounter = 0;
391         block->objects[block->NumObjectTypes].NumInstances = _reg_perfcount_get_numinst(num, names);
392         block->objects[block->NumObjectTypes].counters = NULL;
393         block->objects[block->NumObjectTypes].instances = NULL;
394         block->objects[block->NumObjectTypes].counter_data.ByteLength = sizeof(uint32);
395         block->objects[block->NumObjectTypes].counter_data.data = NULL;
396         block->objects[block->NumObjectTypes].DetailLevel = PERF_DETAIL_NOVICE;
397         block->NumObjectTypes+=1;
398
399         for(i = 0; i < (int)obj->NumInstances; i++) {
400                 success = _reg_perfcount_add_instance(obj, mem_ctx, i, names);
401         }
402
403         return success;
404 }
405
406 /*********************************************************************
407 *********************************************************************/
408
409 static bool _reg_perfcount_get_counter_data(TDB_DATA key, TDB_DATA *data)
410 {
411         TDB_CONTEXT *counters;
412         const char *fname = counters_directory( DATA_DB );
413
414         counters = tdb_open_log(fname, 0, TDB_DEFAULT, O_RDONLY, 0444);
415
416         if(counters == NULL)
417         {
418                 DEBUG(1, ("reg_perfcount_get_counter_data: unable to open [%s].\n", fname));
419                 return False;
420         }    
421
422         *data = tdb_fetch(counters, key);
423
424         tdb_close(counters);
425
426         return True;
427 }
428
429 /*********************************************************************
430 *********************************************************************/
431
432 static uint32 _reg_perfcount_get_size_field(uint32 CounterType)
433 {
434         uint32 retval;
435
436         retval = CounterType;
437
438         /* First mask out reserved lower 8 bits */
439         retval = retval & 0xFFFFFF00;
440         retval = retval << 22;
441         retval = retval >> 22;
442
443         return retval;
444 }
445
446 /*********************************************************************
447 *********************************************************************/
448
449 static uint32 _reg_perfcount_compute_scale(int64_t data)
450 {
451         int scale = 0;
452         if(data == 0)
453                 return scale;
454         while(data > 100)
455         {
456                 data /= 10;
457                 scale--;
458         }
459         while(data < 10)
460         {
461                 data *= 10;
462                 scale++;
463         }
464
465         return (uint32)scale;
466 }
467
468 /*********************************************************************
469 *********************************************************************/
470
471 static bool _reg_perfcount_get_counter_info(struct PERF_DATA_BLOCK *block,
472                                             TALLOC_CTX *mem_ctx,
473                                             int CounterIndex,
474                                             struct PERF_OBJECT_TYPE *obj,
475                                             TDB_CONTEXT *names)
476 {
477         TDB_DATA key, data;
478         char buf[PERFCOUNT_MAX_LEN];
479         size_t dsize, padding;
480         long int data32, dbuf[2];
481         int64_t data64;
482         uint32 counter_size;
483
484         obj->counters[obj->NumCounters].DefaultScale = 0;
485         dbuf[0] = dbuf[1] = 0;
486         padding = 0;
487
488         _reg_perfcount_make_key(&key, buf, PERFCOUNT_MAX_LEN, CounterIndex, "type");
489         data = tdb_fetch(names, key);
490         if(data.dptr == NULL)
491         {
492                 DEBUG(3, ("_reg_perfcount_get_counter_info: No type data for counter [%d].\n", CounterIndex));
493                 return False;
494         }
495         memset(buf, 0, PERFCOUNT_MAX_LEN);
496         memcpy(buf, data.dptr, data.dsize);
497         obj->counters[obj->NumCounters].CounterType = atoi(buf);
498         DEBUG(10, ("_reg_perfcount_get_counter_info: Got type [%d] for counter [%d].\n",
499                    obj->counters[obj->NumCounters].CounterType, CounterIndex));
500         SAFE_FREE(data.dptr);
501
502         /* Fetch the actual data */
503         _reg_perfcount_make_key(&key, buf, PERFCOUNT_MAX_LEN, CounterIndex, "");
504         _reg_perfcount_get_counter_data(key, &data);
505         if(data.dptr == NULL)
506         {
507                 DEBUG(3, ("_reg_perfcount_get_counter_info: No counter data for counter [%d].\n", CounterIndex));
508                 return False;
509         }
510
511         counter_size = _reg_perfcount_get_size_field(obj->counters[obj->NumCounters].CounterType);
512
513         if(counter_size == PERF_SIZE_DWORD)
514         {
515                 dsize = sizeof(data32);
516                 memset(buf, 0, PERFCOUNT_MAX_LEN);
517                 memcpy(buf, data.dptr, data.dsize);
518                 data32 = strtol(buf, NULL, 0);
519                 if((obj->counters[obj->NumCounters].CounterType & 0x00000F00) == PERF_TYPE_NUMBER)
520                         obj->counters[obj->NumCounters].DefaultScale = _reg_perfcount_compute_scale((int64_t)data32);
521                 else
522                         obj->counters[obj->NumCounters].DefaultScale = 0;
523                 dbuf[0] = data32;
524                 padding = (dsize - (obj->counter_data.ByteLength%dsize)) % dsize;
525         }
526         else if(counter_size == PERF_SIZE_LARGE)
527         {
528                 dsize = sizeof(data64);
529                 memset(buf, 0, PERFCOUNT_MAX_LEN);
530                 memcpy(buf, data.dptr, data.dsize);
531                 data64 = atof(buf);
532                 if((obj->counters[obj->NumCounters].CounterType & 0x00000F00) == PERF_TYPE_NUMBER)
533                         obj->counters[obj->NumCounters].DefaultScale = _reg_perfcount_compute_scale(data64);
534                 else
535                         obj->counters[obj->NumCounters].DefaultScale = 0;
536                 memcpy((void *)dbuf, (const void *)&data64, dsize);
537                 padding = (dsize - (obj->counter_data.ByteLength%dsize)) % dsize;
538         }
539         else /* PERF_SIZE_VARIABLE_LEN */
540         {
541                 dsize = data.dsize;
542                 memset(buf, 0, PERFCOUNT_MAX_LEN);
543                 memcpy(buf, data.dptr, data.dsize);
544         }
545         SAFE_FREE(data.dptr);
546
547         obj->counter_data.ByteLength += dsize + padding;
548         obj->counter_data.data = TALLOC_REALLOC_ARRAY(mem_ctx,
549                                                       obj->counter_data.data,
550                                                       uint8,
551                                                       obj->counter_data.ByteLength - sizeof(uint32));
552         if(obj->counter_data.data == NULL)
553                 return False;
554         if(dbuf[0] != 0 || dbuf[1] != 0)
555         {
556                 memcpy((void *)(obj->counter_data.data + 
557                                 (obj->counter_data.ByteLength - (sizeof(uint32) + dsize))), 
558                        (const void *)dbuf, dsize);
559         }
560         else
561         {
562                 /* Handling PERF_SIZE_VARIABLE_LEN */
563                 memcpy((void *)(obj->counter_data.data +
564                                 (obj->counter_data.ByteLength - (sizeof(uint32) + dsize))),
565                        (const void *)buf, dsize);
566         }
567         obj->counters[obj->NumCounters].CounterOffset = obj->counter_data.ByteLength - dsize;
568         if(obj->counters[obj->NumCounters].CounterOffset % dsize != 0)
569         {
570                 DEBUG(3,("Improperly aligned counter [%d]\n", obj->NumCounters));
571         }
572         obj->counters[obj->NumCounters].CounterSize = dsize;
573
574         return True;
575 }
576
577 /*********************************************************************
578 *********************************************************************/
579
580 struct PERF_OBJECT_TYPE *_reg_perfcount_find_obj(struct PERF_DATA_BLOCK *block, int objind)
581 {
582         int i;
583
584         struct PERF_OBJECT_TYPE *obj = NULL;
585
586         for(i = 0; i < block->NumObjectTypes; i++)
587         {
588                 if(block->objects[i].ObjectNameTitleIndex == objind)
589                 {
590                         obj = &(block->objects[i]);
591                 }
592         }
593
594         return obj;
595 }
596
597 /*********************************************************************
598 *********************************************************************/
599
600 static bool _reg_perfcount_add_counter(struct PERF_DATA_BLOCK *block,
601                                        TALLOC_CTX *mem_ctx,
602                                        int num,
603                                        TDB_DATA data,
604                                        TDB_CONTEXT *names)
605 {
606         char *begin, *end, *start, *stop;
607         int parent;
608         struct PERF_OBJECT_TYPE *obj;
609         bool success = True;
610         char buf[PERFCOUNT_MAX_LEN];
611
612         obj = NULL;
613         memset(buf, 0, PERFCOUNT_MAX_LEN);
614         memcpy(buf, data.dptr, data.dsize);
615         begin = strchr(buf, '[');
616         end = strchr(buf, ']');
617         if(begin == NULL || end == NULL)
618                 return False;
619         start = begin+1;
620
621         while(start < end) {
622                 stop = strchr(start, ',');
623                 if(stop == NULL)
624                         stop = end;
625                 *stop = '\0';
626                 parent = atoi(start);
627
628                 obj = _reg_perfcount_find_obj(block, parent);
629                 if(obj == NULL) {
630                         /* At this point we require that the parent object exist.
631                            This can probably be handled better at some later time */
632                         DEBUG(3, ("_reg_perfcount_add_counter: Could not find parent object [%d] for counter [%d].\n",
633                                   parent, num));
634                         return False;
635                 }
636                 obj->counters = (struct PERF_COUNTER_DEFINITION *)TALLOC_REALLOC_ARRAY(mem_ctx,
637                                                                                 obj->counters,
638                                                                                 struct PERF_COUNTER_DEFINITION,
639                                                                                 obj->NumCounters+1);
640                 if(obj->counters == NULL)
641                         return False;
642                 memset((void *)&(obj->counters[obj->NumCounters]), 0, sizeof(struct PERF_COUNTER_DEFINITION));
643                 obj->counters[obj->NumCounters].CounterNameTitleIndex=num;
644                 obj->counters[obj->NumCounters].CounterHelpTitleIndex=num+1;
645                 obj->counters[obj->NumCounters].DetailLevel = PERF_DETAIL_NOVICE;
646                 obj->counters[obj->NumCounters].ByteLength = sizeof(struct PERF_COUNTER_DEFINITION);
647                 success = _reg_perfcount_get_counter_info(block, mem_ctx, num, obj, names);
648                 obj->NumCounters += 1;
649                 start = stop + 1;
650         }
651
652         /* Handle case of Objects/Counters without any counter data, which would suggest
653            that the required instances are not there yet, so change NumInstances from
654            PERF_NO_INSTANCES to 0 */
655
656         return success;
657 }
658
659 /*********************************************************************
660 *********************************************************************/
661
662 static bool _reg_perfcount_get_instance_info(struct PERF_INSTANCE_DEFINITION *inst,
663                                              TALLOC_CTX *mem_ctx,
664                                              int instId,
665                                              struct PERF_OBJECT_TYPE *obj,
666                                              TDB_CONTEXT *names)
667 {
668         TDB_DATA key, data;
669         char buf[PERFCOUNT_MAX_LEN], temp[PERFCOUNT_MAX_LEN];
670         smb_ucs2_t *name = NULL;
671         int pad;
672
673         /* First grab the instance data from the data file */
674         memset(temp, 0, PERFCOUNT_MAX_LEN);
675         snprintf(temp, PERFCOUNT_MAX_LEN, "i%d", instId);
676         _reg_perfcount_make_key(&key, buf, PERFCOUNT_MAX_LEN, obj->ObjectNameTitleIndex, temp);
677         if (!_reg_perfcount_get_counter_data(key, &data)) {
678                 DEBUG(3, ("_reg_perfcount_get_counter_data failed\n"));
679                 return false;
680         }
681         if(data.dptr == NULL)
682         {
683                 DEBUG(3, ("_reg_perfcount_get_instance_info: No instance data for instance [%s].\n",
684                           buf));
685                 return False;
686         }
687         inst->counter_data.ByteLength = data.dsize + sizeof(inst->counter_data.ByteLength);
688         inst->counter_data.data = TALLOC_REALLOC_ARRAY(mem_ctx,
689                                                        inst->counter_data.data,
690                                                        uint8,
691                                                        data.dsize);
692         if(inst->counter_data.data == NULL)
693                 return False;
694         memset(inst->counter_data.data, 0, data.dsize);
695         memcpy(inst->counter_data.data, data.dptr, data.dsize);
696         SAFE_FREE(data.dptr);
697
698         /* Fetch instance name */
699         memset(temp, 0, PERFCOUNT_MAX_LEN);
700         snprintf(temp, PERFCOUNT_MAX_LEN, "i%dname", instId);
701         _reg_perfcount_make_key(&key, buf, PERFCOUNT_MAX_LEN, obj->ObjectNameTitleIndex, temp);
702         data = tdb_fetch(names, key);
703         if(data.dptr == NULL)
704         {
705                 /* Not actually an error, but possibly unintended? -- just logging FYI */
706                 DEBUG(3, ("_reg_perfcount_get_instance_info: No instance name for instance [%s].\n",
707                           buf));
708                 inst->NameLength = 0;
709         }
710         else
711         {
712                 memset(buf, 0, PERFCOUNT_MAX_LEN);
713                 memcpy(buf, data.dptr, MIN(PERFCOUNT_MAX_LEN-1,data.dsize));
714                 buf[PERFCOUNT_MAX_LEN-1] = '\0';
715                 inst->NameLength = rpcstr_push_talloc(mem_ctx, &name, buf);
716                 if (inst->NameLength == (uint32_t)-1 || !name) {
717                         SAFE_FREE(data.dptr);
718                         return False;
719                 }
720                 inst->data = TALLOC_REALLOC_ARRAY(mem_ctx,
721                                                   inst->data,
722                                                   uint8,
723                                                   inst->NameLength);
724                 if (inst->data == NULL) {
725                         SAFE_FREE(data.dptr);
726                         return False;
727                 }
728                 memcpy(inst->data, name, inst->NameLength);
729                 SAFE_FREE(data.dptr);
730         }
731
732         inst->ParentObjectTitleIndex = 0;
733         inst->ParentObjectTitlePointer = 0;
734         inst->UniqueID = PERF_NO_UNIQUE_ID;
735         inst->NameOffset = 6 * sizeof(uint32);
736
737         inst->ByteLength = inst->NameOffset + inst->NameLength;
738         /* Need to be aligned on a 64-bit boundary here for counter_data */
739         if((pad = (inst->ByteLength % 8)))
740         {
741                 pad = 8 - pad;
742                 inst->data = TALLOC_REALLOC_ARRAY(mem_ctx,
743                                                   inst->data,
744                                                   uint8,
745                                                   inst->NameLength + pad);
746                 memset(inst->data + inst->NameLength, 0, pad);
747                 inst->ByteLength += pad;
748         }
749
750         return True;
751 }
752
753 /*********************************************************************
754 *********************************************************************/
755
756 static bool _reg_perfcount_add_instance(struct PERF_OBJECT_TYPE *obj,
757                                         TALLOC_CTX *mem_ctx,
758                                         int instInd,
759                                         TDB_CONTEXT *names)
760 {
761         struct PERF_INSTANCE_DEFINITION *inst;
762
763         if(obj->instances == NULL) {
764                 obj->instances = TALLOC_REALLOC_ARRAY(mem_ctx,
765                                                       obj->instances,
766                                                       struct PERF_INSTANCE_DEFINITION,
767                                                       obj->NumInstances);
768         }
769         if(obj->instances == NULL)
770                 return False;
771
772         memset(&(obj->instances[instInd]), 0, sizeof(struct PERF_INSTANCE_DEFINITION));
773         inst = &(obj->instances[instInd]);
774         return _reg_perfcount_get_instance_info(inst, mem_ctx, instInd, obj, names);
775 }
776
777 /*********************************************************************
778 *********************************************************************/
779
780 static int _reg_perfcount_assemble_global(struct PERF_DATA_BLOCK *block,
781                                           TALLOC_CTX *mem_ctx,
782                                           int base_index,
783                                           TDB_CONTEXT *names)
784 {
785         bool success;
786         int i, j, retval = 0;
787         char keybuf[PERFCOUNT_MAX_LEN];
788         TDB_DATA key, data;
789
790         for(i = 1; i <= base_index; i++)
791         {
792                 j = i*2;
793                 _reg_perfcount_make_key(&key, keybuf, PERFCOUNT_MAX_LEN, j, "rel");
794                 data = tdb_fetch(names, key);
795                 if(data.dptr != NULL)
796                 {
797                         if(_reg_perfcount_isparent(data))
798                                 success = _reg_perfcount_add_object(block, mem_ctx, j, data, names);
799                         else if(_reg_perfcount_ischild(data))
800                                 success = _reg_perfcount_add_counter(block, mem_ctx, j, data, names);
801                         else
802                         {
803                                 DEBUG(3, ("Bogus relationship [%s] for counter [%d].\n", data.dptr, j));
804                                 success = False;
805                         }
806                         if(success == False)
807                         {
808                                 DEBUG(3, ("_reg_perfcount_assemble_global: Failed to add new relationship for counter [%d].\n", j));
809                                 retval = -1;
810                         }
811                         SAFE_FREE(data.dptr);
812                 }
813                 else
814                         DEBUG(3, ("NULL relationship for counter [%d] using key [%s].\n", j, keybuf));
815         }       
816         return retval;
817 }
818
819 /*********************************************************************
820 *********************************************************************/
821
822 static bool _reg_perfcount_get_64(uint64_t *retval,
823                                   TDB_CONTEXT *tdb,
824                                   int key_part1,
825                                   const char *key_part2)
826 {
827         TDB_DATA key, data;
828         char buf[PERFCOUNT_MAX_LEN];
829
830         _reg_perfcount_make_key(&key, buf, PERFCOUNT_MAX_LEN, key_part1, key_part2);
831
832         data = tdb_fetch(tdb, key);
833         if(data.dptr == NULL)
834         {
835                 DEBUG(3,("_reg_perfcount_get_64: No data found for key [%s].\n", key.dptr));
836                 return False;
837         }
838
839         memset(buf, 0, PERFCOUNT_MAX_LEN);
840         memcpy(buf, data.dptr, data.dsize);
841         SAFE_FREE(data.dptr);
842
843         *retval = atof(buf);
844
845         return True;
846 }
847
848 /*********************************************************************
849 *********************************************************************/
850
851 static bool _reg_perfcount_init_data_block_perf(struct PERF_DATA_BLOCK *block,
852                                                 TDB_CONTEXT *names)
853 {
854         uint64_t PerfFreq, PerfTime, PerfTime100nSec;
855         TDB_CONTEXT *counters;
856         bool status = False;
857         const char *fname = counters_directory( DATA_DB );
858
859         counters = tdb_open_log(fname, 0, TDB_DEFAULT, O_RDONLY, 0444);
860
861         if(counters == NULL)
862         {
863                 DEBUG(1, ("reg_perfcount_init_data_block_perf: unable to open [%s].\n", fname));
864                 return False;
865         }    
866
867         status = _reg_perfcount_get_64(&PerfFreq, names, 0, "PerfFreq");
868         if(status == False)
869         {
870                 tdb_close(counters);
871                 return status;
872         }
873         memcpy((void *)&(block->PerfFreq), (const void *)&PerfFreq, sizeof(PerfFreq));
874
875         status = _reg_perfcount_get_64(&PerfTime, counters, 0, "PerfTime");
876         if(status == False)
877         {
878                 tdb_close(counters);
879                 return status;
880         }
881         memcpy((void *)&(block->PerfTime), (const void *)&PerfTime, sizeof(PerfTime));
882
883         status = _reg_perfcount_get_64(&PerfTime100nSec, counters, 0, "PerfTime100nSec");
884         if(status == False)
885         {
886                 tdb_close(counters);
887                 return status;
888         }
889         memcpy((void *)&(block->PerfTime100nSec), (const void *)&PerfTime100nSec, sizeof(PerfTime100nSec));
890
891         tdb_close(counters);
892         return True;
893 }
894
895 /*******************************************************************
896 ********************************************************************/
897
898 static bool make_systemtime(struct SYSTEMTIME *systime, struct tm *unixtime)
899 {
900         systime->year=unixtime->tm_year+1900;
901         systime->month=unixtime->tm_mon+1;
902         systime->dayofweek=unixtime->tm_wday;
903         systime->day=unixtime->tm_mday;
904         systime->hour=unixtime->tm_hour;
905         systime->minute=unixtime->tm_min;
906         systime->second=unixtime->tm_sec;
907         systime->milliseconds=0;
908
909         return True;
910 }
911
912 /*********************************************************************
913 *********************************************************************/
914
915 static bool _reg_perfcount_init_data_block(struct PERF_DATA_BLOCK *block,
916                                            TALLOC_CTX *mem_ctx, TDB_CONTEXT *names,
917                                            bool bigendian_data)
918 {
919         smb_ucs2_t *temp = NULL;
920         time_t tm;
921
922         if (rpcstr_push_talloc(mem_ctx, &temp, "PERF")==(size_t)-1) {
923                 return false;
924         }
925         if (!temp) {
926                 return false;
927         }
928         memcpy(block->Signature, temp, strlen_w(temp) *2);
929
930         if(bigendian_data)
931                 block->LittleEndian = 0;
932         else
933                 block->LittleEndian = 1;
934         block->Version = 1;
935         block->Revision = 1;
936         block->TotalByteLength = 0;
937         block->NumObjectTypes = 0;
938         block->DefaultObject = -1;
939         block->objects = NULL;
940         tm = time(NULL);
941         make_systemtime(&(block->SystemTime), gmtime(&tm));
942         _reg_perfcount_init_data_block_perf(block, names);
943         memset(temp, 0, sizeof(temp));
944         rpcstr_push((void *)temp, global_myname(), sizeof(temp), STR_TERMINATE);
945         block->SystemNameLength = (strlen_w(temp) * 2) + 2;
946         block->data = TALLOC_ZERO_ARRAY(mem_ctx, uint8, block->SystemNameLength + (8 - (block->SystemNameLength % 8)));
947         if (block->data == NULL) {
948                 return False;
949         }
950         memcpy(block->data, temp, block->SystemNameLength);
951         block->SystemNameOffset = sizeof(struct PERF_DATA_BLOCK) - sizeof(block->objects) - sizeof(block->data);
952         block->HeaderLength = block->SystemNameOffset + block->SystemNameLength;
953         /* Make sure to adjust for 64-bit alignment for when we finish writing the system name,
954            so that the PERF_OBJECT_TYPE struct comes out 64-bit aligned */
955         block->HeaderLength += 8 - (block->HeaderLength % 8);
956
957         return True;
958 }
959
960 /*********************************************************************
961 *********************************************************************/
962
963 static uint32 _reg_perfcount_perf_data_block_fixup(struct PERF_DATA_BLOCK *block, TALLOC_CTX *mem_ctx)
964 {
965         int obj, cnt, inst, pad, i;
966         struct PERF_OBJECT_TYPE *object;
967         struct PERF_INSTANCE_DEFINITION *instance;
968         struct PERF_COUNTER_DEFINITION *counter;
969         struct PERF_COUNTER_BLOCK *counter_data;
970         char *temp = NULL, *src_addr, *dst_addr;
971
972         block->TotalByteLength = 0;
973         object = block->objects;
974         for(obj = 0; obj < block->NumObjectTypes; obj++)
975         {
976                 object[obj].TotalByteLength = 0;
977                 object[obj].DefinitionLength = 0;
978                 instance = object[obj].instances;
979                 counter = object[obj].counters;
980                 for(cnt = 0; cnt < object[obj].NumCounters; cnt++)
981                 {
982                         object[obj].TotalByteLength += counter[cnt].ByteLength;
983                         object[obj].DefinitionLength += counter[cnt].ByteLength;
984                 }
985                 if(object[obj].NumInstances != PERF_NO_INSTANCES)
986                 {
987                         for(inst = 0; inst < object[obj].NumInstances; inst++)
988                         {
989                                 instance = &(object[obj].instances[inst]);
990                                 object[obj].TotalByteLength += instance->ByteLength;
991                                 counter_data = &(instance->counter_data);
992                                 counter = &(object[obj].counters[object[obj].NumCounters - 1]);
993                                 counter_data->ByteLength = counter->CounterOffset + counter->CounterSize + sizeof(counter_data->ByteLength);
994                                 temp = TALLOC_REALLOC_ARRAY(mem_ctx,
995                                                             temp, 
996                                                             char, 
997                                                             counter_data->ByteLength- sizeof(counter_data->ByteLength));
998                                 if (temp == NULL) {
999                                         return 0;
1000                                 }
1001                                 memset(temp, 0, counter_data->ByteLength - sizeof(counter_data->ByteLength));
1002                                 src_addr = (char *)counter_data->data;
1003                                 for(i = 0; i < object[obj].NumCounters; i++)
1004                                 {
1005                                         counter = &(object[obj].counters[i]);
1006                                         dst_addr = temp + counter->CounterOffset - sizeof(counter_data->ByteLength);
1007                                         memcpy(dst_addr, src_addr, counter->CounterSize);
1008                                         src_addr += counter->CounterSize;
1009                                 }
1010                                 /* Make sure to be 64-bit aligned */
1011                                 if((pad = (counter_data->ByteLength % 8)))
1012                                 {
1013                                         pad = 8 - pad;
1014                                 }
1015                                 counter_data->data = TALLOC_REALLOC_ARRAY(mem_ctx,
1016                                                                          counter_data->data,
1017                                                                          uint8,
1018                                                                          counter_data->ByteLength - sizeof(counter_data->ByteLength) + pad);
1019                                 if (counter_data->data == NULL) {
1020                                         return 0;
1021                                 }
1022                                 memset(counter_data->data, 0, counter_data->ByteLength - sizeof(counter_data->ByteLength) + pad);
1023                                 memcpy(counter_data->data, temp, counter_data->ByteLength - sizeof(counter_data->ByteLength));
1024                                 counter_data->ByteLength += pad;
1025                                 object[obj].TotalByteLength += counter_data->ByteLength;
1026                         }
1027                 }
1028                 else
1029                 {
1030                         /* Need to be 64-bit aligned at the end of the counter_data block, so pad counter_data to a 64-bit boundary,
1031                            so that the next PERF_OBJECT_TYPE can start on a 64-bit alignment */
1032                         if((pad = (object[obj].counter_data.ByteLength % 8)))
1033                         {
1034                                 pad = 8 - pad;
1035                                 object[obj].counter_data.data = TALLOC_REALLOC_ARRAY(mem_ctx,
1036                                                                                      object[obj].counter_data.data,
1037                                                                                      uint8, 
1038                                                                                      object[obj].counter_data.ByteLength + pad);
1039                                 memset((void *)(object[obj].counter_data.data + object[obj].counter_data.ByteLength), 0, pad);
1040                                 object[obj].counter_data.ByteLength += pad;
1041                         }
1042                         object[obj].TotalByteLength += object[obj].counter_data.ByteLength;
1043                 }
1044                 object[obj].HeaderLength = sizeof(*object) - (sizeof(counter) + sizeof(instance) + sizeof(struct PERF_COUNTER_BLOCK));
1045                 object[obj].TotalByteLength += object[obj].HeaderLength;
1046                 object[obj].DefinitionLength += object[obj].HeaderLength;
1047
1048                 block->TotalByteLength += object[obj].TotalByteLength;
1049         }
1050
1051         return block->TotalByteLength;
1052 }
1053
1054 /*********************************************************************
1055 *********************************************************************/
1056
1057 static uint32 reg_perfcount_get_perf_data_block(uint32 base_index,
1058                                                 TALLOC_CTX *mem_ctx,
1059                                                 struct PERF_DATA_BLOCK *block,
1060                                                 const char *object_ids,
1061                                                 bool bigendian_data)
1062 {
1063         uint32 buffer_size = 0;
1064         const char *fname = counters_directory( NAMES_DB );
1065         TDB_CONTEXT *names;
1066         int retval = 0;
1067
1068         names = tdb_open_log(fname, 0, TDB_DEFAULT, O_RDONLY, 0444);
1069
1070         if(names == NULL)
1071         {
1072                 DEBUG(1, ("reg_perfcount_get_perf_data_block: unable to open [%s].\n", fname));
1073                 return 0;
1074         }
1075
1076         if (!_reg_perfcount_init_data_block(block, mem_ctx, names, bigendian_data)) {
1077                 DEBUG(0, ("_reg_perfcount_init_data_block failed\n"));
1078                 tdb_close(names);
1079                 return 0;
1080         }
1081
1082         reg_perfcount_get_last_counter(base_index);
1083
1084         if(object_ids == NULL)
1085         {
1086                 /* we're getting a request for "Global" here */
1087                 retval = _reg_perfcount_assemble_global(block, mem_ctx, base_index, names);
1088         }
1089         else
1090         {
1091                 /* we're getting a request for a specific set of PERF_OBJECT_TYPES */
1092                 retval = _reg_perfcount_assemble_global(block, mem_ctx, base_index, names);
1093         }
1094         buffer_size = _reg_perfcount_perf_data_block_fixup(block, mem_ctx);
1095
1096         tdb_close(names);
1097
1098         if (retval == -1) {
1099                 return 0;
1100         }
1101
1102         return buffer_size + block->HeaderLength;
1103 }
1104
1105 /*******************************************************************
1106 ********************************************************************/
1107
1108 static bool smb_io_system_time(const char *desc, prs_struct *ps, int depth, struct SYSTEMTIME *systime)
1109 {
1110         if(!prs_uint16("year", ps, depth, &systime->year))
1111                 return False;
1112         if(!prs_uint16("month", ps, depth, &systime->month))
1113                 return False;
1114         if(!prs_uint16("dayofweek", ps, depth, &systime->dayofweek))
1115                 return False;
1116         if(!prs_uint16("day", ps, depth, &systime->day))
1117                 return False;
1118         if(!prs_uint16("hour", ps, depth, &systime->hour))
1119                 return False;
1120         if(!prs_uint16("minute", ps, depth, &systime->minute))
1121                 return False;
1122         if(!prs_uint16("second", ps, depth, &systime->second))
1123                 return False;
1124         if(!prs_uint16("milliseconds", ps, depth, &systime->milliseconds))
1125                 return False;
1126
1127         return True;
1128 }
1129
1130 /*********************************************************************
1131 *********************************************************************/
1132
1133 static bool _reg_perfcount_marshall_perf_data_block(prs_struct *ps, struct PERF_DATA_BLOCK block, int depth)
1134 {
1135         int i;
1136         prs_debug(ps, depth, "", "_reg_perfcount_marshall_perf_data_block");
1137         depth++;
1138
1139         if(!prs_align(ps))
1140                 return False;
1141         for(i = 0; i < 4; i++)
1142         {
1143                 if(!prs_uint16("Signature", ps, depth, &block.Signature[i]))
1144                         return False;
1145         }
1146         if(!prs_uint32("Little Endian", ps, depth, &block.LittleEndian))
1147                 return False;
1148         if(!prs_uint32("Version", ps, depth, &block.Version))
1149                 return False;
1150         if(!prs_uint32("Revision", ps, depth, &block.Revision))
1151                 return False;
1152         if(!prs_uint32("TotalByteLength", ps, depth, &block.TotalByteLength))
1153                 return False;
1154         if(!prs_uint32("HeaderLength", ps, depth, &block.HeaderLength))
1155                 return False;
1156         if(!prs_uint32("NumObjectTypes", ps, depth, &block.NumObjectTypes))
1157                 return False;
1158         if(!prs_uint32("DefaultObject", ps, depth, &block.DefaultObject))
1159                 return False;
1160         if(!smb_io_system_time("SystemTime", ps, depth, &block.SystemTime))
1161                 return False;
1162         if(!prs_uint32("Padding", ps, depth, &block.Padding))
1163                 return False;
1164         if(!prs_align_uint64(ps))
1165                 return False;
1166         if(!prs_uint64("PerfTime", ps, depth, &block.PerfTime))
1167                 return False;
1168         if(!prs_uint64("PerfFreq", ps, depth, &block.PerfFreq))
1169                 return False;
1170         if(!prs_uint64("PerfTime100nSec", ps, depth, &block.PerfTime100nSec))
1171                 return False;
1172         if(!prs_uint32("SystemNameLength", ps, depth, &block.SystemNameLength))
1173                 return False;
1174         if(!prs_uint32("SystemNameOffset", ps, depth, &block.SystemNameOffset))
1175                 return False;
1176         /* hack to make sure we're 64-bit aligned at the end of this whole mess */
1177         if(!prs_uint8s(False, "SystemName", ps, depth, block.data, 
1178                        block.HeaderLength - block.SystemNameOffset)) 
1179                 return False;
1180
1181         return True;
1182 }
1183
1184 /*********************************************************************
1185 *********************************************************************/
1186
1187 static bool _reg_perfcount_marshall_perf_counters(prs_struct *ps,
1188                                                   struct PERF_OBJECT_TYPE object,
1189                                                   int depth)
1190 {
1191         int cnt;
1192         struct PERF_COUNTER_DEFINITION counter;
1193
1194         prs_debug(ps, depth, "", "_reg_perfcount_marshall_perf_counters");
1195         depth++;
1196
1197         for(cnt = 0; cnt < object.NumCounters; cnt++)
1198         {
1199                 counter = object.counters[cnt];
1200
1201                 if(!prs_align(ps))
1202                         return False;
1203                 if(!prs_uint32("ByteLength", ps, depth, &counter.ByteLength))
1204                         return False;
1205                 if(!prs_uint32("CounterNameTitleIndex", ps, depth, &counter.CounterNameTitleIndex))
1206                         return False;
1207                 if(!prs_uint32("CounterNameTitlePointer", ps, depth, &counter.CounterNameTitlePointer))
1208                         return False;
1209                 if(!prs_uint32("CounterHelpTitleIndex", ps, depth, &counter.CounterHelpTitleIndex))
1210                         return False;
1211                 if(!prs_uint32("CounterHelpTitlePointer", ps, depth, &counter.CounterHelpTitlePointer))
1212                         return False;
1213                 if(!prs_uint32("DefaultScale", ps, depth, &counter.DefaultScale))
1214                         return False;
1215                 if(!prs_uint32("DetailLevel", ps, depth, &counter.DetailLevel))
1216                         return False;
1217                 if(!prs_uint32("CounterType", ps, depth, &counter.CounterType))
1218                         return False;
1219                 if(!prs_uint32("CounterSize", ps, depth, &counter.CounterSize))
1220                         return False;
1221                 if(!prs_uint32("CounterOffset", ps, depth, &counter.CounterOffset))
1222                         return False;
1223         }
1224
1225         return True;
1226 }
1227
1228 /*********************************************************************
1229 *********************************************************************/
1230
1231 static bool _reg_perfcount_marshall_perf_counter_data(prs_struct *ps, 
1232                                                       struct PERF_COUNTER_BLOCK counter_data,
1233                                                       int depth)
1234 {
1235         prs_debug(ps, depth, "", "_reg_perfcount_marshall_perf_counter_data");
1236         depth++;
1237
1238         if(!prs_align_uint64(ps))
1239                 return False;
1240
1241         if(!prs_uint32("ByteLength", ps, depth, &counter_data.ByteLength))
1242                 return False;
1243         if(!prs_uint8s(False, "CounterData", ps, depth, counter_data.data, counter_data.ByteLength - sizeof(uint32)))
1244                 return False;
1245         if(!prs_align_uint64(ps))
1246                 return False;
1247
1248         return True;
1249 }
1250
1251 /*********************************************************************
1252 *********************************************************************/
1253
1254 static bool _reg_perfcount_marshall_perf_instances(prs_struct *ps,
1255                                                    struct PERF_OBJECT_TYPE object,
1256                                                    int depth)
1257 {
1258         struct PERF_INSTANCE_DEFINITION instance;
1259         int inst;
1260
1261         prs_debug(ps, depth, "", "_reg_perfcount_marshall_perf_instances");
1262         depth++;
1263
1264         for(inst = 0; inst < object.NumInstances; inst++)
1265         {
1266                 instance = object.instances[inst];
1267
1268                 if(!prs_align(ps))
1269                         return False;
1270                 if(!prs_uint32("ByteLength", ps, depth, &instance.ByteLength))
1271                         return False;
1272                 if(!prs_uint32("ParentObjectTitleIndex", ps, depth, &instance.ParentObjectTitleIndex))
1273                         return False;
1274                 if(!prs_uint32("ParentObjectTitlePointer", ps, depth, &instance.ParentObjectTitlePointer))
1275                         return False;
1276                 if(!prs_uint32("UniqueID", ps, depth, &instance.UniqueID))
1277                         return False;
1278                 if(!prs_uint32("NameOffset", ps, depth, &instance.NameOffset))
1279                         return False;
1280                 if(!prs_uint32("NameLength", ps, depth, &instance.NameLength))
1281                         return False;
1282                 if(!prs_uint8s(False, "InstanceName", ps, depth, instance.data,
1283                                instance.ByteLength - instance.NameOffset))
1284                         return False;
1285                 if(_reg_perfcount_marshall_perf_counter_data(ps, instance.counter_data, depth) == False)
1286                         return False;
1287         }
1288
1289         return True;
1290 }
1291
1292 /*********************************************************************
1293 *********************************************************************/
1294
1295 static bool _reg_perfcount_marshall_perf_objects(prs_struct *ps, struct PERF_DATA_BLOCK block, int depth)
1296 {
1297         int obj;
1298
1299         struct PERF_OBJECT_TYPE object;
1300
1301         prs_debug(ps, depth, "", "_reg_perfcount_marshall_perf_objects");
1302         depth++;
1303
1304         for(obj = 0; obj < block.NumObjectTypes; obj++)
1305         {
1306                 object = block.objects[obj];
1307
1308                 if(!prs_align(ps))
1309                         return False;
1310
1311                 if(!prs_uint32("TotalByteLength", ps, depth, &object.TotalByteLength))
1312                         return False;
1313                 if(!prs_uint32("DefinitionLength", ps, depth, &object.DefinitionLength))
1314                         return False;
1315                 if(!prs_uint32("HeaderLength", ps, depth, &object.HeaderLength))
1316                         return False;
1317                 if(!prs_uint32("ObjectNameTitleIndex", ps, depth, &object.ObjectNameTitleIndex))
1318                         return False;
1319                 if(!prs_uint32("ObjectNameTitlePointer", ps, depth, &object.ObjectNameTitlePointer))
1320                         return False;
1321                 if(!prs_uint32("ObjectHelpTitleIndex", ps, depth, &object.ObjectHelpTitleIndex))
1322                         return False;
1323                 if(!prs_uint32("ObjectHelpTitlePointer", ps, depth, &object.ObjectHelpTitlePointer))
1324                         return False;
1325                 if(!prs_uint32("DetailLevel", ps, depth, &object.DetailLevel))
1326                         return False;
1327                 if(!prs_uint32("NumCounters", ps, depth, &object.NumCounters))
1328                         return False;
1329                 if(!prs_uint32("DefaultCounter", ps, depth, &object.DefaultCounter))
1330                         return False;
1331                 if(!prs_uint32("NumInstances", ps, depth, &object.NumInstances))
1332                         return False;
1333                 if(!prs_uint32("CodePage", ps, depth, &object.CodePage))
1334                         return False;
1335                 if(!prs_align_uint64(ps))
1336                         return False;
1337                 if(!prs_uint64("PerfTime", ps, depth, &object.PerfTime))
1338                         return False;
1339                 if(!prs_uint64("PerfFreq", ps, depth, &object.PerfFreq))
1340                         return False;
1341
1342                 /* Now do the counters */
1343                 /* If no instances, encode counter_data */
1344                 /* If instances, encode instace plus counter data for each instance */
1345                 if(_reg_perfcount_marshall_perf_counters(ps, object, depth) == False)
1346                         return False;
1347                 if(object.NumInstances == PERF_NO_INSTANCES)
1348                 {
1349                         if(_reg_perfcount_marshall_perf_counter_data(ps, object.counter_data, depth) == False)
1350                                 return False;
1351                 }
1352                 else
1353                 {
1354                         if(_reg_perfcount_marshall_perf_instances(ps, object, depth) == False)
1355                                 return False;
1356                 }
1357         }
1358
1359         return True;
1360 }
1361
1362 /*********************************************************************
1363 *********************************************************************/
1364
1365 WERROR reg_perfcount_get_hkpd(prs_struct *ps, uint32 max_buf_size, uint32 *outbuf_len, const char *object_ids)
1366 {
1367         /*
1368          * For a detailed description of the layout of this structure,
1369          * see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/perfmon/base/performance_data_format.asp
1370          *
1371          * By 2006-11-23 this link did not work anymore, I found something
1372          * promising under
1373          * http://msdn2.microsoft.com/en-us/library/aa373105.aspx -- vl
1374          */
1375         struct PERF_DATA_BLOCK block;
1376         uint32 buffer_size, base_index; 
1377
1378         buffer_size = 0;
1379         base_index = reg_perfcount_get_base_index();
1380         ZERO_STRUCT(block);
1381
1382         buffer_size = reg_perfcount_get_perf_data_block(base_index, ps->mem_ctx, &block, object_ids, ps->bigendian_data);
1383
1384         if(buffer_size < max_buf_size)
1385         {
1386                 *outbuf_len = buffer_size;
1387
1388                 if (!_reg_perfcount_marshall_perf_data_block(ps, block, 0))
1389                         return WERR_NOMEM;
1390
1391                 if (!_reg_perfcount_marshall_perf_objects(ps, block, 0))
1392                         return WERR_NOMEM;
1393
1394                 return WERR_OK;
1395         }
1396         else
1397         {
1398                 *outbuf_len = max_buf_size;
1399                 if (!_reg_perfcount_marshall_perf_data_block(ps, block, 0))
1400                         return WERR_NOMEM;
1401
1402                 return WERR_INSUFFICIENT_BUFFER;
1403         }
1404 }