2 * Unix SMB/CIFS implementation.
3 * Virtual Windows Registry Layer
4 * Copyright (C) Gerald Carter 2002-2005
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 /* Implementation of registry virtual views for printing information */
26 #define DBGC_CLASS DBGC_RPC_SRV
28 /* registrt paths used in the print_registry[] */
30 #define KEY_MONITORS "HKLM/SYSTEM/CURRENTCONTROLSET/CONTROL/PRINT/MONITORS"
31 #define KEY_FORMS "HKLM/SYSTEM/CURRENTCONTROLSET/CONTROL/PRINT/FORMS"
32 #define KEY_CONTROL_PRINTERS "HKLM/SYSTEM/CURRENTCONTROLSET/CONTROL/PRINT/PRINTERS"
33 #define KEY_ENVIRONMENTS "HKLM/SYSTEM/CURRENTCONTROLSET/CONTROL/PRINT/ENVIRONMENTS"
34 #define KEY_CONTROL_PRINT "HKLM/SYSTEM/CURRENTCONTROLSET/CONTROL/PRINT"
35 #define KEY_WINNT_PRINTERS "HKLM/SOFTWARE/MICROSOFT/WINDOWS NT/CURRENTVERSION/PRINT/PRINTERS"
36 #define KEY_WINNT_PRINT "HKLM/SOFTWARE/MICROSOFT/WINDOWS NT/CURRENTVERSION/PRINT"
37 #define KEY_PORTS "HKLM/SOFTWARE/MICROSOFT/WINDOWS NT/CURRENTVERSION/PORTS"
39 /* callback table for various registry paths below the ones we service in this module */
42 /* full key path in normalized form */
45 /* callbscks for fetch/store operations */
46 int ( *fetch_subkeys) ( const char *path, REGSUBKEY_CTR *subkeys );
47 BOOL (*store_subkeys) ( const char *path, REGSUBKEY_CTR *subkeys );
48 int (*fetch_values) ( const char *path, REGVAL_CTR *values );
49 BOOL (*store_values) ( const char *path, REGVAL_CTR *values );
53 /**********************************************************************
54 move to next non-delimter character
55 *********************************************************************/
57 static char* remaining_path( const char *key )
59 static pstring new_path;
65 pstrcpy( new_path, key );
66 /* normalize_reg_path( new_path ); */
68 if ( !(p = strchr( new_path, '\\' )) )
70 if ( !(p = strchr( new_path, '/' )) )
81 /***********************************************************************
82 simple function to prune a pathname down to the basename of a file
83 **********************************************************************/
85 static char* dos_basename ( char *path )
89 if ( !(p = strrchr( path, '\\' )) )
97 /**********************************************************************
98 *********************************************************************/
100 static int key_forms_fetch_keys( const char *key, REGSUBKEY_CTR *subkeys )
102 char *p = remaining_path( key + strlen(KEY_FORMS) );
104 /* no keys below Forms */
112 static int key_forms_fetch_values( const char *key, REGVAL_CTR *values )
115 int i, num_values, form_index = 1;
116 nt_forms_struct *forms_list = NULL;
117 nt_forms_struct *form;
119 DEBUG(10,("print_values_forms: key=>[%s]\n", key ? key : "NULL" ));
121 num_values = get_ntforms( &forms_list );
123 DEBUG(10,("hive_forms_fetch_values: [%d] user defined forms returned\n",
126 /* handle user defined forms */
128 for ( i=0; i<num_values; i++ ) {
129 form = &forms_list[i];
131 data[0] = form->width;
132 data[1] = form->length;
133 data[2] = form->left;
135 data[4] = form->right;
136 data[5] = form->bottom;
137 data[6] = form_index++;
138 data[7] = form->flag;
140 regval_ctr_addvalue( values, form->name, REG_BINARY, (char*)data, sizeof(data) );
143 SAFE_FREE( forms_list );
146 /* handle built-on forms */
148 num_values = get_builtin_ntforms( &forms_list );
150 DEBUG(10,("print_subpath_values_forms: [%d] built-in forms returned\n",
153 for ( i=0; i<num_values; i++ ) {
154 form = &forms_list[i];
156 data[0] = form->width;
157 data[1] = form->length;
158 data[2] = form->left;
160 data[4] = form->right;
161 data[5] = form->bottom;
162 data[6] = form_index++;
163 data[7] = form->flag;
165 regval_ctr_addvalue( values, form->name, REG_BINARY, (char*)data, sizeof(data) );
168 SAFE_FREE( forms_list );
170 return regval_ctr_numvals( values );
173 /**********************************************************************
174 *********************************************************************/
176 static int key_printer_fetch_keys( const char *key, REGSUBKEY_CTR *subkeys )
178 int n_services = lp_numservices();
184 char *base, *new_path;
185 NT_PRINTER_INFO_LEVEL *printer = NULL;
186 fstring *subkey_names = NULL;
189 DEBUG(10,("print_subpath_printers: key=>[%s]\n", key ? key : "NULL" ));
191 pstrcpy( path, key );
192 normalize_reg_path( path );
194 /* normalizing the path does not change length, just key delimiters and case */
196 if ( strncmp( path, KEY_WINNT_PRINTERS, strlen(KEY_WINNT_PRINTERS) ) == 0 )
197 keystr = remaining_path( key + strlen(KEY_WINNT_PRINTERS) );
199 keystr = remaining_path( key + strlen(KEY_CONTROL_PRINTERS) );
203 /* enumerate all printers */
205 for (snum=0; snum<n_services; snum++) {
206 if ( !(lp_snum_ok(snum) && lp_print_ok(snum) ) )
209 /* don't report the [printers] share */
211 if ( strequal( lp_servicename(snum), PRINTERS_NAME ) )
214 fstrcpy( sname, lp_servicename(snum) );
216 regsubkey_ctr_addkey( subkeys, sname );
219 num_subkeys = regsubkey_ctr_numkeys( subkeys );
223 /* get information for a specific printer */
225 reg_split_path( keystr, &base, &new_path );
227 if ( !W_ERROR_IS_OK( get_a_printer(NULL, &printer, 2, base) ) )
230 num_subkeys = get_printer_subkeys( &printer->info_2->data, new_path?new_path:"", &subkey_names );
232 for ( i=0; i<num_subkeys; i++ )
233 regsubkey_ctr_addkey( subkeys, subkey_names[i] );
235 free_a_printer( &printer, 2 );
237 /* no other subkeys below here */
240 SAFE_FREE( subkey_names );
245 static BOOL key_printer_store_keys( const char *key, REGSUBKEY_CTR *subkeys )
250 static int key_printer_fetch_values( const char *key, REGVAL_CTR *values )
253 char *keystr, *key2 = NULL;
254 char *base, *new_path;
255 NT_PRINTER_INFO_LEVEL *printer = NULL;
256 NT_PRINTER_INFO_LEVEL_2 *info2;
262 NT_PRINTER_DATA *p_data;
268 * Theres are tw cases to deal with here
269 * (1) enumeration of printer_info_2 values
270 * (2) enumeration of the PrinterDriverData subney
273 pstrcpy( path, key );
274 normalize_reg_path( path );
276 /* normalizing the path does not change length, just key delimiters and case */
278 if ( strncmp( path, KEY_WINNT_PRINTERS, strlen(KEY_WINNT_PRINTERS) ) == 0 )
279 keystr = remaining_path( key + strlen(KEY_WINNT_PRINTERS) );
281 keystr = remaining_path( key + strlen(KEY_CONTROL_PRINTERS) );
284 /* top level key has no values */
288 key2 = SMB_STRDUP( keystr );
290 reg_split_path( keystr, &base, &new_path );
292 fstrcpy( printername, base );
296 uint32 printer_status = PRINTER_STATUS_OK;
298 /* we are dealing with the printer itself */
300 if ( !W_ERROR_IS_OK( get_a_printer(NULL, &printer, 2, printername) ) )
303 info2 = printer->info_2;
306 regval_ctr_addvalue( values, "Attributes", REG_DWORD, (char*)&info2->attributes, sizeof(info2->attributes) );
307 regval_ctr_addvalue( values, "Priority", REG_DWORD, (char*)&info2->priority, sizeof(info2->attributes) );
308 regval_ctr_addvalue( values, "ChangeID", REG_DWORD, (char*)&info2->changeid, sizeof(info2->changeid) );
309 regval_ctr_addvalue( values, "Default Priority", REG_DWORD, (char*)&info2->default_priority, sizeof(info2->default_priority) );
311 /* lie and say everything is ok since we don't want to call print_queue_length() to get the real status */
312 regval_ctr_addvalue( values, "Status", REG_DWORD, (char*)&printer_status, sizeof(info2->status) );
314 regval_ctr_addvalue( values, "StartTime", REG_DWORD, (char*)&info2->starttime, sizeof(info2->starttime) );
315 regval_ctr_addvalue( values, "UntilTime", REG_DWORD, (char*)&info2->untiltime, sizeof(info2->untiltime) );
317 /* strip the \\server\ from this string */
318 if ( !(p = strrchr( info2->printername, '\\' ) ) )
319 p = info2->printername;
322 init_unistr2( &data, p, UNI_STR_TERMINATE);
323 regval_ctr_addvalue( values, "Name", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
325 init_unistr2( &data, info2->location, UNI_STR_TERMINATE);
326 regval_ctr_addvalue( values, "Location", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
328 init_unistr2( &data, info2->comment, UNI_STR_TERMINATE);
329 regval_ctr_addvalue( values, "Description", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
331 init_unistr2( &data, info2->parameters, UNI_STR_TERMINATE);
332 regval_ctr_addvalue( values, "Parameters", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
334 init_unistr2( &data, info2->portname, UNI_STR_TERMINATE);
335 regval_ctr_addvalue( values, "Port", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
337 init_unistr2( &data, info2->sharename, UNI_STR_TERMINATE);
338 regval_ctr_addvalue( values, "Share Name", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
340 init_unistr2( &data, info2->drivername, UNI_STR_TERMINATE);
341 regval_ctr_addvalue( values, "Printer Driver", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
343 init_unistr2( &data, info2->sepfile, UNI_STR_TERMINATE);
344 regval_ctr_addvalue( values, "Separator File", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
346 init_unistr2( &data, "WinPrint", UNI_STR_TERMINATE);
347 regval_ctr_addvalue( values, "Print Processor", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
349 init_unistr2( &data, "RAW", UNI_STR_TERMINATE);
350 regval_ctr_addvalue( values, "Datatype", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
353 /* use a prs_struct for converting the devmode and security
354 descriptor to REG_BINARY */
356 prs_init( &prs, MAX_PDU_FRAG_LEN, regval_ctr_getctx(values), MARSHALL);
358 /* stream the device mode */
360 snum = lp_servicenumber(info2->sharename);
361 if ( (devmode = construct_dev_mode( snum )) != NULL )
363 if ( spoolss_io_devmode( "devmode", &prs, 0, devmode ) ) {
365 offset = prs_offset( &prs );
367 regval_ctr_addvalue( values, "Default Devmode", REG_BINARY, prs_data_p(&prs), offset );
373 prs_mem_clear( &prs );
374 prs_set_offset( &prs, 0 );
376 if ( info2->secdesc_buf && info2->secdesc_buf->len )
378 if ( sec_io_desc("sec_desc", &info2->secdesc_buf->sec, &prs, 0 ) ) {
380 offset = prs_offset( &prs );
382 regval_ctr_addvalue( values, "Security", REG_BINARY, prs_data_p(&prs), offset );
386 prs_mem_free( &prs );
388 num_values = regval_ctr_numvals( values );
394 /* now enumerate the key */
396 if ( !W_ERROR_IS_OK( get_a_printer(NULL, &printer, 2, printername) ) )
399 /* iterate over all printer data and fill the regval container */
401 p_data = &printer->info_2->data;
402 if ( (key_index = lookup_printerkey( p_data, new_path )) == -1 ) {
403 DEBUG(10,("key_printer_fetch_values: Unknown keyname [%s]\n", new_path));
407 num_values = regval_ctr_numvals( &p_data->keys[key_index].values );
409 for ( i=0; i<num_values; i++ )
410 regval_ctr_copyvalue( values, regval_ctr_specific_value(&p_data->keys[key_index].values, i) );
415 free_a_printer( &printer, 2 );
422 static BOOL key_printer_store_values( const char *key, REGVAL_CTR *values )
427 /**********************************************************************
428 *********************************************************************/
429 #define ENVIRONMENT_DRIVERS 1
430 #define ENVIRONMENT_PRINTPROC 2
432 static int key_driver_fetch_keys( const char *key, REGSUBKEY_CTR *subkeys )
434 const char *environments[] = {
438 "Windows NT Alpha_AXP",
439 "Windows NT PowerPC",
443 fstring *drivers = NULL;
444 int i, env_index, num_drivers;
445 char *keystr, *base, *subkeypath;
447 int num_subkeys = -1;
448 int env_subkey_type = 0;
451 DEBUG(10,("key_driver_fetch_keys key=>[%s]\n", key ? key : "NULL" ));
453 keystr = remaining_path( key + strlen(KEY_ENVIRONMENTS) );
455 /* list all possible architectures */
458 for ( num_subkeys=0; environments[num_subkeys]; num_subkeys++ )
459 regsubkey_ctr_addkey( subkeys, environments[num_subkeys] );
464 /* we are dealing with a subkey of "Environments */
466 pstrcpy( key2, keystr );
468 reg_split_path( keystr, &base, &subkeypath );
472 for ( env_index=0; environments[env_index]; env_index++ ) {
473 if ( strequal( environments[env_index], base ) )
476 if ( !environments[env_index] )
479 /* ...\Print\Environements\...\ */
482 regsubkey_ctr_addkey( subkeys, "Drivers" );
483 regsubkey_ctr_addkey( subkeys, "Print Processors" );
488 /* more of the key path to process */
491 reg_split_path( keystr, &base, &subkeypath );
493 /* ...\Print\Environements\...\Drivers\ */
495 if ( strequal(base, "Drivers") )
496 env_subkey_type = ENVIRONMENT_DRIVERS;
497 else if ( strequal(base, "Print Processors") )
498 env_subkey_type = ENVIRONMENT_PRINTPROC;
504 switch ( env_subkey_type ) {
505 case ENVIRONMENT_DRIVERS:
506 switch ( env_index ) {
508 regsubkey_ctr_addkey( subkeys, "Version-0" );
510 default: /* Windows NT based systems */
511 regsubkey_ctr_addkey( subkeys, "Version-2" );
512 regsubkey_ctr_addkey( subkeys, "Version-3" );
516 return regsubkey_ctr_numkeys( subkeys );
518 case ENVIRONMENT_PRINTPROC:
519 if ( env_index == 1 || env_index == 5 || env_index == 6 )
520 regsubkey_ctr_addkey( subkeys, "winprint" );
522 return regsubkey_ctr_numkeys( subkeys );
526 /* we finally get to enumerate the drivers */
529 reg_split_path( keystr, &base, &subkeypath );
531 /* get thr print processors key out of the way */
532 if ( env_subkey_type == ENVIRONMENT_PRINTPROC ) {
533 if ( !strequal( base, "winprint" ) )
535 return !subkeypath ? 0 : -1;
538 /* only dealing with drivers from here on out */
540 version = atoi(&base[strlen(base)-1]);
548 if ( version != 2 && version != 3 )
555 num_drivers = get_ntdrivers( &drivers, environments[env_index], version );
556 for ( i=0; i<num_drivers; i++ )
557 regsubkey_ctr_addkey( subkeys, drivers[i] );
559 return regsubkey_ctr_numkeys( subkeys );
562 /* if anything else left, just say if has no subkeys */
564 DEBUG(1,("key_driver_fetch_keys unhandled key [%s] (subkey == %s\n",
570 static BOOL key_driver_store_keys( const char *key, REGSUBKEY_CTR *subkeys )
575 static int key_driver_fetch_values( const char *key, REGVAL_CTR *values )
577 char *keystr, *base, *subkeypath;
579 fstring arch_environment;
582 NT_PRINTER_DRIVER_INFO_LEVEL driver_ctr;
583 NT_PRINTER_DRIVER_INFO_LEVEL_3 *info3;
586 char *buffer2 = NULL;
591 int env_subkey_type = 0;
594 DEBUG(8,("key_driver_fetch_values: Enter key => [%s]\n", key ? key : "NULL"));
596 keystr = remaining_path( key + strlen(KEY_ENVIRONMENTS) );
601 /* The only keys below KEY_PRINTING\Environments is the
602 specific printer driver info */
606 pstrcpy( key2, keystr);
608 reg_split_path( keystr, &base, &subkeypath );
611 fstrcpy( arch_environment, base );
616 reg_split_path( keystr, &base, &subkeypath );
618 if ( strequal(base, "Drivers") )
619 env_subkey_type = ENVIRONMENT_DRIVERS;
620 else if ( strequal(base, "Print Processors") )
621 env_subkey_type = ENVIRONMENT_PRINTPROC;
629 /* for now bail out if we are seeing anything other than the drivers key */
631 if ( env_subkey_type == ENVIRONMENT_PRINTPROC )
635 reg_split_path( keystr, &base, &subkeypath );
637 /* no values under Version-XX */
642 version = atoi(&base[strlen(base)-1]);
644 /* printer driver name */
647 reg_split_path( keystr, &base, &subkeypath );
648 /* don't go any deeper for now */
651 fstrcpy( driver, base );
653 w_result = get_a_printer_driver( &driver_ctr, 3, driver, arch_environment, version );
655 if ( !W_ERROR_IS_OK(w_result) )
658 /* build the values out of the driver information */
659 info3 = driver_ctr.info_3;
661 filename = dos_basename( info3->driverpath );
662 init_unistr2( &data, filename, UNI_STR_TERMINATE);
663 regval_ctr_addvalue( values, "Driver", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
665 filename = dos_basename( info3->configfile );
666 init_unistr2( &data, filename, UNI_STR_TERMINATE);
667 regval_ctr_addvalue( values, "Configuration File", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
669 filename = dos_basename( info3->datafile );
670 init_unistr2( &data, filename, UNI_STR_TERMINATE);
671 regval_ctr_addvalue( values, "Data File", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
673 filename = dos_basename( info3->helpfile );
674 init_unistr2( &data, filename, UNI_STR_TERMINATE);
675 regval_ctr_addvalue( values, "Help File", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
677 init_unistr2( &data, info3->defaultdatatype, UNI_STR_TERMINATE);
678 regval_ctr_addvalue( values, "Data Type", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
680 regval_ctr_addvalue( values, "Version", REG_DWORD, (char*)&info3->cversion, sizeof(info3->cversion) );
682 if ( info3->dependentfiles ) {
683 /* place the list of dependent files in a single
684 character buffer, separating each file name by
687 for ( i=0; strcmp(info3->dependentfiles[i], ""); i++ ) {
688 /* strip the path to only the file's base name */
690 filename = dos_basename( info3->dependentfiles[i] );
692 length = strlen(filename);
694 buffer2 = SMB_REALLOC( buffer, buffer_size + (length + 1)*sizeof(uint16) );
699 init_unistr2( &data, filename, UNI_STR_TERMINATE);
700 memcpy( buffer+buffer_size, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
702 buffer_size += (length + 1)*sizeof(uint16);
705 /* terminated by double NULL. Add the final one here */
707 buffer2 = SMB_REALLOC( buffer, buffer_size + 2 );
713 buffer[buffer_size++] = '\0';
714 buffer[buffer_size++] = '\0';
718 regval_ctr_addvalue( values, "Dependent Files", REG_MULTI_SZ, buffer, buffer_size );
720 free_a_printer_driver( driver_ctr, 3 );
724 DEBUG(8,("key_driver_fetch_values: Exit\n"));
726 return regval_ctr_numvals( values );
729 static BOOL key_driver_store_values( const char *key, REGVAL_CTR *values )
734 /**********************************************************************
735 Deal with the 'Print' key the same whether it came from SYSTEM
737 *********************************************************************/
739 static int key_print_fetch_keys( const char *key, REGSUBKEY_CTR *subkeys )
741 int key_len = strlen(key);
743 /* no keys below 'Print' handled here */
745 if ( (key_len != strlen(KEY_CONTROL_PRINT)) && (key_len != strlen(KEY_WINNT_PRINT)) )
748 regsubkey_ctr_addkey( subkeys, "Environments" );
749 regsubkey_ctr_addkey( subkeys, "Monitors" );
750 regsubkey_ctr_addkey( subkeys, "Forms" );
751 regsubkey_ctr_addkey( subkeys, "Printers" );
753 return regsubkey_ctr_numkeys( subkeys );
756 /**********************************************************************
757 If I can get rid of the 'enumports command', this code becomes
759 *********************************************************************/
761 static int key_ports_fetch_keys( const char *key, REGSUBKEY_CTR *subkeys )
763 /* no keys below ports */
765 if ( remaining_path( key + strlen(KEY_PORTS) ) )
771 static BOOL key_ports_store_keys( const char *key, REGSUBKEY_CTR *subkeys )
776 static int key_ports_fetch_values( const char *key, REGVAL_CTR *values )
782 char *p = remaining_path( key + strlen(KEY_PORTS) );
784 /* no keys below ports */
788 if ( !W_ERROR_IS_OK(result = enumports_hook( &numlines, &lines )) )
791 init_unistr2( &data, "", UNI_STR_TERMINATE);
792 for ( i=0; i<numlines; i++ )
793 regval_ctr_addvalue( values, lines[i], REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
795 return regval_ctr_numvals( values );
798 static BOOL key_ports_store_values( const char *key, REGVAL_CTR *values )
803 /**********************************************************************
804 Structure to hold dispatch table of ops for various printer keys.
805 Make sure to always store deeper keys along the same path first so
806 we ge a more specific match.
807 *********************************************************************/
809 static struct reg_dyn_tree print_registry[] = {
810 /* just pass the monitor onto the registry tdb */
815 ®db_store_values },
817 &key_forms_fetch_keys,
819 &key_forms_fetch_values,
821 { KEY_CONTROL_PRINTERS,
822 &key_printer_fetch_keys,
823 &key_printer_store_keys,
824 &key_printer_fetch_values,
825 &key_printer_store_values },
827 &key_driver_fetch_keys,
828 &key_driver_store_keys,
829 &key_driver_fetch_values,
830 &key_driver_store_values },
832 &key_print_fetch_keys,
836 { KEY_WINNT_PRINTERS,
837 &key_printer_fetch_keys,
838 &key_printer_store_keys,
839 &key_printer_fetch_values,
840 &key_printer_store_values },
842 &key_ports_fetch_keys,
843 &key_ports_store_keys,
844 &key_ports_fetch_values,
845 &key_ports_store_values },
847 { NULL, NULL, NULL, NULL, NULL }
851 /**********************************************************************
852 *********************************************************************/
854 static int match_registry_path( const char *key )
862 pstrcpy( path, key );
863 normalize_reg_path( path );
865 for ( i=0; print_registry[i].path; i++ ) {
866 if ( strncmp( path, print_registry[i].path, strlen(print_registry[i].path) ) == 0 )
873 /**********************************************************************
874 *********************************************************************/
876 static int regprint_fetch_reg_keys( const char *key, REGSUBKEY_CTR *subkeys )
878 int i = match_registry_path( key );
883 if ( !print_registry[i].fetch_subkeys )
886 return print_registry[i].fetch_subkeys( key, subkeys );
889 /**********************************************************************
890 *********************************************************************/
892 static BOOL regprint_store_reg_keys( const char *key, REGSUBKEY_CTR *subkeys )
894 int i = match_registry_path( key );
899 if ( !print_registry[i].store_subkeys )
902 return print_registry[i].store_subkeys( key, subkeys );
905 /**********************************************************************
906 *********************************************************************/
908 static int regprint_fetch_reg_values( const char *key, REGVAL_CTR *values )
910 int i = match_registry_path( key );
915 /* return 0 values by default since we know the key had
916 to exist because the client opened a handle */
918 if ( !print_registry[i].fetch_values )
921 return print_registry[i].fetch_values( key, values );
924 /**********************************************************************
925 *********************************************************************/
927 static BOOL regprint_store_reg_values( const char *key, REGVAL_CTR *values )
929 int i = match_registry_path( key );
934 if ( !print_registry[i].store_values )
937 return print_registry[i].store_values( key, values );
941 * Table of function pointers for accessing printing data
944 REGISTRY_OPS printing_ops = {
945 regprint_fetch_reg_keys,
946 regprint_fetch_reg_values,
947 regprint_store_reg_keys,
948 regprint_store_reg_values,