int wad_extract (wad_t *wad, lumpinfo_t *pf) { const char *name = pf->name; size_t count; int len; QFile *file; char buffer[16384]; if (make_parents (name) == -1) return -1; if (!(file = Qopen (name, "wb"))) return -1; Qseek (wad->handle, pf->filepos, SEEK_SET); len = pf->size; while (len) { count = len; if (count > sizeof (buffer)) count = sizeof (buffer); count = Qread (wad->handle, buffer, count); Qwrite (file, buffer, count); len -= count; } Qclose (file); return 0; }
// Create all parent directories of name, if necessary. static int make_parents(char* name) { char* p; for (p = name + (strlen(name)-1); p > name; --p) { if (*p != '/') continue; *p = '\0'; if (make_parents(name) < 0) return -1; int result = mkdir(name, 0700); if (result == 0) fprintf(stderr, "symlink(): created [%s]\n", name); *p = '/'; if (result == 0 || errno == EEXIST) { // successfully created or already existed; we're done return 0; } else { fprintf(stderr, "failed to mkdir %s: %s\n", name, strerror(errno)); return -1; } } return 0; }
// symlink target src1 src2 ... // unlinks any previously existing src1, src2, etc before creating symlinks. Value* SymlinkFn(const char* name, State* state, int argc, Expr* argv[]) { if (argc == 0) { return ErrorAbort(state, "%s() expects 1+ args, got %d", name, argc); } char* target; target = Evaluate(state, argv[0]); if (target == NULL) return NULL; char** srcs = ReadVarArgs(state, argc-1, argv+1); if (srcs == NULL) { free(target); return NULL; } int bad = 0; int i; for (i = 0; i < argc-1; ++i) { if (unlink(srcs[i]) < 0) { if (errno != ENOENT) { fprintf(stderr, "%s: failed to remove %s: %s\n", name, srcs[i], strerror(errno)); ++bad; } } if (make_parents(srcs[i])) { fprintf(stderr, "%s: failed to symlink %s to %s: making parents failed\n", name, srcs[i], target); ++bad; } if (symlink(target, srcs[i]) < 0) { fprintf(stderr, "%s: failed to symlink %s to %s: %s\n", name, srcs[i], target, strerror(errno)); ++bad; } free(srcs[i]); } free(srcs); if (bad) { return ErrorAbort(state, "%s: some symlinks failed", name); } return StringValue(strdup("")); }