static void tlink_init (void) { const char *p; symbol_table = htab_create (500, hash_string_hash, hash_string_eq, NULL); file_table = htab_create (500, hash_string_hash, hash_string_eq, NULL); demangled_table = htab_create (500, hash_string_hash, hash_string_eq, NULL); obstack_begin (&symbol_stack_obstack, 0); obstack_begin (&file_stack_obstack, 0); p = getenv ("TLINK_VERBOSE"); if (p) tlink_verbose = atoi (p); else { tlink_verbose = 1; if (vflag) tlink_verbose = 2; if (debug) tlink_verbose = 3; } getcwd (initial_cwd, sizeof (initial_cwd)); }
/*! \brief Prepare hash table before readdir Prepare hash table before readdir. \param dentry Dentry of the directory */ void version_create_dirhtab(internal_dentry dentry) { if (dentry->dirhtab) htab_destroy(dentry->dirhtab); dentry->dirhtab = htab_create(10, dirhtab_hash, dirhtab_eq, dirhtab_del, &dentry->fh->mutex); }
static void fill_hash_bucket (void) { basic_block bb; rtx insn; void **slot; p_hash_bucket bucket; struct hash_bucket_def tmp_bucket; p_hash_elem elem; unsigned long insn_idx; insn_idx = 0; FOR_EACH_BB (bb) { FOR_BB_INSNS_REVERSE (bb, insn) { if (!ABSTRACTABLE_INSN_P (insn)) continue; /* Compute hash value for INSN. */ tmp_bucket.hash = compute_hash (insn); /* Select the hash group. */ bucket = (p_hash_bucket) htab_find (hash_buckets, &tmp_bucket); if (!bucket) { /* Create a new hash group. */ bucket = (p_hash_bucket) xcalloc (1, sizeof (struct hash_bucket_def)); bucket->hash = tmp_bucket.hash; bucket->seq_candidates = NULL; slot = htab_find_slot (hash_buckets, &tmp_bucket, INSERT); *slot = bucket; } /* Create new list for storing sequence candidates. */ if (!bucket->seq_candidates) bucket->seq_candidates = htab_create (HASH_INIT, htab_hash_elem, htab_eq_elem, htab_del_elem); elem = (p_hash_elem) xcalloc (1, sizeof (struct hash_elem_def)); elem->insn = insn; elem->idx = insn_idx; elem->length = get_attr_length (insn); /* Insert INSN into BUCKET hash bucket. */ slot = htab_find_slot (bucket->seq_candidates, elem, INSERT); *slot = elem; insn_idx++; } } }
static unsigned int postreload_load (void) { basic_block bb; init_alias_analysis (); FOR_EACH_BB (bb) { rtx insn; htab_load = htab_create (10, load_htab_hash, load_htab_eq, NULL); FOR_BB_INSNS (bb, insn) { rtx set; struct load **load; /* Set reg_kill, invalidate entries if there is an aliasing store or if the registers making up the address change. */ htab_traverse_noresize (htab_load, find_reg_kill_and_mem_invalidate, insn); set = single_set (insn); if (interesting_second_load (set, &load, insn)) { rtx move; move = gen_move_insn (SET_DEST (set), (*load)->reg); /* Make sure we can generate a move. */ extract_insn (move); if (! constrain_operands (1)) continue; move = emit_insn_before (move, (*load)->reg_kill); delete_insn (insn); if (dump_file) { fputs ("Replaced this load:\n ", dump_file); print_inline_rtx (dump_file, insn, 2); fputs ("\n with this move:\n ", dump_file); print_inline_rtx (dump_file, move, 2); fputs ("\n\n", dump_file); } } else if (interesting_load (set)) alloc_load (set); else if (CALL_P (insn)) htab_empty (htab_load); } htab_empty (htab_load); }
int main (int argc, char **argv) { rtx desc; int pattern_lineno; /* not used */ int code; progname = "genconditions"; if (init_md_reader_args (argc, argv) != SUCCESS_EXIT_CODE) return (FATAL_EXIT_CODE); condition_table = htab_create (1000, hash_c_test, cmp_c_test, NULL); /* Read the machine description. */ while (1) { desc = read_md_rtx (&pattern_lineno, &code); if (desc == NULL) break; /* N.B. define_insn_and_split, define_cond_exec are handled entirely within read_md_rtx; we never see them. */ switch (GET_CODE (desc)) { default: break; case DEFINE_INSN: case DEFINE_EXPAND: add_condition (XSTR (desc, 2)); /* except.h needs to know whether there is an eh_return pattern in the machine description. */ if (!strcmp (XSTR (desc, 0), "eh_return")) saw_eh_return = 1; break; case DEFINE_SPLIT: case DEFINE_PEEPHOLE: case DEFINE_PEEPHOLE2: add_condition (XSTR (desc, 1)); break; } } write_header (); write_conditions (); fflush (stdout); return (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE); }
void lto_streamer_init (void) { /* Check that all the TS_* handled by the reader and writer routines match exactly the structures defined in treestruct.def. When a new TS_* astructure is added, the streamer should be updated to handle it. */ streamer_check_handled_ts_structures (); #ifdef LTO_STREAMER_DEBUG tree_htab = htab_create (31, hash_tree, eq_tree, NULL); #endif }
int windows_common_init(struct libusb_context *ctx) { if (!windows_init_clock(ctx)) goto error_roll_back; if (!htab_create(ctx, HTAB_SIZE)) goto error_roll_back; return LIBUSB_SUCCESS; error_roll_back: windows_common_exit(); return LIBUSB_ERROR_NO_MEM; }
journal_t journal_create(unsigned int nelem, pthread_mutex_t * mutex) { journal_t journal; journal = (journal_t) xmalloc(sizeof(struct journal_def)); journal->htab = htab_create(nelem, journal_hash, journal_eq, NULL, NULL); journal->mutex = mutex; journal->first = NULL; journal->last = NULL; journal->fd = -1; journal->generation = 0; return journal; }
static void resolve_conflicts (struct plugin_symtab *t, struct plugin_symtab *conflicts) { htab_t symtab = htab_create (t->nsyms, hash_sym, eq_sym, NULL); int i; int out; int outlen; outlen = t->nsyms; conflicts->syms = xmalloc (sizeof (struct ld_plugin_symbol) * outlen); conflicts->aux = xmalloc (sizeof (struct sym_aux) * outlen); /* Move all duplicate symbols into the auxiliary conflicts table. */ out = 0; for (i = 0; i < t->nsyms; i++) { struct ld_plugin_symbol *s = &t->syms[i]; struct sym_aux *aux = &t->aux[i]; void **slot; slot = htab_find_slot (symtab, s, INSERT); if (*slot != NULL) { int cnf; struct ld_plugin_symbol *orig = (struct ld_plugin_symbol *)*slot; struct sym_aux *orig_aux = &t->aux[orig - t->syms]; /* Always let the linker resolve the strongest symbol */ if (symbol_strength (orig) < symbol_strength (s)) { SWAP (struct ld_plugin_symbol, *orig, *s); SWAP (uint32_t, orig_aux->slot, aux->slot); SWAP (unsigned long long, orig_aux->id, aux->id); /* Don't swap conflict chain pointer */ } /* Move current symbol into the conflicts table */ cnf = conflicts->nsyms++; conflicts->syms[cnf] = *s; conflicts->aux[cnf] = *aux; aux = &conflicts->aux[cnf]; /* Update conflicts chain of the original symbol */ aux->next_conflict = orig_aux->next_conflict; orig_aux->next_conflict = cnf; continue; }
unsigned int i386_pe_section_type_flags (tree decl, const char *name, int reloc) { static htab_t htab; unsigned int flags; unsigned int **slot; /* The names we put in the hashtable will always be the unique versions given to us by the stringtable, so we can just use their addresses as the keys. */ if (!htab) htab = htab_create (31, htab_hash_pointer, htab_eq_pointer, NULL); if (decl && TREE_CODE (decl) == FUNCTION_DECL) flags = SECTION_CODE; else if (decl && decl_readonly_section (decl, reloc)) flags = 0; else { flags = SECTION_WRITE; if (decl && TREE_CODE (decl) == VAR_DECL /* APPLE LOCAL begin mainline 2005-04-01 */ && lookup_attribute ("shared", DECL_ATTRIBUTES (decl))) flags |= SECTION_PE_SHARED; /* APPLE LOCAL end mainline 2005-04-01 */ } if (decl && DECL_ONE_ONLY (decl)) flags |= SECTION_LINKONCE; /* See if we already have an entry for this section. */ slot = (unsigned int **) htab_find_slot (htab, name, INSERT); if (!*slot) { *slot = (unsigned int *) xmalloc (sizeof (unsigned int)); **slot = flags; } else { if (decl && **slot != flags) error ("%J'%D' causes a section type conflict", decl, decl); } return flags; }
static inline coalesce_list_p create_coalesce_list (void) { coalesce_list_p list; unsigned size = num_ssa_names * 3; if (size < 40) size = 40; list = (coalesce_list_p) xmalloc (sizeof (struct coalesce_list_d)); list->list = htab_create (size, coalesce_pair_map_hash, coalesce_pair_map_eq, NULL); list->sorted = NULL; list->num_sorted = 0; list->cost_one_list = NULL; return list; }
static struct cl_perfunc_opts * make_perfunc_opts (void) { PTR *slot; if (!cl_perfunc_opts_hash_table) cl_perfunc_opts_hash_table = htab_create (11, hash_cl_perfunc_opts, cmp_cl_perfunc_opts, NULL); slot = htab_find_slot (cl_perfunc_opts_hash_table, &cl_pf_opts, INSERT); if (*slot == NULL) { *slot = xmalloc (sizeof (struct cl_perfunc_opts)); memcpy (*slot, &cl_pf_opts, sizeof (struct cl_perfunc_opts)); } return *slot; }
/* For given name, return descriptor, create new if needed. */ static struct varray_descriptor * varray_descriptor (const char *name) { struct varray_descriptor **slot; if (!varray_hash) varray_hash = htab_create (10, hash_descriptor, eq_descriptor, NULL); slot = (struct varray_descriptor **) htab_find_slot_with_hash (varray_hash, name, htab_hash_pointer (name), INSERT); if (*slot) return *slot; *slot = XCNEW (struct varray_descriptor); (*slot)->name = name; return *slot; }
/* For given name, return descriptor, create new if needed. */ static struct alloc_pool_descriptor * alloc_pool_descriptor (const char *name) { struct alloc_pool_descriptor **slot; if (!alloc_pool_hash) alloc_pool_hash = htab_create (10, hash_descriptor, eq_descriptor, NULL); slot = (struct alloc_pool_descriptor **) htab_find_slot_with_hash (alloc_pool_hash, name, htab_hash_pointer (name), 1); if (*slot) return *slot; *slot = xcalloc (sizeof (**slot), 1); (*slot)->name = name; return *slot; }
void record_func_cl_pf_opts_mapping (tree func) { PTR *slot; struct func_cl_pf_opts_mapping map, *entry; if (!func_cl_pf_opts_mapping_hash_table) func_cl_pf_opts_mapping_hash_table = htab_create (101, func_cl_pf_opts_mapping_hash, func_cl_pf_opts_mapping_eq, 0); map.func = func; slot = htab_find_slot (func_cl_pf_opts_mapping_hash_table, &map, INSERT); if (*slot) entry = *slot; else { entry = xmalloc (sizeof (struct func_cl_pf_opts_mapping)); entry->func = func; *slot = entry; } entry->cl_pf_opts = make_perfunc_opts (); }
/* Account the overhead. */ static void register_overhead (struct vec_prefix *ptr, size_t size, const char *name, int line, const char *function) { struct vec_descriptor *loc = vec_descriptor (name, line, function); struct ptr_hash_entry *p = XNEW (struct ptr_hash_entry); PTR *slot; p->ptr = ptr; p->loc = loc; p->allocated = size; if (!ptr_hash) ptr_hash = htab_create (10, hash_ptr, eq_ptr, NULL); slot = htab_find_slot_with_hash (ptr_hash, ptr, htab_hash_pointer (ptr), INSERT); gcc_assert (!*slot); *slot = p; loc->allocated += size; if (loc->peak < loc->allocated) loc->peak += loc->allocated; loc->times++; }
static void rtl_seqabstr (void) { int iter; df_set_flags (DF_LR_RUN_DCE); df_analyze (); /* Create a hash list for COLLECT_PATTERN_SEQS. */ hash_buckets = htab_create (HASH_INIT, htab_hash_bucket , htab_eq_bucket , htab_del_bucket); fill_hash_bucket (); /* Compute the common cost of abstraction. */ compute_init_costs (); /* Build an initial set of pattern sequences from the current function. */ collect_pattern_seqs (); dump_pattern_seqs (); /* Iterate until there are no sequences to abstract. */ for (iter = 1;; iter++) { /* Recompute gain for sequences if necessary and select sequence with biggest gain. */ recompute_gain (); if (!pattern_seqs) break; dump_best_pattern_seq (iter); /* Update the cached info of the other sequences and force gain recomputation where needed. */ update_pattern_seqs (); /* Turn best sequences into pseudo-functions and -calls. */ abstract_best_seq (); } /* Cleanup hash tables. */ htab_delete (hash_buckets); }
/* Return descriptor for given call site, create new one if needed. */ static struct vec_descriptor * vec_descriptor (const char *name, int line, const char *function) { struct vec_descriptor loc; struct vec_descriptor **slot; loc.file = name; loc.line = line; loc.function = function; if (!vec_desc_hash) vec_desc_hash = htab_create (10, hash_descriptor, eq_descriptor, NULL); slot = (struct vec_descriptor **) htab_find_slot (vec_desc_hash, &loc, INSERT); if (*slot) return *slot; *slot = XCNEW (struct vec_descriptor); (*slot)->file = name; (*slot)->line = line; (*slot)->function = function; (*slot)->allocated = 0; (*slot)->peak = 0; return *slot; }
static unsigned int rest_of_handle_simplify_got (void) { df_ref ref; rtx use = NULL_RTX; int i, n_symbol, n_access = 0; struct got_access_info* got_accesses; htab_t var_table = htab_create (VAR_TABLE_SIZE, htab_hash_pointer, htab_eq_pointer, NULL); rtx pic_reg = targetm.got_access.get_pic_reg (); gcc_assert (pic_reg); ref = DF_REG_USE_CHAIN (REGNO (pic_reg)); got_accesses = XNEWVEC(struct got_access_info, DF_REG_USE_COUNT (REGNO (pic_reg))); /* Check if all uses of pic_reg are loading global address through the default method. */ while (ref) { rtx_insn* insn = DF_REF_INSN (ref); /* Check for the special USE insn, it is not a real usage of pic_reg. */ if (GET_CODE (PATTERN (insn)) == USE) use = insn; else { /* If an insn both set and use pic_reg, it is in the process of constructing the value of pic_reg. We should also ignore it. */ rtx set = single_set (insn); if (!(set && SET_DEST (set) == pic_reg)) { rtx offset_reg; rtx offset_insn; rtx symbol = targetm.got_access.loaded_global_var (insn, &offset_reg, &offset_insn); if (symbol) { rtx* slot = (rtx*) htab_find_slot (var_table, symbol, INSERT); if (*slot == HTAB_EMPTY_ENTRY) *slot = symbol; gcc_assert (set); got_accesses[n_access].symbol = symbol; got_accesses[n_access].offset_reg = offset_reg; got_accesses[n_access].address_reg = SET_DEST (set); got_accesses[n_access].load_insn = insn; got_accesses[n_access].offset_insn = offset_insn; n_access++; } else { /* This insn doesn't load a global address, but it has other unexpected usage of pic_reg, give up. */ free (got_accesses); htab_delete (var_table); return 0; } } } ref = DF_REF_NEXT_REG(ref); } /* Check if we can simplify it. */ n_symbol = htab_elements (var_table); gcc_assert (n_symbol <= n_access); if (!targetm.got_access.can_simplify_got_access (n_symbol, n_access)) { free (got_accesses); htab_delete (var_table); return 0; } /* Rewrite the global address loading insns. */ for (i=0; i<n_access; i++) targetm.got_access.load_global_address (got_accesses[i].symbol, got_accesses[i].offset_reg, got_accesses[i].address_reg, got_accesses[i].load_insn, got_accesses[i].offset_insn); /* Since there is no usage of pic_reg now, we can remove it. */ if (use) remove_insn (use); targetm.got_access.clear_pic_reg (); free (got_accesses); htab_delete (var_table); return 0; }
return arc1->smaller == arc2->smaller && arc1->larger == arc2->larger; } /* Creates an empty conflict graph to hold conflicts among NUM_REGS registers. */ conflict_graph conflict_graph_new (int num_regs) { conflict_graph graph = XNEW (struct conflict_graph_def); graph->num_regs = num_regs; /* Set up the hash table. No delete action is specified; memory management of arcs is through the obstack. */ graph->arc_hash_table = htab_create (INITIAL_ARC_CAPACITY, &arc_hash, &arc_eq, NULL); /* Create an obstack for allocating arcs. */ obstack_init (&graph->arc_obstack); /* Create and zero the lookup table by register number. */ graph->neighbor_heads = XCNEWVEC (conflict_graph_arc, num_regs); return graph; } /* Deletes a conflict graph. */ void conflict_graph_delete (conflict_graph graph) {
int main() { htab_t *table = htab_create(); char c; while (scanf("%c", &c) != EOF) { switch (c) { /* Добавить элемент. */ case '+':{ node_t *node = node_create(); int err; err = node_fscan_all(stdin, node); err = htab_addnode(table, node); if (err == -1) fprintf(stderr, "Exist\n"); break; } /* Найти элемент. */ case 'f':{ node_t *tmp_node = node_create(); int err; err = node_fscan_key(stdin, tmp_node); err = htab_findnode(table, tmp_node); if (err == -1) fprintf(stderr, "Not found\n"); else { fprintf(stdout, "%s\n", tmp_node->value); } node_destroy(tmp_node); break; } /* Удалить элемент. */ case '-':{ node_t *tmp_node = node_create(); int err; err = node_fscan_key(stdin, tmp_node); err = htab_delnode(table, tmp_node); if (err == -1) fprintf(stderr, "Not found\n"); node_destroy(tmp_node); break; } /* Распечатать количество элементов */ case 's':{ size_t size = htab_get_size(table); fprintf(stdout, "%ld\n", size); break; } /* Распечатать размер таблицы */ case 'c':{ size_t size = htab_get_cap(table); fprintf(stdout, "%ld\n", size); break; } /* Распечатать хеш-таблицу в JSON */ case 'p':{ htab_tojson(stdout, table); break; } /* Распечатать хеш-таблицу в JSON */ case 'j':{ htab_tojson(stdout, table); break; } /* Распечатать хеш-таблицу в XML */ case 'x':{ htab_toxml(stdout, table); break; } /* Остановить программу */ case 'q':{ htab_destroy(table); return 0; } } } htab_destroy(table); return 0; }
htab_t lto_create_renaming_table (void) { return htab_create (37, hash_name, eq_name, renaming_slot_free); }
/* Initiate the candidate table. */ static void initiate_cand_table (void) { cand_table = htab_create (8000, cand_hash, cand_eq_p, (htab_del) free_cand); }
/* Read the documentation file with name IN_FNAME, perform substitutions to incorporate informtion from hook_array, and emit the result on stdout. Hooks defined with DEFHOOK / DEFHOOKPOD are emitted at the place of a matching @hook in the input file; if there is no matching @hook, the hook is emitted after the hook that precedes it in target.def . Usually, the emitted hook documentation starts with the hook signature, followed by the string from the doc field. The documentation is bracketed in @deftypefn / @deftypevr and a matching @end. While emitting the doc field, @Fcode is translated to @code, and an @findex entry is added to the affected paragraph. If the doc field starts with '*', the leading '*' is stripped, and the doc field is otherwise emitted unaltered; no function signature/ @deftypefn/deftypevr/@end is emitted. In particular, a doc field of "*" means not to emit any ocumentation for this target.def / hook_array entry at all (there might be documentation for this hook in the file named IN_FNAME, though). A doc field of 0 is used to append the hook signature after the previous hook's signture, so that one description can be used for a group of hooks. When the doc field is "", @deftypefn/@deftypevr and the hook signature is emitted, but not the matching @end. This allows all the free-form documentation to be placed in IN_FNAME, to work around GPL/GFDL licensing incompatibility issues. */ static void emit_documentation (const char *in_fname) { int i, j; char buf[1000]; htab_t start_hooks = htab_create (99, s_hook_hash, s_hook_eq_p, (htab_del) 0); FILE *f; bool found_start = false; /* Enter all the start hooks in start_hooks. */ f = fopen (in_fname, "r"); if (!f) { perror (""); fatal ("Couldn't open input file"); } while (fscanf (f, "%*[^@]"), buf[0] = '\0', fscanf (f, "@%5[^ \n]", buf) != EOF) { void **p; struct s_hook *shp; if (strcmp (buf, "hook") != 0) continue; buf[0] = '\0'; fscanf (f, "%999s", buf); shp = XNEW (struct s_hook); shp->name = upstrdup (buf); shp->pos = -1; p = htab_find_slot (start_hooks, shp, INSERT); if (*p != HTAB_EMPTY_ENTRY) fatal ("Duplicate placement for hook %s\n", shp->name); *(struct s_hook **) p = shp; } fclose (f); /* For each hook in hook_array, if it is a start hook, store its position. */ for (i = 0; i < (int) (sizeof hook_array / sizeof hook_array[0]); i++) { struct s_hook sh, *shp; void *p; if (!hook_array[i].doc || strcmp (hook_array[i].doc, "*") == 0) continue; sh.name = upstrdup (hook_array[i].name); p = htab_find (start_hooks, &sh); if (p) { shp = (struct s_hook *) p; if (shp->pos >= 0) fatal ("Duplicate hook %s\n", sh.name); shp->pos = i; found_start = true; } else if (!found_start) fatal ("No place specified to document hook %s\n", sh.name); free (sh.name); } /* Copy input file to stdout, substituting @hook directives with the corresponding hook documentation sequences. */ f = fopen (in_fname, "r"); if (!f) { perror (""); fatal ("Couldn't open input file"); } for (;;) { struct s_hook sh, *shp; int c = getc (f); char *name; if (c == EOF) break; if (c != '@') { putchar (c); continue; } buf[0] = '\0'; fscanf (f, "%5[^ \n]", buf); if (strcmp (buf, "hook") != 0) { printf ("@%s", buf); continue; } fscanf (f, "%999s", buf); sh.name = name = upstrdup (buf); shp = (struct s_hook *) htab_find (start_hooks, &sh); if (!shp || shp->pos < 0) fatal ("No documentation for hook %s\n", sh.name); i = shp->pos; do { const char *q, *e; const char *deftype; const char *doc, *fcode, *p_end; /* A leading '*' means to output the documentation string without further processing. */ if (*hook_array[i].doc == '*') printf ("%s", hook_array[i].doc + 1); else { if (i != shp->pos) printf ("\n\n"); emit_findices (hook_array[i].doc, name); /* Print header. Function-valued hooks have a parameter list, unlike POD-valued ones. */ deftype = hook_array[i].param ? "deftypefn" : "deftypevr"; printf ("@%s {%s} ", deftype, hook_array[i].docname); if (strchr (hook_array[i].type, ' ')) printf ("{%s}", hook_array[i].type); else printf ("%s", hook_array[i].type); printf (" %s", name); if (hook_array[i].param) { /* Print the parameter list, with the parameter names enclosed in @var{}. */ printf (" "); for (q = hook_array[i].param; (e = strpbrk (q, " *,)")); q = e + 1) /* Type names like 'int' are followed by a space, sometimes also by '*'. 'void' should appear only in "(void)". */ if (*e == ' ' || *e == '*' || *q == '(') printf ("%.*s", (int) (e - q + 1), q); else printf ("@var{%.*s}%c", (int) (e - q), q, *e); } /* POD-valued hooks sometimes come in groups with common documentation.*/ for (j = i + 1; j < (int) (sizeof hook_array / sizeof hook_array[0]) && hook_array[j].doc == 0 && hook_array[j].type; j++) { char *namex = upstrdup (hook_array[j].name); printf ("\n@%sx {%s} {%s} %s", deftype, hook_array[j].docname, hook_array[j].type, namex); } if (hook_array[i].doc[0]) { printf ("\n"); /* Print each documentation paragraph in turn. */ for (doc = hook_array[i].doc; *doc; doc = p_end) { /* Find paragraph end. */ p_end = strstr (doc, "\n\n"); p_end = (p_end ? p_end + 2 : doc + strlen (doc)); /* Print paragraph, emitting @Fcode as @code. */ for (; (fcode = strstr (doc, "@Fcode{")) && fcode < p_end; doc = fcode + 2) printf ("%.*s@", (int) (fcode - doc), doc); printf ("%.*s", (int) (p_end - doc), doc); /* Emit function indices for next paragraph. */ emit_findices (p_end, name); } printf ("\n@end %s", deftype); } } if (++i >= (int) (sizeof hook_array / sizeof hook_array[0]) || !hook_array[i].doc) break; free (name); sh.name = name = upstrdup (hook_array[i].name); } while (!htab_find (start_hooks, &sh)); free (name); } }
table->bucket = calloc(sizeof(htab_entry_t *), size); if(table->bucket == NULL){ perror("calloc"); free(table); return NULL; } return table; } htab_t *htab_init(size_t size, htab_hash_cb hash, htab_equal_cb equal, htab_delete_cb delete) { htab_t *table; table = htab_create(size); if(table == NULL){ //TODO: return NULL; } table->size = size; table->items = 0; table->hash = hash; table->equal = equal; table->del = delete; return table; } static int htab_resize(htab_t *table)
/* * Refresh the list of USB devices */ BOOL GetDevices(DWORD devnum) { // List of USB storage drivers we know - list may be incomplete! const char* usbstor_name[] = { // Standard MS USB storage driver "USBSTOR", // USB card readers, with proprietary drivers (Realtek,etc...) // Mostly "guessed" from http://www.carrona.org/dvrref.php "RTSUER", "CMIUCR", "EUCR", // UASP Drivers *MUST* be listed after this, starting with "UASPSTOR" // (which is Microsoft's native UASP driver for Windows 8 and later) // as we use "UASPSTOR" as a delimiter "UASPSTOR", "VUSBSTOR", "ETRONSTOR", "ASUSSTPT" }; // These are the generic (non USB) storage enumerators we also test const char* genstor_name[] = { // Generic storage drivers (Careful now!) "SCSI", // "STORAGE", // "STORAGE" is used by 'Storage Spaces" and stuff => DANGEROUS! // Non-USB card reader drivers - This list *MUST* start with "SD" (delimiter) // See http://itdoc.hitachi.co.jp/manuals/3021/30213B5200e/DMDS0094.HTM // Also http://www.carrona.org/dvrref.php. NB: These should be reported // as enumerators by Rufus when Enum Debug is enabled "SD", "PCISTOR", "RTSOR", "JMCR", "JMCF", "RIMMPTSK", "RIMSPTSK", "RISD", "RIXDPTSK", "TI21SONY", "ESD7SK", "ESM7SK", "O2MD", "O2SD", "VIACR" }; // Oh, and we also have card devices (e.g. 'SCSI\DiskO2Micro_SD_...') under the SCSI enumerator... const char* scsi_disk_prefix = "SCSI\\Disk"; const char* scsi_card_name[] = { "_SD_", "_SDHC_", "_MMC_", "_MS_", "_MSPro_", "_xDPicture_", "_O2Media_" }; const char* usb_speed_name[USB_SPEED_MAX] = { "USB", "USB 1.0", "USB 1.1", "USB 2.0", "USB 3.0" }; // Hash table and String Array used to match a Device ID with the parent hub's Device Interface Path htab_table htab_devid = HTAB_EMPTY; StrArray dev_if_path; char letter_name[] = " (?:)"; char drive_name[] = "?:\\"; char uefi_togo_check[] = "?:\\EFI\\Rufus\\ntfs_x64.efi"; char scsi_card_name_copy[16]; BOOL r = FALSE, found = FALSE, post_backslash; HDEVINFO dev_info = NULL; SP_DEVINFO_DATA dev_info_data; SP_DEVICE_INTERFACE_DATA devint_data; PSP_DEVICE_INTERFACE_DETAIL_DATA_A devint_detail_data; DEVINST parent_inst, grandparent_inst, device_inst; DWORD size, i, j, k, l, datatype, drive_index; DWORD uasp_start = ARRAYSIZE(usbstor_name), card_start = ARRAYSIZE(genstor_name); ULONG list_size[ARRAYSIZE(usbstor_name)] = { 0 }, list_start[ARRAYSIZE(usbstor_name)] = { 0 }, full_list_size, ulFlags; HANDLE hDrive; LONG maxwidth = 0; int s, score, drive_number, remove_drive; char drive_letters[27], *device_id, *devid_list = NULL, entry_msg[128]; char *p, *label, *entry, buffer[MAX_PATH], str[MAX_PATH], *method_str, *hub_path; usb_device_props props; IGNORE_RETVAL(ComboBox_ResetContent(hDeviceList)); StrArrayClear(&DriveID); StrArrayClear(&DriveLabel); StrArrayClear(&DriveHub); StrArrayCreate(&dev_if_path, 128); // Add a dummy for string index zero, as this is what non matching hashes will point to StrArrayAdd(&dev_if_path, "", TRUE); device_id = (char*)malloc(MAX_PATH); if (device_id == NULL) goto out; // Build a hash table associating a CM Device ID of an USB device with the SetupDI Device Interface Path // of its parent hub - this is needed to retrieve the device speed dev_info = SetupDiGetClassDevsA(&_GUID_DEVINTERFACE_USB_HUB, NULL, NULL, DIGCF_PRESENT|DIGCF_DEVICEINTERFACE); if (dev_info != INVALID_HANDLE_VALUE) { if (htab_create(DEVID_HTAB_SIZE, &htab_devid)) { dev_info_data.cbSize = sizeof(dev_info_data); for (i=0; SetupDiEnumDeviceInfo(dev_info, i, &dev_info_data); i++) { uuprintf("Processing Hub %d:", i + 1); devint_detail_data = NULL; devint_data.cbSize = sizeof(devint_data); // Only care about the first interface (MemberIndex 0) if ( (SetupDiEnumDeviceInterfaces(dev_info, &dev_info_data, &_GUID_DEVINTERFACE_USB_HUB, 0, &devint_data)) && (!SetupDiGetDeviceInterfaceDetailA(dev_info, &devint_data, NULL, 0, &size, NULL)) && (GetLastError() == ERROR_INSUFFICIENT_BUFFER) && ((devint_detail_data = (PSP_DEVICE_INTERFACE_DETAIL_DATA_A)calloc(1, size)) != NULL) ) { devint_detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A); if (SetupDiGetDeviceInterfaceDetailA(dev_info, &devint_data, devint_detail_data, size, &size, NULL)) { // Find the Device IDs for all the children of this hub if (CM_Get_Child(&device_inst, dev_info_data.DevInst, 0) == CR_SUCCESS) { device_id[0] = 0; s = StrArrayAdd(&dev_if_path, devint_detail_data->DevicePath, TRUE); uuprintf(" Hub[%d] = '%s'", s, devint_detail_data->DevicePath); if ((s>= 0) && (CM_Get_Device_IDA(device_inst, device_id, MAX_PATH, 0) == CR_SUCCESS)) { ToUpper(device_id); if ((k = htab_hash(device_id, &htab_devid)) != 0) { htab_devid.table[k].data = (void*)(uintptr_t)s; } uuprintf(" Found ID[%03d]: %s", k, device_id); while (CM_Get_Sibling(&device_inst, device_inst, 0) == CR_SUCCESS) { device_id[0] = 0; if (CM_Get_Device_IDA(device_inst, device_id, MAX_PATH, 0) == CR_SUCCESS) { ToUpper(device_id); if ((k = htab_hash(device_id, &htab_devid)) != 0) { htab_devid.table[k].data = (void*)(uintptr_t)s; } uuprintf(" Found ID[%03d]: %s", k, device_id); } } } } } free(devint_detail_data); } } } SetupDiDestroyDeviceInfoList(dev_info); } free(device_id); // Build a single list of Device IDs from all the storage enumerators we know of full_list_size = 0; ulFlags = CM_GETIDLIST_FILTER_SERVICE | CM_GETIDLIST_FILTER_PRESENT; for (s=0; s<ARRAYSIZE(usbstor_name); s++) { // Get a list of device IDs for all USB storage devices // This will be used to find if a device is UASP // Also compute the uasp_start index if (strcmp(usbstor_name[s], "UASPSTOR") == 0) uasp_start = s; if (CM_Get_Device_ID_List_SizeA(&list_size[s], usbstor_name[s], ulFlags) != CR_SUCCESS) list_size[s] = 0; if (list_size[s] != 0) full_list_size += list_size[s]-1; // remove extra NUL terminator } // Compute the card_start index for (s=0; s<ARRAYSIZE(genstor_name); s++) { if (strcmp(genstor_name[s], "SD") == 0) card_start = s; } // Better safe than sorry. And yeah, we could have used arrays of // arrays to avoid this, but it's more readable this way. assert((uasp_start > 0) && (uasp_start < ARRAYSIZE(usbstor_name))); assert((card_start > 0) && (card_start < ARRAYSIZE(genstor_name))); devid_list = NULL; if (full_list_size != 0) { full_list_size += 1; // add extra NUL terminator devid_list = (char*)malloc(full_list_size); if (devid_list == NULL) { uprintf("Could not allocate Device ID list\n"); goto out; } for (s=0, i=0; s<ARRAYSIZE(usbstor_name); s++) { list_start[s] = i; if (list_size[s] > 1) { if (CM_Get_Device_ID_ListA(usbstor_name[s], &devid_list[i], list_size[s], ulFlags) != CR_SUCCESS) continue; if (usb_debug) { uprintf("Processing IDs belonging to '%s':", usbstor_name[s]); for (device_id = &devid_list[i]; *device_id != 0; device_id += strlen(device_id) + 1) uprintf(" %s", device_id); } // The list_size is sometimes larger than required thus we need to find the real end for (i += list_size[s]; i > 2; i--) { if ((devid_list[i-2] != '\0') && (devid_list[i-1] == '\0') && (devid_list[i] == '\0')) break; } } } } // Now use SetupDi to enumerate all our disk storage devices dev_info = SetupDiGetClassDevsA(&_GUID_DEVINTERFACE_DISK, NULL, NULL, DIGCF_PRESENT|DIGCF_DEVICEINTERFACE); if (dev_info == INVALID_HANDLE_VALUE) { uprintf("SetupDiGetClassDevs (Interface) failed: %s\n", WindowsErrorString()); goto out; } dev_info_data.cbSize = sizeof(dev_info_data); for (i=0; SetupDiEnumDeviceInfo(dev_info, i, &dev_info_data); i++) { memset(buffer, 0, sizeof(buffer)); memset(&props, 0, sizeof(props)); method_str = ""; hub_path = NULL; if (!SetupDiGetDeviceRegistryPropertyA(dev_info, &dev_info_data, SPDRP_ENUMERATOR_NAME, &datatype, (LPBYTE)buffer, sizeof(buffer), &size)) { uprintf("SetupDiGetDeviceRegistryProperty (Enumerator Name) failed: %s\n", WindowsErrorString()); continue; } for (j = 0; j < ARRAYSIZE(usbstor_name); j++) { if (safe_stricmp(buffer, usbstor_name[0]) == 0) { props.is_USB = TRUE; if ((j != 0) && (j < uasp_start)) props.is_CARD = TRUE; break; } } // UASP drives are listed under SCSI, and we also have non USB card readers to populate for (j = 0; j < ARRAYSIZE(genstor_name); j++) { if (safe_stricmp(buffer, genstor_name[j]) == 0) { props.is_SCSI = TRUE; if (j >= card_start) props.is_CARD = TRUE; break; } } uuprintf("Processing '%s' device:", buffer); if ((!props.is_USB) && (!props.is_SCSI)) { uuprintf(" Disabled by policy"); continue; } // We can't use the friendly name to find if a drive is a VHD, as friendly name string gets translated // according to your locale, so we poke the Hardware ID memset(buffer, 0, sizeof(buffer)); props.is_VHD = SetupDiGetDeviceRegistryPropertyA(dev_info, &dev_info_data, SPDRP_HARDWAREID, &datatype, (LPBYTE)buffer, sizeof(buffer), &size) && IsVHD(buffer); // Additional detection for SCSI card readers if ((!props.is_CARD) && (safe_strnicmp(buffer, scsi_disk_prefix, sizeof(scsi_disk_prefix)-1) == 0)) { for (j = 0; j < ARRAYSIZE(scsi_card_name); j++) { static_strcpy(scsi_card_name_copy, scsi_card_name[j]); if (safe_strstr(buffer, scsi_card_name_copy) != NULL) { props.is_CARD = TRUE; break; } // Also test for "_SD&" instead of "_SD_" and so on to allow for devices like // "SCSI\DiskRicoh_Storage_SD&REV_3.0" to be detected. scsi_card_name_copy[strlen(scsi_card_name_copy) - 1] = '&'; if (safe_strstr(buffer, scsi_card_name_copy) != NULL) { props.is_CARD = TRUE; break; } } } uuprintf(" Hardware ID: '%s'", buffer); memset(buffer, 0, sizeof(buffer)); props.is_Removable = SetupDiGetDeviceRegistryPropertyA(dev_info, &dev_info_data, SPDRP_REMOVAL_POLICY, &datatype, (LPBYTE)buffer, sizeof(buffer), &size) && IsRemovable(buffer); memset(buffer, 0, sizeof(buffer)); if (!SetupDiGetDeviceRegistryPropertyU(dev_info, &dev_info_data, SPDRP_FRIENDLYNAME, &datatype, (LPBYTE)buffer, sizeof(buffer), &size)) { uprintf("SetupDiGetDeviceRegistryProperty (Friendly Name) failed: %s\n", WindowsErrorString()); // We can afford a failure on this call - just replace the name with "USB Storage Device (Generic)" static_strcpy(buffer, lmprintf(MSG_045)); } else if ((!props.is_VHD) && (devid_list != NULL)) { // Get the properties of the device. We could avoid doing this lookup every time by keeping // a lookup table, but there shouldn't be that many USB storage devices connected... // NB: Each of these Device IDs should have a child, from which we get the Device Instance match. for (device_id = devid_list; *device_id != 0; device_id += strlen(device_id) + 1) { if (CM_Locate_DevNodeA(&parent_inst, device_id, 0) != CR_SUCCESS) { uuprintf("Could not locate device node for '%s'", device_id); continue; } if (CM_Get_Child(&device_inst, parent_inst, 0) != CR_SUCCESS) { uuprintf("Could not get children of '%s'", device_id); continue; } if (device_inst != dev_info_data.DevInst) { // Try the siblings while (CM_Get_Sibling(&device_inst, device_inst, 0) == CR_SUCCESS) { if (device_inst == dev_info_data.DevInst) { uuprintf("NOTE: Matched instance from sibling for '%s'", device_id); break; } } if (device_inst != dev_info_data.DevInst) continue; } post_backslash = FALSE; method_str = ""; // If we're not dealing with the USBSTOR part of our list, then this is an UASP device props.is_UASP = ((((uintptr_t)device_id)+2) >= ((uintptr_t)devid_list)+list_start[uasp_start]); // Now get the properties of the device, and its Device ID, which we need to populate the properties ToUpper(device_id); j = htab_hash(device_id, &htab_devid); uuprintf(" Matched with ID[%03d]: %s", j, device_id); // Try to parse the current device_id string for VID:PID // We'll use that if we can't get anything better for (k = 0, l = 0; (k<strlen(device_id)) && (l<2); k++) { // The ID is in the form USB_VENDOR_BUSID\VID_xxxx&PID_xxxx\... if (device_id[k] == '\\') post_backslash = TRUE; if (!post_backslash) continue; if (device_id[k] == '_') { props.pid = (uint16_t)strtoul(&device_id[k + 1], NULL, 16); if (l++ == 0) props.vid = props.pid; } } if (props.vid != 0) method_str = "[ID]"; // If the hash didn't match a populated string in dev_if_path[] (htab_devid.table[j].data > 0), // we might have an extra vendor driver in between (e.g. "ASUS USB 3.0 Boost Storage Driver" // for UASP devices in ASUS "Turbo Mode" or "Apple Mobile Device USB Driver" for iPods) // so try to see if we can match the grandparent. if ( ((uintptr_t)htab_devid.table[j].data == 0) && (CM_Get_Parent(&grandparent_inst, parent_inst, 0) == CR_SUCCESS) && (CM_Get_Device_IDA(grandparent_inst, str, MAX_PATH, 0) == CR_SUCCESS) ) { device_id = str; method_str = "[GP]"; ToUpper(device_id); j = htab_hash(device_id, &htab_devid); uuprintf(" Matched with (GP) ID[%03d]: %s", j, device_id); } if ((uintptr_t)htab_devid.table[j].data > 0) { uuprintf(" Matched with Hub[%d]: '%s'", (uintptr_t)htab_devid.table[j].data, dev_if_path.String[(uintptr_t)htab_devid.table[j].data]); if (GetUSBProperties(dev_if_path.String[(uintptr_t)htab_devid.table[j].data], device_id, &props)) { method_str = ""; hub_path = dev_if_path.String[(uintptr_t)htab_devid.table[j].data]; } #ifdef FORCED_DEVICE props.vid = FORCED_VID; props.pid = FORCED_PID; static_strcpy(buffer, FORCED_NAME); #endif } break; } } if (props.is_VHD) { uprintf("Found VHD device '%s'", buffer); } else if ((props.is_CARD) && ((!props.is_USB) || ((props.vid == 0) && (props.pid == 0)))) { uprintf("Found card reader device '%s'", buffer); } else if ((!props.is_USB) && (!props.is_UASP) && (props.is_Removable)) { if (!list_non_usb_removable_drives) { uprintf("Found non-USB removable device '%s' => Eliminated", buffer); uuprintf("If you *REALLY* need, you can enable listing of this device with <Ctrl><Alt><F>"); continue; } uprintf("Found non-USB removable device '%s'", buffer); } else { if ((props.vid == 0) && (props.pid == 0)) { if (!props.is_USB) { // If we have a non removable SCSI drive and couldn't get a VID:PID, // we are most likely dealing with a system drive => eliminate it! uuprintf("Found non-USB non-removable device '%s' => Eliminated", buffer); continue; } static_strcpy(str, "????:????"); // Couldn't figure VID:PID } else { static_sprintf(str, "%04X:%04X", props.vid, props.pid); } if (props.speed >= USB_SPEED_MAX) props.speed = 0; uprintf("Found %s%s%s device '%s' (%s) %s\n", props.is_UASP?"UAS (":"", usb_speed_name[props.speed], props.is_UASP?")":"", buffer, str, method_str); if (props.is_LowerSpeed) uprintf("NOTE: This device is an USB 3.0 device operating at lower speed..."); } devint_data.cbSize = sizeof(devint_data); hDrive = INVALID_HANDLE_VALUE; devint_detail_data = NULL; for (j=0; ;j++) { safe_closehandle(hDrive); safe_free(devint_detail_data); if (!SetupDiEnumDeviceInterfaces(dev_info, &dev_info_data, &_GUID_DEVINTERFACE_DISK, j, &devint_data)) { if(GetLastError() != ERROR_NO_MORE_ITEMS) { uprintf("SetupDiEnumDeviceInterfaces failed: %s\n", WindowsErrorString()); } else { uprintf("A device was eliminated because it didn't report itself as a disk\n"); } break; } if (!SetupDiGetDeviceInterfaceDetailA(dev_info, &devint_data, NULL, 0, &size, NULL)) { if(GetLastError() == ERROR_INSUFFICIENT_BUFFER) { devint_detail_data = (PSP_DEVICE_INTERFACE_DETAIL_DATA_A)calloc(1, size); if (devint_detail_data == NULL) { uprintf("Unable to allocate data for SP_DEVICE_INTERFACE_DETAIL_DATA\n"); continue; } devint_detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A); } else { uprintf("SetupDiGetDeviceInterfaceDetail (dummy) failed: %s\n", WindowsErrorString()); continue; } } if (devint_detail_data == NULL) { uprintf("SetupDiGetDeviceInterfaceDetail (dummy) - no data was allocated\n"); continue; } if(!SetupDiGetDeviceInterfaceDetailA(dev_info, &devint_data, devint_detail_data, size, &size, NULL)) { uprintf("SetupDiGetDeviceInterfaceDetail (actual) failed: %s\n", WindowsErrorString()); continue; } hDrive = CreateFileA(devint_detail_data->DevicePath, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if(hDrive == INVALID_HANDLE_VALUE) { uprintf("Could not open '%s': %s\n", devint_detail_data->DevicePath, WindowsErrorString()); continue; } drive_number = GetDriveNumber(hDrive, devint_detail_data->DevicePath); if (drive_number < 0) continue; drive_index = drive_number + DRIVE_INDEX_MIN; if (!IsMediaPresent(drive_index)) { uprintf("Device eliminated because it appears to contain no media\n"); safe_closehandle(hDrive); safe_free(devint_detail_data); break; } if (GetDriveSize(drive_index) < (MIN_DRIVE_SIZE*MB)) { uprintf("Device eliminated because it is smaller than %d MB\n", MIN_DRIVE_SIZE); safe_closehandle(hDrive); safe_free(devint_detail_data); break; } if (GetDriveLabel(drive_index, drive_letters, &label)) { if ((props.is_SCSI) && (!props.is_UASP) && (!props.is_VHD)) { if (!props.is_Removable) { // Non removables should have been eliminated above, but since we // are potentially dealing with system drives, better safe than sorry safe_closehandle(hDrive); safe_free(devint_detail_data); break; } if (!list_non_usb_removable_drives) { // Go over the mounted partitions and find if GetDriveType() says they are // removable. If they are not removable, don't allow the drive to be listed for (p = drive_letters; *p; p++) { drive_name[0] = *p; if (GetDriveTypeA(drive_name) != DRIVE_REMOVABLE) break; } if (*p) { uprintf("Device eliminated because it contains a mounted partition that is set as non-removable"); safe_closehandle(hDrive); safe_free(devint_detail_data); break; } } } if ((!enable_HDDs) && (!props.is_VHD) && (!props.is_CARD) && ((score = IsHDD(drive_index, (uint16_t)props.vid, (uint16_t)props.pid, buffer)) > 0)) { uprintf("Device eliminated because it was detected as a Hard Drive (score %d > 0)", score); if (!list_non_usb_removable_drives) uprintf("If this device is not a Hard Drive, please e-mail the author of this application"); uprintf("NOTE: You can enable the listing of Hard Drives under 'advanced drive properties'"); safe_closehandle(hDrive); safe_free(devint_detail_data); break; } // The empty string is returned for drives that don't have any volumes assigned if (drive_letters[0] == 0) { entry = lmprintf(MSG_046, label, drive_number, SizeToHumanReadable(GetDriveSize(drive_index), FALSE, use_fake_units)); } else { // Find the UEFI:TOGO partition(s) (and eliminate them form our listing) for (k=0; drive_letters[k]; k++) { uefi_togo_check[0] = drive_letters[k]; if (PathFileExistsA(uefi_togo_check)) { for (l=k; drive_letters[l]; l++) drive_letters[l] = drive_letters[l+1]; k--; } } // We have multiple volumes assigned to the same device (multiple partitions) // If that is the case, use "Multiple Volumes" instead of the label static_strcpy(entry_msg, (((drive_letters[0] != 0) && (drive_letters[1] != 0))? lmprintf(MSG_047):label)); for (k=0, remove_drive=0; drive_letters[k] && (!remove_drive); k++) { // Append all the drive letters we detected letter_name[2] = drive_letters[k]; if (right_to_left_mode) static_strcat(entry_msg, RIGHT_TO_LEFT_MARK); static_strcat(entry_msg, letter_name); if (drive_letters[k] == (PathGetDriveNumberU(app_dir) + 'A')) remove_drive = 1; if (drive_letters[k] == (PathGetDriveNumberU(system_dir) + 'A')) remove_drive = 2; } // Make sure that we don't list any drive that should not be listed if (remove_drive) { uprintf("Removing %C: from the list: This is the %s!", drive_letters[--k], (remove_drive==1)?"disk from which " APPLICATION_NAME " is running":"system disk"); safe_closehandle(hDrive); safe_free(devint_detail_data); break; } safe_sprintf(&entry_msg[strlen(entry_msg)], sizeof(entry_msg) - strlen(entry_msg), "%s [%s]", (right_to_left_mode)?RIGHT_TO_LEFT_MARK:"", SizeToHumanReadable(GetDriveSize(drive_index), FALSE, use_fake_units)); entry = entry_msg; } // Must ensure that the combo box is UNSORTED for indexes to be the same StrArrayAdd(&DriveID, buffer, TRUE); StrArrayAdd(&DriveLabel, label, TRUE); if ((hub_path != NULL) && (StrArrayAdd(&DriveHub, hub_path, TRUE) >= 0)) DrivePort[DriveHub.Index - 1] = props.port; IGNORE_RETVAL(ComboBox_SetItemData(hDeviceList, ComboBox_AddStringU(hDeviceList, entry), drive_index)); maxwidth = max(maxwidth, GetEntryWidth(hDeviceList, entry)); safe_closehandle(hDrive); safe_free(devint_detail_data); break; } } } SetupDiDestroyDeviceInfoList(dev_info); // Adjust the Dropdown width to the maximum text size SendMessage(hDeviceList, CB_SETDROPPEDWIDTH, (WPARAM)maxwidth, 0); if (devnum >= DRIVE_INDEX_MIN) { for (i=0; i<ComboBox_GetCount(hDeviceList); i++) { if ((DWORD)ComboBox_GetItemData(hDeviceList, i) == devnum) { found = TRUE; break; } } } if (!found) i = 0; IGNORE_RETVAL(ComboBox_SetCurSel(hDeviceList, i)); SendMessage(hMainDialog, WM_COMMAND, (CBN_SELCHANGE<<16) | IDC_DEVICE, 0); r = TRUE; out: // Set 'Start' as the selected button, so that tab selection works SendMessage(hMainDialog, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hMainDialog, IDC_START), TRUE); safe_free(devid_list); StrArrayDestroy(&dev_if_path); htab_destroy(&htab_devid); return r; }
static void gomp_task_handle_depend (struct gomp_task *task, struct gomp_task *parent, void **depend) { size_t ndepend = (uintptr_t) depend[0]; size_t nout = (uintptr_t) depend[1]; size_t i; hash_entry_type ent; task->depend_count = ndepend; task->num_dependees = 0; if (parent->depend_hash == NULL) parent->depend_hash = htab_create (2 * ndepend > 12 ? 2 * ndepend : 12); for (i = 0; i < ndepend; i++) { task->depend[i].addr = depend[2 + i]; task->depend[i].next = NULL; task->depend[i].prev = NULL; task->depend[i].task = task; task->depend[i].is_in = i >= nout; task->depend[i].redundant = false; task->depend[i].redundant_out = false; hash_entry_type *slot = htab_find_slot (&parent->depend_hash, &task->depend[i], INSERT); hash_entry_type out = NULL, last = NULL; if (*slot) { /* If multiple depends on the same task are the same, all but the first one are redundant. As inout/out come first, if any of them is inout/out, it will win, which is the right semantics. */ if ((*slot)->task == task) { task->depend[i].redundant = true; continue; } for (ent = *slot; ent; ent = ent->next) { if (ent->redundant_out) break; last = ent; /* depend(in:...) doesn't depend on earlier depend(in:...). */ if (i >= nout && ent->is_in) continue; if (!ent->is_in) out = ent; struct gomp_task *tsk = ent->task; if (tsk->dependers == NULL) { tsk->dependers = gomp_malloc (sizeof (struct gomp_dependers_vec) + 6 * sizeof (struct gomp_task *)); tsk->dependers->n_elem = 1; tsk->dependers->allocated = 6; tsk->dependers->elem[0] = task; task->num_dependees++; continue; } /* We already have some other dependency on tsk from earlier depend clause. */ else if (tsk->dependers->n_elem && (tsk->dependers->elem[tsk->dependers->n_elem - 1] == task)) continue; else if (tsk->dependers->n_elem == tsk->dependers->allocated) { tsk->dependers->allocated = tsk->dependers->allocated * 2 + 2; tsk->dependers = gomp_realloc (tsk->dependers, sizeof (struct gomp_dependers_vec) + (tsk->dependers->allocated * sizeof (struct gomp_task *))); } tsk->dependers->elem[tsk->dependers->n_elem++] = task; task->num_dependees++; } task->depend[i].next = *slot; (*slot)->prev = &task->depend[i]; } *slot = &task->depend[i]; /* There is no need to store more than one depend({,in}out:) task per address in the hash table chain for the purpose of creation of deferred tasks, because each out depends on all earlier outs, thus it is enough to record just the last depend({,in}out:). For depend(in:), we need to keep all of the previous ones not terminated yet, because a later depend({,in}out:) might need to depend on all of them. So, if the new task's clause is depend({,in}out:), we know there is at most one other depend({,in}out:) clause in the list (out). For non-deferred tasks we want to see all outs, so they are moved to the end of the chain, after first redundant_out entry all following entries should be redundant_out. */ if (!task->depend[i].is_in && out) { if (out != last) { out->next->prev = out->prev; out->prev->next = out->next; out->next = last->next; out->prev = last; last->next = out; if (out->next) out->next->prev = out; } out->redundant_out = true; } } }
void browse_tree (tree begin) { tree head; TB_CODE tbc = TB_UNUSED_COMMAND; ssize_t rd; char *input = NULL; long input_size = 0; fprintf (TB_OUT_FILE, "\nTree Browser\n"); #define TB_SET_HEAD(N) do { \ TB_history_stack = tree_cons (NULL_TREE, (N), TB_history_stack); \ head = N; \ if (TB_verbose) \ if (head) \ { \ print_generic_expr (TB_OUT_FILE, head, 0); \ fprintf (TB_OUT_FILE, "\n"); \ } \ } while (0) TB_SET_HEAD (begin); /* Store in a hashtable information about previous and upper statements. */ { TB_up_ht = htab_create (1023, htab_hash_pointer, &TB_parent_eq, NULL); TB_update_up (head); } while (24) { fprintf (TB_OUT_FILE, "TB> "); rd = TB_getline (&input, &input_size, TB_IN_FILE); if (rd == -1) /* EOF. */ goto ret; if (rd != 1) /* Get a new command. Otherwise the user just pressed enter, and thus she expects the last command to be reexecuted. */ tbc = TB_get_command (input); switch (tbc) { case TB_UPDATE_UP: TB_update_up (head); break; case TB_MAX: if (head && (INTEGRAL_TYPE_P (head) || TREE_CODE (head) == REAL_TYPE)) TB_SET_HEAD (TYPE_MAX_VALUE (head)); else TB_WF; break; case TB_MIN: if (head && (INTEGRAL_TYPE_P (head) || TREE_CODE (head) == REAL_TYPE)) TB_SET_HEAD (TYPE_MIN_VALUE (head)); else TB_WF; break; case TB_ELT: if (head && TREE_CODE (head) == TREE_VEC) { /* This command takes another argument: the element number: for example "elt 1". */ TB_NIY; } else if (head && TREE_CODE (head) == VECTOR_CST) { /* This command takes another argument: the element number: for example "elt 1". */ TB_NIY; } else TB_WF; break; case TB_VALUE: if (head && TREE_CODE (head) == TREE_LIST) TB_SET_HEAD (TREE_VALUE (head)); else TB_WF; break; case TB_PURPOSE: if (head && TREE_CODE (head) == TREE_LIST) TB_SET_HEAD (TREE_PURPOSE (head)); else TB_WF; break; case TB_IMAG: if (head && TREE_CODE (head) == COMPLEX_CST) TB_SET_HEAD (TREE_IMAGPART (head)); else TB_WF; break; case TB_REAL: if (head && TREE_CODE (head) == COMPLEX_CST) TB_SET_HEAD (TREE_REALPART (head)); else TB_WF; break; case TB_BLOCK: if (head && TREE_CODE (head) == BIND_EXPR) TB_SET_HEAD (TREE_OPERAND (head, 2)); else TB_WF; break; case TB_SUBBLOCKS: if (head && TREE_CODE (head) == BLOCK) TB_SET_HEAD (BLOCK_SUBBLOCKS (head)); else TB_WF; break; case TB_SUPERCONTEXT: if (head && TREE_CODE (head) == BLOCK) TB_SET_HEAD (BLOCK_SUPERCONTEXT (head)); else TB_WF; break; case TB_VARS: if (head && TREE_CODE (head) == BLOCK) TB_SET_HEAD (BLOCK_VARS (head)); else if (head && TREE_CODE (head) == BIND_EXPR) TB_SET_HEAD (TREE_OPERAND (head, 0)); else TB_WF; break; case TB_REFERENCE_TO_THIS: if (head && TYPE_P (head)) TB_SET_HEAD (TYPE_REFERENCE_TO (head)); else TB_WF; break; case TB_POINTER_TO_THIS: if (head && TYPE_P (head)) TB_SET_HEAD (TYPE_POINTER_TO (head)); else TB_WF; break; case TB_BASETYPE: if (head && TREE_CODE (head) == OFFSET_TYPE) TB_SET_HEAD (TYPE_OFFSET_BASETYPE (head)); else TB_WF; break; case TB_ARG_TYPES: if (head && (TREE_CODE (head) == FUNCTION_TYPE || TREE_CODE (head) == METHOD_TYPE)) TB_SET_HEAD (TYPE_ARG_TYPES (head)); else TB_WF; break; case TB_METHOD_BASE_TYPE: if (head && (TREE_CODE (head) == FUNCTION_TYPE || TREE_CODE (head) == METHOD_TYPE) && TYPE_METHOD_BASETYPE (head)) TB_SET_HEAD (TYPE_METHOD_BASETYPE (head)); else TB_WF; break; case TB_FIELDS: if (head && (TREE_CODE (head) == RECORD_TYPE || TREE_CODE (head) == UNION_TYPE || TREE_CODE (head) == QUAL_UNION_TYPE)) TB_SET_HEAD (TYPE_FIELDS (head)); else TB_WF; break; case TB_DOMAIN: if (head && TREE_CODE (head) == ARRAY_TYPE) TB_SET_HEAD (TYPE_DOMAIN (head)); else TB_WF; break; case TB_VALUES: if (head && TREE_CODE (head) == ENUMERAL_TYPE) TB_SET_HEAD (TYPE_VALUES (head)); else TB_WF; break; case TB_ARG_TYPE_AS_WRITTEN: if (head && TREE_CODE (head) == PARM_DECL) TB_SET_HEAD (DECL_ARG_TYPE_AS_WRITTEN (head)); else TB_WF; break; case TB_ARG_TYPE: if (head && TREE_CODE (head) == PARM_DECL) TB_SET_HEAD (DECL_ARG_TYPE (head)); else TB_WF; break; case TB_INITIAL: if (head && DECL_P (head)) TB_SET_HEAD (DECL_INITIAL (head)); else TB_WF; break; case TB_RESULT: if (head && DECL_P (head)) TB_SET_HEAD (DECL_RESULT_FLD (head)); else TB_WF; break; case TB_ARGUMENTS: if (head && DECL_P (head)) TB_SET_HEAD (DECL_ARGUMENTS (head)); else TB_WF; break; case TB_ABSTRACT_ORIGIN: if (head && DECL_P (head)) TB_SET_HEAD (DECL_ABSTRACT_ORIGIN (head)); else if (head && TREE_CODE (head) == BLOCK) TB_SET_HEAD (BLOCK_ABSTRACT_ORIGIN (head)); else TB_WF; break; case TB_ATTRIBUTES: if (head && DECL_P (head)) TB_SET_HEAD (DECL_ATTRIBUTES (head)); else if (head && TYPE_P (head)) TB_SET_HEAD (TYPE_ATTRIBUTES (head)); else TB_WF; break; case TB_CONTEXT: if (head && DECL_P (head)) TB_SET_HEAD (DECL_CONTEXT (head)); else if (head && TYPE_P (head) && TYPE_CONTEXT (head)) TB_SET_HEAD (TYPE_CONTEXT (head)); else TB_WF; break; case TB_OFFSET: if (head && TREE_CODE (head) == FIELD_DECL) TB_SET_HEAD (DECL_FIELD_OFFSET (head)); else TB_WF; break; case TB_BIT_OFFSET: if (head && TREE_CODE (head) == FIELD_DECL) TB_SET_HEAD (DECL_FIELD_BIT_OFFSET (head)); else TB_WF; break; case TB_UNIT_SIZE: if (head && DECL_P (head)) TB_SET_HEAD (DECL_SIZE_UNIT (head)); else if (head && TYPE_P (head)) TB_SET_HEAD (TYPE_SIZE_UNIT (head)); else TB_WF; break; case TB_SIZE: if (head && DECL_P (head)) TB_SET_HEAD (DECL_SIZE (head)); else if (head && TYPE_P (head)) TB_SET_HEAD (TYPE_SIZE (head)); else TB_WF; break; case TB_TYPE: if (head && TREE_TYPE (head)) TB_SET_HEAD (TREE_TYPE (head)); else TB_WF; break; case TB_DECL_SAVED_TREE: if (head && TREE_CODE (head) == FUNCTION_DECL && DECL_SAVED_TREE (head)) TB_SET_HEAD (DECL_SAVED_TREE (head)); else TB_WF; break; case TB_BODY: if (head && TREE_CODE (head) == BIND_EXPR) TB_SET_HEAD (TREE_OPERAND (head, 1)); else TB_WF; break; case TB_CHILD_0: if (head && EXPR_P (head) && TREE_OPERAND (head, 0)) TB_SET_HEAD (TREE_OPERAND (head, 0)); else TB_WF; break; case TB_CHILD_1: if (head && EXPR_P (head) && TREE_OPERAND (head, 1)) TB_SET_HEAD (TREE_OPERAND (head, 1)); else TB_WF; break; case TB_CHILD_2: if (head && EXPR_P (head) && TREE_OPERAND (head, 2)) TB_SET_HEAD (TREE_OPERAND (head, 2)); else TB_WF; break; case TB_CHILD_3: if (head && EXPR_P (head) && TREE_OPERAND (head, 3)) TB_SET_HEAD (TREE_OPERAND (head, 3)); else TB_WF; break; case TB_PRINT: if (head) debug_tree (head); else TB_WF; break; case TB_PRETTY_PRINT: if (head) { print_generic_stmt (TB_OUT_FILE, head, 0); fprintf (TB_OUT_FILE, "\n"); } else TB_WF; break; case TB_SEARCH_NAME: break; case TB_SEARCH_CODE: { enum tree_code code; char *arg_text; arg_text = strchr (input, ' '); if (arg_text == NULL) { fprintf (TB_OUT_FILE, "First argument is missing. This isn't a valid search command. \n"); break; } code = TB_get_tree_code (arg_text + 1); /* Search in the subtree a node with the given code. */ { tree res; res = walk_tree (&head, find_node_with_code, &code, NULL); if (res == NULL_TREE) { fprintf (TB_OUT_FILE, "There's no node with this code (reachable via the walk_tree function from this node).\n"); } else { fprintf (TB_OUT_FILE, "Achoo! I got this node in the tree.\n"); TB_SET_HEAD (res); } } break; } #define TB_MOVE_HEAD(FCT) do { \ if (head) \ { \ tree t; \ t = FCT (head); \ if (t) \ TB_SET_HEAD (t); \ else \ TB_WF; \ } \ else \ TB_WF; \ } while (0) case TB_FIRST: TB_MOVE_HEAD (TB_first_in_bind); break; case TB_LAST: TB_MOVE_HEAD (TB_last_in_bind); break; case TB_UP: TB_MOVE_HEAD (TB_up_expr); break; case TB_PREV: TB_MOVE_HEAD (TB_prev_expr); break; case TB_NEXT: TB_MOVE_HEAD (TB_next_expr); break; case TB_HPREV: /* This command is a little bit special, since it deals with history stack. For this reason it should keep the "head = ..." statement and not use TB_MOVE_HEAD. */ if (head) { tree t; t = TB_history_prev (); if (t) { head = t; if (TB_verbose) { print_generic_expr (TB_OUT_FILE, head, 0); fprintf (TB_OUT_FILE, "\n"); } } else TB_WF; } else TB_WF; break; case TB_CHAIN: /* Don't go further if it's the last node in this chain. */ if (head && TREE_CODE (head) == BLOCK) TB_SET_HEAD (BLOCK_CHAIN (head)); else if (head && TREE_CHAIN (head)) TB_SET_HEAD (TREE_CHAIN (head)); else TB_WF; break; case TB_FUN: /* Go up to the current function declaration. */ TB_SET_HEAD (current_function_decl); fprintf (TB_OUT_FILE, "Current function declaration.\n"); break; case TB_HELP: /* Display a help message. */ { int i; fprintf (TB_OUT_FILE, "Possible commands are:\n\n"); for (i = 0; i < TB_UNUSED_COMMAND; i++) { fprintf (TB_OUT_FILE, "%20s - %s\n", TB_COMMAND_TEXT (i), TB_COMMAND_HELP (i)); } } break; case TB_VERBOSE: if (TB_verbose == 0) { TB_verbose = 1; fprintf (TB_OUT_FILE, "Verbose on.\n"); } else { TB_verbose = 0; fprintf (TB_OUT_FILE, "Verbose off.\n"); } break; case TB_EXIT: case TB_QUIT: /* Just exit from this function. */ goto ret; default: TB_NIY; } } ret:; htab_delete (TB_up_ht); return; }
/* * Refresh the list of USB devices */ BOOL GetUSBDevices(DWORD devnum) { // The first two are standard Microsoft drivers (including the Windows 8 UASP one). // The rest are the vendor UASP drivers I know of so far - list may be incomplete! const char* storage_name[] = { "USBSTOR", "UASPSTOR", "VUSBSTOR", "ETRONSTOR", "ASUSSTPT" }; const char* scsi_name = "SCSI"; const char* usb_speed_name[USB_SPEED_MAX] = { "USB", "USB 1.0", "USB 1.1", "USB 2.0", "USB 3.0" }; // Hash table and String Array used to match a Device ID with the parent hub's Device Interface Path htab_table htab_devid = HTAB_EMPTY; StrArray dev_if_path; char letter_name[] = " (?:)"; char uefi_togo_check[] = "?:\\EFI\\Rufus\\ntfs_x64.efi"; BOOL r = FALSE, found = FALSE, is_SCSI; HDEVINFO dev_info = NULL; SP_DEVINFO_DATA dev_info_data; SP_DEVICE_INTERFACE_DATA devint_data; PSP_DEVICE_INTERFACE_DETAIL_DATA_A devint_detail_data; DEVINST parent_inst, grandparent_inst, device_inst; DWORD size, i, j, k, l, datatype, drive_index; ULONG list_size[ARRAYSIZE(storage_name)] = { 0 }, list_start[ARRAYSIZE(storage_name)] = { 0 }, full_list_size, ulFlags; HANDLE hDrive; LONG maxwidth = 0; int s, score, drive_number; char drive_letters[27], *device_id, *devid_list = NULL, entry_msg[128]; char *label, *entry, buffer[MAX_PATH], str[MAX_PATH], *method_str; usb_device_props props; IGNORE_RETVAL(ComboBox_ResetContent(hDeviceList)); StrArrayClear(&DriveID); StrArrayClear(&DriveLabel); StrArrayCreate(&dev_if_path, 128); // Add a dummy for string index zero, as this is what non matching hashes will point to StrArrayAdd(&dev_if_path, ""); device_id = (char*)malloc(MAX_PATH); if (device_id == NULL) goto out; // Build a hash table associating a CM Device ID of an USB device with the SetupDI Device Interface Path // of its parent hub - this is needed to retrieve the device speed dev_info = SetupDiGetClassDevsA(&_GUID_DEVINTERFACE_USB_HUB, NULL, NULL, DIGCF_PRESENT|DIGCF_DEVICEINTERFACE); if (dev_info != INVALID_HANDLE_VALUE) { if (htab_create(DEVID_HTAB_SIZE, &htab_devid)) { dev_info_data.cbSize = sizeof(dev_info_data); for (i=0; SetupDiEnumDeviceInfo(dev_info, i, &dev_info_data); i++) { if (usb_debug) uprintf("Processing Hub %d:", i + 1); devint_detail_data = NULL; devint_data.cbSize = sizeof(devint_data); // Only care about the first interface (MemberIndex 0) if ( (SetupDiEnumDeviceInterfaces(dev_info, &dev_info_data, &_GUID_DEVINTERFACE_USB_HUB, 0, &devint_data)) && (!SetupDiGetDeviceInterfaceDetailA(dev_info, &devint_data, NULL, 0, &size, NULL)) && (GetLastError() == ERROR_INSUFFICIENT_BUFFER) && ((devint_detail_data = (PSP_DEVICE_INTERFACE_DETAIL_DATA_A)calloc(1, size)) != NULL) ) { devint_detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A); if (SetupDiGetDeviceInterfaceDetailA(dev_info, &devint_data, devint_detail_data, size, &size, NULL)) { // Find the Device IDs for all the children of this hub if (CM_Get_Child(&device_inst, dev_info_data.DevInst, 0) == CR_SUCCESS) { device_id[0] = 0; s = StrArrayAdd(&dev_if_path, devint_detail_data->DevicePath); if ((s>= 0) && (CM_Get_Device_IDA(device_inst, device_id, MAX_PATH, 0) == CR_SUCCESS)) { if ((k = htab_hash(device_id, &htab_devid)) != 0) { htab_devid.table[k].data = (void*)(uintptr_t)s; } if (usb_debug) uprintf(" Found ID[%03d]: %s", k, device_id); while (CM_Get_Sibling(&device_inst, device_inst, 0) == CR_SUCCESS) { device_id[0] = 0; if (CM_Get_Device_IDA(device_inst, device_id, MAX_PATH, 0) == CR_SUCCESS) { if ((k = htab_hash(device_id, &htab_devid)) != 0) { htab_devid.table[k].data = (void*)(uintptr_t)s; } if (usb_debug) uprintf(" Found ID[%03d]: %s", k, device_id); } } } } } free(devint_detail_data); } } } SetupDiDestroyDeviceInfoList(dev_info); } free(device_id); // Build a single list of Device IDs from all the storage enumerators we know of full_list_size = 0; ulFlags = CM_GETIDLIST_FILTER_SERVICE; if (nWindowsVersion >= WINDOWS_7) ulFlags |= CM_GETIDLIST_FILTER_PRESENT; for (s=0; s<ARRAYSIZE(storage_name); s++) { // Get a list of device IDs for all USB storage devices // This will be used to find if a device is UASP if (CM_Get_Device_ID_List_SizeA(&list_size[s], storage_name[s], ulFlags) != CR_SUCCESS) list_size[s] = 0; if (list_size[s] != 0) full_list_size += list_size[s]-1; // remove extra NUL terminator } devid_list = NULL; if (full_list_size != 0) { full_list_size += 1; // add extra NUL terminator devid_list = (char*)malloc(full_list_size); if (devid_list == NULL) { uprintf("Could not allocate Device ID list\n"); return FALSE; } for (s=0, i=0; s<ARRAYSIZE(storage_name); s++) { list_start[s] = i; if (list_size[s] > 1) { if (CM_Get_Device_ID_ListA(storage_name[s], &devid_list[i], list_size[s], ulFlags) != CR_SUCCESS) continue; if (usb_debug) { uprintf("Processing IDs belonging to %s:", storage_name[s]); for (device_id = &devid_list[i]; *device_id != 0; device_id += strlen(device_id) + 1) uprintf(" %s", device_id); } // The list_size is sometimes larger than required thus we need to find the real end for (i += list_size[s]; i > 2; i--) { if ((devid_list[i-2] != '\0') && (devid_list[i-1] == '\0') && (devid_list[i] == '\0')) break; } } } } // Now use SetupDi to enumerate all our storage devices dev_info = SetupDiGetClassDevsA(&_GUID_DEVINTERFACE_DISK, NULL, NULL, DIGCF_PRESENT|DIGCF_DEVICEINTERFACE); if (dev_info == INVALID_HANDLE_VALUE) { uprintf("SetupDiGetClassDevs (Interface) failed: %s\n", WindowsErrorString()); goto out; } dev_info_data.cbSize = sizeof(dev_info_data); for (i=0; SetupDiEnumDeviceInfo(dev_info, i, &dev_info_data); i++) { memset(buffer, 0, sizeof(buffer)); method_str = ""; if (!SetupDiGetDeviceRegistryPropertyA(dev_info, &dev_info_data, SPDRP_ENUMERATOR_NAME, &datatype, (LPBYTE)buffer, sizeof(buffer), &size)) { uprintf("SetupDiGetDeviceRegistryProperty (Enumerator Name) failed: %s\n", WindowsErrorString()); continue; } // UASP drives are listed under SCSI (along with regular SYSTEM drives => "DANGER, WILL ROBINSON!!!") is_SCSI = (safe_stricmp(buffer, scsi_name) == 0); if ((safe_stricmp(buffer, storage_name[0]) != 0) && (!is_SCSI)) continue; // We can't use the friendly name to find if a drive is a VHD, as friendly name string gets translated // according to your locale, so we poke the Hardware ID memset(&props, 0, sizeof(props)); memset(buffer, 0, sizeof(buffer)); props.is_VHD = SetupDiGetDeviceRegistryPropertyA(dev_info, &dev_info_data, SPDRP_HARDWAREID, &datatype, (LPBYTE)buffer, sizeof(buffer), &size) && IsVHD(buffer); if (usb_debug) uprintf("Processing Device: '%s'", buffer); memset(buffer, 0, sizeof(buffer)); if (!SetupDiGetDeviceRegistryPropertyA(dev_info, &dev_info_data, SPDRP_FRIENDLYNAME, &datatype, (LPBYTE)buffer, sizeof(buffer), &size)) { uprintf("SetupDiGetDeviceRegistryProperty (Friendly Name) failed: %s\n", WindowsErrorString()); // We can afford a failure on this call - just replace the name with "USB Storage Device (Generic)" safe_strcpy(buffer, sizeof(buffer), lmprintf(MSG_045)); } else if ((!props.is_VHD) && (devid_list != NULL)) { // Get the properties of the device. We could avoid doing this lookup every time by keeping // a lookup table, but there shouldn't be that many USB storage devices connected... // NB: Each of these Device IDs have an _only_ child, from which we get the Device Instance match. for (device_id = devid_list; *device_id != 0; device_id += strlen(device_id) + 1) { if ( (CM_Locate_DevNodeA(&parent_inst, device_id, 0) == CR_SUCCESS) && (CM_Get_Child(&device_inst, parent_inst, 0) == CR_SUCCESS) && (device_inst == dev_info_data.DevInst) ) { // If we're not dealing with the USBSTOR part of our list, then this is an UASP device props.is_UASP = ((((uintptr_t)device_id)+2) >= ((uintptr_t)devid_list)+list_start[1]); // Now get the properties of the device, and its Device ID, which we need to populate the properties j = htab_hash(device_id, &htab_devid); if (usb_debug) uprintf(" Matched with ID[%03d]: %s", j, device_id); // If the hash didn't match a populated string in dev_if_path[] (htab_devid.table[j].data > 0), // we might have an extra vendor driver in between (e.g. "ASUS USB 3.0 Boost Storage Driver" // for UASP devices in ASUS "Turbo Mode" or "Apple Mobile Device USB Driver" for iPods) // so try to see if we can match the grandparent. if ( ((uint32_t)htab_devid.table[j].data == 0) && (CM_Get_Parent(&grandparent_inst, parent_inst, 0) == CR_SUCCESS) && (CM_Get_Device_IDA(grandparent_inst, str, MAX_PATH, 0) == CR_SUCCESS) ) { device_id = str; method_str = "[GP]"; j = htab_hash(device_id, &htab_devid); if (usb_debug) uprintf(" Matched with (GP) ID[%03d]: %s", j, device_id); } if ((uint32_t)htab_devid.table[j].data > 0) GetUSBProperties(dev_if_path.String[(uint32_t)htab_devid.table[j].data], device_id, &props); if (usb_debug) uprintf(" Props VID:PID = %04X:%04X", props.vid, props.pid); // If previous calls still didn't succeed, try reading the VID:PID from the device_id if ((props.vid == 0) && (props.pid == 0)) { BOOL post_backslash = FALSE; method_str = "[ID]"; for (j=0, k=0; (j<strlen(device_id))&&(k<2); j++) { // The ID is in the form USB_VENDOR_BUSID\VID_xxxx&PID_xxxx\... if (device_id[j] == '\\') post_backslash = TRUE; if (!post_backslash) continue; if (device_id[j] == '_') { props.pid = (uint16_t)strtoul(&device_id[j+1], NULL, 16); if (k++==0) props.vid = props.pid; } } } } } } if (props.is_VHD) { uprintf("Found VHD device '%s'", buffer); } else { if ((props.vid == 0) && (props.pid == 0)) { if (is_SCSI) { // If we have an SCSI drive and couldn't get a VID:PID, we are most likely // dealing with a system drive => eliminate it! if (usb_debug) uprintf(" Non USB => Eliminated"); continue; } safe_strcpy(str, sizeof(str), "????:????"); // Couldn't figure VID:PID } else { static_sprintf(str, "%04X:%04X", props.vid, props.pid); } if (props.speed >= USB_SPEED_MAX) props.speed = 0; uprintf("Found %s%s%s device '%s' (%s) %s\n", props.is_UASP?"UAS (":"", usb_speed_name[props.speed], props.is_UASP?")":"", buffer, str, method_str); if (props.is_LowerSpeed) uprintf("NOTE: This device is an USB 3.0 device operating at lower speed..."); } devint_data.cbSize = sizeof(devint_data); hDrive = INVALID_HANDLE_VALUE; devint_detail_data = NULL; for (j=0; ;j++) { safe_closehandle(hDrive); safe_free(devint_detail_data); if (!SetupDiEnumDeviceInterfaces(dev_info, &dev_info_data, &_GUID_DEVINTERFACE_DISK, j, &devint_data)) { if(GetLastError() != ERROR_NO_MORE_ITEMS) { uprintf("SetupDiEnumDeviceInterfaces failed: %s\n", WindowsErrorString()); } else { uprintf("A device was eliminated because it didn't report itself as a disk\n"); } break; } if (!SetupDiGetDeviceInterfaceDetailA(dev_info, &devint_data, NULL, 0, &size, NULL)) { if(GetLastError() == ERROR_INSUFFICIENT_BUFFER) { devint_detail_data = (PSP_DEVICE_INTERFACE_DETAIL_DATA_A)calloc(1, size); if (devint_detail_data == NULL) { uprintf("Unable to allocate data for SP_DEVICE_INTERFACE_DETAIL_DATA\n"); continue; } devint_detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A); } else { uprintf("SetupDiGetDeviceInterfaceDetail (dummy) failed: %s\n", WindowsErrorString()); continue; } } if (devint_detail_data == NULL) { uprintf("SetupDiGetDeviceInterfaceDetail (dummy) - no data was allocated\n"); continue; } if(!SetupDiGetDeviceInterfaceDetailA(dev_info, &devint_data, devint_detail_data, size, &size, NULL)) { uprintf("SetupDiGetDeviceInterfaceDetail (actual) failed: %s\n", WindowsErrorString()); continue; } hDrive = CreateFileA(devint_detail_data->DevicePath, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if(hDrive == INVALID_HANDLE_VALUE) { uprintf("Could not open '%s': %s\n", devint_detail_data->DevicePath, WindowsErrorString()); continue; } drive_number = GetDriveNumber(hDrive, devint_detail_data->DevicePath); if (drive_number < 0) continue; drive_index = drive_number + DRIVE_INDEX_MIN; if (!IsMediaPresent(drive_index)) { uprintf("Device eliminated because it appears to contain no media\n"); safe_closehandle(hDrive); safe_free(devint_detail_data); break; } if (GetDriveLabel(drive_index, drive_letters, &label)) { if ((!enable_HDDs) && (!props.is_VHD) && ((score = IsHDD(drive_index, (uint16_t)props.vid, (uint16_t)props.pid, buffer)) > 0)) { uprintf("Device eliminated because it was detected as an USB Hard Drive (score %d > 0)\n", score); uprintf("If this device is not an USB Hard Drive, please e-mail the author of this application\n"); uprintf("NOTE: You can enable the listing of USB Hard Drives in 'Advanced Options' (after clicking the white triangle)"); safe_closehandle(hDrive); safe_free(devint_detail_data); break; } // The empty string is returned for drives that don't have any volumes assigned if (drive_letters[0] == 0) { entry = lmprintf(MSG_046, label, drive_number, SizeToHumanReadable(GetDriveSize(drive_index), FALSE, use_fake_units)); } else { // Find the UEFI:TOGO partition(s) (and eliminate them form our listing) for (k=0; drive_letters[k]; k++) { uefi_togo_check[0] = drive_letters[k]; if (PathFileExistsA(uefi_togo_check)) { for (l=k; drive_letters[l]; l++) drive_letters[l] = drive_letters[l+1]; k--; } } // We have multiple volumes assigned to the same device (multiple partitions) // If that is the case, use "Multiple Volumes" instead of the label safe_strcpy(entry_msg, sizeof(entry_msg), ((drive_letters[0] != 0) && (drive_letters[1] != 0))? lmprintf(MSG_047):label); for (k=0; drive_letters[k]; k++) { // Append all the drive letters we detected letter_name[2] = drive_letters[k]; if (right_to_left_mode) safe_strcat(entry_msg, sizeof(entry_msg), RIGHT_TO_LEFT_MARK); safe_strcat(entry_msg, sizeof(entry_msg), letter_name); if (drive_letters[k] == (PathGetDriveNumberU(app_dir) + 'A')) break; } // Repeat as we need to break the outside loop if (drive_letters[k] == (PathGetDriveNumberU(app_dir) + 'A')) { uprintf("Removing %c: from the list: This is the disk from which " APPLICATION_NAME " is running!\n", app_dir[0]); safe_closehandle(hDrive); safe_free(devint_detail_data); break; } safe_sprintf(&entry_msg[strlen(entry_msg)], sizeof(entry_msg) - strlen(entry_msg), "%s [%s]", (right_to_left_mode)?RIGHT_TO_LEFT_MARK:"", SizeToHumanReadable(GetDriveSize(drive_index), FALSE, use_fake_units)); entry = entry_msg; } // Must ensure that the combo box is UNSORTED for indexes to be the same StrArrayAdd(&DriveID, buffer); StrArrayAdd(&DriveLabel, label); IGNORE_RETVAL(ComboBox_SetItemData(hDeviceList, ComboBox_AddStringU(hDeviceList, entry), drive_index)); maxwidth = max(maxwidth, GetEntryWidth(hDeviceList, entry)); safe_closehandle(hDrive); safe_free(devint_detail_data); break; } } } SetupDiDestroyDeviceInfoList(dev_info); // Adjust the Dropdown width to the maximum text size SendMessage(hDeviceList, CB_SETDROPPEDWIDTH, (WPARAM)maxwidth, 0); if (devnum >= DRIVE_INDEX_MIN) { for (i=0; i<ComboBox_GetCount(hDeviceList); i++) { if ((DWORD)ComboBox_GetItemData(hDeviceList, i) == devnum) { found = TRUE; break; } } } if (!found) i = 0; IGNORE_RETVAL(ComboBox_SetCurSel(hDeviceList, i)); SendMessage(hMainDialog, WM_COMMAND, (CBN_SELCHANGE<<16) | IDC_DEVICE, 0); SendMessage(hMainDialog, WM_COMMAND, (CBN_SELCHANGE<<16) | IDC_FILESYSTEM, ComboBox_GetCurSel(hFileSystem)); r = TRUE; out: // Set 'Start' as the selected button, so that tab selection works SendMessage(hMainDialog, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hMainDialog, IDC_START), TRUE); safe_free(devid_list); StrArrayDestroy(&dev_if_path); htab_destroy(&htab_devid); return r; }
static int windows_init(struct libusb_context *ctx) { struct windows_context_priv *priv = _context_priv(ctx); HANDLE semaphore; char sem_name[11 + 8 + 1]; // strlen("libusb_init") + (32-bit hex PID) + '\0' int r = LIBUSB_ERROR_OTHER; bool winusb_backend_init = false; sprintf(sem_name, "libusb_init%08X", (unsigned int)(GetCurrentProcessId() & 0xFFFFFFFF)); semaphore = CreateSemaphoreA(NULL, 1, 1, sem_name); if (semaphore == NULL) { usbi_err(ctx, "could not create semaphore: %s", windows_error_str(0)); return LIBUSB_ERROR_NO_MEM; } // A successful wait brings our semaphore count to 0 (unsignaled) // => any concurent wait stalls until the semaphore's release if (WaitForSingleObject(semaphore, INFINITE) != WAIT_OBJECT_0) { usbi_err(ctx, "failure to access semaphore: %s", windows_error_str(0)); CloseHandle(semaphore); return LIBUSB_ERROR_NO_MEM; } // NB: concurrent usage supposes that init calls are equally balanced with // exit calls. If init is called more than exit, we will not exit properly if (++init_count == 1) { // First init? // Load DLL imports if (!windows_init_dlls()) { usbi_err(ctx, "could not resolve DLL functions"); goto init_exit; } get_windows_version(); if (windows_version == WINDOWS_UNDEFINED) { usbi_err(ctx, "failed to detect Windows version"); r = LIBUSB_ERROR_NOT_SUPPORTED; goto init_exit; } if (!windows_init_clock(ctx)) goto init_exit; if (!htab_create(ctx)) goto init_exit; r = winusb_backend.init(ctx); if (r != LIBUSB_SUCCESS) goto init_exit; winusb_backend_init = true; r = usbdk_backend.init(ctx); if (r == LIBUSB_SUCCESS) { usbi_dbg("UsbDk backend is available"); usbdk_available = true; } else { usbi_info(ctx, "UsbDk backend is not available"); // Do not report this as an error r = LIBUSB_SUCCESS; } } // By default, new contexts will use the WinUSB backend priv->backend = &winusb_backend; r = LIBUSB_SUCCESS; init_exit: // Holds semaphore here if ((init_count == 1) && (r != LIBUSB_SUCCESS)) { // First init failed? if (winusb_backend_init) winusb_backend.exit(ctx); htab_destroy(); windows_destroy_clock(); windows_exit_dlls(); --init_count; } ReleaseSemaphore(semaphore, 1, NULL); // increase count back to 1 CloseHandle(semaphore); return r; }