static boolean MojoArchive_uz2_enumerate(MojoArchive *ar) { UZ2info *info = (UZ2info *) ar->opaque; MojoArchive_resetEntry(&ar->prevEnum); info->enumerated = false; return true; } // MojoArchive_uz2_enumerate
static void MojoArchive_tar_close(MojoArchive *ar) { TARinfo *info = (TARinfo *) ar->opaque; MojoArchive_resetEntry(&ar->prevEnum); ar->io->close(ar->io); free(info); free(ar); } // MojoArchive_tar_close
static boolean MojoArchive_tar_enumerate(MojoArchive *ar) { TARinfo *info = (TARinfo *) ar->opaque; MojoArchive_resetEntry(&ar->prevEnum); if (info->input != NULL) fatal("BUG: tar entry still open on new enumeration"); info->curFileStart = info->nextEnumPos = 0; return true; } // MojoArchive_tar_enumerate
static void MojoArchive_uz2_close(MojoArchive *ar) { UZ2info *info = (UZ2info *) ar->opaque; MojoArchive_resetEntry(&ar->prevEnum); ar->io->close(ar->io); free(info->outname); free(info); free(ar); } // MojoArchive_uz2_close
static void MojoArchive_dir_close(MojoArchive *ar) { MojoArchiveDirInstance *inst = (MojoArchiveDirInstance *) ar->opaque; freeDirStack(&inst->dirs); free(inst->base); free(inst); MojoArchive_resetEntry(&ar->prevEnum); free(ar); } // MojoArchive_dir_close
static boolean MojoArchive_dir_enumerate(MojoArchive *ar) { MojoArchiveDirInstance *inst = (MojoArchiveDirInstance *) ar->opaque; void *dir = NULL; freeDirStack(&inst->dirs); MojoArchive_resetEntry(&ar->prevEnum); dir = MojoPlatform_opendir(inst->base); if (dir != NULL) pushDirStack(&inst->dirs, inst->base, dir); return (dir != NULL); } // MojoArchive_dir_enumerate
static const MojoArchiveEntry *MojoArchive_uz2_enumNext(MojoArchive *ar) { UZ2info *info = (UZ2info *) ar->opaque; MojoArchive_resetEntry(&ar->prevEnum); if (info->enumerated) return NULL; // only one file in this "archive". ar->prevEnum.perms = MojoPlatform_defaultFilePerms(); ar->prevEnum.filesize = info->outsize; ar->prevEnum.filename = xstrdup(info->outname); ar->prevEnum.type = MOJOARCHIVE_ENTRY_FILE; info->enumerated = true; return &ar->prevEnum; } // MojoArchive_uz2_enumNext
static const MojoArchiveEntry *MojoArchive_tar_enumNext(MojoArchive *ar) { TARinfo *info = (TARinfo *) ar->opaque; boolean zeroes = true; boolean ustar = false; uint8 scratch[512]; uint8 block[512]; size_t fnamelen = 0; int type = 0; memset(scratch, '\0', sizeof (scratch)); MojoArchive_resetEntry(&ar->prevEnum); if (info->input != NULL) fatal("BUG: tar entry still open on new enumeration"); if (!ar->io->seek(ar->io, info->nextEnumPos)) return NULL; // Find a non-zero block of data. Tarballs have two 512 blocks filled with // null bytes at the end of the archive, but you can cat tarballs // together, so you can't treat them as EOF indicators. Just skip them. while (zeroes) { if (ar->io->read(ar->io, block, sizeof (block)) != sizeof (block)) return NULL; // !!! FIXME: fatal() ? zeroes = (memcmp(block, scratch, sizeof (block)) == 0); } // while // !!! FIXME We should probably check the checksum. ustar = is_ustar(block); ar->prevEnum.perms = (uint16) octal_convert(&block[TAR_MODE], TAR_MODELEN); ar->prevEnum.filesize = octal_convert(&block[TAR_SIZE], TAR_SIZELEN); info->curFileStart = info->nextEnumPos + 512; info->nextEnumPos += 512 + ar->prevEnum.filesize; if (ar->prevEnum.filesize % 512) info->nextEnumPos += 512 - (ar->prevEnum.filesize % 512); // We count on (scratch) being zeroed out here! // prefix of filename is at the end for legacy compat. if (ustar) memcpy(scratch, &block[TAR_FNAMEPRE], TAR_FNAMEPRELEN); fnamelen = strlen((const char *) scratch); memcpy(&scratch[fnamelen], &block[TAR_FNAME], TAR_FNAMELEN); fnamelen += strlen((const char *) &scratch[fnamelen]); if (fnamelen == 0) return NULL; // corrupt file. !!! FIXME: fatal() ? ar->prevEnum.filename = xstrdup((const char *) scratch); type = block[TAR_TYPE]; if (type == 0) // some archivers do the file type as 0 instead of '0'. type = TAR_TYPE_FILE; if (ar->prevEnum.filename[fnamelen-1] == '/') { while (ar->prevEnum.filename[fnamelen-1] == '/') ar->prevEnum.filename[--fnamelen] = '\0'; // legacy tar entries don't have a dir type, they just append a '/' to // the filename... if ((!ustar) && (type == TAR_TYPE_FILE)) type = TAR_TYPE_DIRECTORY; } // if ar->prevEnum.type = MOJOARCHIVE_ENTRY_UNKNOWN; if (type == TAR_TYPE_FILE) ar->prevEnum.type = MOJOARCHIVE_ENTRY_FILE; else if (type == TAR_TYPE_DIRECTORY) ar->prevEnum.type = MOJOARCHIVE_ENTRY_DIR; else if (type == TAR_TYPE_SYMLINK) { ar->prevEnum.type = MOJOARCHIVE_ENTRY_SYMLINK; memcpy(scratch, &block[TAR_LINKNAME], TAR_LINKNAMELEN); scratch[TAR_LINKNAMELEN] = '\0'; // just in case. ar->prevEnum.linkdest = xstrdup((const char *) scratch); } // else if return &ar->prevEnum; } // MojoArchive_tar_enumNext
static const MojoArchiveEntry *MojoArchive_dir_enumNext(MojoArchive *ar) { uint16 perms = 0644; //(S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); char *fullpath = NULL; char *dent = NULL; // "dent" == "directory entry" MojoArchiveDirInstance *inst = (MojoArchiveDirInstance *) ar->opaque; const char *basepath; MojoArchive_resetEntry(&ar->prevEnum); if (inst->dirs == NULL) return NULL; basepath = inst->dirs->basepath; // if readdir fails, it's end of dir (!!! FIXME: what about i/o failures?) dent = MojoPlatform_readdir(inst->dirs->dir); if (dent == NULL) // end of dir? { popDirStack(&inst->dirs); return MojoArchive_dir_enumNext(ar); // try higher level in tree. } // if // MojoPlatform layer shouldn't return "." or ".." paths. assert((strcmp(dent, ".") != 0) && (strcmp(dent, "..") != 0)); fullpath = (char *) xmalloc(strlen(basepath) + strlen(dent) + 2); sprintf(fullpath, "%s/%s", basepath, dent); free(dent); ar->prevEnum.filename = xstrdup(fullpath + strlen(inst->base) + 1); ar->prevEnum.filesize = 0; ar->prevEnum.type = MOJOARCHIVE_ENTRY_UNKNOWN; // We currently force the perms from physical files, since CDs on // Linux tend to mark every files as executable and read-only. If you // want to install something with specific permissions, wrap it in a // tarball, or use Setup.File.permissions, or return a permissions // string from Setup.File.filter. //MojoPlatform_perms(fullpath, &perms); ar->prevEnum.perms = perms; if (MojoPlatform_isfile(fullpath)) { ar->prevEnum.type = MOJOARCHIVE_ENTRY_FILE; ar->prevEnum.filesize = MojoPlatform_filesize(fullpath); } // if else if (MojoPlatform_issymlink(fullpath)) { ar->prevEnum.type = MOJOARCHIVE_ENTRY_SYMLINK; ar->prevEnum.linkdest = MojoPlatform_readlink(fullpath); if (ar->prevEnum.linkdest == NULL) { free(fullpath); return MojoArchive_dir_enumNext(ar); } // if } // else if else if (MojoPlatform_isdir(fullpath)) { void *dir = MojoPlatform_opendir(fullpath); ar->prevEnum.type = MOJOARCHIVE_ENTRY_DIR; if (dir == NULL) { free(fullpath); return MojoArchive_dir_enumNext(ar); } // if // push this dir on the stack. Next enum will start there. pushDirStack(&inst->dirs, fullpath, dir); } // else if else { assert(false && "possible file i/o error?"); } // else free(fullpath); return &ar->prevEnum; } // MojoArchive_dir_enumNext
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