コード例 #1
0
ファイル: MosDecoder.cpp プロジェクト: avsmal/darktable
RawImage MosDecoder::decodeRawInternal() {
  vector<TiffIFD*> data;
  TiffIFD* raw = NULL;
  uint32 off = 0;

  uint32 base = 8;
  // We get a pointer up to the end of the file as we check offset bounds later
  const uchar8 *insideTiff = mFile->getData(base, mFile->getSize()-base);
  if (get4LE(insideTiff, 0) == 0x49494949) {
    uint32 offset = get4LE(insideTiff, 8);
    if (offset+base+4 > mFile->getSize())
      ThrowRDE("MOS: PhaseOneC offset out of bounds");

    uint32 entries = get4LE(insideTiff, offset);
    uint32 pos = 8; // Skip another 4 bytes

    uint32 width=0, height=0, strip_offset=0, data_offset=0, wb_offset=0;
    while (entries--) {
      if (offset+base+pos+16 > mFile->getSize())
        ThrowRDE("MOS: PhaseOneC offset out of bounds");

      uint32 tag  = get4LE(insideTiff, offset+pos);
      //uint32 type = get4LE(insideTiff, offset+pos+4);
      //uint32 len  = get4LE(insideTiff, offset+pos+8);
      uint32 data = get4LE(insideTiff, offset+pos+12);
      pos += 16;
      switch(tag) {
      case 0x107: wb_offset    = data+base;      break;
      case 0x108: width        = data;      break;
      case 0x109: height       = data;      break;
      case 0x10f: data_offset  = data+base; break;
      case 0x21c: strip_offset = data+base; break;
      case 0x21d: black_level  = data>>2;   break;
      }
    }
    if (width <= 0 || height <= 0)
      ThrowRDE("MOS: PhaseOneC couldn't find width and height");
    if (strip_offset+height*4 > mFile->getSize())
      ThrowRDE("MOS: PhaseOneC strip offsets out of bounds");
    if (data_offset > mFile->getSize())
      ThrowRDE("MOS: PhaseOneC data offset out of bounds");

    mRaw->dim = iPoint2D(width, height);
    mRaw->createData();

    DecodePhaseOneC(data_offset, strip_offset, width, height);

    const uchar8 *data = mFile->getData(wb_offset, 12);
    for(int i=0; i<3; i++) {
      // Use get4LE instead of going straight to float so this is endian clean
      uint32 value = get4LE(data, i*4);
      mRaw->metadata.wbCoeffs[i] = *((float *) &value);
    }

    return mRaw;
  } else {
コード例 #2
0
/**
 * Convert a binary log entry to ASCII form.
 *
 * For convenience we mimic the processLogBuffer API.  There is no
 * pre-defined output length for the binary data, since we're free to format
 * it however we choose, which means we can't really use a fixed-size buffer
 * here.
 */
int android_log_processBinaryLogBuffer(struct logger_entry *buf,
    AndroidLogEntry *entry, const EventTagMap* map, char* messageBuf,
    int messageBufLen)
{
    size_t inCount;
    unsigned int tagIndex;
    const unsigned char* eventData;

    entry->tv_sec = buf->sec;
    entry->tv_nsec = buf->nsec;
    entry->priority = ANDROID_LOG_INFO;
    entry->pid = buf->pid;
    entry->tid = buf->tid;

    /*
     * Pull the tag out.
     */
    eventData = (const unsigned char*) buf->msg;
    inCount = buf->len;
    if (inCount < 4)
        return -1;
    tagIndex = get4LE(eventData);
    eventData += 4;
    inCount -= 4;

    if (map != NULL) {
        entry->tag = android_lookupEventTag(map, tagIndex);
    } else {
        entry->tag = NULL;
    }

    /*
     * If we don't have a map, or didn't find the tag number in the map,
     * stuff a generated tag value into the start of the output buffer and
     * shift the buffer pointers down.
     */
    if (entry->tag == NULL) {
        int tagLen;

        tagLen = snprintf(messageBuf, messageBufLen, "[%d]", tagIndex);
        entry->tag = messageBuf;
        messageBuf += tagLen+1;
        messageBufLen -= tagLen+1;
    }

    /*
     * Format the event log data into the buffer.
     */
    char* outBuf = messageBuf;
    size_t outRemaining = messageBufLen-1;      /* leave one for nul byte */
    int result;
    result = android_log_printBinaryEvent(&eventData, &inCount, &outBuf,
                &outRemaining);
    if (result < 0) {
        fprintf(stderr, "Binary log entry conversion failed\n");
        return -1;
    } else if (result == 1) {
        if (outBuf > messageBuf) {
            /* leave an indicator */
            *(outBuf-1) = '!';
        } else {
            /* no room to output anything at all */
            *outBuf++ = '!';
            outRemaining--;
        }
        /* pretend we ate all the data */
        inCount = 0;
    }

    /* eat the silly terminating '\n' */
    if (inCount == 1 && *eventData == '\n') {
        eventData++;
        inCount--;
    }

    if (inCount != 0) {
        fprintf(stderr,
            "Warning: leftover binary log data (%zu bytes)\n", inCount);
    }

    /*
     * Terminate the buffer.  The NUL byte does not count as part of
     * entry->messageLen.
     */
    *outBuf = '\0';
    entry->messageLen = outBuf - messageBuf;
    assert(entry->messageLen == (messageBufLen-1) - outRemaining);

    entry->message = messageBuf;

    return 0;
}
コード例 #3
0
/*
 * Recursively convert binary log data to printable form.
 *
 * This needs to be recursive because you can have lists of lists.
 *
 * If we run out of room, we stop processing immediately.  It's important
 * for us to check for space on every output element to avoid producing
 * garbled output.
 *
 * Returns 0 on success, 1 on buffer full, -1 on failure.
 */
static int android_log_printBinaryEvent(const unsigned char** pEventData,
    size_t* pEventDataLen, char** pOutBuf, size_t* pOutBufLen)
{
    const unsigned char* eventData = *pEventData;
    size_t eventDataLen = *pEventDataLen;
    char* outBuf = *pOutBuf;
    size_t outBufLen = *pOutBufLen;
    unsigned char type;
    size_t outCount;
    int result = 0;

    if (eventDataLen < 1)
        return -1;
    type = *eventData++;
    eventDataLen--;

    //fprintf(stderr, "--- type=%d (rem len=%d)\n", type, eventDataLen);

    switch (type) {
    case EVENT_TYPE_INT:
        /* 32-bit signed int */
        {
            int ival;

            if (eventDataLen < 4)
                return -1;
            ival = get4LE(eventData);
            eventData += 4;
            eventDataLen -= 4;

            outCount = snprintf(outBuf, outBufLen, "%d", ival);
            if (outCount < outBufLen) {
                outBuf += outCount;
                outBufLen -= outCount;
            } else {
                /* halt output */
                goto no_room;
            }
        }
        break;
    case EVENT_TYPE_LONG:
        /* 64-bit signed long */
        {
            long long lval;

            if (eventDataLen < 8)
                return -1;
            lval = get8LE(eventData);
            eventData += 8;
            eventDataLen -= 8;

            outCount = snprintf(outBuf, outBufLen, "%lld", lval);
            if (outCount < outBufLen) {
                outBuf += outCount;
                outBufLen -= outCount;
            } else {
                /* halt output */
                goto no_room;
            }
        }
        break;
    case EVENT_TYPE_STRING:
        /* UTF-8 chars, not NULL-terminated */
        {
            unsigned int strLen;

            if (eventDataLen < 4)
                return -1;
            strLen = get4LE(eventData);
            eventData += 4;
            eventDataLen -= 4;

            if (eventDataLen < strLen)
                return -1;

            if (strLen < outBufLen) {
                memcpy(outBuf, eventData, strLen);
                outBuf += strLen;
                outBufLen -= strLen;
            } else if (outBufLen > 0) {
                /* copy what we can */
                memcpy(outBuf, eventData, outBufLen);
                outBuf += outBufLen;
                outBufLen -= outBufLen;
                goto no_room;
            }
            eventData += strLen;
            eventDataLen -= strLen;
            break;
        }
    case EVENT_TYPE_LIST:
        /* N items, all different types */
        {
            unsigned char count;
            int i;

            if (eventDataLen < 1)
                return -1;

            count = *eventData++;
            eventDataLen--;

            if (outBufLen > 0) {
                *outBuf++ = '[';
                outBufLen--;
            } else {
                goto no_room;
            }

            for (i = 0; i < count; i++) {
                result = android_log_printBinaryEvent(&eventData, &eventDataLen,
                        &outBuf, &outBufLen);
                if (result != 0)
                    goto bail;

                if (i < count-1) {
                    if (outBufLen > 0) {
                        *outBuf++ = ',';
                        outBufLen--;
                    } else {
                        goto no_room;
                    }
                }
            }

            if (outBufLen > 0) {
                *outBuf++ = ']';
                outBufLen--;
            } else {
                goto no_room;
            }
        }
        break;
    default:
        fprintf(stderr, "Unknown binary event type %d\n", type);
        return -1;
    }

bail:
    *pEventData = eventData;
    *pEventDataLen = eventDataLen;
    *pOutBuf = outBuf;
    *pOutBufLen = outBufLen;
    return result;

no_room:
    result = 1;
    goto bail;
}
コード例 #4
0
status_t LogSection::BlockingCall(int pipeWriteFd) const {
    // Open log buffer and getting logs since last retrieved time if any.
    unique_ptr<logger_list, void (*)(logger_list*)> loggers(
            gLastLogsRetrieved.find(mLogID) == gLastLogsRetrieved.end()
                    ? android_logger_list_alloc(ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 0, 0)
                    : android_logger_list_alloc_time(ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK,
                                                     gLastLogsRetrieved[mLogID], 0),
            android_logger_list_free);

    if (android_logger_open(loggers.get(), mLogID) == NULL) {
        ALOGE("LogSection %s: Can't get logger.", this->name.string());
        return -1;
    }

    log_msg msg;
    log_time lastTimestamp(0);

    ProtoOutputStream proto;
    while (true) {  // keeps reading until logd buffer is fully read.
        status_t err = android_logger_list_read(loggers.get(), &msg);
        // err = 0 - no content, unexpected connection drop or EOF.
        // err = +ive number - size of retrieved data from logger
        // err = -ive number, OS supplied error _except_ for -EAGAIN
        // err = -EAGAIN, graceful indication for ANDRODI_LOG_NONBLOCK that this is the end of data.
        if (err <= 0) {
            if (err != -EAGAIN) {
                ALOGW("LogSection %s: fails to read a log_msg.\n", this->name.string());
            }
            // dump previous logs and don't consider this error a failure.
            break;
        }
        if (mBinary) {
            // remove the first uint32 which is tag's index in event log tags
            android_log_context context = create_android_log_parser(msg.msg() + sizeof(uint32_t),
                                                                    msg.len() - sizeof(uint32_t));
            ;
            android_log_list_element elem;

            lastTimestamp.tv_sec = msg.entry_v1.sec;
            lastTimestamp.tv_nsec = msg.entry_v1.nsec;

            // format a BinaryLogEntry
            uint64_t token = proto.start(LogProto::BINARY_LOGS);
            proto.write(BinaryLogEntry::SEC, msg.entry_v1.sec);
            proto.write(BinaryLogEntry::NANOSEC, msg.entry_v1.nsec);
            proto.write(BinaryLogEntry::UID, (int)msg.entry_v4.uid);
            proto.write(BinaryLogEntry::PID, msg.entry_v1.pid);
            proto.write(BinaryLogEntry::TID, msg.entry_v1.tid);
            proto.write(BinaryLogEntry::TAG_INDEX,
                        get4LE(reinterpret_cast<uint8_t const*>(msg.msg())));
            do {
                elem = android_log_read_next(context);
                uint64_t elemToken = proto.start(BinaryLogEntry::ELEMS);
                switch (elem.type) {
                    case EVENT_TYPE_INT:
                        proto.write(BinaryLogEntry::Elem::TYPE,
                                    BinaryLogEntry::Elem::EVENT_TYPE_INT);
                        proto.write(BinaryLogEntry::Elem::VAL_INT32, (int)elem.data.int32);
                        break;
                    case EVENT_TYPE_LONG:
                        proto.write(BinaryLogEntry::Elem::TYPE,
                                    BinaryLogEntry::Elem::EVENT_TYPE_LONG);
                        proto.write(BinaryLogEntry::Elem::VAL_INT64, (long long)elem.data.int64);
                        break;
                    case EVENT_TYPE_STRING:
                        proto.write(BinaryLogEntry::Elem::TYPE,
                                    BinaryLogEntry::Elem::EVENT_TYPE_STRING);
                        proto.write(BinaryLogEntry::Elem::VAL_STRING, elem.data.string, elem.len);
                        break;
                    case EVENT_TYPE_FLOAT:
                        proto.write(BinaryLogEntry::Elem::TYPE,
                                    BinaryLogEntry::Elem::EVENT_TYPE_FLOAT);
                        proto.write(BinaryLogEntry::Elem::VAL_FLOAT, elem.data.float32);
                        break;
                    case EVENT_TYPE_LIST:
                        proto.write(BinaryLogEntry::Elem::TYPE,
                                    BinaryLogEntry::Elem::EVENT_TYPE_LIST);
                        break;
                    case EVENT_TYPE_LIST_STOP:
                        proto.write(BinaryLogEntry::Elem::TYPE,
                                    BinaryLogEntry::Elem::EVENT_TYPE_LIST_STOP);
                        break;
                    case EVENT_TYPE_UNKNOWN:
                        proto.write(BinaryLogEntry::Elem::TYPE,
                                    BinaryLogEntry::Elem::EVENT_TYPE_UNKNOWN);
                        break;
                }
                proto.end(elemToken);
            } while ((elem.type != EVENT_TYPE_UNKNOWN) && !elem.complete);
            proto.end(token);
            if (context) {
                android_log_destroy(&context);
            }
        } else {
            AndroidLogEntry entry;
            err = android_log_processLogBuffer(&msg.entry_v1, &entry);
            if (err != NO_ERROR) {
                ALOGW("LogSection %s: fails to process to an entry.\n", this->name.string());
                break;
            }
            lastTimestamp.tv_sec = entry.tv_sec;
            lastTimestamp.tv_nsec = entry.tv_nsec;

            // format a TextLogEntry
            uint64_t token = proto.start(LogProto::TEXT_LOGS);
            proto.write(TextLogEntry::SEC, (long long)entry.tv_sec);
            proto.write(TextLogEntry::NANOSEC, (long long)entry.tv_nsec);
            proto.write(TextLogEntry::PRIORITY, (int)entry.priority);
            proto.write(TextLogEntry::UID, entry.uid);
            proto.write(TextLogEntry::PID, entry.pid);
            proto.write(TextLogEntry::TID, entry.tid);
            proto.write(TextLogEntry::TAG, entry.tag, trimTail(entry.tag, entry.tagLen));
            proto.write(TextLogEntry::LOG, entry.message,
                        trimTail(entry.message, entry.messageLen));
            proto.end(token);
        }
    }
    gLastLogsRetrieved[mLogID] = lastTimestamp;
    if (!proto.flush(pipeWriteFd) && errno == EPIPE) {
        ALOGE("[%s] wrote to a broken pipe\n", this->name.string());
        return EPIPE;
    }
    return NO_ERROR;
}
コード例 #5
0
/**
 * Convert a binary log entry to ASCII form.
 *
 * For convenience we mimic the processLogBuffer API.  There is no
 * pre-defined output length for the binary data, since we're free to format
 * it however we choose, which means we can't really use a fixed-size buffer
 * here.
 */
LIBLOG_ABI_PUBLIC int android_log_processBinaryLogBuffer(
        struct logger_entry *buf,
        AndroidLogEntry *entry,
        const EventTagMap *map,
        char *messageBuf, int messageBufLen)
{
    size_t inCount;
    unsigned int tagIndex;
    const unsigned char* eventData;

    entry->tv_sec = buf->sec;
    entry->tv_nsec = buf->nsec;
    entry->priority = ANDROID_LOG_INFO;
    entry->uid = -1;
    entry->pid = buf->pid;
    entry->tid = buf->tid;

    /*
     * Pull the tag out, fill in some additional details based on incoming
     * buffer version (v3 adds lid, v4 adds uid).
     */
    eventData = (const unsigned char*) buf->msg;
    struct logger_entry_v2 *buf2 = (struct logger_entry_v2 *)buf;
    if (buf2->hdr_size) {
        if ((buf2->hdr_size < sizeof(((struct log_msg *)NULL)->entry_v1)) ||
                (buf2->hdr_size > sizeof(((struct log_msg *)NULL)->entry))) {
            fprintf(stderr, "+++ LOG: entry illegal hdr_size\n");
            return -1;
        }
        eventData = ((unsigned char *)buf2) + buf2->hdr_size;
        if ((buf2->hdr_size >= sizeof(struct logger_entry_v3)) &&
                (((struct logger_entry_v3 *)buf)->lid == LOG_ID_SECURITY)) {
            entry->priority = ANDROID_LOG_WARN;
        }
        if (buf2->hdr_size >= sizeof(struct logger_entry_v4)) {
            entry->uid = ((struct logger_entry_v4 *)buf)->uid;
        }
    }
    inCount = buf->len;
    if (inCount < 4)
        return -1;
    tagIndex = get4LE(eventData);
    eventData += 4;
    inCount -= 4;

    entry->tagLen = 0;
    if (map != NULL) {
        entry->tag = android_lookupEventTag_len(map, &entry->tagLen, tagIndex);
    } else {
        entry->tag = NULL;
    }

    /*
     * If we don't have a map, or didn't find the tag number in the map,
     * stuff a generated tag value into the start of the output buffer and
     * shift the buffer pointers down.
     */
    if (entry->tag == NULL) {
        size_t tagLen;

        tagLen = snprintf(messageBuf, messageBufLen, "[%d]", tagIndex);
        if (tagLen >= (size_t)messageBufLen) {
            tagLen = messageBufLen - 1;
        }
        entry->tag = messageBuf;
        entry->tagLen = tagLen;
        messageBuf += tagLen + 1;
        messageBufLen -= tagLen + 1;
    }

    /*
     * Format the event log data into the buffer.
     */
    char* outBuf = messageBuf;
    size_t outRemaining = messageBufLen-1;      /* leave one for nul byte */
    int result;
    result = android_log_printBinaryEvent(&eventData, &inCount, &outBuf,
                &outRemaining);
    if (result < 0) {
        fprintf(stderr, "Binary log entry conversion failed\n");
        return -1;
    } else if (result == 1) {
        if (outBuf > messageBuf) {
            /* leave an indicator */
            *(outBuf-1) = '!';
        } else {
            /* no room to output anything at all */
            *outBuf++ = '!';
            outRemaining--;
        }
        /* pretend we ate all the data */
        inCount = 0;
    }

    /* eat the silly terminating '\n' */
    if (inCount == 1 && *eventData == '\n') {
        eventData++;
        inCount--;
    }

    if (inCount != 0) {
        fprintf(stderr,
            "Warning: leftover binary log data (%zu bytes)\n", inCount);
    }

    /*
     * Terminate the buffer.  The NUL byte does not count as part of
     * entry->messageLen.
     */
    *outBuf = '\0';
    entry->messageLen = outBuf - messageBuf;
    assert(entry->messageLen == (messageBufLen-1) - outRemaining);

    entry->message = messageBuf;

    return 0;
}
コード例 #6
0
bool ObbFile::parseObbFile(int fd)
{
    off64_t fileLength = lseek64(fd, 0, SEEK_END);

    if (fileLength < kFooterMinSize) {
        if (fileLength < 0) {
            ALOGW("error seeking in ObbFile: %s\n", strerror(errno));
        } else {
            ALOGW("file is only %lld (less than %d minimum)\n", fileLength, kFooterMinSize);
        }
        return false;
    }

    ssize_t actual;
    size_t footerSize;

    {
        lseek64(fd, fileLength - kFooterTagSize, SEEK_SET);

        char *footer = new char[kFooterTagSize];
        actual = TEMP_FAILURE_RETRY(read(fd, footer, kFooterTagSize));
        if (actual != kFooterTagSize) {
            ALOGW("couldn't read footer signature: %s\n", strerror(errno));
            return false;
        }

        unsigned int fileSig = get4LE((unsigned char*)footer + sizeof(int32_t));
        if (fileSig != kSignature) {
            ALOGW("footer didn't match magic string (expected 0x%08x; got 0x%08x)\n",
                    kSignature, fileSig);
            return false;
        }

        footerSize = get4LE((unsigned char*)footer);
        if (footerSize > (size_t)fileLength - kFooterTagSize
                || footerSize > kMaxBufSize) {
            ALOGW("claimed footer size is too large (0x%08zx; file size is 0x%08llx)\n",
                    footerSize, fileLength);
            return false;
        }

        if (footerSize < (kFooterMinSize - kFooterTagSize)) {
            ALOGW("claimed footer size is too small (0x%zx; minimum size is 0x%x)\n",
                    footerSize, kFooterMinSize - kFooterTagSize);
            return false;
        }
    }

    off64_t fileOffset = fileLength - footerSize - kFooterTagSize;
    if (lseek64(fd, fileOffset, SEEK_SET) != fileOffset) {
        ALOGW("seek %lld failed: %s\n", fileOffset, strerror(errno));
        return false;
    }

    mFooterStart = fileOffset;

    char* scanBuf = (char*)malloc(footerSize);
    if (scanBuf == NULL) {
        ALOGW("couldn't allocate scanBuf: %s\n", strerror(errno));
        return false;
    }

    actual = TEMP_FAILURE_RETRY(read(fd, scanBuf, footerSize));
    // readAmount is guaranteed to be less than kMaxBufSize
    if (actual != (ssize_t)footerSize) {
        ALOGI("couldn't read ObbFile footer: %s\n", strerror(errno));
        free(scanBuf);
        return false;
    }

#ifdef DEBUG
    for (int i = 0; i < footerSize; ++i) {
        ALOGI("char: 0x%02x\n", scanBuf[i]);
    }
#endif

    uint32_t sigVersion = get4LE((unsigned char*)scanBuf);
    if (sigVersion != kSigVersion) {
        ALOGW("Unsupported ObbFile version %d\n", sigVersion);
        free(scanBuf);
        return false;
    }

    mVersion = (int32_t) get4LE((unsigned char*)scanBuf + kPackageVersionOffset);
    mFlags = (int32_t) get4LE((unsigned char*)scanBuf + kFlagsOffset);

    memcpy(&mSalt, (unsigned char*)scanBuf + kSaltOffset, sizeof(mSalt));

    size_t packageNameLen = get4LE((unsigned char*)scanBuf + kPackageNameLenOffset);
    if (packageNameLen == 0
            || packageNameLen > (footerSize - kPackageNameOffset)) {
        ALOGW("bad ObbFile package name length (0x%04zx; 0x%04zx possible)\n",
                packageNameLen, footerSize - kPackageNameOffset);
        free(scanBuf);
        return false;
    }

    char* packageName = reinterpret_cast<char*>(scanBuf + kPackageNameOffset);
    mPackageName = String8(const_cast<char*>(packageName), packageNameLen);

    free(scanBuf);

#ifdef DEBUG
    ALOGI("Obb scan succeeded: packageName=%s, version=%d\n", mPackageName.string(), mVersion);
#endif

    return true;
}
コード例 #7
0
ファイル: ZipArchive.c プロジェクト: sdklite/Dalvik_CAR
/*
 * Get the useful fields from the zip entry.
 *
 * Returns non-zero if the contents of the fields (particularly the data
 * offset) appear to be bogus.
 */
int dexZipGetEntryInfo(const ZipArchive* pArchive, ZipEntry entry,
    int* pMethod, size_t* pUncompLen, size_t* pCompLen, off_t* pOffset,
    long* pModWhen, long* pCrc32)
{
    int ent = entryToIndex(pArchive, entry);
    if (ent < 0)
        return -1;

    /*
     * Recover the start of the central directory entry from the filename
     * pointer.  The filename is the first entry past the fixed-size data,
     * so we can just subtract back from that.
     */
    const unsigned char* basePtr = (const unsigned char*)
        pArchive->mDirectoryMap.addr;
    const unsigned char* ptr = (const unsigned char*)
        pArchive->mHashTable[ent].name;
    off_t cdOffset = pArchive->mDirectoryOffset;

    ptr -= kCDELen;

    int method = get2LE(ptr + kCDEMethod);
    if (pMethod != NULL)
        *pMethod = method;

    if (pModWhen != NULL)
        *pModWhen = get4LE(ptr + kCDEModWhen);
    if (pCrc32 != NULL)
        *pCrc32 = get4LE(ptr + kCDECRC);

    size_t compLen = get4LE(ptr + kCDECompLen);
    if (pCompLen != NULL)
        *pCompLen = compLen;
    size_t uncompLen = get4LE(ptr + kCDEUncompLen);
    if (pUncompLen != NULL)
        *pUncompLen = uncompLen;

    /*
     * If requested, determine the offset of the start of the data.  All we
     * have is the offset to the Local File Header, which is variable size,
     * so we have to read the contents of the struct to figure out where
     * the actual data starts.
     *
     * We also need to make sure that the lengths are not so large that
     * somebody trying to map the compressed or uncompressed data runs
     * off the end of the mapped region.
     *
     * Note we don't verify compLen/uncompLen if they don't request the
     * dataOffset, because dataOffset is expensive to determine.  However,
     * if they don't have the file offset, they're not likely to be doing
     * anything with the contents.
     */
    if (pOffset != NULL) {
        long localHdrOffset = (long) get4LE(ptr + kCDELocalOffset);
        if (localHdrOffset + kLFHLen >= cdOffset) {
            LOGW("Zip: bad local hdr offset in zip\n");
            return -1;
        }

        u1 lfhBuf[kLFHLen];
        if (lseek(pArchive->mFd, localHdrOffset, SEEK_SET) != localHdrOffset) {
            LOGW("Zip: failed seeking to lfh at offset %ld\n", localHdrOffset);
            return -1;
        }
        ssize_t actual =
            TEMP_FAILURE_RETRY(read(pArchive->mFd, lfhBuf, sizeof(lfhBuf)));
        if (actual != sizeof(lfhBuf)) {
            LOGW("Zip: failed reading lfh from offset %ld\n", localHdrOffset);
            return -1;
        }

        if (get4LE(lfhBuf) != kLFHSignature) {
            LOGW("Zip: didn't find signature at start of lfh, offset=%ld\n",
                localHdrOffset);
            return -1;
        }

        off_t dataOffset = localHdrOffset + kLFHLen
            + get2LE(lfhBuf + kLFHNameLen) + get2LE(lfhBuf + kLFHExtraLen);
        if (dataOffset >= cdOffset) {
            LOGW("Zip: bad data offset %ld in zip\n", (long) dataOffset);
            return -1;
        }

        /* check lengths */
        if ((off_t)(dataOffset + compLen) > cdOffset) {
            LOGW("Zip: bad compressed length in zip (%ld + %zd > %ld)\n",
                (long) dataOffset, compLen, (long) cdOffset);
            return -1;
        }

        if (method == kCompressStored &&
            (off_t)(dataOffset + uncompLen) > cdOffset)
        {
            LOGW("Zip: bad uncompressed length in zip (%ld + %zd > %ld)\n",
                (long) dataOffset, uncompLen, (long) cdOffset);
            return -1;
        }

        *pOffset = dataOffset;
    }
    return 0;
}
コード例 #8
0
ファイル: ZipArchive.c プロジェクト: sdklite/Dalvik_CAR
/*
 * Find the zip Central Directory and memory-map it.
 *
 * On success, returns 0 after populating fields from the EOCD area:
 *   mDirectoryOffset
 *   mDirectoryMap
 *   mNumEntries
 */
static int mapCentralDirectory(int fd, const char* debugFileName,
    ZipArchive* pArchive)
{
    u1* scanBuf = NULL;
    int result = -1;

    /*
     * Get and test file length.
     */
    off_t fileLength = lseek(fd, 0, SEEK_END);
    if (fileLength < kEOCDLen) {
        LOGV("Zip: length %ld is too small to be zip\n", (long) fileLength);
        goto bail;
    }

    /*
     * Perform the traditional EOCD snipe hunt.
     *
     * We're searching for the End of Central Directory magic number,
     * which appears at the start of the EOCD block.  It's followed by
     * 18 bytes of EOCD stuff and up to 64KB of archive comment.  We
     * need to read the last part of the file into a buffer, dig through
     * it to find the magic number, parse some values out, and use those
     * to determine the extent of the CD.
     *
     * We start by pulling in the last part of the file.
     */
    size_t readAmount = kMaxEOCDSearch;
    if (readAmount > (size_t) fileLength)
        readAmount = fileLength;
    off_t searchStart = fileLength - readAmount;

    scanBuf = (u1*) malloc(readAmount);
    if (lseek(fd, searchStart, SEEK_SET) != searchStart) {
        LOGW("Zip: seek %ld failed: %s\n", (long) searchStart, strerror(errno));
        goto bail;
    }
    ssize_t actual = TEMP_FAILURE_RETRY(read(fd, scanBuf, readAmount));
    if (actual != (ssize_t) readAmount) {
        LOGW("Zip: read %zd failed: %s\n", readAmount, strerror(errno));
        goto bail;
    }

    /*
     * Scan backward for the EOCD magic.  In an archive without a trailing
     * comment, we'll find it on the first try.  (We may want to consider
     * doing an initial minimal read; if we don't find it, retry with a
     * second read as above.)
     */
    int i;
    for (i = readAmount - kEOCDLen; i >= 0; i--) {
        if (scanBuf[i] == 0x50 && get4LE(&scanBuf[i]) == kEOCDSignature) {
            LOGV("+++ Found EOCD at buf+%d\n", i);
            break;
        }
    }
    if (i < 0) {
        LOGD("Zip: EOCD not found, %s is not zip\n", debugFileName);
        goto bail;
    }

    off_t eocdOffset = searchStart + i;
    const u1* eocdPtr = scanBuf + i;

    assert(eocdOffset < fileLength);

    /*
     * Grab the CD offset and size, and the number of entries in the
     * archive.  Verify that they look reasonable.
     */
    u4 numEntries = get2LE(eocdPtr + kEOCDNumEntries);
    u4 dirSize = get4LE(eocdPtr + kEOCDSize);
    u4 dirOffset = get4LE(eocdPtr + kEOCDFileOffset);

    if ((long long) dirOffset + (long long) dirSize > (long long) eocdOffset) {
        LOGW("Zip: bad offsets (dir %ld, size %u, eocd %ld)\n",
            (long) dirOffset, dirSize, (long) eocdOffset);
        goto bail;
    }
    if (numEntries == 0) {
        LOGW("Zip: empty archive?\n");
        goto bail;
    }

    LOGV("+++ numEntries=%d dirSize=%d dirOffset=%d\n",
        numEntries, dirSize, dirOffset);

    /*
     * It all looks good.  Create a mapping for the CD, and set the fields
     * in pArchive.
     */
    if (sysMapFileSegmentInShmem(fd, dirOffset, dirSize,
            &pArchive->mDirectoryMap) != 0)
    {
        LOGW("Zip: cd map failed\n");
        goto bail;
    }

    pArchive->mNumEntries = numEntries;
    pArchive->mDirectoryOffset = dirOffset;

    result = 0;

bail:
    free(scanBuf);
    return result;
}
コード例 #9
0
ファイル: ZipArchive.c プロジェクト: sdklite/Dalvik_CAR
/*
 * Parses the Zip archive's Central Directory.  Allocates and populates the
 * hash table.
 *
 * Returns 0 on success.
 */
static int parseZipArchive(ZipArchive* pArchive)
{
    int result = -1;
    const u1* cdPtr = (const u1*)pArchive->mDirectoryMap.addr;
    size_t cdLength = pArchive->mDirectoryMap.length;
    int numEntries = pArchive->mNumEntries;

    /*
     * Create hash table.  We have a minimum 75% load factor, possibly as
     * low as 50% after we round off to a power of 2.  There must be at
     * least one unused entry to avoid an infinite loop during creation.
     */
    pArchive->mHashTableSize = dexRoundUpPower2(1 + (numEntries * 4) / 3);
    pArchive->mHashTable = (ZipHashEntry*)
            calloc(pArchive->mHashTableSize, sizeof(ZipHashEntry));

    /*
     * Walk through the central directory, adding entries to the hash
     * table and verifying values.
     */
    const u1* ptr = cdPtr;
    int i;
    for (i = 0; i < numEntries; i++) {
        if (get4LE(ptr) != kCDESignature) {
            LOGW("Zip: missed a central dir sig (at %d)\n", i);
            goto bail;
        }
        if (ptr + kCDELen > cdPtr + cdLength) {
            LOGW("Zip: ran off the end (at %d)\n", i);
            goto bail;
        }

        long localHdrOffset = (long) get4LE(ptr + kCDELocalOffset);
        if (localHdrOffset >= pArchive->mDirectoryOffset) {
            LOGW("Zip: bad LFH offset %ld at entry %d\n", localHdrOffset, i);
            goto bail;
        }

        unsigned int fileNameLen, extraLen, commentLen, hash;
        fileNameLen = get2LE(ptr + kCDENameLen);
        extraLen = get2LE(ptr + kCDEExtraLen);
        commentLen = get2LE(ptr + kCDECommentLen);

        /* add the CDE filename to the hash table */
        hash = computeHash((const char*)ptr + kCDELen, fileNameLen);
        addToHash(pArchive, (const char*)ptr + kCDELen, fileNameLen, hash);

        ptr += kCDELen + fileNameLen + extraLen + commentLen;
        if ((size_t)(ptr - cdPtr) > cdLength) {
            LOGW("Zip: bad CD advance (%d vs %zd) at entry %d\n",
                (int) (ptr - cdPtr), cdLength, i);
            goto bail;
        }
    }
    LOGV("+++ zip good scan %d entries\n", numEntries);

    result = 0;

bail:
    return result;
}
コード例 #10
0
/*
 * Get the useful fields from the zip entry.
 *
 * Returns "false" if the offsets to the fields or the contents of the fields
 * appear to be bogus.
 */
bool dexZipGetEntryInfo(const ZipArchive* pArchive, ZipEntry entry,
    int* pMethod, long* pUncompLen, long* pCompLen, off_t* pOffset,
    long* pModWhen, long* pCrc32)
{
    int ent = entryToIndex(pArchive, entry);
    if (ent < 0)
        return false;

    /*
     * Recover the start of the central directory entry from the filename
     * pointer.
     */
    const unsigned char* basePtr = (const unsigned char*)
        pArchive->mMap.addr;
    const unsigned char* ptr = (const unsigned char*)
        pArchive->mHashTable[ent].name;
    size_t zipLength =
        pArchive->mMap.length;

    ptr -= kCDELen;

    int method = get2LE(ptr + kCDEMethod);
    if (pMethod != NULL)
        *pMethod = method;

    if (pModWhen != NULL)
        *pModWhen = get4LE(ptr + kCDEModWhen);
    if (pCrc32 != NULL)
        *pCrc32 = get4LE(ptr + kCDECRC);

    /*
     * We need to make sure that the lengths are not so large that somebody
     * trying to map the compressed or uncompressed data runs off the end
     * of the mapped region.
     */
    unsigned long localHdrOffset = get4LE(ptr + kCDELocalOffset);
    if (localHdrOffset + kLFHLen >= zipLength) {
        LOGE("ERROR: bad local hdr offset in zip\n");
        return false;
    }
    const unsigned char* localHdr = basePtr + localHdrOffset;
    off_t dataOffset = localHdrOffset + kLFHLen
        + get2LE(localHdr + kLFHNameLen) + get2LE(localHdr + kLFHExtraLen);
    if ((unsigned long) dataOffset >= zipLength) {
        LOGE("ERROR: bad data offset in zip\n");
        return false;
    }

    if (pCompLen != NULL) {
        *pCompLen = get4LE(ptr + kCDECompLen);
        if (*pCompLen < 0 || (size_t)(dataOffset + *pCompLen) >= zipLength) {
            LOGE("ERROR: bad compressed length in zip\n");
            return false;
        }
    }
    if (pUncompLen != NULL) {
        *pUncompLen = get4LE(ptr + kCDEUncompLen);
        if (*pUncompLen < 0) {
            LOGE("ERROR: negative uncompressed length in zip\n");
            return false;
        }
        if (method == kCompressStored &&
            (size_t)(dataOffset + *pUncompLen) >= zipLength)
        {
            LOGE("ERROR: bad uncompressed length in zip\n");
            return false;
        }
    }

    if (pOffset != NULL) {
        *pOffset = dataOffset;
    }
    return true;
}
コード例 #11
0
void __android_log_btwrite_multiple__helper(int count) {
    log_time ts(CLOCK_MONOTONIC);

    struct logger_list *logger_list;
    ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
        LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, 0)));

    log_time ts1(CLOCK_MONOTONIC);

    pid_t pid = fork();

    if (pid == 0) {
        // child
        for (int i = count; i; --i) {
            ASSERT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)));
            usleep(100);
        }
        ASSERT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts1, sizeof(ts1)));
        usleep(1000000);

        _exit(0);
    }

    siginfo_t info{};
    ASSERT_EQ(0, TEMP_FAILURE_RETRY(waitid(P_PID, pid, &info, WEXITED)));

    int expected_count = (count < 2) ? count : 2;
    int expected_chatty_count = (count <= 2) ? 0 : 1;
    int expected_expire_count = (count < 2) ? 0 : (count - 2);

    count = 0;
    int second_count = 0;
    int chatty_count = 0;
    int expire_count = 0;

    for (;;) {
        log_msg log_msg;
        if (android_logger_list_read(logger_list, &log_msg) <= 0) break;

        if ((log_msg.entry.pid != pid) ||
            (log_msg.entry.len < (4 + 1 + 8)) ||
            (log_msg.id() != LOG_ID_EVENTS)) continue;

        char *eventData = log_msg.msg();
        if (!eventData) continue;

        uint32_t tag = get4LE(eventData);

        if ((eventData[4] == EVENT_TYPE_LONG) && (log_msg.entry.len == (4 + 1 + 8))) {
            if (tag != 0) continue;

            log_time tx(eventData + 4 + 1);
            if (ts == tx) {
                ++count;
            } else if (ts1 == tx) {
                ++second_count;
            }
        } else if (eventData[4] == EVENT_TYPE_STRING) {
            // chatty
            if (tag != 1004) continue;
            ++chatty_count;
            // int len = get4LE(eventData + 4 + 1);
            const char *cp = strstr(eventData + 4 + 1 + 4, " expire ");
            if (!cp) continue;
            unsigned val = 0;
            sscanf(cp, " expire %u lines", &val);
            expire_count += val;
        }
    }

    EXPECT_EQ(expected_count, count);
    EXPECT_EQ(1, second_count);
    EXPECT_EQ(expected_chatty_count, chatty_count);
    EXPECT_EQ(expected_expire_count, expire_count);

    android_logger_list_close(logger_list);
}
コード例 #12
0
/*
 * Parse the Zip archive, verifying its contents and initializing internal
 * data structures.
 */
static bool parseZipArchive(ZipArchive* pArchive, const MemMapping* pMap)
{
#define CHECK_OFFSET(_off) {                                                \
        if ((unsigned int) (_off) >= maxOffset) {                           \
            LOGE("ERROR: bad offset %u (max %d): %s\n",                     \
                (unsigned int) (_off), maxOffset, #_off);                   \
            goto bail;                                                      \
        }                                                                   \
    }
    bool result = false;
    const unsigned char* basePtr = (const unsigned char*)pMap->addr;
    const unsigned char* ptr;
    size_t length = pMap->length;
    unsigned int i, numEntries, cdOffset;
    unsigned int val;

    /*
     * The first 4 bytes of the file will either be the local header
     * signature for the first file (kLFHSignature) or, if the archive doesn't
     * have any files in it, the end-of-central-directory signature
     * (kEOCDSignature).
     */
    val = get4LE(basePtr);
    if (val == kEOCDSignature) {
        LOGI("Found Zip archive, but it looks empty\n");
        goto bail;
    } else if (val != kLFHSignature) {
        LOGV("Not a Zip archive (found 0x%08x)\n", val);
        goto bail;
    }

    /*
     * Find the EOCD.  We'll find it immediately unless they have a file
     * comment.
     */
    ptr = basePtr + length - kEOCDLen;

    while (ptr >= basePtr) {
        if (*ptr == (kEOCDSignature & 0xff) && get4LE(ptr) == kEOCDSignature)
            break;
        ptr--;
    }
    if (ptr < basePtr) {
        LOGI("Could not find end-of-central-directory in Zip\n");
        goto bail;
    }

    /*
     * There are two interesting items in the EOCD block: the number of
     * entries in the file, and the file offset of the start of the
     * central directory.
     *
     * (There's actually a count of the #of entries in this file, and for
     * all files which comprise a spanned archive, but for our purposes
     * we're only interested in the current file.  Besides, we expect the
     * two to be equivalent for our stuff.)
     */
    numEntries = get2LE(ptr + kEOCDNumEntries);
    cdOffset = get4LE(ptr + kEOCDFileOffset);

    /* valid offsets are [0,EOCD] */
    unsigned int maxOffset;
    maxOffset = (ptr - basePtr) +1;

    LOGV("+++ numEntries=%d cdOffset=%d\n", numEntries, cdOffset);
    if (numEntries == 0 || cdOffset >= length) {
        LOGW("Invalid entries=%d offset=%d (len=%zd)\n",
            numEntries, cdOffset, length);
        goto bail;
    }

    /*
     * Create hash table.  We have a minimum 75% load factor, possibly as
     * low as 50% after we round off to a power of 2.  There must be at
     * least one unused entry to avoid an infinite loop during creation.
     */
    pArchive->mNumEntries = numEntries;
    pArchive->mHashTableSize = dexRoundUpPower2(1 + (numEntries * 4) / 3);
    pArchive->mHashTable = (ZipHashEntry*)
            calloc(pArchive->mHashTableSize, sizeof(ZipHashEntry));

    /*
     * Walk through the central directory, adding entries to the hash
     * table.
     */
    ptr = basePtr + cdOffset;
    for (i = 0; i < numEntries; i++) {
        unsigned int fileNameLen, extraLen, commentLen, localHdrOffset;
        const unsigned char* localHdr;
        unsigned int hash;

        if (get4LE(ptr) != kCDESignature) {
            LOGW("Missed a central dir sig (at %d)\n", i);
            goto bail;
        }
        if (ptr + kCDELen > basePtr + length) {
            LOGW("Ran off the end (at %d)\n", i);
            goto bail;
        }

        localHdrOffset = get4LE(ptr + kCDELocalOffset);
        CHECK_OFFSET(localHdrOffset);
        fileNameLen = get2LE(ptr + kCDENameLen);
        extraLen = get2LE(ptr + kCDEExtraLen);
        commentLen = get2LE(ptr + kCDECommentLen);

        //LOGV("+++ %d: localHdr=%d fnl=%d el=%d cl=%d\n",
        //    i, localHdrOffset, fileNameLen, extraLen, commentLen);
        //LOGV(" '%.*s'\n", fileNameLen, ptr + kCDELen);

        /* add the CDE filename to the hash table */
        hash = computeHash((const char*)ptr + kCDELen, fileNameLen);
        addToHash(pArchive, (const char*)ptr + kCDELen, fileNameLen, hash);

        localHdr = basePtr + localHdrOffset;
        if (get4LE(localHdr) != kLFHSignature) {
            LOGW("Bad offset to local header: %d (at %d)\n",
                localHdrOffset, i);
            goto bail;
        }

        ptr += kCDELen + fileNameLen + extraLen + commentLen;
        CHECK_OFFSET(ptr - basePtr);
    }

    result = true;

bail:
    return result;
#undef CHECK_OFFSET
}
コード例 #13
0
ファイル: ZipArchive.cpp プロジェクト: 0x4d4e/platform_dalvik
static int mapCentralDirectory0(int fd, const char* debugFileName,
        ZipArchive* pArchive, off_t fileLength, size_t readAmount, u1* scanBuf)
{
    off_t searchStart = fileLength - readAmount;

    if (lseek(fd, searchStart, SEEK_SET) != searchStart) {
        LOGW("Zip: seek %ld failed: %s", (long) searchStart, strerror(errno));
        return -1;
    }
    ssize_t actual = TEMP_FAILURE_RETRY(read(fd, scanBuf, readAmount));
    if (actual != (ssize_t) readAmount) {
        LOGW("Zip: read %zd failed: %s", readAmount, strerror(errno));
        return -1;
    }

    /*
     * Scan backward for the EOCD magic.  In an archive without a trailing
     * comment, we'll find it on the first try.  (We may want to consider
     * doing an initial minimal read; if we don't find it, retry with a
     * second read as above.)
     */
    int i;
    for (i = readAmount - kEOCDLen; i >= 0; i--) {
        if (scanBuf[i] == 0x50 && get4LE(&scanBuf[i]) == kEOCDSignature) {
            LOGV("+++ Found EOCD at buf+%d", i);
            break;
        }
    }
    if (i < 0) {
        LOGD("Zip: EOCD not found, %s is not zip", debugFileName);
        return -1;
    }

    off_t eocdOffset = searchStart + i;
    const u1* eocdPtr = scanBuf + i;

    assert(eocdOffset < fileLength);

    /*
     * Grab the CD offset and size, and the number of entries in the
     * archive.  Verify that they look reasonable.
     */
    u4 numEntries = get2LE(eocdPtr + kEOCDNumEntries);
    u4 dirSize = get4LE(eocdPtr + kEOCDSize);
    u4 dirOffset = get4LE(eocdPtr + kEOCDFileOffset);

    if ((long long) dirOffset + (long long) dirSize > (long long) eocdOffset) {
        LOGW("Zip: bad offsets (dir %ld, size %u, eocd %ld)",
            (long) dirOffset, dirSize, (long) eocdOffset);
        return -1;
    }
    if (numEntries == 0) {
        LOGW("Zip: empty archive?");
        return -1;
    }

    LOGV("+++ numEntries=%d dirSize=%d dirOffset=%d",
        numEntries, dirSize, dirOffset);

    /*
     * It all looks good.  Create a mapping for the CD, and set the fields
     * in pArchive.
     */
    if (sysMapFileSegmentInShmem(fd, dirOffset, dirSize,
            &pArchive->mDirectoryMap) != 0)
    {
        LOGW("Zip: cd map failed");
        return -1;
    }

    pArchive->mNumEntries = numEntries;
    pArchive->mDirectoryOffset = dirOffset;

    return 0;
}
コード例 #14
0
ファイル: zip.c プロジェクト: chshxi1989/notes
int main(int argc, char** argv) {
    // get file size
    if( argc != 2) {
        printf("usage: zip [zipfilename]\n");
        return -1;
    }
    struct stat zipstat;
    int ret = stat(argv[1], &zipstat);
    if (ret != 0) {
        printf("stat file(%s) failed, %s\n", argv[1], strerror(errno));
        return -1;
    }
    long zipFileLength = zipstat.st_size;
    
    // get EOCD
    int fd = open(argv[1], O_RDONLY);
    if (fd == -1) {
        printf("can not open %s\n", argv[1]);
        return -1;
    }
    unsigned char eocdBuffer[ENDHDR];
    lseek(fd, zipFileLength - ENDHDR, SEEK_SET);
    read(fd, eocdBuffer, ENDHDR);
    unsigned int entrynum = get2LE(eocdBuffer + ENDSUB);
    unsigned int entryoffset = get4LE(eocdBuffer + ENDOFF);
    
    // search central directory area
    lseek(fd, entryoffset, SEEK_SET);
    int i = 0;
    unsigned char cdBuffer[CENHDR];
    uint32_t fileNameLen = 0;
    uint32_t extraLen = 0;
    uint32_t fileCommentLen = 0;
    uint32_t u32offset = entryoffset;
    char nameBuffer[PATH_MAX];
    for(i = 0; i < entrynum; i++) {
        printf("CD info offset: 0x%x\n", u32offset);
        read(fd, cdBuffer, CENHDR);
        uint32_t u32sig = get4LE(cdBuffer);
        if (u32sig != 0x02014b50) {
            printf("central directory sig error: 0x%x, expert 0x02014b50\n", u32sig);
            close(fd);
            return -1;
        }
        fileNameLen = get2LE(cdBuffer + CENNAM);
        extraLen = get2LE(cdBuffer + CENEXT);
        fileCommentLen = get2LE(cdBuffer + CENCOM);
        printf("fileNameLen: %d, extraLen: %d, fileCommentLen: %d\n", fileNameLen, extraLen, fileCommentLen);
        if (fileNameLen > PATH_MAX) {
            printf("file name length(0x%x) should not larger than PATH_MAX\n", fileNameLen);
            close(fd);
            return -1;
        }
        read(fd, nameBuffer, fileNameLen);
        nameBuffer[fileNameLen] = '\0';
        printf("num %d file name: %s\n", i, nameBuffer);
        // seek next central directory
        u32offset += CENHDR + fileNameLen + extraLen + fileCommentLen;
        lseek(fd, u32offset, SEEK_SET);
    }
    close(fd);
    return 0;
}
コード例 #15
0
ファイル: ZipArchive.cpp プロジェクト: Aireed/DexHunter
/*
 * Parses the Zip archive's Central Directory.  Allocates and populates the
 * hash table.
 *
 * Returns 0 on success.
 */
static int parseZipArchive(ZipArchive* pArchive)
{
    int result = -1;
    const u1* cdPtr = (const u1*)pArchive->mDirectoryMap.addr;
    size_t cdLength = pArchive->mDirectoryMap.length;
    int numEntries = pArchive->mNumEntries;

    /*
     * Create hash table.  We have a minimum 75% load factor, possibly as
     * low as 50% after we round off to a power of 2.  There must be at
     * least one unused entry to avoid an infinite loop during creation.
     */
    pArchive->mHashTableSize = dexRoundUpPower2(1 + (numEntries * 4) / 3);
    pArchive->mHashTable = (ZipHashEntry*)
            calloc(pArchive->mHashTableSize, sizeof(ZipHashEntry));

    /*
     * Walk through the central directory, adding entries to the hash
     * table and verifying values.
     */
    const u1* ptr = cdPtr;
    int i;
    for (i = 0; i < numEntries; i++) {
        if (get4LE(ptr) != kCDESignature) {
            ALOGW("Zip: missed a central dir sig (at %d)", i);
            goto bail;
        }
        if (ptr + kCDELen > cdPtr + cdLength) {
            ALOGW("Zip: ran off the end (at %d)", i);
            goto bail;
        }

        long localHdrOffset = (long) get4LE(ptr + kCDELocalOffset);
        if (localHdrOffset >= pArchive->mDirectoryOffset) {
            ALOGW("Zip: bad LFH offset %ld at entry %d", localHdrOffset, i);
            goto bail;
        }

        unsigned int gpbf = get2LE(ptr + kCDEGPBFlags);
        if ((gpbf & kGPFUnsupportedMask) != 0) {
            ALOGW("Invalid General Purpose Bit Flag: %d", gpbf);
            goto bail;
        }

        unsigned int nameLen, extraLen, commentLen, hash;
        nameLen = get2LE(ptr + kCDENameLen);
        extraLen = get2LE(ptr + kCDEExtraLen);
        commentLen = get2LE(ptr + kCDECommentLen);

        const char *name = (const char *) ptr + kCDELen;

        /* Check name for NULL characters */
        if (memchr(name, 0, nameLen) != NULL) {
            ALOGW("Filename contains NUL byte");
            goto bail;
        }

        /* add the CDE filename to the hash table */
        hash = computeHash(name, nameLen);
        addToHash(pArchive, name, nameLen, hash);

        /* We don't care about the comment or extra data. */
        ptr += kCDELen + nameLen + extraLen + commentLen;
        if ((size_t)(ptr - cdPtr) > cdLength) {
            ALOGW("Zip: bad CD advance (%d vs %zd) at entry %d",
                (int) (ptr - cdPtr), cdLength, i);
            goto bail;
        }
    }
    ALOGV("+++ zip good scan %d entries", numEntries);

    result = 0;

bail:
    return result;
}
コード例 #16
0
ファイル: ZipArchive.cpp プロジェクト: Aireed/DexHunter
static int mapCentralDirectory0(int fd, const char* debugFileName,
        ZipArchive* pArchive, off64_t fileLength, size_t readAmount, u1* scanBuf)
{
    /*
     * Make sure this is a Zip archive.
     */
    if (lseek64(pArchive->mFd, 0, SEEK_SET) != 0) {
        ALOGW("seek to start failed: %s", strerror(errno));
        return false;
    }

    ssize_t actual = TEMP_FAILURE_RETRY(read(pArchive->mFd, scanBuf, sizeof(int32_t)));
    if (actual != (ssize_t) sizeof(int32_t)) {
        ALOGI("couldn't read first signature from zip archive: %s", strerror(errno));
        return false;
    }

    unsigned int header = get4LE(scanBuf);
    if (header != kLFHSignature) {
        ALOGV("Not a Zip archive (found 0x%08x)\n", header);
        return false;
    }

    /*
     * Perform the traditional EOCD snipe hunt.
     *
     * We're searching for the End of Central Directory magic number,
     * which appears at the start of the EOCD block.  It's followed by
     * 18 bytes of EOCD stuff and up to 64KB of archive comment.  We
     * need to read the last part of the file into a buffer, dig through
     * it to find the magic number, parse some values out, and use those
     * to determine the extent of the CD.
     *
     * We start by pulling in the last part of the file.
     */
    off64_t searchStart = fileLength - readAmount;

    if (lseek64(pArchive->mFd, searchStart, SEEK_SET) != searchStart) {
        ALOGW("seek %ld failed: %s\n",  (long) searchStart, strerror(errno));
        return false;
    }
    actual = TEMP_FAILURE_RETRY(read(pArchive->mFd, scanBuf, readAmount));
    if (actual != (ssize_t) readAmount) {
        ALOGW("Zip: read %zd, expected %zd. Failed: %s\n",
            actual, readAmount, strerror(errno));
        return false;
    }


    /*
     * Scan backward for the EOCD magic.  In an archive without a trailing
     * comment, we'll find it on the first try.  (We may want to consider
     * doing an initial minimal read; if we don't find it, retry with a
     * second read as above.)
     */
    int i;
    for (i = readAmount - kEOCDLen; i >= 0; i--) {
        if (scanBuf[i] == 0x50 && get4LE(&scanBuf[i]) == kEOCDSignature) {
            ALOGV("+++ Found EOCD at buf+%d", i);
            break;
        }
    }
    if (i < 0) {
        ALOGD("Zip: EOCD not found, %s is not zip", debugFileName);
        return -1;
    }

    off64_t eocdOffset = searchStart + i;
    const u1* eocdPtr = scanBuf + i;

    assert(eocdOffset < fileLength);

    /*
     * Grab the CD offset and size, and the number of entries in the
     * archive.  Verify that they look reasonable.
     */
    u4 diskNumber = get2LE(eocdPtr + kEOCDDiskNumber);
    u4 diskWithCentralDir = get2LE(eocdPtr + kEOCDDiskNumberForCD);
    u4 numEntries = get2LE(eocdPtr + kEOCDNumEntries);
    u4 totalNumEntries = get2LE(eocdPtr + kEOCDTotalNumEntries);
    u4 centralDirSize = get4LE(eocdPtr + kEOCDSize);
    u4 centralDirOffset = get4LE(eocdPtr + kEOCDFileOffset);
    u4 commentSize = get2LE(eocdPtr + kEOCDCommentSize);

    // Verify that they look reasonable.
    if ((long long) centralDirOffset + (long long) centralDirSize > (long long) eocdOffset) {
        ALOGW("bad offsets (dir %ld, size %u, eocd %ld)\n",
            (long) centralDirOffset, centralDirSize, (long) eocdOffset);
        return false;
    }
    if (numEntries == 0) {
        ALOGW("empty archive?\n");
        return false;
    } else if (numEntries != totalNumEntries || diskNumber != 0 || diskWithCentralDir != 0) {
        ALOGW("spanned archives not supported");
        return false;
    }

    // Check to see if comment is a sane size
    if (((size_t) commentSize > (fileLength - kEOCDLen))
            || (eocdOffset > (fileLength - kEOCDLen) - commentSize)) {
        ALOGW("comment size runs off end of file");
        return false;
    }

    ALOGV("+++ numEntries=%d dirSize=%d dirOffset=%d\n",
        numEntries, centralDirSize, centralDirOffset);

    /*
     * It all looks good.  Create a mapping for the CD, and set the fields
     * in pArchive.
     */
    if (sysMapFileSegmentInShmem(fd, centralDirOffset, centralDirSize,
            &pArchive->mDirectoryMap) != 0)
    {
        ALOGW("Zip: cd map failed");
        return -1;
    }

    pArchive->mNumEntries = numEntries;
    pArchive->mDirectoryOffset = centralDirOffset;

    return 0;
}