/** * Search executable within the user's PATH. * * @return full path if found, NULL otherwise. * The returned string is allocated with halloc(). */ char * file_locate_from_path(const char *argv0) { static bool already_done; char *path; char *tok; char filepath[MAX_PATH_LEN + 1]; char *result = NULL; char *ext = ""; if (is_running_on_mingw() && !is_strsuffix(argv0, (size_t) -1, ".exe")) { ext = ".exe"; } if (filepath_basename(argv0) != argv0) { if (!already_done) { s_warning("can't locate \"%s\" in PATH: name contains '%c' already", argv0, strchr(argv0, G_DIR_SEPARATOR) != NULL ? G_DIR_SEPARATOR : '/'); } goto done; } path = getenv("PATH"); if (NULL == path) { if (!already_done) { s_warning("can't locate \"%s\" in PATH: " "no such environment variable", argv0); } goto done; } path = h_strdup(path); tok = strtok(path, G_SEARCHPATH_SEPARATOR_S); while (NULL != tok) { const char *dir = tok; filestat_t buf; if ('\0' == *dir) dir = "."; concat_strings(filepath, sizeof filepath, dir, G_DIR_SEPARATOR_S, argv0, ext, NULL); if (-1 != stat(filepath, &buf)) { if (S_ISREG(buf.st_mode) && -1 != access(filepath, X_OK)) { result = h_strdup(filepath); break; } } tok = strtok(NULL, G_SEARCHPATH_SEPARATOR_S); } hfree(path); done: already_done = TRUE; /* No warning on subsequent invocation */ return result; }
/** * Get the full program path. * * @return a newly allocated string (through halloc()) that points to the * path of the program being run, NULL if we can't compute a suitable path. */ char * file_program_path(const char *argv0) { filestat_t buf; char *file = deconstify_char(argv0); char filepath[MAX_PATH_LEN + 1]; if (is_running_on_mingw() && !is_strsuffix(argv0, (size_t) -1, ".exe")) { concat_strings(filepath, sizeof filepath, argv0, ".exe", NULL_PTR); } else { clamp_strcpy(filepath, sizeof filepath, argv0); } if (-1 == stat(filepath, &buf)) { int saved_errno = errno; file = file_locate_from_path(argv0); if (NULL == file) { errno = saved_errno; s_warning("%s(): could not stat() \"%s\": %m", G_STRFUNC, filepath); return NULL; } } if (file != NULL && file != argv0) return file; /* Allocated by file_locate_from_path() */ return h_strdup(filepath); }
G_GNUC_COLD void statusbar_gui_init(void) { GtkStatusbar *sb; sb = statusbar_get(); statusbar_set_shadow_type(GTK_STATUSBAR(sb), GTK_SHADOW_ETCHED_IN); scid_bottom = gtk_statusbar_get_context_id(sb, "default"); scid_hostsfile = gtk_statusbar_get_context_id(sb, "reading hosts file"); scid_queue_freezed = gtk_statusbar_get_context_id(sb, "queue freezed"); scid_info = gtk_statusbar_get_context_id(sb, "information"); scid_ip_changed = gtk_statusbar_get_context_id(sb, "ip changed"); scid_warn = gtk_statusbar_get_context_id(sb, "warning"); /* * This message lies at the bottom of the statusbar, and is never removed, * but to be replaced by an updated message. * * The current string held at the bottom is stored in `statbar_botstr'. * If a new string is pending replacement in `statbar_botstr_new', then * it will replace the current one when the last timeout for pushed * messages expires, at which time we'll know the bottom message is shown. * --RAM, 27/06/2002 */ statbar_botstr = h_strdup(product_get_website()); statusbar_gui_push(SB_MESSAGE, scid_bottom, 0, "%s", statbar_botstr); main_gui_add_timer(statusbar_gui_clear_timeouts); }
static SmProp *make_string_list_propv_full(int num_vals, const char *name, char const * const *values, const char *prop_type) { int n; SmProp *prop = malloc(sizeof(SmProp)); prop->name = h_strdup(name); prop->type = h_strdup(prop_type); prop->num_vals = num_vals; prop->vals = malloc(sizeof(SmPropValue) * num_vals); for (n = 0; n < num_vals; ++n) { fill_in_prop_val(prop->vals + n, values[n]); } return prop; }
/** * @return NULL on error, a newly allocated string via halloc() otherwise. */ static char * ghc_get_next(void) { struct ghc *ghc; char *url; time_t now; g_return_val_if_fail(ghc_list, NULL); now = tm_time(); ghc = list_head(ghc_list); if (NULL == ghc) return NULL; /* * Wait GHC_RETRY_AFTER secs before contacting the GHC again. */ if (ghc->stamp && delta_time(now, ghc->stamp) < GHC_RETRY_AFTER) return NULL; ghc->stamp = now; url = h_strdup(ghc->url); if (ghc->used < GHC_MAX_ATTEMPTS) { ghc->used++; list_moveto_tail(ghc_list, ghc); } else { list_remove(ghc_list, ghc); ghc_free_null(&ghc); } return url; }
/** * Creates a copy with the given pathname with the basename cut off. A slash * is always considered a separator but G_DIR_SEPARATOR is considered as * well. Thus "/whatever/blah\\yadda" returns "/whatever/blah" if G_DIR_SEPARATOR * is a backslash, otherwise "/whatever" is returned. * * @return A newly allocated string holding the given pathname with the * basename cut off. If the string contained no directory separator, * NULL is returned. The string must be freed via hfree(). */ char * filepath_directory(const char *pathname) { const char *sep; char *dir; sep = filepath_directory_end(pathname, '/'); if (G_DIR_SEPARATOR != '/') { const char *alt; alt = filepath_directory_end(pathname, G_DIR_SEPARATOR); if (sep && alt) { sep = (sep - pathname > alt - pathname) ? sep : alt; } else if (alt) { sep = alt; } } if (sep == pathname) { dir = h_strdup(G_DIR_SEPARATOR_S); } else if (sep) { dir = h_strndup(pathname, sep - pathname); } else { dir = NULL; } return dir; }
/** * Add header line to the `headers' hash for specified field name. * A private copy of the `field' name and of the `text' data is made. */ static void add_header(header_t *o, const char *field, const char *text) { htable_t *ht; str_t *v; header_check(o); ht = header_get_table(o); v = htable_lookup(ht, field); if (v) { /* * Header already exists, according to RFC2616 we need to append * the value, comma-separated. */ STR_CAT(v, ", "); str_cat(v, text); } else { char *key; /* * Create a new header entry in the hash table. */ key = h_strdup(field); v = str_new_from(text); htable_insert(ht, key, v); } }
/** * Allocate a new descriptor for managing large keys and values. */ DBMBIG * big_alloc(const char *datname, int flags, int mode) { DBMBIG *dbg; struct datfile *file; WALLOC0(dbg); dbg->fd = -1; dbg->bitbno = -1; WALLOC(file); file->datname = h_strdup(datname); file->flags = flags; file->mode = mode; dbg->file = file; /* * If the .dat file exists and O_TRUNC was given in the flags and the * database is opened for writing, then the database is re-initialized: * unlink the .dat file, which will be re-created on-demand. */ if ((flags & (O_RDWR | O_WRONLY)) && (flags & O_TRUNC)) { unlink(datname); } return dbg; }
/** * Create the string representation of the push-proxies, for inclusion * in the push:// URL. * * @return An empty string (""), if the list is empty or the address NULL; * otherwise a colon-separated list of IP:port, beginning with a colon. The * string is newly allocated via halloc(). */ char * magnet_proxies_to_string(const sequence_t *proxies) { if (NULL == proxies) return h_strdup(""); return proxy_sequence_to_string(proxies); }
/** * Append line of text to given header field. * A private copy of the data is made. */ static void hfield_append(header_field_t *h, const char *text) { header_field_check(h); if (!h->lines) { h->lines = slist_new(); } slist_append(h->lines, h_strdup(text)); }
static inline void tls_log_function(int level, const char *text) { if (GNET_PROPERTY(tls_debug) > UNSIGNED(level)) { char *str = h_strdup(text); strchomp(str, 0); g_debug("TLS(%d): %s", level, str); hfree(str); } }
void statusbar_gui_set_default(const char *format, ...) { static gchar buf[1024]; va_list args; va_start(args, format); HFREE_NULL(statbar_botstr_new); if (format != NULL) { str_vbprintf(buf, sizeof(buf), format, args); statbar_botstr_new = h_strdup(buf); } else { statbar_botstr_new = h_strdup(product_get_website()); } va_end(args); }
/** * Create a new empty header field, whose name is `name'. * A private copy of `name' is done. */ static header_field_t * hfield_make(const char *name) { header_field_t *h; WALLOC0(h); h->magic = HEADER_FIELD_MAGIC; h->name = h_strdup(name); return h; }
/** * Allocate a new attribute key/value. * * @param uri the namespace URI (may be NULL) * @param local the local name * @param value the attribute value (copied) * * @return a new attribute key/value. */ static struct xattr * xattr_alloc(const char *uri, const char *local, const char *value) { struct xattr *xa; WALLOC(xa); xa->uri = (NULL == uri) ? NULL : atom_str_get(uri); xa->local = atom_str_get(local); xa->value = h_strdup(value); return xa; }
/** * @return NULL on error, a newly allocated string via halloc() otherwise. */ static char * uhc_get_next(void) { struct uhc *uhc; char *host; time_t now; size_t n; g_return_val_if_fail(uhc_list, NULL); now = tm_time(); n = hash_list_count(uhc_list); if (0 == n) return NULL; /* * Wait UHC_RETRY_AFTER secs before contacting the UHC again. * Can't be too long because the UDP reply may get lost if the * requesting host already has a saturated b/w. * If we come here, it's because we're lacking hosts for establishing * a Gnutella connection, after we exhausted our caches. */ while (n-- != 0) { uhc = hash_list_head(uhc_list); g_assert(uhc != NULL); /* We computed count on entry */ if (delta_time(now, uhc->stamp) >= UHC_RETRY_AFTER) goto found; hash_list_moveto_tail(uhc_list, uhc); } return NULL; found: uhc->stamp = now; host = h_strdup(uhc->host); if (uhc->used < UHC_MAX_ATTEMPTS) { uhc->used++; hash_list_moveto_tail(uhc_list, uhc); } else { hash_list_remove(uhc_list, uhc); uhc_free(&uhc); } return host; }
/** * Create a new comment node, inserted under parent node as the last child. * * @param parent the parent node (NULL creates a standalone node * @param text the comment text, copied ("--" will be emitted as "- -") */ xnode_t * xnode_new_comment(xnode_t *parent, const char *text) { xnode_t *xn; g_assert(text != NULL); xn = xnode_new(XNODE_T_COMMENT); xn->u.c.text = h_strdup(text); if (parent != NULL) xnode_add_child(parent, xn); return xn; }
/** * Parse options. * @return halloc()-ed option string, or NULL on error. */ static char * ctl_parse_options(struct ctl_string *s) { struct ctl_tok *tok = ctl_next_token(s); char *opt = NULL; if (CTL_TOK_ID != tok->type) { ctl_error(s, tok, "country options"); } else { opt = h_strdup(tok->val.s); } ctl_token_free_null(&tok); return opt; }
/** * Create an absolute path. * The resulting string must be freed with hfree(). */ char * absolute_pathname(const char *file) { g_assert(file != NULL); if (is_absolute_path(file)) { return h_strdup(file); } else if ('\0' == file[0]) { return NULL; } else { char buf[4096], *ret; ret = getcwd(buf, sizeof buf); return ret ? make_pathname(ret, file) : NULL; } }
/** * Create a new text node, inserted under parent node as the last child.. * * When created as verbatim, any '&' character is left as-is, otherwise they * are escaped. All '<' and '>' are escaped regardless. * * @param parent the parent node (NULL creates a standalone node * @param text the text * @param verbatim whether text is to be emitted verbatim or escaped */ xnode_t * xnode_new_text(xnode_t *parent, const char *text, bool verbatim) { xnode_t *xn; g_assert(text != NULL); xn = xnode_new(XNODE_T_TEXT); xn->u.t.text = h_strdup(text); xn->u.t.asis = booleanize(verbatim); if (parent != NULL) xnode_add_child(parent, xn); return xn; }
static gboolean search_by_regex(GtkTreeModel *model, gint column, const gchar *key, GtkTreeIter *iter, gpointer unused_data) { static const gboolean found = FALSE; static gchar *last_key; /* This will be "leaked" on exit */ static regex_t re; /* The last regex will be "leaked" on exit */ gint ret; g_return_val_if_fail(model, !found); g_return_val_if_fail(column >= 0, !found); g_return_val_if_fail((guint) column < SEARCH_RESULTS_VISIBLE_COLUMNS, !found); g_return_val_if_fail(key, !found); g_return_val_if_fail(iter, !found); (void) unused_data; if (!last_key || 0 != strcmp(last_key, key)) { if (last_key) { regfree(&re); HFREE_NULL(last_key); } ret = regcomp(&re, key, REG_EXTENDED | REG_NOSUB | REG_ICASE); g_return_val_if_fail(0 == ret, !found); last_key = h_strdup(key); } { const struct result_data *rd; rd = get_result_data(model, iter); g_return_val_if_fail(NULL != rd, !found); g_return_val_if_fail(NULL != rd->record->utf8_name, !found); ret = regexec(&re, rd->record->utf8_name, 0, NULL, 0); } return 0 == ret ? found : !found; }
char * bitzi_gui_get_metadata(const bitzi_data_t *data) { g_assert(data != NULL); /* * Build string */ if ( data->judgment == BITZI_FJ_FAILURE || data->judgment == BITZI_FJ_WRONG_FILESIZE ) { return h_strdup(bitzi_fj_to_string(data->judgment)); } else if (data->mime_type) { if (data->mime_desc) { return h_strdup_printf("%s (%1.1f): %s (%s)%s%s", bitzi_fj_to_string(data->judgment), data->goodness, data->mime_type, data->mime_desc, data->duration != 0 ? "; " : "", data->duration != 0 ? short_time(data->duration) : ""); } else { return h_strdup_printf("%s (%1.1f): %s%s%s", bitzi_fj_to_string(data->judgment), data->goodness, data->mime_type, data->duration != 0 ? "; " : "", data->duration != 0 ? short_time(data->duration) : ""); } } else if (data->judgment != BITZI_FJ_UNKNOWN) { return h_strdup_printf("%s (%1.1f): %s", bitzi_fj_to_string(data->judgment), data->goodness, _("No other data")); } return NULL; }
/** * Retrieve more hosts from web cache, asynchronously. */ void gwc_get_hosts(void) { void *handle; char *url; const char *msg; static time_t last_called = 0; time_t now = tm_time(); /* * Make sure we don't probe more than one webcache at a time. * Ancient versions should rely on their hostcache to be connected. */ if (gwc_get_running || GNET_PROPERTY(ancient_version)) return; /* * This routine is called each time we run out of hosts to try in our * cache, so we have absolutely no guarantee about the frequency at which * it will be called. * * Force picking up a new cache (well, randomly) if we were called less * than an hour ago. Note that we don't remember whether it was THIS * particular current cache that was accessed last time we were called. * We only care about the calling frequency, and bet on the high number * of available web caches and the random selection process to behave. * properly. * --RAM, 24/11/2003 */ if (delta_time(now, last_called) < REUSE_PERIOD) gwc_clear_current_url(FALSE); last_called = now; if (!gwc_check_current_url()) return; /* * Give some GUI feedback. */ msg = str_smsg(_("Connecting to web cache %s"), gwc_current_url); gcu_statusbar_message(msg); if (GNET_PROPERTY(bootstrap_debug)) g_message("BOOT connecting to web cache %s", gwc_current_url); /* * Launch the asynchronous request and attach parsing information. */ msg = str_smsg("%s?get=1&net=gnutella2&%s", gwc_current_url, CLIENT_INFO); url = h_strdup(msg); if (GNET_PROPERTY(bootstrap_debug) > 2) g_message("GWC host request: %s", url); handle = http_async_get(url, NULL, gwc_host_data_ind, gwc_host_error_ind); if (NULL == handle) { g_warning("could not launch a \"GET %s\" request: %s", url, http_async_strerror(http_async_errno)); gwc_clear_current_url(TRUE); } else { http_async_set_op_gotreply(handle, gwc_got_reply); gwc_parse_context_set(handle, MAX_IP_LINES); gwc_get_running = TRUE; } hfree(url); }
/** * Load spam database from the supplied FILE. * * The current file format is as follows: * * # Comment * SHA1 <SHA-1> * ADDED <date> * END * * @returns the amount of entries loaded or -1 on failure. */ static G_GNUC_COLD gulong spam_load(FILE *f) { static const struct spam_item zero_item; struct spam_item item; char line[1024]; guint line_no = 0; bit_array_t tag_used[BIT_ARRAY_SIZE(NUM_SPAM_TAGS)]; gulong item_count = 0; g_assert(f); /* Reset state */ item = zero_item; bit_array_init(tag_used, NUM_SPAM_TAGS); while (fgets(line, sizeof line, f)) { const char *tag_name, *value; char *sp, *nl; spam_tag_t tag; line_no++; nl = strchr(line, '\n'); if (!nl) { /* * If the line is too long or unterminated the file is either * corrupt or was manually edited without respecting the * exact format. If we continued, we would read from the * middle of a line which could be the filename or ID. */ g_warning("spam_load(): " "line too long or missing newline in line %u", line_no); break; } *nl = '\0'; /* Skip comments and empty lines */ if (*line == '#' || *line == '\0') continue; sp = strchr(line, ' '); if (sp) { *sp = '\0'; value = &sp[1]; } else { value = strchr(line, '\0'); } tag_name = line; tag = spam_string_to_tag(tag_name); g_assert(UNSIGNED(tag) < UNSIGNED(NUM_SPAM_TAGS)); if (SPAM_TAG_UNKNOWN != tag && !bit_array_flip(tag_used, tag)) { g_warning("spam_load(): duplicate tag \"%s\" in entry in line %u", tag_name, line_no); continue; } switch (tag) { case SPAM_TAG_ADDED: { time_t t; t = date2time(value, tm_time()); if ((time_t) -1 == t) { item.damaged = TRUE; } } break; case SPAM_TAG_SHA1: { if (strlen(value) != SHA1_BASE32_SIZE) { item.damaged = TRUE; g_warning("spam_load(): SHA-1 has wrong length."); } else { const struct sha1 *raw; raw = base32_sha1(value); if (raw) item.sha1 = *raw; else item.damaged = TRUE; } } break; case SPAM_TAG_NAME: { if ('\0' == value[0]) { item.damaged = TRUE; g_warning("spam_load(): Missing filename pattern."); } else if (!utf8_is_valid_string(value)) { item.damaged = TRUE; g_warning("spam_load(): Filename pattern is not UTF-8."); } else { item.name = h_strdup(value); } } break; case SPAM_TAG_SIZE: { const char *endptr; guint64 u; int error; u = parse_uint64(value, &endptr, 10, &error); if (error) { item.damaged = TRUE; g_warning("spam_load(): Cannot parse SIZE: %s", value); } else { item.min_size = u; item.max_size = u; if ('-' == endptr[0]) { u = parse_uint64(&endptr[1], &endptr, 10, &error); if (error) { item.damaged = TRUE; g_warning("spam_load(): Cannot parse SIZE: %s", value); } if (u < item.min_size) { item.damaged = TRUE; g_warning("spam_load(): " "Maximum size below minimum size"); } else { item.max_size = u; } } } } break; case SPAM_TAG_END: if ( !bit_array_get(tag_used, SPAM_TAG_SHA1) && !bit_array_get(tag_used, SPAM_TAG_NAME) ) { g_warning("spam_load(): missing SHA1 or NAME tag"); item.damaged = TRUE; } if (!bit_array_get(tag_used, SPAM_TAG_ADDED)) { g_warning("spam_load(): missing ADDED tag"); item.damaged = TRUE; } item.done = TRUE; break; case SPAM_TAG_UNKNOWN: /* Ignore */ break; case NUM_SPAM_TAGS: g_assert_not_reached(); break; } if (item.done && !item.damaged) { if (bit_array_get(tag_used, SPAM_TAG_SHA1)) { spam_sha1_add(&item.sha1); item_count++; } if (bit_array_get(tag_used, SPAM_TAG_NAME)) { if (!bit_array_get(tag_used, SPAM_TAG_SIZE)) { item.min_size = 0; item.max_size = MAX_INT_VAL(filesize_t); } if ( spam_add_name_and_size(item.name, item.min_size, item.max_size) ) { item.damaged = TRUE; } else { item_count++; } } } if (item.damaged) { g_warning("Damaged spam entry in line %u: " "tag_name=\"%s\", value=\"%s\"", line_no, tag_name, value); } if (item.done) { /* Reset state */ HFREE_NULL(item.name); item = zero_item; bit_array_clear_range(tag_used, 0, NUM_SPAM_TAGS - 1U); } } spam_sha1_sync(); return item_count; }
/** * Search executable within the user's PATH. * * @return full path if found, NULL otherwise. * The returned string is allocated with halloc(). */ char * file_locate_from_path(const char *argv0) { static bool already_done; char *path; char *tok; char filepath[MAX_PATH_LEN + 1]; char *result = NULL; char *ext = ""; if (is_running_on_mingw() && !is_strsuffix(argv0, (size_t) -1, ".exe")) { ext = ".exe"; } if (filepath_basename(argv0) != argv0) { if (!already_done) { s_warning("can't locate \"%s\" in PATH: name contains '%c' already", argv0, strchr(argv0, G_DIR_SEPARATOR) != NULL ? G_DIR_SEPARATOR : '/'); } result = h_strdup(argv0); goto done; } path = getenv("PATH"); if (NULL == path) { if (!already_done) { s_warning("can't locate \"%s\" in PATH: " "no such environment variable", argv0); } goto done; } /* * On Windows, we need to implicitly add "." to the path if not already * present -- this is done by appending a separator and a dot, not by * checking whether "." is already part of the path. * * The reason is that "." is implied, and also because one may omit the * ".exe" extension when launching a program. This means checks done * in crash_init() for instance to see whether the file listed in * argv[0] exists and which do not account for a missing ".exe" will * attempt to locate the program in the PATH to get a full name and will * fail if we do not add ".". * * On UNIX this cannot happen because there is no hidden extension and * the "." is never made part of the PATH implictly. * * --RAM, 2015-12-06 */ if (is_running_on_mingw()) path = h_strdup_printf("%s%c.", path, *G_SEARCHPATH_SEPARATOR_S); else path = h_strdup(path); path = h_strdup(path); /* FIXME: strtok() is not thread-safe --RAM, 2015-12-06 */ tok = strtok(path, G_SEARCHPATH_SEPARATOR_S); while (NULL != tok) { const char *dir = tok; filestat_t buf; if ('\0' == *dir) dir = "."; concat_strings(filepath, sizeof filepath, dir, G_DIR_SEPARATOR_S, argv0, ext, NULL_PTR); if (-1 != stat(filepath, &buf)) { if (S_ISREG(buf.st_mode) && -1 != access(filepath, X_OK)) { result = h_strdup(filepath); break; } } tok = strtok(NULL, G_SEARCHPATH_SEPARATOR_S); } hfree(path); done: already_done = TRUE; /* No warning on subsequent invocation */ return result; }
int csm_update_service(csm_service_list *services, csm_service *s, csm_ctx *ctx, int validate) { if (validate) CHECK(csm_validate_fields(ctx, s), "Service doesn't validate"); // assert(s->lifetime); long lifetime = s->lifetime; // check if service is attached to service_list CHECK(co_list_contains(services->services, (co_obj_t*)container_of(s, co_service_t, service)), "Cannot update service not in service list"); // detach s->fields from s and attach to services->service_fields if (!co_list_contains(services->service_fields, s->fields)) { co_obj_t *fields = s->fields; hattach(fields, NULL); CHECK(co_list_append(services->service_fields, fields), "Failed to add service fields to service list"); } /* Create or verify signature */ if (s->signature) CHECK(csm_verify_signature(s),"Invalid signature"); else CHECK(csm_create_signature(s),"Failed to create signature"); /* Set expiration timer on the service */ #ifdef USE_UCI long def_lifetime = default_lifetime(); if (lifetime == 0 || (def_lifetime < lifetime && def_lifetime > 0)) lifetime = def_lifetime; #endif if (lifetime > 0) { struct timeval tv; avahi_elapse_time(&tv, 1000*lifetime, 0); time_t current_time = time(NULL); // create expiration event for service s->timeout = avahi_simple_poll_get(simple_poll)->timeout_new(avahi_simple_poll_get(simple_poll), &tv, _csm_expire_service, s); /* Convert lifetime period into timestamp */ if (current_time != ((time_t)-1)) { struct tm *timestr = localtime(¤t_time); timestr->tm_sec += lifetime; current_time = mktime(timestr); char *c_time_string = ctime(¤t_time); if (c_time_string) { c_time_string[strlen(c_time_string)-1] = '\0'; /* ctime adds \n to end of time string; remove it */ s->expiration = h_strdup(c_time_string); CHECK_MEM(s->expiration); service_attach(s->expiration, s); } } } // finalize service by running update handlers csm_services_commit(services); return 1; error: return 0; }
/** * Analyze the data we have received, and give each line to the supplied * dispatcher callback `cb', after having chomped it. On EOF, call `eof' * to finalize parsing. */ static void parse_dispatch_lines(void *handle, const char *buf, size_t len, parse_dispatch_t cb, parse_eof_t eofile) { struct parse_context *ctx; const char *p = buf; size_t remain = len; /* * Retrieve parsing context, stored as an opaque attribute in the * asynchronous HTTP request handle. */ ctx = http_async_get_opaque(handle); g_assert(ctx->handle == handle); /* Make sure it's the right context */ if (len == 0) { /* Nothing to parse, got EOF */ if (eofile != NULL) (*eofile)(ctx); return; } /* * Read a line at a time. */ for (;;) { char *line; bool error; size_t line_len; size_t parsed; switch (getline_read(ctx->getline, p, remain, &parsed)) { case READ_OVERFLOW: http_async_cancel(handle); ghc_connecting = FALSE; return; case READ_DONE: p += parsed; remain -= parsed; break; case READ_MORE: /* ok, but needs more data */ g_assert(parsed == remain); return; } /* * We come here everytime we get a full line. */ line = h_strdup(getline_str(ctx->getline)); line_len = getline_length(ctx->getline); line_len = strchomp(line, line_len); error = !(*cb)(ctx, line, line_len); /* An ERROR was reported */ HFREE_NULL(line); if (error) { ghc_ctx.ha = NULL; ghc_connecting = FALSE; return; } /* * Make sure we don't process lines ad infinitum. */ ctx->lines++; if (ctx->lines >= ctx->maxlines) { const char *req; const char *url = http_async_info(handle, &req, NULL, NULL, NULL); if (GNET_PROPERTY(bootstrap_debug)) g_warning("BOOT GHC got %u+ lines from \"%s %s\", stopping", ctx->lines, req, url); http_async_close(handle); ghc_connecting = FALSE; return; } getline_reset(ctx->getline); } }
inline static void fill_in_prop_val(SmPropValue *val, const char *s) { val->length = strlen(s); val->value = (SmPointer) h_strdup(s); }
/** * Creates a valid and sanitized filename from the supplied string. For most * Unix-like platforms anything goes but for security reasons, shell meta * characters are replaced by harmless characters. * * @param filename the suggested filename. * @param no_spaces if TRUE, spaces are replaced with underscores. * @param no_evil if TRUE, "evil" characters are replaced with underscores. * * @returns a newly allocated string using halloc() or ``filename'' * if it was a valid filename already. */ char * filename_sanitize(const char *filename, bool no_spaces, bool no_evil) { const char *p; const char *s; char *q; g_assert(filename); /* Almost all evil characters are forbidden on Windows, anyway */ no_evil |= is_running_on_mingw(); /* Leading spaces are just confusing */ p = skip_ascii_spaces(filename); /* Make sure the filename isn't too long */ if (strlen(p) >= FILENAME_MAXBYTES) { q = halloc(FILENAME_MAXBYTES); filename_shrink(p, q, FILENAME_MAXBYTES); s = q; } else { s = p; q = NULL; } /* * Replace shell meta characters and likely problematic characters. * * Although parentheses are not evil per se, they make it a pain to * copy-n-paste filenames without going through the shell's auto- * completion (which normally does the necessary escaping). * * To keep things "readable", we replace parentheses with brackets. * Although brackets are meaningful for the shells, they are only * interpreted in the presence of "*" or "?", two characters that we * strip already. * --RAM, 2013-11-03 */ { size_t i; uchar c; for (i = 0; '\0' != (c = s[i]); i++) { if ( c < 32 || is_ascii_cntrl(c) || G_DIR_SEPARATOR == c || '/' == c || (0 == i && ('.' == c || '-' == c)) || (no_spaces && is_ascii_space(c)) || (no_evil && filename_is_evil_char(c)) ) { if (!q) q = h_strdup(s); q[i] = '_'; /* replace undesired char with underscore */ } else if ('(' == c) { if (!q) q = h_strdup(s); q[i] = '['; } else if (')' == c) { if (!q) q = h_strdup(s); q[i] = ']'; } } /** * Windows does not like filenames ending with a space or period. */ while (i-- > 0 && (is_ascii_space(s[i]) || '.' == s[i])) { if (!q) q = h_strdup(s); q[i] = '\0'; /* truncate string */ } } if (filename_is_reserved(q ? q : s)) { HFREE_NULL(q); q = h_strdup("noname"); } if (NULL == q && s != filename) q = h_strdup(s); /* Trimmed leading white space, must copy */ return q ? q : deconstify_gchar(s); }
/** * Make filename prettier, by removing leading "_", making sure the filename * does not start with "-" or ".", and stripping consecutive "_" or "_" that * surround a punctuation character. * * Finally, ensure the filename is not completely empty, as this is * awkward to manipulate from a shell. * * @param filename the filename to beautify * * @returns a newly allocated string holding the beautified filename, even if * it is a mere copy of the original. */ char * filename_beautify(const char *filename) { const char *s; char *q; uchar c; size_t len; size_t j = 0; static const char punct[] = "_-+=.,<>{}[]"; /* 1st MUST be '_' */ static const char strip[] = "_-."; static const char empty[] = "{empty}"; g_assert(filename); s = filename; len = strlen(filename); q = halloc(len + 1); /* Trailing NUL */ while ((c = *s++)) { uchar d; /* Beautified filename cannot start with stripped characters */ if (j == 0) { if (NULL == strchr(strip, c)) q[j++] = c; continue; } g_assert(j > 0); d = q[j - 1]; /* Last char we've kept in beautified name */ /* A "_" followed by a punctuation character, strip the "_" */ if (d == '_' && NULL != strchr(punct, c)) { q[j - 1] = c; continue; } /* A punctuation character followed by "_", ignore that "_" */ if (NULL != strchr(&punct[1], d) && c == '_') continue; q[j++] = c; } g_assert(j <= len); q[j] = '\0'; /* Ensure we have no empty name */ if (j == 0) { HFREE_NULL(q); return h_strdup(empty); } /* * If there was an extension following stripped chars (e.g. "_.ext"), * then the filename kept will become "ext" (we assume a valid extension * cannot contain "escaped" chars). In which case we will prepend the * string "{empty}." to it. */ if (NULL == strchr(q, '.') && j < len && '.' == filename[len - j]) { char *r = h_strconcat(empty, ".", q, NULL_PTR); HFREE_NULL(q); return r; } return q; }
static char * thex_download_handle_xml(struct thex_download *ctx, const char *data, size_t size) { xnode_t *hashtree = NULL, *node; char *hashtree_id = NULL; bool success = FALSE; vxml_parser_t *vp; vxml_error_t e; if (size <= 0) { if (GNET_PROPERTY(tigertree_debug)) { g_debug("TTH XML record has no data"); } goto finish; } /* * Parse the XML record. */ vp = vxml_parser_make("THEX record", VXML_O_STRIP_BLANKS); vxml_parser_add_data(vp, data, size); e = vxml_parse_tree(vp, &hashtree); vxml_parser_free(vp); if (VXML_E_OK != e) { if (GNET_PROPERTY(tigertree_debug)) { g_warning("TTH cannot parse XML record: %s", vxml_strerror(e)); dump_hex(stderr, "XML record", data, size); } goto finish; } if (0 != strcmp("hashtree", xnode_element_name(hashtree))) { if (GNET_PROPERTY(tigertree_debug)) { g_debug("TTH couldn't find root hashtree element"); } goto finish; } node = find_element_by_name(hashtree, "file"); if (node) { if (!verify_element(node, "size", filesize_to_string(ctx->filesize))) goto finish; if (!verify_element(node, "segmentsize", THEX_SEGMENT_SIZE)) goto finish; } else { if (GNET_PROPERTY(tigertree_debug)) { g_debug("TTH couldn't find hashtree/file element"); } goto finish; } node = find_element_by_name(hashtree, "digest"); if (node) { if (!verify_element(node, "algorithm", THEX_HASH_ALGO)) goto finish; if (!verify_element(node, "outputsize", THEX_HASH_SIZE)) goto finish; } else { if (GNET_PROPERTY(tigertree_debug)) { g_debug("TTH couldn't find hashtree/digest element"); } goto finish; } node = find_element_by_name(hashtree, "serializedtree"); if (node) { const char *value; int error; if (!verify_element(node, "type", THEX_TREE_TYPE)) goto finish; value = xnode_prop_get(node, "uri"); if (NULL == value) { if (GNET_PROPERTY(tigertree_debug)) { g_debug("TTH couldn't find property \"uri\" of node \"%s\"", xnode_element_name(node)); } goto finish; } hashtree_id = h_strdup(value); value = xnode_prop_get(node, "depth"); if (NULL == value) { if (GNET_PROPERTY(tigertree_debug)) { g_debug("TTH couldn't find property \"depth\" of node \"%s\"", xnode_element_name(node)); } goto finish; } ctx->depth = parse_uint16(value, NULL, 10, &error); error |= ctx->depth > tt_full_depth(ctx->filesize); if (error) { ctx->depth = 0; g_warning("TTH bad value for \"depth\" of node \"%s\": \"%s\"", xnode_element_name(node), value); } if (error) goto finish; } else { if (GNET_PROPERTY(tigertree_debug)) g_debug("TTH couldn't find hashtree/serializedtree element"); goto finish; } success = TRUE; finish: if (!success) HFREE_NULL(hashtree_id); xnode_tree_free_null(&hashtree); return hashtree_id; }