void memory_tracking_init(void) { char *env; /* if CURL_MEMDEBUG is set, this starts memory tracking message logging */ env = curlx_getenv("CURL_MEMDEBUG"); if(env) { /* use the value as file name */ char fname[CURL_MT_LOGFNAME_BUFSIZE]; if(strlen(env) >= CURL_MT_LOGFNAME_BUFSIZE) env[CURL_MT_LOGFNAME_BUFSIZE-1] = '\0'; strcpy(fname, env); curl_free(env); curl_memdebug(fname); /* this weird stuff here is to make curl_free() get called before curl_memdebug() as otherwise memory tracking will log a free() without an alloc! */ } /* if CURL_MEMLIMIT is set, this enables fail-on-alloc-number-N feature */ env = curlx_getenv("CURL_MEMLIMIT"); if(env) { char *endptr; long num = strtol(env, &endptr, 10); if((endptr != env) && (endptr == env + strlen(env)) && (num > 0)) curl_memlimit(num); curl_free(env); } }
/* Extracts the name portion of the URL. * Returns a pointer to a heap-allocated string or NULL if * no name part, at location indicated by first argument. */ CURLcode get_url_file_name(char **filename, const char *url) { const char *pc; *filename = NULL; /* Find and get the remote file name */ pc = strstr(url, "://"); if(pc) pc += 3; else pc = url; pc = strrchr(pc, '/'); if(pc) /* duplicate the string beyond the slash */ pc++; else /* no slash => empty string */ pc = ""; *filename = strdup(pc); if(!*filename) return CURLE_OUT_OF_MEMORY; #if defined(MSDOS) || defined(WIN32) { char *sanitized; SANITIZEcode sc = sanitize_file_name(&sanitized, *filename, 0); Curl_safefree(*filename); if(sc) return CURLE_URL_MALFORMAT; *filename = sanitized; } #endif /* MSDOS || WIN32 */ /* in case we built debug enabled, we allow an environment variable * named CURL_TESTDIR to prefix the given file name to put it into a * specific directory */ #ifdef DEBUGBUILD { char *tdir = curlx_getenv("CURL_TESTDIR"); if(tdir) { char buffer[512]; /* suitably large */ snprintf(buffer, sizeof(buffer), "%s/%s", tdir, *filename); Curl_safefree(*filename); *filename = strdup(buffer); /* clone the buffer */ curl_free(tdir); if(!*filename) return CURLE_OUT_OF_MEMORY; } } #endif return CURLE_OK; }
void progressbarinit(struct ProgressData *bar, struct Configurable *config) { #ifdef __EMX__ /* 20000318 mgs */ int scr_size[2]; #endif char *colp; memset(bar, 0, sizeof(struct ProgressData)); /* pass this through to progress function so * it can display progress towards total file * not just the part that's left. (21-may-03, dbyron) */ if(config->use_resume) bar->initial_size = config->resume_from; /* TODO: get terminal width through ansi escapes or something similar. try to update width when xterm is resized... - 19990617 larsa */ #ifndef __EMX__ /* 20000318 mgs * OS/2 users most likely won't have this env var set, and besides that * we're using our own way to determine screen width */ colp = curlx_getenv("COLUMNS"); if(colp) { char *endptr; long num = strtol(colp, &endptr, 10); if((endptr != colp) && (endptr == colp + strlen(colp)) && (num > 0)) bar->width = (int)num; else bar->width = 79; curl_free(colp); } else bar->width = 79; #else /* 20000318 mgs * We use this emx library call to get the screen width, and subtract * one from what we got in order to avoid a problem with the cursor * advancing to the next line if we print a string that is as long as * the screen is wide. */ _scrsize(scr_size); bar->width = scr_size[0] - 1; #endif bar->out = config->errors; }
/* Extracts the name portion of the URL. * Returns a pointer to a heap-allocated string or NULL if * no name part, at location indicated by first argument. */ CURLcode get_url_file_name(char **filename, const char *url) { const char *pc; *filename = NULL; /* Find and get the remote file name */ pc = strstr(url, "://"); if(pc) pc += 3; else pc = url; pc = strrchr(pc, '/'); if(pc) { /* duplicate the string beyond the slash */ pc++; if(*pc) { *filename = strdup(pc); if(!*filename) return CURLE_OUT_OF_MEMORY; } } /* in case we built debug enabled, we allow an environment variable * named CURL_TESTDIR to prefix the given file name to put it into a * specific directory */ #ifdef DEBUGBUILD { char *tdir = curlx_getenv("CURL_TESTDIR"); if(tdir) { char buffer[512]; /* suitably large */ snprintf(buffer, sizeof(buffer), "%s/%s", tdir, *filename); Curl_safefree(*filename); *filename = strdup(buffer); /* clone the buffer */ curl_free(tdir); } } #endif return CURLE_OK; }
/* * Copies a file name part and returns an ALLOCATED data buffer. */ static char *parse_filename(const char *ptr, size_t len) { char *copy; char *p; char *q; char stop = '\0'; /* simple implementation of strndup() */ copy = malloc(len+1); if(!copy) return NULL; memcpy(copy, ptr, len); copy[len] = '\0'; p = copy; if(*p == '\'' || *p == '"') { /* store the starting quote */ stop = *p; p++; } else stop = ';'; /* if the filename contains a path, only use filename portion */ q = strrchr(copy, '/'); if(q) { p = q + 1; if(!*p) { Curl_safefree(copy); return NULL; } } /* If the filename contains a backslash, only use filename portion. The idea is that even systems that don't handle backslashes as path separators probably want the path removed for convenience. */ q = strrchr(p, '\\'); if(q) { p = q + 1; if(!*p) { Curl_safefree(copy); return NULL; } } /* scan for the end letter and stop there */ q = p; while(*q) { if(q[1] && (q[0] == '\\')) q++; else if(q[0] == stop) break; q++; } *q = '\0'; /* make sure the file name doesn't end in \r or \n */ q = strchr(p, '\r'); if(q) *q = '\0'; q = strchr(p, '\n'); if(q) *q = '\0'; if(copy != p) memmove(copy, p, strlen(p) + 1); /* in case we built debug enabled, we allow an evironment variable * named CURL_TESTDIR to prefix the given file name to put it into a * specific directory */ #ifdef DEBUGBUILD { char *tdir = curlx_getenv("CURL_TESTDIR"); if(tdir) { char buffer[512]; /* suitably large */ snprintf(buffer, sizeof(buffer), "%s/%s", tdir, copy); Curl_safefree(copy); copy = strdup(buffer); /* clone the buffer, we don't use the libcurl aprintf() or similar since we want to use the same memory code as the "real" parse_filename function */ curl_free(tdir); } } #endif return copy; }
size_t tool_write_cb(char *buffer, size_t sz, size_t nmemb, void *userdata) { size_t rc; struct OutStruct *outs = userdata; struct OperationConfig *config = outs->config; size_t bytes = sz * nmemb; bool is_tty = config->global->isatty; /* * Once that libcurl has called back tool_write_cb() the returned value * is checked against the amount that was intended to be written, if * it does not match then it fails with CURLE_WRITE_ERROR. So at this * point returning a value different from sz*nmemb indicates failure. */ const size_t failure = bytes ? 0 : 1; #ifdef DEBUGBUILD { char *tty = curlx_getenv("CURL_ISATTY"); if(tty) { is_tty = TRUE; curl_free(tty); } } if(config->show_headers) { if(bytes > (size_t)CURL_MAX_HTTP_HEADER) { warnf(config->global, "Header data size exceeds single call write " "limit!\n"); return failure; } } else { if(bytes > (size_t)CURL_MAX_WRITE_SIZE) { warnf(config->global, "Data size exceeds single call write limit!\n"); return failure; } } { /* Some internal congruency checks on received OutStruct */ bool check_fails = FALSE; if(outs->filename) { /* regular file */ if(!*outs->filename) check_fails = TRUE; if(!outs->s_isreg) check_fails = TRUE; if(outs->fopened && !outs->stream) check_fails = TRUE; if(!outs->fopened && outs->stream) check_fails = TRUE; if(!outs->fopened && outs->bytes) check_fails = TRUE; } else { /* standard stream */ if(!outs->stream || outs->s_isreg || outs->fopened) check_fails = TRUE; if(outs->alloc_filename || outs->is_cd_filename || outs->init) check_fails = TRUE; } if(check_fails) { warnf(config->global, "Invalid output struct data for write callback\n"); return failure; } } #endif if(!outs->stream && !tool_create_output_file(outs)) return failure; if(is_tty && (outs->bytes < 2000) && !config->terminal_binary_ok) { /* binary output to terminal? */ if(memchr(buffer, 0, bytes)) { warnf(config->global, "Binary output can mess up your terminal. " "Use \"--output -\" to tell curl to output it to your terminal " "anyway, or consider \"--output <FILE>\" to save to a file.\n"); config->synthetic_error = ERR_BINARY_TERMINAL; return failure; } } #ifdef _WIN32 if(isatty(fileno(outs->stream))) { DWORD in_len = (DWORD)(sz * nmemb); wchar_t* wc_buf; DWORD wc_len; intptr_t fhnd; /* calculate buffer size for wide characters */ wc_len = MultiByteToWideChar(CP_UTF8, 0, buffer, in_len, NULL, 0); wc_buf = (wchar_t*) malloc(wc_len * sizeof(wchar_t)); if(!wc_buf) return failure; /* calculate buffer size for multi-byte characters */ wc_len = MultiByteToWideChar(CP_UTF8, 0, buffer, in_len, wc_buf, wc_len); if(!wc_len) { free(wc_buf); return failure; } fhnd = _get_osfhandle(fileno(outs->stream)); if(!WriteConsoleW( (HANDLE) fhnd, wc_buf, wc_len, &wc_len, NULL)) { free(wc_buf); return failure; } free(wc_buf); rc = bytes; } else #endif rc = fwrite(buffer, sz, nmemb, outs->stream); if(bytes == rc) /* we added this amount of data to the output */ outs->bytes += bytes; if(config->readbusy) { config->readbusy = FALSE; curl_easy_pause(config->easy, CURLPAUSE_CONT); } if(config->nobuffer) { /* output buffering disabled */ int res = fflush(outs->stream); if(res) return failure; } return rc; }