source: releases/0.2.2/src/reglookup.c@ 209

Last change on this file since 209 was 59, checked in by tim, 20 years ago

Updated version

Code format cleanup, some comments added.

  • Property svn:keywords set to Id
File size: 19.7 KB
Line 
1/*
2 * A utility to read a Windows NT/2K/XP/2K3 registry file, using
3 * Gerald Carter''s regfio interface.
4 *
5 * Copyright (C) 2005 Timothy D. Morgan
6 * Copyright (C) 2002 Richard Sharpe, rsharpe@richardsharpe.com
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; version 2 of the License.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 *
21 * $Id: reglookup.c 59 2005-10-03 01:26:12Z tim $
22 */
23
24
25#include <stdlib.h>
26#include <stdio.h>
27#include <string.h>
28#include <strings.h>
29#include <time.h>
30#include "../include/regfio.h"
31#include "../include/void_stack.h"
32
33/* Globals, influenced by command line parameters */
34bool print_verbose = false;
35bool print_security = false;
36bool print_header = true;
37bool path_filter_enabled = false;
38bool type_filter_enabled = false;
39char* path_filter = NULL;
40int type_filter;
41char* registry_file = NULL;
42
43/* Other globals */
44const char* special_chars = ",\"\\";
45
46void bailOut(int code, char* message)
47{
48 fprintf(stderr, message);
49 exit(code);
50}
51
52
53/* Returns a newly malloc()ed string which contains original buffer,
54 * except for non-printable or special characters are quoted in hex
55 * with the syntax '\xQQ' where QQ is the hex ascii value of the quoted
56 * character. A null terminator is added, as only ascii, not binary,
57 * is returned.
58 */
59static char* quote_buffer(const unsigned char* str,
60 unsigned int len, const char* special)
61{
62 unsigned int i;
63 unsigned int num_written=0;
64 unsigned int out_len = sizeof(char)*len+1;
65 char* ret_val = malloc(out_len);
66
67 if(ret_val == NULL)
68 return NULL;
69
70 for(i=0; i<len; i++)
71 {
72 if(str[i] < 32 || str[i] > 126 || strchr(special, str[i]) != NULL)
73 {
74 out_len += 3;
75 /* XXX: may not be the most efficient way of getting enough memory. */
76 ret_val = realloc(ret_val, out_len);
77 if(ret_val == NULL)
78 break;
79 num_written += snprintf(ret_val+num_written, (out_len)-num_written,
80 "\\x%.2X", str[i]);
81 }
82 else
83 ret_val[num_written++] = str[i];
84 }
85 ret_val[num_written] = '\0';
86
87 return ret_val;
88}
89
90
91/* Returns a newly malloc()ed string which contains original string,
92 * except for non-printable or special characters are quoted in hex
93 * with the syntax '\xQQ' where QQ is the hex ascii value of the quoted
94 * character.
95 */
96static char* quote_string(const char* str, const char* special)
97{
98 unsigned int len;
99
100 if(str == NULL)
101 return NULL;
102
103 len = strlen(str);
104 return quote_buffer((const unsigned char*)str, len, special);
105}
106
107
108/*
109 * Convert from UniCode to Ascii ... Does not take into account other lang
110 * Restrict by ascii_max if > 0
111 */
112static int uni_to_ascii(unsigned char *uni, unsigned char *ascii,
113 int ascii_max, int uni_max)
114{
115 int i = 0;
116
117 while (i < ascii_max && (uni[i*2] || uni[i*2+1]))
118 {
119 if (uni_max > 0 && (i*2) >= uni_max) break;
120 ascii[i] = uni[i*2];
121 i++;
122 }
123 ascii[i] = '\0';
124
125 return i;
126}
127
128
129/*
130 * Convert a data value to a string for display
131 */
132static unsigned char* data_to_ascii(unsigned char *datap, int len, int type)
133{
134 unsigned char *asciip;
135 unsigned int i;
136 unsigned short num_nulls;
137 unsigned char* ascii;
138 unsigned char* cur_str;
139 unsigned char* cur_ascii;
140 char* cur_quoted;
141 unsigned int cur_str_len;
142 unsigned int ascii_max, cur_str_max;
143 unsigned int str_rem, cur_str_rem, alen;
144
145 switch (type)
146 {
147 case REG_SZ:
148 ascii_max = sizeof(char)*len;
149 ascii = malloc(ascii_max+4);
150 if(ascii == NULL)
151 return NULL;
152
153 /* XXX: This has to be fixed. It has to be UNICODE */
154 uni_to_ascii(datap, ascii, len, ascii_max);
155 cur_quoted = quote_string((char*)ascii, special_chars);
156 free(ascii);
157 return (unsigned char*)cur_quoted;
158 break;
159
160 case REG_EXPAND_SZ:
161 ascii_max = sizeof(char)*len;
162 ascii = malloc(ascii_max+2);
163 if(ascii == NULL)
164 return NULL;
165
166 uni_to_ascii(datap, ascii, len, ascii_max);
167 cur_quoted = quote_string((char*)ascii, special_chars);
168 free(ascii);
169 return (unsigned char*)cur_quoted;
170 break;
171
172 case REG_DWORD:
173 ascii_max = sizeof(char)*11;
174 ascii = malloc(ascii_max);
175 if(ascii == NULL)
176 return NULL;
177
178 snprintf((char*)ascii, ascii_max, "0x%.2X%.2X%.2X%.2X",
179 datap[0], datap[1], datap[2], datap[3]);
180 return ascii;
181 break;
182
183 case REG_DWORD_BE:
184 ascii_max = sizeof(char)*11;
185 ascii = malloc(ascii_max);
186 if(ascii == NULL)
187 return NULL;
188
189 snprintf((char*)ascii, ascii_max, "0x%.2X%.2X%.2X%.2X",
190 datap[3], datap[2], datap[1], datap[0]);
191 return ascii;
192 break;
193
194 /* XXX: this MULTI_SZ parser is pretty inefficient. Should be
195 * redone with fewer malloc calls and better string concatenation.
196 */
197 case REG_MULTI_SZ:
198 ascii_max = sizeof(char)*len*4;
199 cur_str_max = sizeof(char)*len+1;
200 cur_str = malloc(cur_str_max);
201 cur_ascii = malloc(cur_str_max);
202 ascii = malloc(ascii_max+4);
203 if(ascii == NULL || cur_str == NULL || cur_ascii == NULL)
204 return NULL;
205
206 /* Reads until it reaches 4 consecutive NULLs,
207 * which is two nulls in unicode, or until it reaches len, or until we
208 * run out of buffer. The latter should never happen, but we shouldn't
209 * trust our file to have the right lengths/delimiters.
210 */
211 asciip = ascii;
212 num_nulls = 0;
213 str_rem = ascii_max;
214 cur_str_rem = cur_str_max;
215 cur_str_len = 0;
216
217 for(i=0; (i < len) && str_rem > 0; i++)
218 {
219 *(cur_str+cur_str_len) = *(datap+i);
220 if(*(cur_str+cur_str_len) == 0)
221 num_nulls++;
222 else
223 num_nulls = 0;
224 cur_str_len++;
225
226 if(num_nulls == 2)
227 {
228 uni_to_ascii(cur_str, cur_ascii, cur_str_max, 0);
229 cur_quoted = quote_string((char*)cur_ascii, ",|\"\\");
230 alen = snprintf((char*)asciip, str_rem, "%s", cur_quoted);
231 asciip += alen;
232 str_rem -= alen;
233 free(cur_quoted);
234
235 if(*(datap+i+1) == 0 && *(datap+i+2) == 0)
236 break;
237 else
238 {
239 alen = snprintf((char*)asciip, str_rem, "%c", '|');
240 asciip += alen;
241 str_rem -= alen;
242 memset(cur_str, 0, cur_str_max);
243 cur_str_len = 0;
244 num_nulls = 0;
245 /* To eliminate leading nulls in subsequent strings. */
246 i++;
247 }
248 }
249 }
250 *asciip = 0;
251 free(cur_str);
252 free(cur_ascii);
253 return ascii;
254 break;
255
256 /* XXX: Dont know what to do with these yet, just print as binary... */
257 case REG_RESOURCE_LIST:
258 case REG_FULL_RESOURCE_DESCRIPTOR:
259 case REG_RESOURCE_REQUIREMENTS_LIST:
260
261 case REG_BINARY:
262 return (unsigned char*)quote_buffer(datap, len, special_chars);
263 break;
264
265 default:
266 return NULL;
267 break;
268 }
269
270 return NULL;
271}
272
273
274void_stack* path2Stack(const char* s)
275{
276 void_stack* ret_val;
277 void_stack* rev_ret = void_stack_new(1024);
278 const char* cur = s;
279 char* next = NULL;
280 char* copy;
281
282 if (rev_ret == NULL)
283 return NULL;
284 if (s == NULL)
285 return rev_ret;
286
287 while((next = strchr(cur, '/')) != NULL)
288 {
289 if ((next-cur) > 0)
290 {
291 copy = (char*)malloc((next-cur+1)*sizeof(char));
292 if(copy == NULL)
293 bailOut(2, "ERROR: Memory allocation problem.\n");
294
295 memcpy(copy, cur, next-cur);
296 copy[next-cur] = '\0';
297 void_stack_push(rev_ret, copy);
298 }
299 cur = next+1;
300 }
301 if(strlen(cur) > 0)
302 {
303 copy = strdup(cur);
304 void_stack_push(rev_ret, copy);
305 }
306
307 ret_val = void_stack_copy_reverse(rev_ret);
308 void_stack_destroy(rev_ret);
309
310 return ret_val;
311}
312
313
314char* stack2Path(void_stack* nk_stack)
315{
316 const REGF_NK_REC* cur;
317 uint32 buf_left = 127;
318 uint32 buf_len = buf_left+1;
319 uint32 name_len = 0;
320 uint32 grow_amt;
321 char* buf;
322 char* new_buf;
323 void_stack_iterator* iter;
324
325 buf = (char*)malloc((buf_len)*sizeof(char));
326 if (buf == NULL)
327 return NULL;
328 buf[0] = '\0';
329
330 iter = void_stack_iterator_new(nk_stack);
331 if (iter == NULL)
332 {
333 free(buf);
334 return NULL;
335 }
336
337 /* skip root element */
338 cur = void_stack_iterator_next(iter);
339
340 while((cur = void_stack_iterator_next(iter)) != NULL)
341 {
342 buf[buf_len-buf_left-1] = '/';
343 buf_left -= 1;
344 name_len = strlen(cur->keyname);
345 if(name_len+1 > buf_left)
346 {
347 grow_amt = (uint32)(buf_len/2);
348 buf_len += name_len+1+grow_amt-buf_left;
349 if((new_buf = realloc(buf, buf_len)) == NULL)
350 {
351 free(buf);
352 free(iter);
353 return NULL;
354 }
355 buf = new_buf;
356 buf_left = grow_amt + name_len + 1;
357 }
358 strncpy(buf+(buf_len-buf_left-1), cur->keyname, name_len);
359 buf_left -= name_len;
360 buf[buf_len-buf_left-1] = '\0';
361 }
362
363 return buf;
364}
365
366
367void printValue(REGF_VK_REC* vk, char* prefix)
368{
369 uint32 size;
370 uint8 tmp_buf[4];
371 unsigned char* quoted_value;
372 char* quoted_prefix;
373 char* quoted_name;
374
375 /* Thanks Microsoft for making this process so straight-forward!!! */
376 size = (vk->data_size & ~VK_DATA_IN_OFFSET);
377 if(vk->data_size & VK_DATA_IN_OFFSET)
378 {
379 tmp_buf[0] = (uint8)((vk->data_off >> 3) & 0xFF);
380 tmp_buf[1] = (uint8)((vk->data_off >> 2) & 0xFF);
381 tmp_buf[2] = (uint8)((vk->data_off >> 1) & 0xFF);
382 tmp_buf[3] = (uint8)(vk->data_off & 0xFF);
383 if(size > 4)
384 size = 4;
385 quoted_value = data_to_ascii(tmp_buf, 4, vk->type);
386 }
387 else
388 {
389 /* XXX: This is a safety hack. No data fields have yet been found
390 * larger, but length limits are probably better got from fields
391 * in the registry itself, within reason.
392 */
393 if(size > 16384)
394 {
395 fprintf(stderr, "WARNING: key size %d larger than "
396 "16384, truncating...\n", size);
397 size = 16384;
398 }
399 quoted_value = data_to_ascii(vk->data, vk->data_size, vk->type);
400 }
401
402 /* XXX: Sometimes value names can be NULL in registry. Need to
403 * figure out why and when, and generate the appropriate output
404 * for that condition.
405 */
406 quoted_prefix = quote_string(prefix, special_chars);
407 quoted_name = quote_string(vk->valuename, special_chars);
408
409 if(print_security)
410 printf("%s/%s,%s,%s,,,,,\n", quoted_prefix, quoted_name,
411 regfio_type_val2str(vk->type), quoted_value);
412 else
413 printf("%s/%s,%s,%s,\n", quoted_prefix, quoted_name,
414 regfio_type_val2str(vk->type), quoted_value);
415
416 if(quoted_value != NULL)
417 free(quoted_value);
418 if(quoted_prefix != NULL)
419 free(quoted_prefix);
420 if(quoted_name != NULL)
421 free(quoted_name);
422}
423
424
425void printValueList(REGF_NK_REC* nk, char* prefix)
426{
427 uint32 i;
428
429 for(i=0; i < nk->num_values; i++)
430 if(!type_filter_enabled || (nk->values[i].type == type_filter))
431 printValue(&nk->values[i], prefix);
432}
433
434
435void printKey(REGF_NK_REC* k, char* full_path)
436{
437 static char empty_str[1] = "";
438 char* owner = NULL;
439 char* group = NULL;
440 char* sacl = NULL;
441 char* dacl = NULL;
442 char mtime[20];
443 time_t tmp_time[1];
444 struct tm* tmp_time_s = NULL;
445
446 *tmp_time = nt_time_to_unix(&k->mtime);
447 tmp_time_s = gmtime(tmp_time);
448 strftime(mtime, sizeof(mtime), "%Y-%m-%d %H:%M:%S", tmp_time_s);
449
450 if(print_security)
451 {
452 owner = regfio_get_owner(k->sec_desc->sec_desc);
453 group = regfio_get_group(k->sec_desc->sec_desc);
454 sacl = regfio_get_sacl(k->sec_desc->sec_desc);
455 dacl = regfio_get_dacl(k->sec_desc->sec_desc);
456 if(owner == NULL)
457 owner = empty_str;
458 if(group == NULL)
459 group = empty_str;
460 if(sacl == NULL)
461 sacl = empty_str;
462 if(dacl == NULL)
463 dacl = empty_str;
464
465 printf("%s,KEY,,%s,%s,%s,%s,%s\n", full_path, mtime,
466 owner, group, sacl, dacl);
467
468 if(owner != empty_str)
469 free(owner);
470 if(group != empty_str)
471 free(group);
472 if(sacl != empty_str)
473 free(sacl);
474 if(dacl != empty_str)
475 free(dacl);
476 }
477 else
478 printf("%s,KEY,,%s\n", full_path, mtime);
479}
480
481
482/* XXX: this function is awful. Needs to be re-designed. */
483void printKeyTree(REGF_FILE* f, void_stack* nk_stack, char* prefix)
484{
485 REGF_NK_REC* cur = NULL;
486 REGF_NK_REC* sub = NULL;
487 char* path = NULL;
488 char* val_path = NULL;
489 int key_type = regfio_type_str2val("KEY");
490
491 if((cur = (REGF_NK_REC*)void_stack_cur(nk_stack)) != NULL)
492 {
493 cur->subkey_index = 0;
494 path = stack2Path(nk_stack);
495
496 if(print_verbose)
497 {
498 if(prefix[0] == '\0')
499 fprintf(stderr, "VERBOSE: Printing key tree under path: /\n");
500 else
501 fprintf(stderr, "VERBOSE: Printing key tree under path: %s\n",
502 prefix);
503 }
504
505 val_path = (char*)malloc(strlen(prefix)+strlen(path)+1);
506 sprintf(val_path, "%s%s", prefix, path);
507 if(val_path[0] == '\0')
508 {
509 val_path[0] = '/';
510 val_path[1] = '\0';
511 }
512
513 if(!type_filter_enabled || (key_type == type_filter))
514 printKey(cur, val_path);
515 if(!type_filter_enabled || (key_type != type_filter))
516 printValueList(cur, val_path);
517 if(val_path != NULL)
518 free(val_path);
519 while((cur = (REGF_NK_REC*)void_stack_cur(nk_stack)) != NULL)
520 {
521 if((sub = regfio_fetch_subkey(f, cur)) != NULL)
522 {
523 sub->subkey_index = 0;
524 void_stack_push(nk_stack, sub);
525 path = stack2Path(nk_stack);
526 if(path != NULL)
527 {
528 val_path = (char*)malloc(strlen(prefix)+strlen(path)+1);
529 sprintf(val_path, "%s%s", prefix, path);
530 if(!type_filter_enabled || (key_type == type_filter))
531 printKey(sub, val_path);
532 if(!type_filter_enabled || (key_type != type_filter))
533 printValueList(sub, val_path);
534 if(val_path != NULL)
535 free(val_path);
536 }
537 }
538 else
539 {
540 cur = void_stack_pop(nk_stack);
541 /* XXX: This is just a shallow free. Need to write deep free
542 * routines to replace the Samba code for this.
543 */
544 if(cur != NULL)
545 free(cur);
546 }
547 }
548 }
549 if(print_verbose)
550 fprintf(stderr, "VERBOSE: Finished printing key tree.\n");
551}
552
553
554/*
555 * Returns 0 if path was found.
556 * Returns 1 if path was not found.
557 * Returns less than 0 on other error.
558 */
559int retrievePath(REGF_FILE* f, void_stack* nk_stack,
560 void_stack* path_stack)
561{
562 REGF_NK_REC* sub = NULL;
563 REGF_NK_REC* cur = NULL;
564 void_stack* sub_nk_stack;
565 char* prefix;
566 uint32 prefix_len;
567 char* cur_str = NULL;
568 char* path = NULL;
569 bool found_cur = true;
570 uint32 i;
571 uint16 path_depth;
572 if(path_stack == NULL)
573 return -1;
574
575 path_depth = void_stack_size(path_stack);
576 if(path_depth < 1)
577 return -2;
578
579 if(void_stack_size(nk_stack) < 1)
580 return -3;
581 cur = (REGF_NK_REC*)void_stack_cur(nk_stack);
582
583 if(print_verbose)
584 fprintf(stderr, "VERBOSE: Beginning retrieval of specified path: %s\n",
585 path_filter);
586
587 while(void_stack_size(path_stack) > 1)
588 {
589 /* Search key records only */
590 cur_str = (char*)void_stack_pop(path_stack);
591
592 found_cur = false;
593 while(!found_cur &&
594 (sub = regfio_fetch_subkey(f, cur)) != NULL)
595 {
596 if(strcasecmp(sub->keyname, cur_str) == 0)
597 {
598 cur = sub;
599 void_stack_push(nk_stack, sub);
600 found_cur = true;
601 }
602 }
603 if(print_verbose && !found_cur)
604 fprintf(stderr, "VERBOSE: Could not find KEY '%s' in specified path.\n",
605 cur_str);
606
607 free(cur_str);
608 if(!found_cur)
609 return 1;
610 }
611
612 /* Last round, search value and key records */
613 cur_str = (char*)void_stack_pop(path_stack);
614
615 if(print_verbose)
616 fprintf(stderr, "VERBOSE: Searching values for last component"
617 " of specified path.\n");
618
619 for(i=0; (i < cur->num_values); i++)
620 {
621 /* XXX: Not sure when/why this can be NULL, but it's happened. */
622 if(sub->values[i].valuename != NULL
623 && strcasecmp(sub->values[i].valuename, cur_str) == 0)
624 {
625 path = stack2Path(nk_stack);
626
627 if(print_verbose)
628 fprintf(stderr, "VERBOSE: Found final path element as value.\n");
629
630 if(!type_filter_enabled || (sub->values[i].type == type_filter))
631 printValue(&sub->values[i], path);
632 if(path != NULL)
633 free(path);
634
635 return 0;
636 }
637 }
638
639 if(print_verbose)
640 fprintf(stderr, "VERBOSE: Searching keys for last component"
641 " of specified path.\n");
642
643 while((sub = regfio_fetch_subkey(f, cur)) != NULL)
644 {
645 if(strcasecmp(sub->keyname, cur_str) == 0)
646 {
647 sub_nk_stack = void_stack_new(1024);
648 void_stack_push(sub_nk_stack, sub);
649 prefix = stack2Path(nk_stack);
650 prefix_len = strlen(prefix);
651 prefix = realloc(prefix, prefix_len+strlen(sub->keyname)+2);
652 if(prefix == NULL)
653 return -1;
654 strcat(prefix, "/");
655 strcat(prefix, sub->keyname);
656
657 if(print_verbose)
658 fprintf(stderr, "VERBOSE: Found final path element as key.\n");
659
660 printKeyTree(f, sub_nk_stack, prefix);
661
662 return 0;
663 }
664 }
665
666 if(print_verbose)
667 fprintf(stderr, "VERBOSE: Could not find last element of path.\n");
668
669 return 1;
670}
671
672
673static void usage(void)
674{
675 fprintf(stderr, "Usage: readreg [-v] [-s]"
676 " [-p <PATH_FILTER>] [-t <TYPE_FILTER>]"
677 " <REGISTRY_FILE>\n");
678 /* XXX: replace version string with Subversion property? */
679 fprintf(stderr, "Version: 0.2.2\n");
680 fprintf(stderr, "Options:\n");
681 fprintf(stderr, "\t-v\t sets verbose mode.\n");
682 fprintf(stderr, "\t-h\t enables header row. (default)\n");
683 fprintf(stderr, "\t-H\t disables header row.\n");
684 fprintf(stderr, "\t-s\t enables security descriptor output.\n");
685 fprintf(stderr, "\t-S\t disables security descriptor output. (default)\n");
686 fprintf(stderr, "\t-p\t restrict output to elements below this path.\n");
687 fprintf(stderr, "\t-t\t restrict results to this specific data type.\n");
688 fprintf(stderr, "\n");
689}
690
691
692int main(int argc, char** argv)
693{
694 void_stack* nk_stack;
695 void_stack* path_stack;
696 REGF_FILE* f;
697 REGF_NK_REC* root;
698 int retr_path_ret;
699 uint32 argi, arge;
700
701 /* Process command line arguments */
702 if(argc < 2)
703 {
704 usage();
705 bailOut(1, "ERROR: Requires at least one argument.\n");
706 }
707
708 arge = argc-1;
709 for(argi = 1; argi < arge; argi++)
710 {
711 if (strcmp("-p", argv[argi]) == 0)
712 {
713 if(++argi >= arge)
714 {
715 usage();
716 bailOut(1, "ERROR: '-p' option requires parameter.\n");
717 }
718 if((path_filter = strdup(argv[argi])) == NULL)
719 bailOut(2, "ERROR: Memory allocation problem.\n");
720
721 path_filter_enabled = true;
722 }
723 else if (strcmp("-t", argv[argi]) == 0)
724 {
725 if(++argi >= arge)
726 {
727 usage();
728 bailOut(1, "ERROR: '-t' option requires parameter.\n");
729 }
730 if((type_filter = regfio_type_str2val(argv[argi])) == 0)
731 {
732 fprintf(stderr, "ERROR: Invalid type specified: %s.\n", argv[argi]);
733 bailOut(1, "");
734 }
735
736 type_filter_enabled = true;
737 }
738 else if (strcmp("-h", argv[argi]) == 0)
739 print_header = true;
740 else if (strcmp("-H", argv[argi]) == 0)
741 print_header = false;
742 else if (strcmp("-s", argv[argi]) == 0)
743 print_security = true;
744 else if (strcmp("-S", argv[argi]) == 0)
745 print_security = false;
746 else if (strcmp("-v", argv[argi]) == 0)
747 print_verbose = true;
748 else
749 {
750 usage();
751 fprintf(stderr, "ERROR: Unrecognized option: %s\n", argv[argi]);
752 bailOut(1, "");
753 }
754 }
755 if((registry_file = strdup(argv[argi])) == NULL)
756 bailOut(2, "ERROR: Memory allocation problem.\n");
757
758 f = regfio_open(registry_file);
759 if(f == NULL)
760 {
761 fprintf(stderr, "ERROR: Couldn't open registry file: %s\n", registry_file);
762 bailOut(3, "");
763 }
764
765 root = regfio_rootkey(f);
766 nk_stack = void_stack_new(1024);
767
768 if(void_stack_push(nk_stack, root))
769 {
770 if(print_header)
771 {
772 if(print_security)
773 printf("PATH,TYPE,VALUE,MTIME,OWNER,GROUP,SACL,DACL\n");
774 else
775 printf("PATH,TYPE,VALUE,MTIME\n");
776 }
777
778 path_stack = path2Stack(path_filter);
779 if(void_stack_size(path_stack) < 1)
780 printKeyTree(f, nk_stack, "");
781 else
782 {
783 retr_path_ret = retrievePath(f, nk_stack, path_stack);
784 if(retr_path_ret == 1)
785 fprintf(stderr, "WARNING: specified path not found.\n");
786 else if(retr_path_ret != 0)
787 bailOut(4, "ERROR:\n");
788 }
789 }
790 else
791 bailOut(2, "ERROR: Memory allocation problem.\n");
792
793 void_stack_destroy_deep(nk_stack);
794 regfio_close(f);
795
796 return 0;
797}
Note: See TracBrowser for help on using the repository browser.