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