static void fs_sis_file_close(struct fs_file *_file) { struct sis_fs_file *file = (struct sis_fs_file *)_file; if (file->hash_input != NULL) i_stream_unref(&file->hash_input); fs_file_close(file->hash_file); fs_file_close(file->super); }
static void fs_compress_file_close(struct fs_file *_file) { struct compress_fs_file *file = (struct compress_fs_file *)_file; if (file->input != NULL) i_stream_unref(&file->input); if (file->super_read != NULL) fs_file_close(file->super_read); if (_file->parent != NULL) fs_file_close(_file->parent); }
bool code_write(code_t *code, const char *filename, const char *lnofile) { prog_header_t code_header; fs_file_t *fp = NULL; code_create_header(code, &code_header, filename, lnofile); if (lnofile) { uint32_t version = 1; fp = fs_file_open(lnofile, "wb"); if (!fp) return false; util_endianswap(&version, 1, sizeof(version)); util_endianswap(code->linenums, vec_size(code->linenums), sizeof(code->linenums[0])); util_endianswap(code->columnnums, vec_size(code->columnnums), sizeof(code->columnnums[0])); if (fs_file_write("LNOF", 4, 1, fp) != 1 || fs_file_write(&version, sizeof(version), 1, fp) != 1 || fs_file_write(&code_header.defs.length, sizeof(code_header.defs.length), 1, fp) != 1 || fs_file_write(&code_header.globals.length, sizeof(code_header.globals.length), 1, fp) != 1 || fs_file_write(&code_header.fields.length, sizeof(code_header.fields.length), 1, fp) != 1 || fs_file_write(&code_header.statements.length, sizeof(code_header.statements.length), 1, fp) != 1 || fs_file_write(code->linenums, sizeof(code->linenums[0]), vec_size(code->linenums), fp) != vec_size(code->linenums) || fs_file_write(code->columnnums, sizeof(code->columnnums[0]), vec_size(code->columnnums), fp) != vec_size(code->columnnums)) { con_err("failed to write lno file\n"); } fs_file_close(fp); fp = NULL; } fp = fs_file_open(filename, "wb"); if (!fp) return false; if (1 != fs_file_write(&code_header, sizeof(prog_header_t) , 1 , fp) || vec_size(code->statements) != fs_file_write(code->statements, sizeof(prog_section_statement_t), vec_size(code->statements), fp) || vec_size(code->defs) != fs_file_write(code->defs, sizeof(prog_section_def_t) , vec_size(code->defs) , fp) || vec_size(code->fields) != fs_file_write(code->fields, sizeof(prog_section_field_t) , vec_size(code->fields) , fp) || vec_size(code->functions) != fs_file_write(code->functions, sizeof(prog_section_function_t) , vec_size(code->functions) , fp) || vec_size(code->globals) != fs_file_write(code->globals, sizeof(int32_t) , vec_size(code->globals) , fp) || vec_size(code->chars) != fs_file_write(code->chars, 1 , vec_size(code->chars) , fp)) { fs_file_close(fp); return false; } fs_file_close(fp); code_stats(filename, lnofile, code, &code_header); return true; }
static int task_pclose(fs_file_t **files) { popen_t *open = ((popen_t*)files); fs_file_close(files[1]); fs_file_close(files[2]); remove(open->name_err); remove(open->name_out); mem_d(open); return EXIT_SUCCESS; }
/* * Extraction abilities. These work as you expect them to. */ static bool pak_extract_one(pak_file_t *pak, const char *file, const char *outdir) { pak_directory_t *dir = NULL; unsigned char *dat = NULL; char *local = NULL; FILE *out = NULL; if (!pak_exists(pak, file, &dir)) { return false; } if (!(dat = (unsigned char *)mem_a(dir->len))) goto err; /* * Generate the directory structure / tree that will be required * to store the extracted file. */ pak_tree_build(file); /* TODO portable path seperators */ util_asprintf(&local, "%s/%s", outdir, file); /* * Now create the file, if this operation fails. Then abort * It shouldn't fail though. */ if (!(out = fs_file_open(local, "wb"))) goto err; /* free memory for directory string */ mem_d(local); /* read */ if (fs_file_seek (pak->handle, dir->pos, SEEK_SET) != 0) goto err; fs_file_read (dat, 1, dir->len, pak->handle); fs_file_write(dat, 1, dir->len, out); fs_file_close(out); mem_d(dat); return true; err: if (dat) mem_d(dat); if (out) fs_file_close(out); return false; }
/* * Actual loading subsystem, this finds the ini or cfg file, and properly * loads it and executes it to set compiler options. */ void opts_ini_init(const char *file) { /* * Possible matches are: * gmqcc.ini * gmqcc.cfg */ char *error = NULL; char *parse_file = NULL; size_t line; fs_file_t *ini; if (!file) { /* try ini */ if (!(ini = fs_file_open((file = "gmqcc.ini"), "r"))) /* try cfg */ if (!(ini = fs_file_open((file = "gmqcc.cfg"), "r"))) return; } else if (!(ini = fs_file_open(file, "r"))) return; con_out("found ini file `%s`\n", file); parse_file = util_strdup(file); if ((line = opts_ini_parse(ini, &opts_ini_load, &error, &parse_file)) != 0) { /* there was a parse error with the ini file */ con_printmsg(LVL_ERROR, parse_file, line, 0 /*TODO: column for ini error*/, "error", error); vec_free(error); } mem_d(parse_file); fs_file_close(ini); }
static void fs_sis_queue_file_close(struct fs_file *_file) { struct sis_queue_fs_file *file = (struct sis_queue_fs_file *)_file; if (file->super != NULL) fs_file_close(file->super); }
static bool pak_close(pak_file_t *pak) { size_t itr; long tell; if (!pak) return false; /* * In insert mode we need to patch the header, and write * our directory entries at the end of the file. */ if (pak->insert) { if ((tell = fs_file_tell(pak->handle)) != 0) goto err; pak->header.dirlen = vec_size(pak->directories) * 64; pak->header.diroff = tell; /* patch header */ if (fs_file_seek (pak->handle, 0, SEEK_SET) != 0) goto err; fs_file_write(&(pak->header), sizeof(pak_header_t), 1, pak->handle); /* write directories */ if (fs_file_seek (pak->handle, pak->header.diroff, SEEK_SET) != 0) goto err; for (itr = 0; itr < vec_size(pak->directories); itr++) { fs_file_write(&(pak->directories[itr]), sizeof(pak_directory_t), 1, pak->handle); } } vec_free (pak->directories); fs_file_close(pak->handle); mem_d (pak); return true; err: vec_free (pak->directories); fs_file_close(pak->handle); mem_d (pak); return false; }
static pak_file_t *pak_open_read(const char *file) { pak_file_t *pak; size_t itr; if (!(pak = (pak_file_t*)mem_a(sizeof(pak_file_t)))) return NULL; if (!(pak->handle = fs_file_open(file, "rb"))) { mem_d(pak); return NULL; } pak->directories = NULL; pak->insert = false; /* read doesn't allow insert */ memset (&pak->header, 0, sizeof(pak_header_t)); fs_file_read (&pak->header, sizeof(pak_header_t), 1, pak->handle); util_endianswap(&pak->header.magic, 1, sizeof(pak->header.magic)); util_endianswap(&pak->header.diroff, 1, sizeof(pak->header.diroff)); util_endianswap(&pak->header.dirlen, 1, sizeof(pak->header.dirlen)); /* * Every PAK file has "PACK" stored as FOURCC data in the * header. If this data cannot compare (as checked here), it's * probably not a PAK file. */ if (pak->header.magic != PAK_FOURCC) { fs_file_close(pak->handle); mem_d (pak); return NULL; } /* * Time to read in the directory handles and prepare the directories * vector. We're going to be reading some the file inwards soon. */ fs_file_seek(pak->handle, pak->header.diroff, FS_FILE_SEEK_SET); /* * Read in all directories from the PAK file. These are considered * to be the "file entries". */ for (itr = 0; itr < pak->header.dirlen / 64; itr++) { pak_directory_t dir; fs_file_read (&dir, sizeof(pak_directory_t), 1, pak->handle); /* Don't translate name - it's just an array of bytes. */ util_endianswap(&dir.pos, 1, sizeof(dir.pos)); util_endianswap(&dir.len, 1, sizeof(dir.len)); vec_push(pak->directories, dir); } return pak; }
static void task_destroy(void) { /* * Free all the data in the task list and finally the list itself * then proceed to cleanup anything else outside the program like * temporary files. */ size_t i; for (i = 0; i < vec_size(task_tasks); i++) { /* * Close any open handles to files or processes here. It's mighty * annoying to have to do all this cleanup work. */ if (task_tasks[i].stdoutlog) fs_file_close (task_tasks[i].stdoutlog); if (task_tasks[i].stderrlog) fs_file_close (task_tasks[i].stderrlog); /* * Only remove the log files if the test actually compiled otherwise * forget about it (or if it didn't compile, and the procedure type * was set to -fail (meaning it shouldn't compile) .. stil remove) */ if (task_tasks[i].compiled || !strcmp(task_tasks[i].tmpl->proceduretype, "-fail")) { if (remove(task_tasks[i].stdoutlogfile)) con_err("error removing stdout log file: %s\n", task_tasks[i].stdoutlogfile); if (remove(task_tasks[i].stderrlogfile)) con_err("error removing stderr log file: %s\n", task_tasks[i].stderrlogfile); (void)!remove(task_tasks[i].tmpl->tempfilename); } /* free util_strdup data for log files */ mem_d(task_tasks[i].stdoutlogfile); mem_d(task_tasks[i].stderrlogfile); task_template_destroy(task_tasks[i].tmpl); } vec_free(task_tasks); }
/* * This executes the QCVM task for a specificly compiled progs.dat * using the template passed into it for call-flags and user defined * messages IF the procedure type is -execute, otherwise it matches * the preprocessor output. */ static bool task_trymatch(size_t i, char ***line) { bool success = true; bool process = true; int retval = EXIT_SUCCESS; fs_file_t *execute; char buffer[4096]; task_template_t *tmpl = task_tasks[i].tmpl; memset (buffer,0,sizeof(buffer)); if (!strcmp(tmpl->proceduretype, "-execute")) { /* * Drop the execution flags for the QCVM if none where * actually specified. */ if (!strcmp(tmpl->executeflags, "$null")) { util_snprintf(buffer, sizeof(buffer), "%s %s", task_bins[TASK_EXECUTE], tmpl->tempfilename ); } else { util_snprintf(buffer, sizeof(buffer), "%s %s %s", task_bins[TASK_EXECUTE], tmpl->executeflags, tmpl->tempfilename ); } execute = (fs_file_t*)popen(buffer, "r"); if (!execute) return false; } else if (!strcmp(tmpl->proceduretype, "-pp")) { /* * we're preprocessing, which means we need to read int * the produced file and do some really weird shit. */ if (!(execute = fs_file_open(tmpl->tempfilename, "r"))) return false; process = false; } else { /* * we're testing diagnostic output, which means it will be * in runhandles[2] (stderr) since that is where the compiler * puts it's errors. */ if (!(execute = fs_file_open(task_tasks[i].stderrlogfile, "r"))) return false; process = false; } /* * Now lets read the lines and compare them to the matches we expect * and handle accordingly. */ { char *data = NULL; size_t size = 0; size_t compare = 0; while (fs_file_getline(&data, &size, execute) != FS_FILE_EOF) { if (!strcmp(data, "No main function found\n")) { con_err("test failure: `%s` (No main function found) [%s]\n", tmpl->description, tmpl->rulesfile ); if (!process) fs_file_close(execute); else pclose((FILE*)execute); return false; } /* * Trim newlines from data since they will just break our * ability to properly validate matches. */ if (strrchr(data, '\n')) *strrchr(data, '\n') = '\0'; /* * We remove the file/directory and stuff from the error * match messages when testing diagnostics. */ if(!strcmp(tmpl->proceduretype, "-diagnostic")) { if (strstr(data, "there have been errors, bailing out")) continue; /* ignore it */ if (strstr(data, ": error: ")) { char *claim = util_strdup(data + (strstr(data, ": error: ") - data) + 9); mem_d(data); data = claim; } } /* * We need to ignore null lines for when -pp is used (preprocessor), since * the preprocessor is likely to create empty newlines in certain macro * instantations, otherwise it's in the wrong nature to ignore empty newlines. */ if (!strcmp(tmpl->proceduretype, "-pp") && !*data) continue; if (vec_size(tmpl->comparematch) > compare) { if (strcmp(data, tmpl->comparematch[compare++])) { success = false; } } else { success = false; } /* * Copy to output vector for diagnostics if execution match * fails. */ vec_push(*line, data); /* reset */ data = NULL; size = 0; } if (compare != vec_size(tmpl->comparematch)) success = false; mem_d(data); data = NULL; } if (process) retval = pclose((FILE*)execute); else fs_file_close(execute); return success && retval == EXIT_SUCCESS; }
static task_template_t *task_template_compile(const char *file, const char *dir, size_t *pad) { /* a page should be enough */ char fullfile[4096]; size_t filepadd = 0; fs_file_t *tempfile = NULL; task_template_t *tmpl = NULL; util_snprintf(fullfile, sizeof(fullfile), "%s/%s", dir, file); tempfile = fs_file_open(fullfile, "r"); tmpl = (task_template_t*)mem_a(sizeof(task_template_t)); task_template_nullify(tmpl); /* * Create some padding for the printing to align the * printing of the rules file to the console. */ if ((filepadd = strlen(fullfile)) > pad[1]) pad[1] = filepadd; tmpl->rulesfile = util_strdup(fullfile); /* * Esnure the file even exists for the task, this is pretty useless * to even do. */ if (!tempfile) { con_err("template file: %s does not exist or invalid permissions\n", file ); goto failure; } if (!task_template_parse(file, tmpl, tempfile, pad)) { con_err("template parse error: error during parsing\n"); goto failure; } /* * Regardless procedure type, the following tags must exist: * D * T * C * I */ if (!tmpl->description) { con_err("template compile error: %s missing `D:` tag\n", file); goto failure; } if (!tmpl->proceduretype) { con_err("template compile error: %s missing `T:` tag\n", file); goto failure; } if (!tmpl->compileflags) { con_err("template compile error: %s missing `C:` tag\n", file); goto failure; } if (!tmpl->sourcefile) { con_err("template compile error: %s missing `I:` tag\n", file); goto failure; } /* * Now lets compile the template, compilation is really just * the process of validating the input. */ if (!strcmp(tmpl->proceduretype, "-compile")) { if (tmpl->executeflags) con_err("template compile warning: %s erroneous tag `E:` when only compiling\n", file); if (tmpl->comparematch) con_err("template compile warning: %s erroneous tag `M:` when only compiling\n", file); goto success; } else if (!strcmp(tmpl->proceduretype, "-execute")) { if (!tmpl->executeflags) { /* default to $null */ tmpl->executeflags = util_strdup("$null"); } if (!tmpl->comparematch) { con_err("template compile error: %s missing `M:` tag (use `$null` for exclude)\n", file); goto failure; } } else if (!strcmp(tmpl->proceduretype, "-fail")) { if (tmpl->executeflags) con_err("template compile warning: %s erroneous tag `E:` when only failing\n", file); if (tmpl->comparematch) con_err("template compile warning: %s erroneous tag `M:` when only failing\n", file); } else if (!strcmp(tmpl->proceduretype, "-diagnostic")) { if (tmpl->executeflags) con_err("template compile warning: %s erroneous tag `E:` when only diagnostic\n", file); if (!tmpl->comparematch) { con_err("template compile error: %s missing `M:` tag (use `$null` for exclude)\n", file); goto failure; } } else if (!strcmp(tmpl->proceduretype, "-pp")) { if (tmpl->executeflags) con_err("template compile warning: %s erroneous tag `E:` when only preprocessing\n", file); if (!tmpl->comparematch) { con_err("template compile error: %s missing `M:` tag (use `$null` for exclude)\n", file); goto failure; } } else { con_err("template compile error: %s invalid procedure type: %s\n", file, tmpl->proceduretype); goto failure; } success: fs_file_close(tempfile); return tmpl; failure: /* * The file might not exist and we jump here when that doesn't happen * so the check to see if it's not null here is required. */ if (tempfile) fs_file_close(tempfile); mem_d (tmpl); return NULL; }
static char *opts_ini_load(const char *section, const char *name, const char *value, char **parse_file) { char *error = NULL; bool found = false; /* * undef all of these because they may still be defined like in my * case they where. */ #undef GMQCC_TYPE_FLAGS #undef GMQCC_TYPE_OPTIMIZATIONS #undef GMQCC_TYPE_WARNS /* deal with includes */ if (!strcmp(section, "includes")) { static const char *include_error_beg = "failed to open file `"; static const char *include_error_end = "' for inclusion"; fs_file_t *file = fs_file_open(value, "r"); found = true; if (!file) { vec_append(error, strlen(include_error_beg), include_error_beg); vec_append(error, strlen(value), value); vec_append(error, strlen(include_error_end), include_error_end); } else { if (opts_ini_parse(file, &opts_ini_load, &error, parse_file) != 0) found = false; /* Change the file name */ mem_d(*parse_file); *parse_file = util_strdup(value); fs_file_close(file); } } /* flags */ #define GMQCC_TYPE_FLAGS #define GMQCC_DEFINE_FLAG(X) \ if (!strcmp(section, "flags") && !strcmp(name, #X)) { \ opts_set(opts.flags, X, opts_ini_bool(value)); \ found = true; \ } #include "opts.def" /* warnings */ #define GMQCC_TYPE_WARNS #define GMQCC_DEFINE_FLAG(X) \ if (!strcmp(section, "warnings") && !strcmp(name, #X)) { \ opts_set(opts.warn, WARN_##X, opts_ini_bool(value)); \ found = true; \ } #include "opts.def" /* Werror-individuals */ #define GMQCC_TYPE_WARNS #define GMQCC_DEFINE_FLAG(X) \ if (!strcmp(section, "errors") && !strcmp(name, #X)) { \ opts_set(opts.werror, WARN_##X, opts_ini_bool(value)); \ found = true; \ } #include "opts.def" /* optimizations */ #define GMQCC_TYPE_OPTIMIZATIONS #define GMQCC_DEFINE_FLAG(X,Y) \ if (!strcmp(section, "optimizations") && !strcmp(name, #X)) { \ opts_set(opts.optimization, OPTIM_##X, opts_ini_bool(value)); \ found = true; \ } #include "opts.def" /* nothing was found ever! */ if (!found) { if (strcmp(section, "includes") && strcmp(section, "flags") && strcmp(section, "warnings") && strcmp(section, "optimizations")) { static const char *invalid_section = "invalid_section `"; vec_append(error, strlen(invalid_section), invalid_section); vec_append(error, strlen(section), section); vec_push(error, '`'); } else if (strcmp(section, "includes")) { static const char *invalid_variable = "invalid_variable `"; static const char *in_section = "` in section: `"; vec_append(error, strlen(invalid_variable), invalid_variable); vec_append(error, strlen(name), name); vec_append(error, strlen(in_section), in_section); vec_append(error, strlen(section), section); vec_push(error, '`'); } else { static const char *expected_something = "expected something"; vec_append(error, strlen(expected_something), expected_something); } } vec_push(error, '\0'); return error; }
void fs_wrapper_file_close(struct fs_file *file) { fs_file_close(file->parent); }
/* * Insertion functions (the opposite of extraction). Yes for generating * PAKs. */ static bool pak_insert_one(pak_file_t *pak, const char *file) { pak_directory_t dir; unsigned char *dat; long len; FILE *fp; /* * We don't allow insertion on files that already exist within the * pak file. Weird shit can happen if we allow that ;). We also * don't allow insertion if the pak isn't opened in write mode. */ if (!pak || !file || !pak->insert || pak_exists(pak, file, NULL)) return false; if (!(fp = fs_file_open(file, "rb"))) return false; /* * Calculate the total file length, since it will be wrote to * the directory entry, and the actual contents of the file * to the PAK file itself. */ if (fs_file_seek(fp, 0, SEEK_END) != 0 || ((len = fs_file_tell(fp)) < 0)) goto err; if (fs_file_seek(fp, 0, SEEK_SET) != 0) goto err; dir.len = len; dir.pos = fs_file_tell(pak->handle); /* * We're limited to 56 bytes for a file name string, that INCLUDES * the directory and '/' seperators. */ if (strlen(file) >= 56) goto err; util_strncpy(dir.name, file, strlen(file)); /* * Allocate some memory for loading in the data that will be * redirected into the PAK file. */ if (!(dat = (unsigned char *)mem_a(dir.len))) goto err; fs_file_read (dat, dir.len, 1, fp); fs_file_close(fp); fs_file_write(dat, dir.len, 1, pak->handle); /* * Now add the directory to the directories vector, so pak_close * can actually write it. */ vec_push(pak->directories, dir); return true; err: fs_file_close(fp); return false; }
void con_close() { if (!GMQCC_IS_DEFINE(console.handle_err)) fs_file_close(console.handle_err); if (!GMQCC_IS_DEFINE(console.handle_out)) fs_file_close(console.handle_out); }