/* 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; }
CURLcode glob_match_url(char **result, char *filename, URLGlob *glob) { char *target; size_t allocsize; char numbuf[18]; char *appendthis = NULL; size_t appendlen = 0; size_t stringlen = 0; *result = NULL; /* We cannot use the glob_buffer for storage here since the filename may * be longer than the URL we use. We allocate a good start size, then * we need to realloc in case of need. */ allocsize = strlen(filename) + 1; /* make it at least one byte to store the trailing zero */ target = malloc(allocsize); if(!target) return CURLE_OUT_OF_MEMORY; while(*filename) { if(*filename == '#' && ISDIGIT(filename[1])) { unsigned long i; char *ptr = filename; unsigned long num = strtoul(&filename[1], &filename, 10); URLPattern *pat =NULL; if(num < glob->size) { num--; /* make it zero based */ /* find the correct glob entry */ for(i=0; i<glob->size; i++) { if(glob->pattern[i].globindex == (int)num) { pat = &glob->pattern[i]; break; } } } if(pat) { switch (pat->type) { case UPTSet: if(pat->content.Set.elements) { appendthis = pat->content.Set.elements[pat->content.Set.ptr_s]; appendlen = strlen(pat->content.Set.elements[pat->content.Set.ptr_s]); } break; case UPTCharRange: numbuf[0] = pat->content.CharRange.ptr_c; numbuf[1] = 0; appendthis = numbuf; appendlen = 1; break; case UPTNumRange: snprintf(numbuf, sizeof(numbuf), "%0*d", pat->content.NumRange.padlength, pat->content.NumRange.ptr_n); appendthis = numbuf; appendlen = strlen(numbuf); break; default: fprintf(stderr, "internal error: invalid pattern type (%d)\n", (int)pat->type); Curl_safefree(target); return CURLE_FAILED_INIT; } } else { /* #[num] out of range, use the #[num] in the output */ filename = ptr; appendthis = filename++; appendlen = 1; } } else { appendthis = filename++; appendlen = 1; } if(appendlen + stringlen >= allocsize) { char *newstr; /* we append a single byte to allow for the trailing byte to be appended at the end of this function outside the while() loop */ allocsize = (appendlen + stringlen) * 2; newstr = realloc(target, allocsize + 1); if(!newstr) { Curl_safefree(target); return CURLE_OUT_OF_MEMORY; } target = newstr; } memcpy(&target[stringlen], appendthis, appendlen); stringlen += appendlen; } target[stringlen]= '\0'; #if defined(MSDOS) || defined(WIN32) { char *sanitized; SANITIZEcode sc = sanitize_file_name(&sanitized, target, (SANITIZE_ALLOW_PATH | SANITIZE_ALLOW_RESERVED)); Curl_safefree(target); if(sc) return CURLE_URL_MALFORMAT; target = sanitized; } #endif /* MSDOS || WIN32 */ *result = target; 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 */ for(q = p; *q; ++q) { if(*q == stop) { *q = '\0'; break; } } /* 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); #if defined(MSDOS) || defined(WIN32) { char *sanitized; SANITIZEcode sc = sanitize_file_name(&sanitized, copy, 0); Curl_safefree(copy); if(sc) return NULL; copy = sanitized; } #endif /* MSDOS || WIN32 */ /* 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; }