/*
 * If appropriate, rewrite the path to point to a different location.
 *
 * Returns either "pathBuf" or "origPath" depending on whether or not we
 * chose to rewrite the path.  "origPath" must be a buffer capable of
 * holding an extended pathname; for best results use PATH_MAX.
 */
static const char* rewritePath(const char* func, char* pathBuf,
    const char* origPath)
{
    /*
     * Rewrite paths that start with "/system/" or "/data/"
     */
    if (origPath[0] != '/')
        goto skip_rewrite;
    if (memcmp(origPath+1, "system", 6) == 0 &&
        (origPath[7] == '/' || origPath[7] == '\0'))
            goto do_rewrite;
    if (memcmp(origPath+1, "data", 4) == 0 &&
        (origPath[5] == '/' || origPath[5] == '\0'))
            goto do_rewrite;

skip_rewrite:
    /* check to see if something is side-stepping the rewrite */
    if (memcmp(origPath, gWrapSim.remapBaseDir, gWrapSim.remapBaseDirLen) == 0)
    {
        wsLog("NOTE: full path used: %s(%s)\n", func, origPath);
    }

    CALLTRACE("rewrite %s('%s') --> (not rewritten)\n", func, origPath);
    return origPath;

do_rewrite:
    memcpy(pathBuf, gWrapSim.remapBaseDir, gWrapSim.remapBaseDirLen);
    strcpy(pathBuf + gWrapSim.remapBaseDirLen, origPath);
    CALLTRACE("rewrite %s('%s') --> '%s'\n", func, origPath, pathBuf);
    return pathBuf;
}
/*
 * Debug dump.
 */
static void dumpExecArgs(const char* callName, const char* path,
    int argc, const char* argv[], char* const envp[])
{
    int i;

    CALLTRACE("Calling %s '%s' (envp=%p)\n", callName, path, envp);
    for (i = 0; i <= argc; i++)
        CALLTRACE("  %d: %s\n", i, argv[i]);
}
static void doDestroyMemory(struct PVR2DPixmap *ppix)
{
	CALLTRACE("%s: Start\n", __func__);

#if SGX_CACHE_SEGMENTS
	if (AddToCache (ppix))
		return;
#endif

	if (ppix->pvr2dmem) {
		PVR2DMemFree(pvr2d_get_screen()->context, ppix->pvr2dmem);
		ppix->pvr2dmem = NULL;
	}

	if (ppix->shmid != -1) {
		shmdt(ppix->shmaddr);
		ppix->shmaddr = NULL;
		ppix->shmid = -1;
		PERF_DECREMENT2(shm_bytes, ppix->shmsize);
		PERF_DECREMENT(shm_segments);
		ppix->shmsize = 0;
	}

	if (ppix->mallocaddr) {
		free(ppix->mallocaddr);
		ppix->mallocaddr = NULL;
		PERF_DECREMENT2(malloc_bytes, ppix->mallocsize);
		PERF_DECREMENT(malloc_segments);
		ppix->mallocsize = 0;
	}
}
static Bool PVR2DAllocSHM(struct PVR2DPixmap *ppix)
{
	CALLTRACE("%s: Start\n", __func__);

	assert(!ppix->pvr2dmem);
	assert(ppix->shmid < 0);
	assert(!ppix->shmaddr);
	assert(!ppix->mallocaddr);
	assert(!ppix->mallocsize);

	if (!ppix->shmsize)
		return TRUE;

	assert(ppix->shmsize == ALIGN(ppix->shmsize, page_size));

#if SGX_CACHE_SEGMENTS
	if (GetFromCache (ppix))
	    if (ppix->shmaddr)
			return TRUE;
#endif

	ppix->shmid = shmget(IPC_PRIVATE, ppix->shmsize, IPC_CREAT | 0666);

	if (ppix->shmid == -1) {
		perror("shmget failed");
		return FALSE;
	}

	/* lock the SHM segment. This prevents swapping out the memory.
	 * Cache flush/invalidate could cause unhandled page fault
	 * if shared memory was swapped out
	 */
	if (0 != shmctl(ppix->shmid, SHM_LOCK, 0))
		ErrorF("shmctl(SHM_LOCK) failed\n");

	ppix->shmaddr = shmat(ppix->shmid, NULL, 0);

	/*
	 * Mark the segment as destroyed immediately. POSIX doesn't allow
	 * shmat() after this, but Linux does. This is much nicer since
	 * the segment can't be leaked if the X server crashes.
	 */
	shmctl(ppix->shmid, IPC_RMID, NULL);

	if (!ppix->shmaddr) {
		perror("shmat failed");
		ppix->shmid = -1;
		return FALSE;
	}

	/* Allocating memory makes it CPU owned and dirty */
	ppix->owner = PVR2D_OWNER_CPU;
	ppix->bCPUWrites = TRUE;

	PERF_INCREMENT2(shm_bytes, ppix->shmsize);
	PERF_INCREMENT(shm_segments);

	return TRUE;
}
/*
 * Opposite of path translation -- remove prefix.
 *
 * It looks like BSD allows you to pass a NULL value for "buf" to inspire
 * getcwd to allocate storage with malloc() (as an extension to the POSIX
 * definition, which doesn't specify this).  getcwd() is a system call
 * under Linux, so this doesn't work, but that doesn't stop gdb from
 * trying to use it anyway.
 */
char* getcwd(char* buf, size_t size)
{
    CALLTRACEV("%s %p %d\n", __FUNCTION__, buf, size);

    char* result = _ws_getcwd(buf, size);
    if (buf != NULL && result != NULL) {
        if (memcmp(buf, gWrapSim.remapBaseDir,
                    gWrapSim.remapBaseDirLen) == 0)
        {
            memmove(buf, buf + gWrapSim.remapBaseDirLen,
                strlen(buf + gWrapSim.remapBaseDirLen)+1);
            CALLTRACE("rewrite getcwd() -> %s\n", result);
        } else {
            CALLTRACE("not rewriting getcwd(%s)\n", result);
        }
    }
    return result;
}