/*
 * Extract all binaries (type 'b') and all data files (type 'x') to the filesystem
 * and checks for dependencies (type 'd'). If dependencies are found, extract them.
 *
 * 'Multipackage' feature includes dependencies. Dependencies are files in other
 * .exe files. Having files in other executables allows share binary files among
 * executables and thus reduce the final size of the executable.
 */
int pyi_launch_extract_binaries(ARCHIVE_STATUS *archive_status)
{
    int retcode = 0;
    ptrdiff_t index = 0;

    /*
     * archive_pool[0] is reserved for the main process, the others for dependencies.
     */
    ARCHIVE_STATUS *archive_pool[_MAX_ARCHIVE_POOL_LEN];
	TOC * ptoc = archive_status->tocbuff;

    /* Clean memory for archive_pool list. */
    memset(&archive_pool, 0, _MAX_ARCHIVE_POOL_LEN * sizeof(ARCHIVE_STATUS *));

    /* Current process is the 1st item. */
    archive_pool[0] = archive_status;

	VS("LOADER: Extracting binaries\n");

	while (ptoc < archive_status->tocend) {
		if (ptoc->typcd == ARCHIVE_ITEM_BINARY || ptoc->typcd == ARCHIVE_ITEM_DATA ||
                ptoc->typcd == ARCHIVE_ITEM_ZIPFILE) {
			if (pyi_arch_extract2fs(archive_status, ptoc)) {
				retcode = -1;
                break;  /* No need to extract other items in case of error. */
            }
        }

        else {
            /* 'Multipackage' feature - dependency is stored in different executables. */
            if (ptoc->typcd == ARCHIVE_ITEM_DEPENDENCY) {
                if (_extract_dependency(archive_pool, ptoc->name) == -1) {
                    retcode = -1;
                    break;  /* No need to extract other items in case of error. */
                }

            }
        }
		ptoc = pyi_arch_increment_toc_ptr(archive_status, ptoc);
	}


    /*
     * Free memory allocated for archive_pool data. Do not free memory
     * of the main process - start with 2nd item.
     */
    for (index = 1; archive_pool[index] != NULL; index++) {
        pyi_arch_status_free_memory(archive_pool[index]);
    }

	return retcode;
}
/*
 * Check if binaries need to be extracted. If not, this is probably a onedir solution,
 * and a child process will not be required on windows.
 */
int pyi_launch_need_to_extract_binaries(ARCHIVE_STATUS *archive_status)
{
	TOC * ptoc = archive_status->tocbuff;
	while (ptoc < archive_status->tocend) {
		if (ptoc->typcd == ARCHIVE_ITEM_BINARY || ptoc->typcd == ARCHIVE_ITEM_DATA ||
                ptoc->typcd == ARCHIVE_ITEM_ZIPFILE)
            return true;
        if (ptoc->typcd == ARCHIVE_ITEM_DEPENDENCY) {
            return true;
        }
		ptoc = pyi_arch_increment_toc_ptr(archive_status, ptoc);
	}
	return false;
}
/* Extract a file identifed by filename from the archive associated to status. */
static int extractDependencyFromArchive(ARCHIVE_STATUS *status, const char *filename)
{
	TOC * ptoc = status->tocbuff;
	VS("LOADER: Extracting dependencies from archive\n");
	while (ptoc < status->tocend) {
		if (strcmp(ptoc->name, filename) == 0) {
			if (pyi_arch_extract2fs(status, ptoc)) {
				return -1;
            }
        }
		ptoc = pyi_arch_increment_toc_ptr(status, ptoc);
	}
	return 0;
}
Beispiel #4
0
/*
 * Install PYZ
 * Return non zero on failure
 */
int pyi_pylib_install_zlibs(ARCHIVE_STATUS *status)
{
	TOC * ptoc;
	VS("LOADER: Installing PYZ archive with Python modules.\n");

	/* Iterate through toc looking for zlibs (PYZ, type 'z') */
	ptoc = status->tocbuff;
	while (ptoc < status->tocend) {
		if (ptoc->typcd == ARCHIVE_ITEM_PYZ)
		{
			VS("LOADER: PYZ archive: %s\n", ptoc->name);
			pyi_pylib_install_zlib(status, ptoc);
		}

		ptoc = pyi_arch_increment_toc_ptr(status, ptoc);
	}
	return 0;
}
Beispiel #5
0
/*
 * Run scripts
 * Return non zero on failure
 */
int pyi_pylib_run_scripts(ARCHIVE_STATUS *status)
{
	unsigned char *data;
	char buf[PATH_MAX];
	int rc = 0;
	TOC * ptoc = status->tocbuff;
	PyObject *__main__ = PI_PyImport_AddModule("__main__");
	PyObject *__file__;
	VS("LOADER: Running scripts\n");

	/* Iterate through toc looking for scripts (type 's') */
	while (ptoc < status->tocend) {
		if (ptoc->typcd == ARCHIVE_ITEM_PYSOURCE) {
			/* Get data out of the archive.  */
			data = pyi_arch_extract(status, ptoc);
			/* Set the __file__ attribute within the __main__ module,
			   for full compatibility with normal execution. */
			strcpy(buf, ptoc->name);
			strcat(buf, ".py");
			VS("LOADER: Running %s\n", buf);
            __file__ = PI_PyString_FromStringAndSize(buf, strlen(buf));
            PI_PyObject_SetAttrString(__main__, "__file__", __file__);
            Py_DECREF(__file__);
			/* Run it */
			rc = PI_PyRun_SimpleString((char *) data);
			/* log errors and abort */
			if (rc != 0) {
				VS("LOADER: RC: %d from %s\n", rc, ptoc->name);
				return rc;
			}
			free(data);
		}

		ptoc = pyi_arch_increment_toc_ptr(status, ptoc);
	}
	return 0;
}
Beispiel #6
0
/*
 * Import modules embedded in the archive - return 0 on success
 */
int pyi_pylib_import_modules(ARCHIVE_STATUS *status)
{
	PyObject *marshal;
	PyObject *marshaldict;
	PyObject *loadfunc;
	TOC *ptoc;
	PyObject *co;
	PyObject *mod;
	PyObject *meipass_obj;
	char * meipass_ansi;

	VS("LOADER: setting sys._MEIPASS\n");
	// TODO extract function pyi_char_to_pyobject
	if(is_py2) {
#ifdef _WIN32
		meipass_ansi = pyi_win32_utf8_to_mbs_sfn(NULL, status->mainpath, 0);
		if(!meipass_ansi) {
			FATALERROR("Failed to encode _MEIPASS as ANSI.\n");
			return -1;
		}
		meipass_obj = PI_PyString_FromString(meipass_ansi);
		free(meipass_ansi);
#else
		meipass_obj = PI_PyString_FromString(status->mainpath);
#endif
	} else {
#ifdef _WIN32
		meipass_obj = PI_PyUnicode_Decode(status->mainpath,
									      strlen(status->mainpath),
										  "utf-8",
										  "strict");
#else
		meipass_obj = PI_PyUnicode_DecodeFSDefault(status->mainpath);
#endif
	}
	if(!meipass_obj) {
		FATALERROR("Failed to get _MEIPASS as PyObject.\n");
		return -1;
	}

	PI_PySys_SetObject("_MEIPASS", meipass_obj);

	VS("LOADER: importing modules from CArchive\n");

	/* Get the Python function marshall.load
		* Here we collect some reference to PyObject that we don't dereference
		* Doesn't matter because the objects won't be going away anyway.
		*/
	marshal = PI_PyImport_ImportModule("marshal");
	marshaldict = PI_PyModule_GetDict(marshal);
	loadfunc = PI_PyDict_GetItemString(marshaldict, "loads");

	/* Iterate through toc looking for module entries (type 'm')
		* this is normally just bootstrap stuff (archive and iu)
		*/
	ptoc = status->tocbuff;
	while (ptoc < status->tocend) {
		if (ptoc->typcd == ARCHIVE_ITEM_PYMODULE || ptoc->typcd == ARCHIVE_ITEM_PYPACKAGE)
		{
			unsigned char *modbuf = pyi_arch_extract(status, ptoc);

			VS("LOADER: extracted %s\n", ptoc->name);

			/* .pyc/.pyo files have 8 bytes header. Skip it and load marshalled
			 * data form the right point.
			 */
			if (is_py2) {
			  co = PI_PyObject_CallFunction(loadfunc, "s#", modbuf+8, ntohl(ptoc->ulen)-8);
			} else {
			  // It looks like from python 3.3 the header
			  // size was changed to 12 bytes.
			  co = PI_PyObject_CallFunction(loadfunc, "y#", modbuf+12, ntohl(ptoc->ulen)-12);
			};
			if (co != NULL) {
				VS("LOADER: callfunction returned...\n");
				mod = PI_PyImport_ExecCodeModule(ptoc->name, co);
			} else {
                // TODO callfunctions might return NULL - find yout why and foor what modules.
				VS("LOADER: callfunction returned NULL");
				mod = NULL;
			}

			/* Check for errors in loading */
			if (mod == NULL) {
				FATALERROR("mod is NULL - %s", ptoc->name);
			}
			if (PI_PyErr_Occurred())
			{
				PI_PyErr_Print();
				PI_PyErr_Clear();
			}

			free(modbuf);
		}
		ptoc = pyi_arch_increment_toc_ptr(status, ptoc);
	}

	return 0;
}
Beispiel #7
0
/*
 * A toc entry of type 'o' holds runtime options
 * toc->name is the arg
 * this is so you can freeze in command line args to Python
 */
static int pyi_pylib_set_runtime_opts(ARCHIVE_STATUS *status)
{
	int unbuffered = 0;
	TOC *ptoc = status->tocbuff;
	wchar_t wchar_tmp[PATH_MAX+1];

	/*
     * Startup flags - default values. 1 means enabled, 0 disabled.
     */
     /* Suppress 'import site'. */
	*PI_Py_NoSiteFlag = 1;
	/* Needed by getpath.c from Python. */
    *PI_Py_FrozenFlag = 1;
    /* Suppress writing bytecode files (*.py[co]) */
    *PI_Py_DontWriteBytecodeFlag = 1;
    /* Do not try to find any packages in user's site directory. */
    *PI_Py_NoUserSiteDirectory = 1;
    /* This flag ensures PYTHONPATH and PYTHONHOME are ignored by Python. */
    *PI_Py_IgnoreEnvironmentFlag = 1;
    /* Disalbe verbose imports by default. */
    *PI_Py_VerboseFlag = 0;

    /* Override some runtime options by custom values from PKG archive.
     * User is allowed to changes these options. */
	for (; ptoc < status->tocend; ptoc = pyi_arch_increment_toc_ptr(status, ptoc)) {
		if (ptoc->typcd == ARCHIVE_ITEM_RUNTIME_OPTION) {
			if(0 == strncmp(ptoc->name, "pyi-", 4)) {
				VS("LOADER: Bootloader option: %s\n", ptoc->name);
				continue;  // Not handled here - use pyi_arch_get_option(status, ...)
			}
			VS("LOADER: Runtime option: %s\n", ptoc->name);
			switch (ptoc->name[0]) {
			case 'v':
				*PI_Py_VerboseFlag = 1;
			break;
			case 'u':
				unbuffered = 1;
			break;
			case 'W':
			  if (is_py2) {
			    PI_Py2Sys_AddWarnOption(&ptoc->name[2]);
			  } else {
			    // TODO: what encoding is ptoc->name? May not be important
			    // as all known Wflags are ASCII.
			    if ((size_t)-1 == mbstowcs(wchar_tmp, &ptoc->name[2], PATH_MAX)) {
			      FATALERROR("Failed to convert Wflag %s using mbstowcs "
			                 "(invalid multibyte string)", &ptoc->name[2]);
			      return -1;
			    }
			    PI_PySys_AddWarnOption(wchar_tmp);
			  };
			  break;
			case 'O':
				*PI_Py_OptimizeFlag = 1;
			break;
			}
		}
	}
	if (unbuffered) {
#ifdef _WIN32
		_setmode(fileno(stdin), _O_BINARY);
		_setmode(fileno(stdout), _O_BINARY);
#endif
		fflush(stdout);
		fflush(stderr);

		setbuf(stdin, (char *)NULL);
		setbuf(stdout, (char *)NULL);
		setbuf(stderr, (char *)NULL);
	}
	return 0;
}
Beispiel #8
0
/*
 * Run scripts
 * Return non zero on failure
 */
int
pyi_launch_run_scripts(ARCHIVE_STATUS *status)
{
    unsigned char *data;
    char buf[PATH_MAX];
    size_t namelen;
    TOC * ptoc = status->tocbuff;
    PyObject *__main__;
    PyObject *__file__;
    PyObject *main_dict;
    PyObject *code, *retval;

    __main__ = PI_PyImport_AddModule("__main__");

    if (!__main__) {
        FATALERROR("Could not get __main__ module.");
        return -1;
    }

    main_dict = PI_PyModule_GetDict(__main__);

    if (!main_dict) {
        FATALERROR("Could not get __main__ module's dict.");
        return -1;
    }

    /* Iterate through toc looking for scripts (type 's') */
    while (ptoc < status->tocend) {
        if (ptoc->typcd == ARCHIVE_ITEM_PYSOURCE) {
            /* Get data out of the archive.  */
            data = pyi_arch_extract(status, ptoc);
            /* Set the __file__ attribute within the __main__ module,
             *  for full compatibility with normal execution. */
            namelen = strnlen(ptoc->name, PATH_MAX);
            if (namelen >= PATH_MAX-strlen(".py")-1) {
                FATALERROR("Name exceeds PATH_MAX\n");
                return -1;
            }

            strcpy(buf, ptoc->name);
            strcat(buf, ".py");
            VS("LOADER: Running %s\n", buf);

            if (is_py2) {
                __file__ = PI_PyString_FromString(buf);
            }
            else {
                __file__ = PI_PyUnicode_FromString(buf);
            };
            PI_PyObject_SetAttrString(__main__, "__file__", __file__);
            Py_DECREF(__file__);

            /* Unmarshall code object */
            code = PI_PyMarshal_ReadObjectFromString((const char *) data, ntohl(ptoc->ulen));

            if (!code) {
                FATALERROR("Failed to unmarshal code object for %s\n", ptoc->name);
                PI_PyErr_Print();
                return -1;
            }
            /* Run it */
            retval = PI_PyEval_EvalCode(code, main_dict, main_dict);

            /* If retval is NULL, an error occured. Otherwise, it is a Python object.
             * (Since we evaluate module-level code, which is not allowed to return an
             * object, the Python object returned is always None.) */
            if (!retval) {
                PI_PyErr_Print();
                /* If the error was SystemExit, PyErr_Print calls exit() without
                 * returning. So don't print "Failed to execute" on SystemExit. */
                FATALERROR("Failed to execute script %s\n", ptoc->name);
                return -1;
            }
            free(data);
        }

        ptoc = pyi_arch_increment_toc_ptr(status, ptoc);
    }
    return 0;
}