/* extern int qsort(); */ static int #ifndef ANSI_PROTOTYPES name_cmp(s1, s2) char **s1; char **s2; #else /* ANSI_PROTOTYPES */ name_cmp(char **s1, char **s2) #endif /* ANSI_PROTOTYPES */ { return strcmp(*s1, *s2); } char * #ifndef ANSI_PROTOTYPES expand_tilde(pat) char *pat; #else /* ANSI_PROTOTYPES */ expand_tilde(char *pat) #endif /* ANSI_PROTOTYPES */ { static char buf[BUFSIZ]; struct passwd *pw; char *tmp; char *bp; if (*pat != '~') return 0; pat++; if (*pat && *pat != '/') { bp = buf; for (tmp = pat; *tmp && *tmp != '/'; ) *bp++ = *tmp++; *bp = '\0'; pw = getpwnam(buf); if (pw == 0) { (void)sprintf(globerr_buf, "%s: Unknown user.", pat); globerr = globerr_buf; return 0; } pat = tmp ? tmp : ""; tmp = pw->pw_dir; } else { if (*pat) pat++; tmp = (char *)getenv("HOME"); } for (bp = buf; *tmp; ) *bp++ = *tmp++; *bp++ = '/'; while (*pat) *bp++ = *pat++; *bp = '\0'; return buf; } char ** #ifndef ANSI_PROTOTYPES glob(pat) char *pat; #else /* ANSI_PROTOTYPES */ glob(char *pat) #endif /* ANSI_PROTOTYPES */ { char **names; int nnames; if (*pat == '~') { pat = expand_tilde(pat); if (pat == 0) return 0; } nnames = glob_path(pat, &names); switch (nnames) { case -1: globerr = sys_errlist[errno]; return 0; case 0: globerr = "No match."; return 0; default: qsort(names, nnames, sizeof(char *), name_cmp); return names; } }
static int x_command_glob(int flags, const char *str, int slen, char ***wordsp) { char *toglob; char *pat; char *fpath; int nwords; XPtrV w; struct block *l; if (slen < 0) return 0; toglob = add_glob(str, slen); /* Convert "foo*" (toglob) to a pattern for future use */ pat = evalstr(toglob, DOPAT|DOTILDE); afree(toglob, ATEMP); XPinit(w, 32); glob_table(pat, &w, &keywords); glob_table(pat, &w, &aliases); glob_table(pat, &w, &builtins); for (l = e->loc; l; l = l->next) glob_table(pat, &w, &l->funs); glob_path(flags, pat, &w, path); if ((fpath = str_val(global("FPATH"))) != null) glob_path(flags, pat, &w, fpath); nwords = XPsize(w); if (!nwords) { *wordsp = NULL; XPfree(w); return 0; } /* Sort entries */ if (flags & XCF_FULLPATH) { /* Sort by basename, then path order */ struct path_order_info *info; struct path_order_info *last_info = NULL; char **words = (char **) XPptrv(w); int path_order = 0; int i; info = areallocarray(NULL, nwords, sizeof(struct path_order_info), ATEMP); for (i = 0; i < nwords; i++) { info[i].word = words[i]; info[i].base = x_basename(words[i], NULL); if (!last_info || info[i].base != last_info->base || strncmp(words[i], last_info->word, info[i].base) != 0) { last_info = &info[i]; path_order++; } info[i].path_order = path_order; } qsort(info, nwords, sizeof(struct path_order_info), path_order_cmp); for (i = 0; i < nwords; i++) words[i] = info[i].word; afree(info, ATEMP); } else { /* Sort and remove duplicate entries */ char **words = (char **) XPptrv(w); int i, j; qsortp(XPptrv(w), (size_t) nwords, xstrcmp); for (i = j = 0; i < nwords - 1; i++) { if (strcmp(words[i], words[i + 1])) words[j++] = words[i]; else afree(words[i], ATEMP); } words[j++] = words[i]; nwords = j; w.cur = (void **) &words[j]; } XPput(w, NULL); *wordsp = (char **) XPclose(w); return nwords; }
/* * fstream_open * * Allocate a new file stream given a path (a url). in case of wildcards, * expand them here. we end up with a final list of files and include them * in our filestream that we return. * * In case of errors we set the proper http response code to send to the client. */ fstream_t* fstream_open(const char *path, const struct fstream_options *options, int *response_code, const char **response_string) { int i; fstream_t* fs; *response_code = 500; *response_string = "Internal Server Error"; if (0 == (fs = gfile_malloc(sizeof *fs))) { gfile_printf_then_putc_newline("fstream out of memory"); return 0; } memset(fs, 0, sizeof *fs); fs->options = *options; fs->buffer = gfile_malloc(options->bufsize); /* * get a list of all files that were requested to be read and include them * in our fstream. This includes any wildcard pattern matching. */ if (glob_path(fs, path)) { fstream_close(fs); return 0; } /* * If the list of files in our filestrem includes a directory name, expand * the directory and add all the files inside of it. */ if (fpath_all_directories(&fs->glob)) { if (expand_directories(fs)) { fstream_close(fs); return 0; } } /* * check if we don't have any matching files */ if (fs->glob.gl_pathc == 0) { gfile_printf_then_putc_newline("fstream bad path: %s", path); fstream_close(fs); *response_code = 404; *response_string = "No matching file(s) found"; return 0; } if (fs->glob.gl_pathc != 1 && options->forwrite) { gfile_printf_then_putc_newline("fstream open for write found more than one file (%d)", fs->glob.gl_pathc); *response_code = 404; *response_string = "More than 1 file found for writing. Unsupported operation."; fstream_close(fs); return 0; } #ifdef GPFXDIST /* * when the subprocess transformation wants to handle iteration over the files * we write the paths to a temporary file and replace the fs->glob items with * just a single entry referencing the path to the temporary file. */ if (options->transform && options->transform->pass_paths) { apr_pool_t* mp = options->transform->mp; apr_file_t* f = NULL; const char* tempdir = NULL; char* tempfilename = NULL; apr_status_t rv; if ((rv = apr_temp_dir_get(&tempdir, mp)) != APR_SUCCESS) { *response_code = 500; *response_string = "failed to get temporary directory for paths file"; gfile_printf_then_putc_newline(*response_string); fstream_close(fs); return 0; } tempfilename = apr_pstrcat(mp, tempdir, "/pathsXXXXXX", NULL); if ((rv = apr_file_mktemp(&f, tempfilename, APR_CREATE|APR_WRITE|APR_EXCL, mp)) != APR_SUCCESS) { *response_code = 500; *response_string = "failed to open temporary paths file"; gfile_printf_then_putc_newline(*response_string); fstream_close(fs); return 0; } options->transform->tempfilename = tempfilename; for (i = 0; i<fs->glob.gl_pathc; i++) { char* filename = fs->glob.gl_pathv[i]; apr_size_t expected = strlen(filename) + 1; if (apr_file_printf(f, "%s\n", filename) < expected) { apr_file_close(f); *response_code = 500; *response_string = "failed to fully write path to temporary paths file"; gfile_printf_then_putc_newline(*response_string); fstream_close(fs); return 0; } } apr_file_close(f); if (glob_adjust(fs, tempfilename, response_code, response_string)) { fstream_close(fs); return 0; } } #endif /* * if writing - check write access rights for the one file. * if reading - check read access right for all files, and * then close them, leaving the first file open. * */ for (i = fs->glob.gl_pathc; --i >= 0;) { /* * CR-2173 - the fstream code allows the upper level logic to treat a * collection of input sources as a single stream. One problem it has * to handle is the possibility that some of the underlying sources may * not be readable. Here we're trying to detect potential problems in * advance by checking that we can open and close each source in our * list in reverse order. * * However in the case of subprocess transformations, we don't want to * start and stop each transformation in this manner. The check that * each transformation's underlying input source can be read is still * useful so we do those until we get to the first source, at which * point we proceed to just setup the tranformation for it. */ struct gpfxdist_t* transform = (i == 0) ? options->transform : NULL; gfile_close(&fs->fd); if (gfile_open(&fs->fd, fs->glob.gl_pathv[i], gfile_open_flags(options->forwrite, options->usesync), response_code, response_string, transform)) { gfile_printf_then_putc_newline("fstream unable to open file %s", fs->glob.gl_pathv[i]); fstream_close(fs); return 0; } fs->compressed_size += gfile_get_compressed_size(&fs->fd); } fs->line_number = 1; fs->skip_header_line = options->header; return fs; }