/* * nextFile * * open the next source file, if any. * * return 1 if could not open the next file. * return 0 otherwise. */ static int nextFile(fstream_t*fs) { int response_code; const char *response_string; struct gpfxdist_t* transform = fs->options.transform; fs->compressed_position += gfile_get_compressed_size(&fs->fd); gfile_close(&fs->fd); fs->foff = 0; fs->line_number = 1; fs->fidx++; if (fs->fidx < fs->glob.gl_pathc) { fs->skip_header_line = fs->options.header; if (gfile_open(&fs->fd, fs->glob.gl_pathv[fs->fidx], GFILE_OPEN_FOR_READ, &response_code, &response_string, transform)) { gfile_printf_then_putc_newline("fstream unable to open file %s", fs->glob.gl_pathv[fs->fidx]); fs->ferror = "unable to open file"; return 1; } } return 0; }
/* * fstream_rewind * * close the currently open file. open the first file in the file stream * chain, reset state and start from scratch. */ int fstream_rewind(fstream_t *fs) { int response_code; const char* response_string; struct gpfxdist_t* transform = fs->options.transform; fs->fidx = 0; fs->foff = 0; fs->line_number = 1; fs->ferror = 0; fs->skip_header_line = fs->options.header; fs->buffer_cur_size = 0; fs->compressed_position = 0; gfile_close(&fs->fd); if (gfile_open(&fs->fd, fs->glob.gl_pathv[0], GFILE_OPEN_FOR_READ, &response_code, &response_string, transform)) { gfile_printf_then_putc_newline("fstream unable to open file %s", fs->glob.gl_pathv[0]); fs->ferror = "unable to open file"; return -1; } return 0; }
int game_open(struct gfile *f, const char *name) { return gfile_open(gfs, f, name); }
/* * 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; }