#ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #if HAVE_MKDIR # if MKDIR_TAKES_ONE_ARG # define mkdir(a, b) mkdir(a) # endif #else # if HAVE__MKDIR # define mkdir(a, b) _mkdir(a) # else # error "Don't know how to create a directory on this system." # endif #endif mode_t user_umask; /** * Ensures that all directory components in a filepath exist. New directory * components are created, if necessary. * * @param path the filepath to check * @return non-zero if all directory components in a filepath exist, zero * if components do not exist and cannot be created */ static int ensure_filepath(char *path) { struct stat st_buf; char *p; int ok; for (p = &path[1]; *p; p++) { if (*p != '/') continue; *p = '\0'; ok = (stat(path, &st_buf) == 0) && S_ISDIR(st_buf.st_mode); if (!ok) ok = (mkdir(path, 0777 & ~user_umask) == 0); *p = '/'; if (!ok) return 0; } return 1; } char *create_output_name(char *fname) { char *out, *p; if ((out = malloc(strlen(fname) + 1))) { /* remove leading slashes */ while (*fname == '/' || *fname == '\\') fname++; /* if that removes all characters, just call it "x" */ strcpy(out, (*fname) ? fname : "x"); /* change "../" to "xx/" */ for (p = out; *p; p++) { if (p[0] == '.' && p[1] == '.' && (p[2] == '/' || p[2] == '\\')) { p[0] = p[1] = 'x'; } } } return out; } static int sortfunc(const void *a, const void *b) { off_t diff = ((* ((struct mschmd_file **) a))->offset) - ((* ((struct mschmd_file **) b))->offset); return (diff < 0) ? -1 : ((diff > 0) ? 1 : 0); } int main(int argc, char *argv[]) { struct mschm_decompressor *chmd; struct mschmd_header *chm; struct mschmd_file *file, **f; unsigned int numf, i; setbuf(stdout, NULL); setbuf(stderr, NULL); user_umask = umask(0); umask(user_umask); MSPACK_SYS_SELFTEST(i); if (i) return 0; if ((chmd = mspack_create_chm_decompressor(NULL))) { for (argv++; *argv; argv++) { printf("%s\n", *argv); if ((chm = chmd->open(chmd, *argv))) { /* build an ordered list of files for maximum extraction speed */ for (numf=0, file=chm->files; file; file = file->next) numf++; if ((f = (struct mschmd_file **) calloc(numf, sizeof(struct mschmd_file *)))) { for (i=0, file=chm->files; file; file = file->next) f[i++] = file; qsort(f, numf, sizeof(struct mschmd_file *), &sortfunc); for (i = 0; i < numf; i++) { char *outname = create_output_name(f[i]->filename); printf("Extracting %s\n", outname); ensure_filepath(outname); if (chmd->extract(chmd, f[i], outname)) { printf("%s: extract error on \"%s\": %s\n", *argv, f[i]->filename, ERROR(chmd)); } free(outname); } free(f); } chmd->close(chmd, chm); } else { printf("%s: can't open -- %s\n", *argv, ERROR(chmd)); } } mspack_destroy_chm_decompressor(chmd); } return 0; }