/*
 * Copyright (C) 2008 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * Open an unoptimized DEX file.
 */

#include "Dalvik.h"
#include "libdex/OptInvocation.h"

#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

/*
 * Copy the given number of bytes from one fd to another, first
 * seeking the source fd to the start of the file.
 */
static int copyFileToFile(int destFd, int srcFd, size_t size)
{
    if (lseek(srcFd, 0, SEEK_SET) != 0) {
        LOGE("lseek failure: %s", strerror(errno));
        return -1;
    }

    return sysCopyFileToFile(destFd, srcFd, size);
}

/*
 * Get the modification time and size in bytes for the given fd.
 */
static int getModTimeAndSize(int fd, u4* modTime, size_t* size)
{
    struct stat buf;
    int result = fstat(fd, &buf);

    if (result < 0) {
        LOGE("Unable to determine mod time: %s", strerror(errno));
        return -1;
    }

    *modTime = (u4) buf.st_mtime;
    *size = (size_t) buf.st_size;
    assert((size_t) buf.st_size == buf.st_size);

    return 0;
}

/*
 * Verify the dex file magic number, and get the adler32 checksum out
 * of the given fd, which is presumed to be a reference to a dex file
 * with the cursor at the start of the file. The fd's cursor is
 * modified by this operation.
 */
static int verifyMagicAndGetAdler32(int fd, u4 *adler32)
{
    /*
     * The start of a dex file is eight bytes of magic followed by
     * four bytes of checksum.
     */
    u1 headerStart[12];
    ssize_t amt = read(fd, headerStart, sizeof(headerStart));

    if (amt < 0) {
        LOGE("Unable to read header: %s", strerror(errno));
        return -1;
    }

    if (amt != sizeof(headerStart)) {
        LOGE("Unable to read full header (only got %d bytes)", (int) amt);
        return -1;
    }

    if (!dexHasValidMagic((DexHeader*) (void*) headerStart)) {
        return -1;
    }

    /*
     * We can't just cast the data to a u4 and read it, since the
     * platform might be big-endian (also, because that would make the
     * compiler complain about type-punned pointers). We assume here
     * that the dex file is in the standard little-endian format; if
     * that assumption turns out to be invalid, code that runs later
     * will notice and complain.
     */
    *adler32 = (u4) headerStart[8]
        | (((u4) headerStart[9]) << 8)
        | (((u4) headerStart[10]) << 16)
        | (((u4) headerStart[11]) << 24);

    return 0;
}

/* See documentation comment in header. */
int dvmRawDexFileOpen(const char* fileName, const char* odexOutputName,
    RawDexFile** ppRawDexFile, bool isBootstrap)
{
    /*
     * TODO: This duplicates a lot of code from dvmJarFileOpen() in
     * JarFile.c. This should be refactored.
     */

    DvmDex* pDvmDex = NULL;
    char* cachedName = NULL;
    int result = -1;
    int dexFd = -1;
    int optFd = -1;
    u4 modTime = 0;
    u4 adler32 = 0;
    size_t fileSize = 0;
    bool newFile = false;
    bool locked = false;

    dexFd = open(fileName, O_RDONLY);
    if (dexFd < 0) goto bail;

    /* If we fork/exec into dexopt, don't let it inherit the open fd. */
    dvmSetCloseOnExec(dexFd);

    if (verifyMagicAndGetAdler32(dexFd, &adler32) < 0) {
        LOGE("Error with header for %s", fileName);
        goto bail;
    }

    if (getModTimeAndSize(dexFd, &modTime, &fileSize) < 0) {
        LOGE("Error with stat for %s", fileName);
        goto bail;
    }

    /*
     * See if the cached file matches. If so, optFd will become a reference
     * to the cached file and will have been seeked to just past the "opt"
     * header.
     */

    if (odexOutputName == NULL) {
        cachedName = dexOptGenerateCacheFileName(fileName, NULL);
        if (cachedName == NULL)
            goto bail;
    } else {
        cachedName = strdup(odexOutputName);
    }

    ALOGV("dvmRawDexFileOpen: Checking cache for %s (%s)",
            fileName, cachedName);

    optFd = dvmOpenCachedDexFile(fileName, cachedName, modTime,
        adler32, isBootstrap, &newFile, /*createIfMissing=*/true);

    if (optFd < 0) {
        ALOGI("Unable to open or create cache for %s (%s)",
                fileName, cachedName);
        goto bail;
    }
    locked = true;

    /*
     * If optFd points to a new file (because there was no cached
     * version, or the cached version was stale), generate the
     * optimized DEX. The file descriptor returned is still locked,
     * and is positioned just past the optimization header.
     */
    if (newFile) {
        u8 startWhen, copyWhen, endWhen;
        bool result;
        off_t dexOffset;

        dexOffset = lseek(optFd, 0, SEEK_CUR);
        result = (dexOffset > 0);

        if (result) {
            startWhen = dvmGetRelativeTimeUsec();
            result = copyFileToFile(optFd, dexFd, fileSize) == 0;
            copyWhen = dvmGetRelativeTimeUsec();
        }

        if (result) {
            result = dvmOptimizeDexFile(optFd, dexOffset, fileSize,
                fileName, modTime, adler32, isBootstrap);
        }

        if (!result) {
            LOGE("Unable to extract+optimize DEX from '%s'", fileName);
            goto bail;
        }

        endWhen = dvmGetRelativeTimeUsec();
        ALOGD("DEX prep '%s': copy in %dms, rewrite %dms",
            fileName,
            (int) (copyWhen - startWhen) / 1000,
            (int) (endWhen - copyWhen) / 1000);
    }

    /*
     * Map the cached version.  This immediately rewinds the fd, so it
     * doesn't have to be seeked anywhere in particular.
     */
    if (dvmDexFileOpenFromFd(optFd, &pDvmDex) != 0) {
        ALOGI("Unable to map cached %s", fileName);
        goto bail;
    }

    if (locked) {
        /* unlock the fd */
        if (!dvmUnlockCachedDexFile(optFd)) {
            /* uh oh -- this process needs to exit or we'll wedge the system */
            LOGE("Unable to unlock DEX file");
            goto bail;
        }
        locked = false;
    }

    ALOGV("Successfully opened '%s'", fileName);

    *ppRawDexFile = (RawDexFile*) calloc(1, sizeof(RawDexFile));
    (*ppRawDexFile)->cacheFileName = cachedName;
    (*ppRawDexFile)->pDvmDex = pDvmDex;
    cachedName = NULL;      // don't free it below
    result = 0;

bail:
    free(cachedName);
    if (dexFd >= 0) {
        close(dexFd);
    }
    if (optFd >= 0) {
        if (locked)
            (void) dvmUnlockCachedDexFile(optFd);
        close(optFd);
    }
    return result;
}

/* See documentation comment in header. */
int dvmRawDexFileOpenArray(u1* pBytes, u4 length, RawDexFile** ppRawDexFile)
{
    DvmDex* pDvmDex = NULL;

    if (!dvmPrepareDexInMemory(pBytes, length, &pDvmDex)) {
        ALOGD("Unable to open raw DEX from array");
        return -1;
    }
    assert(pDvmDex != NULL);

    *ppRawDexFile = (RawDexFile*) calloc(1, sizeof(RawDexFile));
    (*ppRawDexFile)->pDvmDex = pDvmDex;

    return 0;
}

/*
 * Close a RawDexFile and free the struct.
 */
void dvmRawDexFileFree(RawDexFile* pRawDexFile)
{
    if (pRawDexFile == NULL)
        return;

    dvmDexFileFree(pRawDexFile->pDvmDex);
    free(pRawDexFile->cacheFileName);
    free(pRawDexFile);
}
