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