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