static MojoInput *MojoInput_subset_duplicate(MojoInput *io) { MojoInputSubsetInstance *srcinst = (MojoInputSubsetInstance *) io->opaque; MojoInput *dupio = io->duplicate(io); MojoInput *retval = NULL; MojoInputSubsetInstance *inst = NULL; if (dupio == NULL) return NULL; if (!dupio->seek(dupio, 0)) { dupio->close(dupio); return NULL; } // if inst = (MojoInputSubsetInstance*) xmalloc(sizeof (MojoInputSubsetInstance)); memcpy(inst, srcinst, sizeof (MojoInputSubsetInstance)); inst->io = dupio; inst->pos = 0; retval = (MojoInput *) xmalloc(sizeof (MojoInput)); memcpy(retval, io, sizeof (MojoInput)); retval->opaque = inst; return retval; } // MojoInput_subset_duplicate
static MojoInput* MojoInput_xz_duplicate(MojoInput *io) { XZinfo *info = (XZinfo *) io->opaque; MojoInput *retval = NULL; MojoInput *newio = info->origio->duplicate(info->origio); if (newio != NULL) { retval = make_xz_input(newio); if (retval != NULL) retval->seek(retval, io->tell(io)); // slow, slow, slow... } // if return retval; } // MojoInput_xz_duplicate
static int64 MojoInput_xz_read(MojoInput *io, void *buf, uint32 bufsize) { XZinfo *info = (XZinfo *) io->opaque; MojoInput *origio = info->origio; int64 retval = 0; if (bufsize == 0) return 0; // quick rejection. info->stream.next_out = buf; info->stream.avail_out = bufsize; while (retval < ((int64) bufsize)) { const uint32 before = info->stream.total_out; lzma_ret rc; lzma_action action = LZMA_FINISH; if (info->stream.avail_in == 0) { int64 br = origio->length(origio) - origio->tell(origio); if (br > 0) { action = LZMA_RUN; if (br > XZ_READBUFSIZE) br = XZ_READBUFSIZE; br = origio->read(origio, info->buffer, (uint32) br); if (br <= 0) return -1; info->stream.next_in = info->buffer; info->stream.avail_in = (uint32) br; } // if } // if rc = lzma_code(&info->stream, LZMA_RUN); retval += (info->stream.total_out - before); if (rc != LZMA_OK) return -1; } // while assert(retval >= 0); info->uncompressed_position += (uint32) retval; return retval; } // MojoInput_xz_read
static int64 MojoInput_gzip_read(MojoInput *io, void *buf, uint32 bufsize) { GZIPinfo *info = (GZIPinfo *) io->opaque; MojoInput *origio = info->origio; int64 retval = 0; if (bufsize == 0) return 0; // quick rejection. info->stream.next_out = buf; info->stream.avail_out = bufsize; while (retval < ((int64) bufsize)) { const uint32 before = info->stream.total_out; int rc; if (info->stream.avail_in == 0) { int64 br = origio->length(origio) - origio->tell(origio); if (br > 0) { if (br > GZIP_READBUFSIZE) br = GZIP_READBUFSIZE; br = origio->read(origio, info->buffer, (uint32) br); if (br <= 0) return -1; info->stream.next_in = info->buffer; info->stream.avail_in = (uint32) br; } // if } // if rc = inflate(&info->stream, Z_SYNC_FLUSH); retval += (info->stream.total_out - before); if ((rc == Z_STREAM_END) && (retval == 0)) return 0; else if ((rc != Z_OK) && (rc != Z_STREAM_END)) return -1; } // while assert(retval >= 0); info->uncompressed_position += (uint32) retval; return retval; } // MojoInput_gzip_read
static int64 MojoInput_bzip2_read(MojoInput *io, void *buf, uint32 bufsize) { BZIP2info *info = (BZIP2info *) io->opaque; MojoInput *origio = info->origio; int64 retval = 0; if (bufsize == 0) return 0; // quick rejection. info->stream.next_out = buf; info->stream.avail_out = bufsize; while (retval < ((int64) bufsize)) { const uint32 before = info->stream.total_out_lo32; int rc; if (info->stream.avail_in == 0) { int64 br = origio->length(origio) - origio->tell(origio); if (br > 0) { if (br > BZIP2_READBUFSIZE) br = BZIP2_READBUFSIZE; br = origio->read(origio, info->buffer, (uint32) br); if (br <= 0) return -1; info->stream.next_in = (char *) info->buffer; info->stream.avail_in = (uint32) br; } // if } // if rc = BZ2_bzDecompress(&info->stream); retval += (info->stream.total_out_lo32 - before); if (rc != BZ_OK) return -1; } // while assert(retval >= 0); info->uncompressed_position += (uint32) retval; return retval; } // MojoInput_bzip2_read
static void trySwitchBinary(MojoArchive *ar) { MojoInput *io = ar->openCurrentEntry(ar); if (io != NULL) { const uint32 imglen = (uint32) io->length(io); uint8 *img = (uint8 *) xmalloc(imglen); const uint32 br = io->read(io, img, imglen); io->close(io); if (br == imglen) { logInfo("Switching binary with '%0'...", ar->prevEnum.filename); MojoPlatform_switchBin(img, imglen); // no return on success. logError("...Switch binary failed."); } // if free(img); } // if } // trySwitchBinary
MojoArchive *MojoArchive_newFromInput(MojoInput *_io, const char *origfname) { int i; MojoArchive *retval = NULL; const char *ext = NULL; MojoInput *io = MojoInput_newCompressedStream(_io); if (io == NULL) io = _io; if (origfname != NULL) { ext = strrchr(origfname, '/'); if (ext == NULL) ext = strchr(origfname, '.'); else ext = strchr(ext+1, '.'); } // if while (ext != NULL) { // Try for an exact match by filename extension. ext++; // skip that '.' for (i = 0; i < STATICARRAYLEN(archives); i++) { const MojoArchiveType *arc = &archives[i]; if (strcasecmp(ext, arc->ext) == 0) return arc->create(io); } // for ext = strchr(ext, '.'); } // while // Try any that could be determined without the file extension... for (i = 0; i < STATICARRAYLEN(archives); i++) { const MojoArchiveType *arc = &archives[i]; if ((arc->hasMagic) && ((retval = arc->create(io)) != NULL)) return retval; } // for io->close(io); return NULL; // nothing can handle this data. } // MojoArchive_newFromInput
static boolean unpack(UZ2input *inp) { MojoInput *io = inp->io; uLongf ul = (uLongf) inp->uncompsize; // we checked these formally elsewhere. assert(inp->compsize > 0); assert(inp->uncompsize > 0); assert(inp->compsize <= MAXCOMPSIZE); assert(inp->uncompsize <= MAXUNCOMPSIZE); if (io->read(io, inp->compbuf, inp->compsize) != inp->compsize) return false; if (uncompress(inp->uncompbuf, &ul, inp->compbuf, inp->compsize) != Z_OK) return false; if (ul != ((uLongf) inp->uncompsize)) // corrupt data. return false; inp->uncompindex = 0; return true; } // unpack
static MojoInput *MojoInput_tar_duplicate(MojoInput *io) { MojoInput *retval = NULL; fatal(_("BUG: Can't duplicate tar inputs")); // !!! FIXME: why not? #if 0 TARinput *input = (TARinput *) io->opaque; MojoInput *origio = (MojoInput *) io->opaque; MojoInput *newio = origio->duplicate(origio); if (newio != NULL) { TARinput *newopaque = (TARinput *) xmalloc(sizeof (TARinput)); newopaque->origio = newio; newopaque->fsize = input->fsize; newopaque->offset = input->offset; retval = (MojoInput *) xmalloc(sizeof (MojoInput)); memcpy(retval, io, sizeof (MojoInput)); retval->opaque = newopaque; } // if #endif return retval; } // MojoInput_tar_duplicate
int MojoSetup_testNetworkCode(int argc, char **argv) { int i; fprintf(stderr, "Testing networking code...\n\n"); for (i = 1; i < argc; i++) { static char buf[64 * 1024]; uint32 start = 0; const char *url = argv[i]; int64 length = -1; int64 total_br = 0; int64 br = 0; printf("\n\nFetching '%s' ...\n", url); MojoInput *io = MojoInput_newFromURL(url); if (io == NULL) { fprintf(stderr, "failed!\n"); continue; } // if start = MojoPlatform_ticks(); while (!io->ready(io)) MojoPlatform_sleep(10); fprintf(stderr, "took about %d ticks to get started\n", (int) (MojoPlatform_ticks() - start)); length = io->length(io); fprintf(stderr, "Ready to read (%lld) bytes.\n", (long long) length); do { start = MojoPlatform_ticks(); if (!io->ready(io)) { fprintf(stderr, "Not ready!\n"); while (!io->ready(io)) MojoPlatform_sleep(10); fprintf(stderr, "took about %d ticks to get ready\n", (int) (MojoPlatform_ticks() - start)); } // if start = MojoPlatform_ticks(); br = io->read(io, buf, sizeof (buf)); fprintf(stderr, "read blocked for about %d ticks\n", (int) (MojoPlatform_ticks() - start)); if (br > 0) { total_br += br; fprintf(stderr, "read %lld bytes\n", (long long) br); fwrite(buf, br, 1, stdout); } // if } while (br > 0); if (br < 0) fprintf(stderr, "ERROR IN TRANSMISSION.\n\n"); else { fprintf(stderr, "TRANSMISSION COMPLETE!\n\n"); fprintf(stderr, "(Read %lld bytes, expected %lld.)\n", (long long) total_br, length); } // else io->close(io); } // for return 0; } // MojoSetup_testNetworkCode
int MojoSetup_testArchiveCode(int argc, char **argv) { int i; printf("Testing archiver code...\n\n"); for (i = 1; i < argc; i++) { MojoArchive *archive = MojoArchive_newFromDirectory(argv[i]); if (archive != NULL) printf("directory '%s'...\n", argv[i]); else { MojoInput *io = MojoInput_newFromFile(argv[i]); if (io != NULL) { archive = MojoArchive_newFromInput(io, argv[i]); if (archive != NULL) printf("archive '%s'...\n", argv[i]); } // if } // else if (archive == NULL) fprintf(stderr, "Couldn't handle '%s'\n", argv[i]); else { if (!archive->enumerate(archive)) fprintf(stderr, "enumerate() failed.\n"); else { const MojoArchiveEntry *ent; while ((ent = archive->enumNext(archive)) != NULL) { printf("%s ", ent->filename); if (ent->type == MOJOARCHIVE_ENTRY_FILE) { printf("(file, %d bytes, %o)\n", (int) ent->filesize, ent->perms); MojoInput *input = archive->openCurrentEntry(archive); if(&archive->prevEnum != ent) { fprintf(stderr, "Address of MojoArchiveEntry pointer differs\n"); exit(EXIT_FAILURE); } // if if(!input) { fprintf(stderr, "Could not open current entry\n"); exit(EXIT_FAILURE); } // if if(!input->ready(input)) { input->close(input); continue; } // if uint64 pos = input->tell(input); if(0 != pos) { fprintf(stderr, "position has to be 0 on start, is: %d\n", (int) pos); exit(EXIT_FAILURE); } // if int64 filesize = input->length(input); if(filesize != ent->filesize) { fprintf(stderr, "file size mismatch %d != %d\n", (int) filesize, (int) ent->filesize); exit(EXIT_FAILURE); } // if boolean ret = input->seek(input, filesize - 1); if(!ret) { fprintf(stderr, "seek() has to return 'true'.\n"); exit(EXIT_FAILURE); } // if ret = input->seek(input, filesize); if(ret) { fprintf(stderr, "seek() has to return 'false'.\n"); exit(EXIT_FAILURE); } // if pos = input->tell(input); if(filesize -1 != pos) { fprintf(stderr, "position should be %d after seek(), is: %d\n", (int) filesize - 1, (int) pos); exit(EXIT_FAILURE); } // if input->close(input); } // if else if (ent->type == MOJOARCHIVE_ENTRY_DIR) printf("(dir, %o)\n", ent->perms); else if (ent->type == MOJOARCHIVE_ENTRY_SYMLINK) printf("(symlink -> '%s')\n", ent->linkdest); else { printf("(UNKNOWN?!, %d bytes, -> '%s', %o)\n", (int) ent->filesize, ent->linkdest, ent->perms); } // else } // while } // else archive->close(archive); printf("\n\n"); } // else } // for return 0; } // MojoSetup_testArchiveCode
MojoArchive *MojoArchive_initBaseArchive(void) { char *basepath = NULL; const char *cmd = NULL; MojoInput *io = NULL; if (GBaseArchive != NULL) return GBaseArchive; // already initialized. if ((cmd = cmdlinestr("base", "MOJOSETUP_BASE", NULL)) != NULL) { char *real = MojoPlatform_realpath(cmd); if (real != NULL) { if (MojoPlatform_isdir(real)) GBaseArchive = MojoArchive_newFromDirectory(real); else { io = MojoInput_newFromFile(real); if (io != NULL) GBaseArchive = MojoArchive_newFromInput(io, real); } // else if (GBaseArchive != NULL) basepath = real; else free(real); } // if } // else if else { basepath = MojoPlatform_appBinaryPath(); if (basepath != NULL) { io = MojoInput_newFromFile(basepath); if (io != NULL) { // See if there's a MOJOBASE signature at the end of the // file. This means we appended an archive to the executable, // for a self-extracting installer. This method works with // any archive type, even if it wasn't specifically designed // to be appended. uint8 buf[8]; uint64 size = 0; const int64 flen = io->length(io) - 16; if ( (flen > 0) && (io->seek(io, flen)) && (io->read(io, buf, 8) == 8) && (memcmp(buf, "MOJOBASE", 8) == 0) && (MojoInput_readui64(io, &size)) && (size < flen) ) { MojoInput *newio; newio = MojoInput_newFromSubset(io, flen - size, flen); if (newio != NULL) io = newio; } // if GBaseArchive = MojoArchive_newFromInput(io, basepath); } // if if (GBaseArchive == NULL) { // Just use the same directory as the binary instead. char *ptr = strrchr(basepath, '/'); if (ptr != NULL) *ptr = '\0'; else { free(basepath); // oh well, try cwd. basepath = MojoPlatform_currentWorkingDir(); } // else GBaseArchive = MojoArchive_newFromDirectory(basepath); // !!! FIXME: failing this, maybe default.mojosetup? } // if } // if } // else if (GBaseArchive == NULL) { free(basepath); basepath = NULL; } // if GBaseArchivePath = basepath; return GBaseArchive; } // MojoArchive_initBaseArchive
static boolean MojoArchive_pck_enumerate(MojoArchive *ar) { MojoArchiveEntry *archiveEntries = NULL; PCKinfo *info = (PCKinfo *) ar->opaque; const int dataStart = info->dataStart; const int fileCount = dataStart / sizeof (PCKentry); const size_t len = fileCount * sizeof (MojoArchiveEntry); PCKentry fileEntry; uint64 i, realFileCount = 0; char directory[256] = {'\0'}; MojoInput *io = ar->io; MojoArchive_resetEntry(&ar->prevEnum); archiveEntries = (MojoArchiveEntry *) xmalloc(len); for (i = 0; i < fileCount; i++) { int dotdot; int64 br; br = io->read(io, fileEntry.filename, sizeof (fileEntry.filename)); if (br != sizeof (fileEntry.filename)) return false; else if (!MojoInput_readui32(io, &fileEntry.filesize)) return false; dotdot = (strcmp(fileEntry.filename, "..") == 0); if ((!dotdot) && (fileEntry.filesize == 0x80000000)) { MojoArchiveEntry *entry = &archiveEntries[realFileCount]; strcat(directory, fileEntry.filename); strcat(directory, "/"); entry->filename = xstrdup(directory); entry->type = MOJOARCHIVE_ENTRY_DIR; entry->perms = MojoPlatform_defaultDirPerms(); entry->filesize = 0; realFileCount++; } // if else if ((dotdot) && (fileEntry.filesize == 0x80000000)) { // remove trailing path separator char *pathSep; const size_t strLength = strlen(directory); directory[strLength - 1] = '\0'; pathSep = strrchr(directory, '/'); if(pathSep != NULL) { pathSep++; *pathSep = '\0'; } // if } // else if else { MojoArchiveEntry *entry = &archiveEntries[realFileCount]; if (directory[0] == '\0') entry->filename = xstrdup(fileEntry.filename); else { const size_t len = sizeof (char) * strlen(directory) + strlen(fileEntry.filename) + 1; entry->filename = (char *) xmalloc(len); strcat(entry->filename, directory); strcat(entry->filename, fileEntry.filename); } // else entry->perms = MojoPlatform_defaultFilePerms(); entry->type = MOJOARCHIVE_ENTRY_FILE; entry->filesize = fileEntry.filesize; realFileCount++; } // else } // for info->fileCount = realFileCount; info->archiveEntries = archiveEntries; info->nextEnumPos = 0; info->nextFileStart = dataStart; return true; } // MojoArchive_pck_enumerate