From bd65a5efa174eaba46d096827968573ec2e8853b Mon Sep 17 00:00:00 2001 From: Castro-Fidel Date: Sun, 10 May 2020 20:01:48 +0300 Subject: [PATCH] Proton files embedded --- data_from_portwine/LICENSE | 221 ++++++ data_from_portwine/filelock.py | 451 +++++++++++ data_from_portwine/proton | 708 ++++++++++++++++++ .../scripts}/debug | 0 .../scripts}/lang | 0 .../scripts}/port_update | 0 .../scripts}/remove | 0 .../scripts}/restart | 0 .../scripts}/runlib | 0 .../scripts}/setup | 0 .../scripts}/start | 0 .../scripts}/vars | 0 .../scripts}/wineboot | 0 .../scripts}/winecfg | 0 .../scripts}/winecmd | 0 .../scripts}/winefile | 0 .../scripts}/winereg | 0 .../scripts}/winetricks | 0 .../scripts}/winetricks-q-force | 0 19 files changed, 1380 insertions(+) create mode 100644 data_from_portwine/LICENSE create mode 100644 data_from_portwine/filelock.py create mode 100755 data_from_portwine/proton rename {portwine_run_scripts => data_from_portwine/scripts}/debug (100%) rename {portwine_run_scripts => data_from_portwine/scripts}/lang (100%) rename {portwine_run_scripts => data_from_portwine/scripts}/port_update (100%) rename {portwine_run_scripts => data_from_portwine/scripts}/remove (100%) rename {portwine_run_scripts => data_from_portwine/scripts}/restart (100%) rename {portwine_run_scripts => data_from_portwine/scripts}/runlib (100%) rename {portwine_run_scripts => data_from_portwine/scripts}/setup (100%) rename {portwine_run_scripts => data_from_portwine/scripts}/start (100%) rename {portwine_run_scripts => data_from_portwine/scripts}/vars (100%) rename {portwine_run_scripts => data_from_portwine/scripts}/wineboot (100%) rename {portwine_run_scripts => data_from_portwine/scripts}/winecfg (100%) rename {portwine_run_scripts => data_from_portwine/scripts}/winecmd (100%) rename {portwine_run_scripts => data_from_portwine/scripts}/winefile (100%) rename {portwine_run_scripts => data_from_portwine/scripts}/winereg (100%) rename {portwine_run_scripts => data_from_portwine/scripts}/winetricks (100%) rename {portwine_run_scripts => data_from_portwine/scripts}/winetricks-q-force (100%) diff --git a/data_from_portwine/LICENSE b/data_from_portwine/LICENSE new file mode 100644 index 00000000..69c95ec4 --- /dev/null +++ b/data_from_portwine/LICENSE @@ -0,0 +1,221 @@ +Copyright (c) 2018-2020, Valve Corporation +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Browse the source code for more information + + https://github.com/ValveSoftware/Proton + +---- ---- ---- ---- + +This software contains a modified version of Wine licensed under the LGPL 2.1. Wine is + + Copyright (c) 1993-2020 the Wine project authors + +Visit Wine at + + https://winehq.org + +View our modifications at + + https://github.com/ValveSoftware/wine + +---- ---- ---- ---- + +This software contains a modified version of DXVK licensed under the zlib/libpng license. DXVK is + + Copyright (c) 2017-2020 Philip Rebohle + Copyright (c) 2019-2020 Joshua Ashton + +Visit DXVK at + + https://github.com/doitsujin/dxvk + +View our modifications at + + https://github.com/ValveSoftware/dxvk + +---- ---- ---- ---- + +This software contains FAudio licensed under the zlib license. FAudio is + + Copyright (c) 2011-2020 Ethan Lee, Luigi Auriemma, and the MonoGame Team + +Visit FAudio at + + https://github.com/FNA-XNA/FAudio + +---- ---- ---- ---- + +This software contains some Liberation Fonts licensed under the SIL Open Font License, available at LICENSE.OFL. These fonts are + + Copyright (c) 2010 Google Corporation + Copyright (c) 2012 Red Hat, Inc. + +Visit Liberation Fonts at + + https://github.com/liberationfonts/liberation-fonts + +---- ---- ---- ---- + +This software contains Source Han Sans licensed under the SIL Open Font License, available at LICENSE.OFL. This font is + + Copyright 2014-2019 Adobe (http://www.adobe.com/) + +Visit Source Han Sans at + + https://github.com/adobe-fonts/source-han-sans + +---- ---- ---- ---- + +This software contains wine-mono, parts of which are included under a variety of licenses. + + Parts of Mono (mono/) are variously licensed under the GPL, LGPL, and MIT X11 licenses. All parts are available as LGPL or MIT X11 except for the following: + * The ICSharpCode.SharpZipLib library is available as GPL with an exception (see mono/mcs/class/ICSharpCode.SharpZipLib/README). + * mcs/jay is BSD-licensed. + + The Visual Basic class libraries (mono-basic/) are MIT X11. The compiler is LGPL v2. + + FNA is a mix of MSPL and MIT. It has the following library dependencies: + * FAudio, MojoShader, Theorafile, SDL2, SDL_image_compact, and SDL2-CS are zlib-licensed. SDL2-CS is built into FNA.dll. + * FNA.NetStub is MSPL. + + The winforms and wpf libraries are MIT. + +wine-mono itself is included under the MIT license. wine-mono is + + Copyright (c) 2012 Vincent Povirk for CodeWeavers + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +Visit wine-mono at + + https://github.com/madewokherd/wine-mono + +View wine-mono's complete license at + + https://github.com/madewokherd/wine-mono/blob/master/COPYING + +---- ---- ---- ---- + +This software contains wine-gecko, parts of which are included under a variety of licenses. + +wine-gecko itself is included under the Mozilla Public License 2.0. + +wine-gecko is available in Source Code form at + + https://sourceforge.net/p/wine/wine-gecko + +---- ---- ---- ---- + +This software contains a modified version of Vkd3d licensed under the LGPL 2.1. Vkd3d is + + Copyright 2016-2019 the Vkd3d project authors + +Visit Vkd3d at + + https://source.winehq.org/git/vkd3d.git + +View our modifications at + + https://github.com/ValveSoftware/vkd3d + +---- ---- ---- ---- + +Parts of this software are based on the OpenVR SDK, which is + + Copyright (c) 2015, Valve Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Visit OpenVR at + + https://github.com/ValveSoftware/openvr + +---- ---- ---- ---- + +Parts of this software are based on the AMD AGS library, which is + + Copyright (c) 2017 Advanced Micro Devices, Inc. All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. diff --git a/data_from_portwine/filelock.py b/data_from_portwine/filelock.py new file mode 100644 index 00000000..4c981672 --- /dev/null +++ b/data_from_portwine/filelock.py @@ -0,0 +1,451 @@ +# This is free and unencumbered software released into the public domain. +# +# Anyone is free to copy, modify, publish, use, compile, sell, or +# distribute this software, either in source code form or as a compiled +# binary, for any purpose, commercial or non-commercial, and by any +# means. +# +# In jurisdictions that recognize copyright laws, the author or authors +# of this software dedicate any and all copyright interest in the +# software to the public domain. We make this dedication for the benefit +# of the public at large and to the detriment of our heirs and +# successors. We intend this dedication to be an overt act of +# relinquishment in perpetuity of all present and future rights to this +# software under copyright law. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +# For more information, please refer to + +""" +A platform independent file lock that supports the with-statement. +""" + + +# Modules +# ------------------------------------------------ +import logging +import os +import threading +import time +try: + import warnings +except ImportError: + warnings = None + +try: + import msvcrt +except ImportError: + msvcrt = None + +try: + import fcntl +except ImportError: + fcntl = None + + +# Backward compatibility +# ------------------------------------------------ +try: + TimeoutError +except NameError: + TimeoutError = OSError + + +# Data +# ------------------------------------------------ +__all__ = [ + "Timeout", + "BaseFileLock", + "WindowsFileLock", + "UnixFileLock", + "SoftFileLock", + "FileLock" +] + +__version__ = "3.0.12" + + +_logger = None +def logger(): + """Returns the logger instance used in this module.""" + global _logger + _logger = _logger or logging.getLogger(__name__) + return _logger + + +# Exceptions +# ------------------------------------------------ +class Timeout(TimeoutError): + """ + Raised when the lock could not be acquired in *timeout* + seconds. + """ + + def __init__(self, lock_file): + """ + """ + #: The path of the file lock. + self.lock_file = lock_file + return None + + def __str__(self): + temp = "The file lock '{}' could not be acquired."\ + .format(self.lock_file) + return temp + + +# Classes +# ------------------------------------------------ + +# This is a helper class which is returned by :meth:`BaseFileLock.acquire` +# and wraps the lock to make sure __enter__ is not called twice when entering +# the with statement. +# If we would simply return *self*, the lock would be acquired again +# in the *__enter__* method of the BaseFileLock, but not released again +# automatically. +# +# :seealso: issue #37 (memory leak) +class _Acquire_ReturnProxy(object): + + def __init__(self, lock): + self.lock = lock + return None + + def __enter__(self): + return self.lock + + def __exit__(self, exc_type, exc_value, traceback): + self.lock.release() + return None + + +class BaseFileLock(object): + """ + Implements the base class of a file lock. + """ + + def __init__(self, lock_file, timeout = -1): + """ + """ + # The path to the lock file. + self._lock_file = lock_file + + # The file descriptor for the *_lock_file* as it is returned by the + # os.open() function. + # This file lock is only NOT None, if the object currently holds the + # lock. + self._lock_file_fd = None + + # The default timeout value. + self.timeout = timeout + + # We use this lock primarily for the lock counter. + self._thread_lock = threading.Lock() + + # The lock counter is used for implementing the nested locking + # mechanism. Whenever the lock is acquired, the counter is increased and + # the lock is only released, when this value is 0 again. + self._lock_counter = 0 + return None + + @property + def lock_file(self): + """ + The path to the lock file. + """ + return self._lock_file + + @property + def timeout(self): + """ + You can set a default timeout for the filelock. It will be used as + fallback value in the acquire method, if no timeout value (*None*) is + given. + + If you want to disable the timeout, set it to a negative value. + + A timeout of 0 means, that there is exactly one attempt to acquire the + file lock. + + .. versionadded:: 2.0.0 + """ + return self._timeout + + @timeout.setter + def timeout(self, value): + """ + """ + self._timeout = float(value) + return None + + # Platform dependent locking + # -------------------------------------------- + + def _acquire(self): + """ + Platform dependent. If the file lock could be + acquired, self._lock_file_fd holds the file descriptor + of the lock file. + """ + raise NotImplementedError() + + def _release(self): + """ + Releases the lock and sets self._lock_file_fd to None. + """ + raise NotImplementedError() + + # Platform independent methods + # -------------------------------------------- + + @property + def is_locked(self): + """ + True, if the object holds the file lock. + + .. versionchanged:: 2.0.0 + + This was previously a method and is now a property. + """ + return self._lock_file_fd is not None + + def acquire(self, timeout=None, poll_intervall=0.05): + """ + Acquires the file lock or fails with a :exc:`Timeout` error. + + .. code-block:: python + + # You can use this method in the context manager (recommended) + with lock.acquire(): + pass + + # Or use an equivalent try-finally construct: + lock.acquire() + try: + pass + finally: + lock.release() + + :arg float timeout: + The maximum time waited for the file lock. + If ``timeout < 0``, there is no timeout and this method will + block until the lock could be acquired. + If ``timeout`` is None, the default :attr:`~timeout` is used. + + :arg float poll_intervall: + We check once in *poll_intervall* seconds if we can acquire the + file lock. + + :raises Timeout: + if the lock could not be acquired in *timeout* seconds. + + .. versionchanged:: 2.0.0 + + This method returns now a *proxy* object instead of *self*, + so that it can be used in a with statement without side effects. + """ + # Use the default timeout, if no timeout is provided. + if timeout is None: + timeout = self.timeout + + # Increment the number right at the beginning. + # We can still undo it, if something fails. + with self._thread_lock: + self._lock_counter += 1 + + lock_id = id(self) + lock_filename = self._lock_file + start_time = time.time() + try: + while True: + with self._thread_lock: + if not self.is_locked: + logger().debug('Attempting to acquire lock %s on %s', lock_id, lock_filename) + self._acquire() + + if self.is_locked: + logger().info('Lock %s acquired on %s', lock_id, lock_filename) + break + elif timeout >= 0 and time.time() - start_time > timeout: + logger().debug('Timeout on acquiring lock %s on %s', lock_id, lock_filename) + raise Timeout(self._lock_file) + else: + logger().debug( + 'Lock %s not acquired on %s, waiting %s seconds ...', + lock_id, lock_filename, poll_intervall + ) + time.sleep(poll_intervall) + except: + # Something did go wrong, so decrement the counter. + with self._thread_lock: + self._lock_counter = max(0, self._lock_counter - 1) + + raise + return _Acquire_ReturnProxy(lock = self) + + def release(self, force = False): + """ + Releases the file lock. + + Please note, that the lock is only completly released, if the lock + counter is 0. + + Also note, that the lock file itself is not automatically deleted. + + :arg bool force: + If true, the lock counter is ignored and the lock is released in + every case. + """ + with self._thread_lock: + + if self.is_locked: + self._lock_counter -= 1 + + if self._lock_counter == 0 or force: + lock_id = id(self) + lock_filename = self._lock_file + + logger().debug('Attempting to release lock %s on %s', lock_id, lock_filename) + self._release() + self._lock_counter = 0 + logger().info('Lock %s released on %s', lock_id, lock_filename) + + return None + + def __enter__(self): + self.acquire() + return self + + def __exit__(self, exc_type, exc_value, traceback): + self.release() + return None + + def __del__(self): + self.release(force = True) + return None + + +# Windows locking mechanism +# ~~~~~~~~~~~~~~~~~~~~~~~~~ + +class WindowsFileLock(BaseFileLock): + """ + Uses the :func:`msvcrt.locking` function to hard lock the lock file on + windows systems. + """ + + def _acquire(self): + open_mode = os.O_RDWR | os.O_CREAT | os.O_TRUNC + + try: + fd = os.open(self._lock_file, open_mode) + except OSError: + pass + else: + try: + msvcrt.locking(fd, msvcrt.LK_NBLCK, 1) + except (IOError, OSError): + os.close(fd) + else: + self._lock_file_fd = fd + return None + + def _release(self): + fd = self._lock_file_fd + self._lock_file_fd = None + msvcrt.locking(fd, msvcrt.LK_UNLCK, 1) + os.close(fd) + + try: + os.remove(self._lock_file) + # Probably another instance of the application + # that acquired the file lock. + except OSError: + pass + return None + +# Unix locking mechanism +# ~~~~~~~~~~~~~~~~~~~~~~ + +class UnixFileLock(BaseFileLock): + """ + Uses the :func:`fcntl.flock` to hard lock the lock file on unix systems. + """ + + def _acquire(self): + open_mode = os.O_RDWR | os.O_CREAT | os.O_TRUNC + fd = os.open(self._lock_file, open_mode) + + try: + fcntl.flock(fd, fcntl.LOCK_EX | fcntl.LOCK_NB) + except (IOError, OSError): + os.close(fd) + else: + self._lock_file_fd = fd + return None + + def _release(self): + # Do not remove the lockfile: + # + # https://github.com/benediktschmitt/py-filelock/issues/31 + # https://stackoverflow.com/questions/17708885/flock-removing-locked-file-without-race-condition + fd = self._lock_file_fd + self._lock_file_fd = None + fcntl.flock(fd, fcntl.LOCK_UN) + os.close(fd) + return None + +# Soft lock +# ~~~~~~~~~ + +class SoftFileLock(BaseFileLock): + """ + Simply watches the existence of the lock file. + """ + + def _acquire(self): + open_mode = os.O_WRONLY | os.O_CREAT | os.O_EXCL | os.O_TRUNC + try: + fd = os.open(self._lock_file, open_mode) + except (IOError, OSError): + pass + else: + self._lock_file_fd = fd + return None + + def _release(self): + os.close(self._lock_file_fd) + self._lock_file_fd = None + + try: + os.remove(self._lock_file) + # The file is already deleted and that's what we want. + except OSError: + pass + return None + + +# Platform filelock +# ~~~~~~~~~~~~~~~~~ + +#: Alias for the lock, which should be used for the current platform. On +#: Windows, this is an alias for :class:`WindowsFileLock`, on Unix for +#: :class:`UnixFileLock` and otherwise for :class:`SoftFileLock`. +FileLock = None + +if msvcrt: + FileLock = WindowsFileLock +elif fcntl: + FileLock = UnixFileLock +else: + FileLock = SoftFileLock + + if warnings is not None: + warnings.warn("only soft file lock is available") diff --git a/data_from_portwine/proton b/data_from_portwine/proton new file mode 100755 index 00000000..8131abeb --- /dev/null +++ b/data_from_portwine/proton @@ -0,0 +1,708 @@ +#!/usr/bin/env python3 + +#script to launch Wine with the correct environment + +import fcntl +import array +import filecmp +import json +import os +import shutil +import errno +import subprocess +import sys +import tarfile + +from filelock import FileLock + +#To enable debug logging, copy "user_settings.sample.py" to "user_settings.py" +#and edit it if needed. + +CURRENT_PREFIX_VERSION="5.6-GE-2" + +PFX="Proton: " +ld_path_var = "LD_LIBRARY_PATH" + +def nonzero(s): + return len(s) > 0 and s != "0" + +def log(msg): + sys.stderr.write(PFX + msg + os.linesep) + sys.stderr.flush() + +def file_is_wine_fake_dll(path): + if not os.path.exists(path): + return False + try: + sfile = open(path, "rb") + sfile.seek(0x40) + tag = sfile.read(20) + return tag == b"Wine placeholder DLL" + except IOError: + return False + +def makedirs(path): + try: + os.makedirs(path) + except OSError: + #already exists + pass + +def try_copy(src, dst): + try: + if os.path.isdir(dst): + dstfile = dst + "/" + os.path.basename(src) + if os.path.lexists(dstfile): + os.remove(dstfile) + elif os.path.lexists(dst): + os.remove(dst) + shutil.copy(src, dst) + except PermissionError as e: + if e.errno == errno.EPERM: + #be forgiving about permissions errors; if it's a real problem, things will explode later anyway + log('Error while copying to \"' + dst + '\": ' + e.strerror) + else: + raise + +def real_copy(src, dst): + if os.path.islink(src): + os.symlink(os.readlink(src), dst) + else: + try_copy(src, dst) + +EXT2_IOC_GETFLAGS = 0x80086601 +EXT2_IOC_SETFLAGS = 0x40086602 + +EXT4_CASEFOLD_FL = 0x40000000 + +def set_dir_casefold_bit(dir_path): + dr = os.open(dir_path, 0o644) + if dr < 0: + return + try: + dat = array.array('I', [0]) + if fcntl.ioctl(dr, EXT2_IOC_GETFLAGS, dat, True) >= 0: + dat[0] = dat[0] | EXT4_CASEFOLD_FL + fcntl.ioctl(dr, EXT2_IOC_SETFLAGS, dat, False) + except OSError: + #no problem + pass + os.close(dr) + +class Proton: + def __init__(self, base_dir): + self.base_dir = os.environ["STEAM_COMPAT_DATA_PATH"] + self.dist_dir = self.path("dist/") + self.bin_dir = self.path("dist/bin/") + self.lib_dir = self.path("dist/lib/") + self.lib64_dir = self.path("dist/lib64/") + self.fonts_dir = self.path("dist/share/fonts/") + self.version_file = self.path("version") + self.default_pfx_dir = self.path("dist/share/default_pfx/") + self.user_settings_file = self.path("user_settings.py") + self.wine_bin = self.bin_dir + "wine" + self.wineserver_bin = self.bin_dir + "wineserver" + self.dist_lock = FileLock(self.path("dist.lock"), timeout=-1) + + def path(self, d): + return self.base_dir + d + + def extract_tarball(self): + with self.dist_lock: + if not os.path.exists(self.dist_dir) or \ + not os.path.exists(self.path("dist/version")) or \ + not filecmp.cmp(self.version_file, self.path("dist/version")): + if os.path.exists(self.dist_dir): + shutil.rmtree(self.dist_dir) + tar = None + for sf in ["", ".xz", ".bz2", ".gz"]: + if os.path.exists(self.path("proton_dist.tar" + sf)): + tar = tarfile.open(self.path("proton_dist.tar" + sf), mode="r:*") + break + if not tar: + log("No proton_dist tarball??") + sys.exit(1) + tar.extractall(path=self.dist_dir) + tar.close() + try_copy(self.version_file, self.dist_dir) + + def make_default_prefix(self): + with self.dist_lock: + local_env = dict(g_session.env) + if not os.path.isdir(self.default_pfx_dir): + #make default prefix + local_env["WINEPREFIX"] = self.default_pfx_dir + local_env["WINEDEBUG"] = "-all" + g_session.run_proc([self.wine_bin, "wineboot"], local_env) + g_session.run_proc([self.wineserver_bin, "-w"], local_env) + +class CompatData: + def __init__(self, compatdata): + self.base_dir = os.environ["STEAM_COMPAT_DATA_PATH"] + self.prefix_dir = self.path("pfx/") + self.version_file = self.path("version") + self.tracked_files_file = self.path("tracked_files") + self.prefix_lock = FileLock(self.path("pfx.lock"), timeout=-1) + + def path(self, d): + return self.base_dir + d + + def remove_tracked_files(self): + if not os.path.exists(self.tracked_files_file): + log("Prefix has no tracked_files??") + return + + with open(self.tracked_files_file, "r") as tracked_files: + dirs = [] + for f in tracked_files: + path = self.prefix_dir + f.strip() + if os.path.exists(path): + if os.path.isfile(path) or os.path.islink(path): + os.remove(path) + else: + dirs.append(path) + for d in dirs: + try: + os.rmdir(d) + except OSError: + #not empty + pass + + os.remove(self.tracked_files_file) + os.remove(self.version_file) + + def upgrade_pfx(self, old_ver): + if old_ver == CURRENT_PREFIX_VERSION: + return + + log("Upgrading prefix from " + str(old_ver) + " to " + CURRENT_PREFIX_VERSION + " (" + self.base_dir + ")") + + if old_ver is None: + return + + if not '-' in old_ver: + #How can this happen?? + log("Prefix has an invalid version?! You may want to back up user files and delete this prefix.") + #If it does, just let the Wine upgrade happen and hope it works... + return + + try: + old_proton_ver, old_prefix_ver = old_ver.split('-') + old_proton_maj, old_proton_min = old_proton_ver.split('.') + new_proton_ver, new_prefix_ver = CURRENT_PREFIX_VERSION.split('-') + new_proton_maj, new_proton_min = new_proton_ver.split('.') + + if int(new_proton_maj) < int(old_proton_maj) or \ + (int(new_proton_maj) == int(old_proton_maj) and \ + int(new_proton_min) < int(old_proton_min)): + log("Removing newer prefix") + if old_proton_ver == "3.7" and not os.path.exists(self.tracked_files_file): + #proton 3.7 did not generate tracked_files, so copy it into place first + try_copy(g_proton.path("proton_3.7_tracked_files"), self.tracked_files_file) + self.remove_tracked_files() + return + + if old_proton_ver == "3.7" and old_prefix_ver == "1": + if not os.path.exists(self.prefix_dir + "/drive_c/windows/syswow64/kernel32.dll"): + #shipped a busted 64-bit-only installation on 20180822. detect and wipe clean + log("Detected broken 64-bit-only installation, re-creating prefix.") + shutil.rmtree(self.prefix_dir) + return + + #replace broken .NET installations with wine-mono support + if os.path.exists(self.prefix_dir + "/drive_c/windows/Microsoft.NET/NETFXRepair.exe") and \ + file_is_wine_fake_dll(self.prefix_dir + "/drive_c/windows/system32/mscoree.dll"): + log("Broken .NET installation detected, switching to wine-mono.") + #deleting this directory allows wine-mono to work + shutil.rmtree(self.prefix_dir + "/drive_c/windows/Microsoft.NET") + + #prior to prefix version 4.11-2, all controllers were xbox controllers. wipe out the old registry entries. + if (int(old_proton_maj) < 4 or (int(old_proton_maj) == 4 and int(old_proton_min) == 11)) and \ + int(old_prefix_ver) < 2: + log("Removing old xinput registry entries.") + with open(self.prefix_dir + "system.reg", "r") as reg_in: + with open(self.prefix_dir + "system.reg.new", "w") as reg_out: + for line in reg_in: + if line[0] == '[' and "CurrentControlSet" in line and "IG_" in line: + if "DeviceClasses" in line: + reg_out.write(line.replace("DeviceClasses", "DeviceClasses_old")) + elif "Enum" in line: + reg_out.write(line.replace("Enum", "Enum_old")) + else: + reg_out.write(line) + try: + os.rename(self.prefix_dir + "system.reg", self.prefix_dir + "system.reg.old") + except OSError: + os.remove(self.prefix_dir + "system.reg") + pass + + try: + os.rename(self.prefix_dir + "system.reg.new", self.prefix_dir + "system.reg") + except OSError: + log("Unable to write new registry file to " + self.prefix_dir + "system.reg") + pass + + except ValueError: + log("Prefix has an invalid version?! You may want to back up user files and delete this prefix.") + #Just let the Wine upgrade happen and hope it works... + return + + def copy_pfx(self): + with open(self.tracked_files_file, "w") as tracked_files: + for src_dir, dirs, files in os.walk(g_proton.default_pfx_dir): + rel_dir = src_dir.replace(g_proton.default_pfx_dir, "", 1).lstrip('/') + if len(rel_dir) > 0: + rel_dir = rel_dir + "/" + dst_dir = src_dir.replace(g_proton.default_pfx_dir, self.prefix_dir, 1) + if not os.path.exists(dst_dir): + os.makedirs(dst_dir) + tracked_files.write(rel_dir + "\n") + for dir_ in dirs: + src_file = os.path.join(src_dir, dir_) + dst_file = os.path.join(dst_dir, dir_) + if os.path.islink(src_file) and not os.path.exists(dst_file): + real_copy(src_file, dst_file) + for file_ in files: + src_file = os.path.join(src_dir, file_) + dst_file = os.path.join(dst_dir, file_) + if not os.path.exists(dst_file): + real_copy(src_file, dst_file) + tracked_files.write(rel_dir + file_ + "\n") + + def create_fonts_symlinks(self): + fontsmap = [ + ( "LiberationSans-Regular.ttf", "arial.ttf" ), + ( "LiberationSans-Bold.ttf", "arialbd.ttf" ), + ( "LiberationSerif-Regular.ttf", "times.ttf" ), + ( "LiberationMono-Regular.ttf", "cour.ttf" ), + ( "SourceHanSansSCRegular.otf", "msyh.ttf" ), + ] + + windowsfonts = self.prefix_dir + "/drive_c/windows/Fonts" + makedirs(windowsfonts) + for p in fontsmap: + lname = os.path.join(windowsfonts, p[1]) + fname = os.path.join(g_proton.fonts_dir, p[0]) + if os.path.lexists(lname): + if os.path.islink(lname): + os.remove(lname) + os.symlink(fname, lname) + else: + os.symlink(fname, lname) + + def setup_prefix(self): + with self.prefix_lock: + if os.path.exists(self.version_file): + with open(self.version_file, "r") as f: + self.upgrade_pfx(f.readline().strip()) + else: + self.upgrade_pfx(None) + + if not os.path.exists(self.prefix_dir): + makedirs(self.prefix_dir + "/drive_c") + set_dir_casefold_bit(self.prefix_dir + "/drive_c") + + if not os.path.exists(self.prefix_dir + "/user.reg"): + self.copy_pfx() + + with open(self.version_file, "w") as f: + f.write(CURRENT_PREFIX_VERSION + "\n") + + #create font files symlinks + self.create_fonts_symlinks() + + #copy steam files into place + if "STEAM_COMPAT_CLIENT_INSTALL_PATH" in os.environ: + #modern steam client sets this + steamdir = os.environ["STEAM_COMPAT_CLIENT_INSTALL_PATH"] + else: + #linux-only fallback, really shouldn't get here + steamdir = os.environ["HOME"] + ".steam/root/" + dst = self.prefix_dir + "/drive_c/Program Files (x86)/" + makedirs(dst + "Steam") + filestocopy = ["steamclient.dll", + "steamclient64.dll", + "Steam.dll"] + for f in filestocopy: + if os.path.isfile(steamdir + "/legacycompat/" + f): + dstfile = dst + "Steam/" + f + if os.path.isfile(dstfile): + os.remove(dstfile) + try_copy(steamdir + "/legacycompat/" + f, dstfile) + + #copy openvr files into place + dst = self.prefix_dir + "/drive_c/vrclient/bin/" + makedirs(dst) + try_copy(g_proton.lib_dir + "wine/fakedlls/vrclient.dll", dst) + try_copy(g_proton.lib64_dir + "wine/fakedlls/vrclient_x64.dll", dst) + + try_copy(g_proton.lib_dir + "wine/dxvk/openvr_api_dxvk.dll", self.prefix_dir + "/drive_c/windows/syswow64/") + try_copy(g_proton.lib64_dir + "wine/dxvk/openvr_api_dxvk.dll", self.prefix_dir + "/drive_c/windows/system32/") + + if "wined3d" in g_session.compat_config: + dxvkfiles = ["dxvk_config"] + wined3dfiles = ["d3d11", "d3d10", "d3d10core", "d3d10_1", "d3d9"] + else: + dxvkfiles = ["dxvk_config", "d3d11", "d3d10", "d3d10core", "d3d10_1", "d3d9"] + wined3dfiles = [] + + #if the user asked for dxvk's dxgi (dxgi=n), then copy it into place + if "WINEDLLOVERRIDES" in os.environ and "dxgi=n" in os.environ["WINEDLLOVERRIDES"]: + dxvkfiles.append("dxgi") + else: + wined3dfiles.append("dxgi") + + for f in wined3dfiles: + try_copy(g_proton.default_pfx_dir + "drive_c/windows/system32/" + f + ".dll", + self.prefix_dir + "drive_c/windows/system32/" + f + ".dll") + try_copy(g_proton.default_pfx_dir + "drive_c/windows/syswow64/" + f + ".dll", + self.prefix_dir + "drive_c/windows/syswow64/" + f + ".dll") + + for f in dxvkfiles: + try_copy(g_proton.lib64_dir + "wine/dxvk/" + f + ".dll", + self.prefix_dir + "drive_c/windows/system32/" + f + ".dll") + try_copy(g_proton.lib_dir + "wine/dxvk/" + f + ".dll", + self.prefix_dir + "drive_c/windows/syswow64/" + f + ".dll") + g_session.dlloverrides[f] = "n" + +def comma_escaped(s): + escaped = False + idx = -1 + while s[idx] == '\\': + escaped = not escaped + idx = idx - 1 + return escaped + +class Session: + def __init__(self): + self.log_file = None + self.env = dict(os.environ) + self.dlloverrides = { + "steam.exe": "b" #always use our special built-in steam.exe + } + + self.compat_config = set() + self.cmdlineappend = [] + + if "STEAM_COMPAT_CONFIG" in os.environ: + config = os.environ["STEAM_COMPAT_CONFIG"] + + while config: + (cur, sep, config) = config.partition(',') + if cur.startswith("cmdlineappend:"): + while comma_escaped(cur): + (a, b, c) = config.partition(',') + cur = cur[:-1] + ',' + a + config = c + self.cmdlineappend.append(cur[14:].replace('\\\\','\\')) + else: + self.compat_config.add(cur) + + #turn forcelgadd on by default unless it is disabled in compat config + if not "noforcelgadd" in self.compat_config: + self.compat_config.add("forcelgadd") + + def init_wine(self): + if "HOST_LC_ALL" in self.env and len(self.env["HOST_LC_ALL"]) > 0: + #steam sets LC_ALL=C to help some games, but Wine requires the real value + #in order to do path conversion between win32 and host. steam sets + #HOST_LC_ALL to allow us to use the real value. + self.env["LC_ALL"] = self.env["HOST_LC_ALL"] + else: + self.env.pop("LC_ALL", "") + + self.env.pop("WINEARCH", "") + + if 'ORIG_'+ld_path_var not in os.environ: + # Allow wine to restore this when calling an external app. + self.env['ORIG_'+ld_path_var] = os.environ.get(ld_path_var, '') + + if ld_path_var in os.environ: + self.env[ld_path_var] = g_proton.lib64_dir + ":" + g_proton.lib_dir + ":" + os.environ[ld_path_var] + else: + self.env[ld_path_var] = g_proton.lib64_dir + ":" + g_proton.lib_dir + + self.env["WINEDLLPATH"] = g_proton.lib64_dir + "/wine:" + g_proton.lib_dir + "/wine" + + self.env["GST_PLUGIN_SYSTEM_PATH_1_0"] = g_proton.lib64_dir + "gstreamer-1.0" + ":" + g_proton.lib_dir + "gstreamer-1.0" + self.env["WINE_GST_REGISTRY_DIR"] = g_compatdata.path("gstreamer-1.0/") + + if "PATH" in os.environ: + self.env["PATH"] = g_proton.bin_dir + ":" + os.environ["PATH"] + else: + self.env["PATH"] = g_proton.bin_dir + + def check_environment(self, env_name, config_name): + if not env_name in self.env: + return False + if nonzero(self.env[env_name]): + self.compat_config.add(config_name) + else: + self.compat_config.discard(config_name) + return True + + def init_session(self): + self.env["WINEPREFIX"] = g_compatdata.prefix_dir + + #load environment overrides + if os.path.exists(g_proton.user_settings_file): + try: + import user_settings + for key, value in user_settings.user_settings.items(): + self.env.setdefault(key, value) + except: + log("************************************************") + log("THERE IS AN ERROR IN YOUR user_settings.py FILE:") + log("%s" % sys.exc_info()[1]) + log("************************************************") + + if "PROTON_LOG" in self.env and nonzero(self.env["PROTON_LOG"]): + self.env.setdefault("WINEDEBUG", "+timestamp,+pid,+tid,+seh,+debugstr,+loaddll,+mscoree") + self.env.setdefault("DXVK_LOG_LEVEL", "info") + self.env.setdefault("VKD3D_DEBUG", "warn") + self.env.setdefault("WINE_MONO_TRACE", "E:System.NotImplementedException") + + #for performance, logging is disabled by default; override with user_settings.py + self.env.setdefault("WINEDEBUG", "-all") + self.env.setdefault("DXVK_LOG_LEVEL", "none") + self.env.setdefault("VKD3D_DEBUG", "none") + + #default wine-mono override for FNA games + self.env.setdefault("WINE_MONO_OVERRIDES", "Microsoft.Xna.Framework.*,Gac=n") + + if "wined3d11" in self.compat_config: + self.compat_config.add("wined3d") + + if not self.check_environment("PROTON_USE_WINED3D", "wined3d"): + self.check_environment("PROTON_USE_WINED3D11", "wined3d") + self.check_environment("PROTON_NO_D3D11", "nod3d11") + self.check_environment("PROTON_NO_D3D10", "nod3d10") + self.check_environment("PROTON_NO_D9VK", "nod3d9") + self.check_environment("PROTON_NO_ESYNC", "noesync") + self.check_environment("PROTON_NO_FSYNC", "nofsync") + self.check_environment("PROTON_FORCE_LARGE_ADDRESS_AWARE", "forcelgadd") + self.check_environment("PROTON_OLD_GL_STRING", "oldglstr") + self.check_environment("PROTON_USE_SECCOMP", "seccomp") + + if not "noesync" in self.compat_config: + self.env["WINEESYNC"] = "1" if "SteamGameId" in self.env else "0" + + if not "nofsync" in self.compat_config: + self.env["WINEFSYNC"] = "1" if "SteamGameId" in self.env else "0" + + if "seccomp" in self.compat_config: + self.env["WINESECCOMP"] = "1" + + if "oldglstr" in self.compat_config: + #mesa override + self.env["MESA_EXTENSION_MAX_YEAR"] = "2003" + #nvidia override + self.env["__GL_ExtensionStringVersion"] = "17700" + + if "forcelgadd" in self.compat_config: + self.env["WINE_LARGE_ADDRESS_AWARE"] = "1" + + if "SteamGameId" in self.env: + if self.env["WINEDEBUG"] != "-all": + lfile_path = os.environ["HOME"] + "/steam-" + os.environ["SteamGameId"] + ".log" + if os.path.exists(lfile_path): + os.remove(lfile_path) + self.log_file = open(lfile_path, "w+") + self.log_file.write("======================\n") + with open(g_proton.version_file, "r") as f: + self.log_file.write("Proton: " + f.readline().strip() + "\n") + self.log_file.write("SteamGameId: " + self.env["SteamGameId"] + "\n") + self.log_file.write("Command: " + str(sys.argv[2:] + self.cmdlineappend) + "\n") + self.log_file.write("Options: " + str(self.compat_config) + "\n") + self.log_file.write("======================\n") + self.log_file.flush() + else: + self.env["WINEDEBUG"] = "-all" + + g_compatdata.setup_prefix() + + if "nod3d11" in self.compat_config: + self.dlloverrides["d3d11"] = "" + if "dxgi" in self.dlloverrides: + del self.dlloverrides["dxgi"] + + if "nod3d10" in self.compat_config: + self.dlloverrides["d3d10_1"] = "" + self.dlloverrides["d3d10"] = "" + self.dlloverrides["dxgi"] = "" + + if "nod3d9" in self.compat_config: + self.dlloverrides["d3d9"] = "" + + s = "" + for dll in self.dlloverrides: + setting = self.dlloverrides[dll] + if len(s) > 0: + s = s + ";" + dll + "=" + setting + else: + s = dll + "=" + setting + if "WINEDLLOVERRIDES" in os.environ: + self.env["WINEDLLOVERRIDES"] = os.environ["WINEDLLOVERRIDES"] + ";" + s + else: + self.env["WINEDLLOVERRIDES"] = s + + def dump_dbg_env(self, f): + f.write("PATH=\"" + self.env["PATH"] + "\" \\\n") + f.write("\tTERM=\"xterm\" \\\n") #XXX + f.write("\tWINEDEBUG=\"-all\" \\\n") + f.write("\tWINEDLLPATH=\"" + self.env["WINEDLLPATH"] + "\" \\\n") + f.write("\t" + ld_path_var + "=\"" + self.env[ld_path_var] + "\" \\\n") + f.write("\tWINEPREFIX=\"" + self.env["WINEPREFIX"] + "\" \\\n") + if "WINEESYNC" in self.env: + f.write("\tWINEESYNC=\"" + self.env["WINEESYNC"] + "\" \\\n") + if "WINEFSYNC" in self.env: + f.write("\tWINEFSYNC=\"" + self.env["WINEFSYNC"] + "\" \\\n") + if "SteamGameId" in self.env: + f.write("\tSteamGameId=\"" + self.env["SteamGameId"] + "\" \\\n") + if "SteamAppId" in self.env: + f.write("\tSteamAppId=\"" + self.env["SteamAppId"] + "\" \\\n") + if "WINEDLLOVERRIDES" in self.env: + f.write("\tWINEDLLOVERRIDES=\"" + self.env["WINEDLLOVERRIDES"] + "\" \\\n") + if "STEAM_COMPAT_CLIENT_INSTALL_PATH" in self.env: + f.write("\tSTEAM_COMPAT_CLIENT_INSTALL_PATH=\"" + self.env["STEAM_COMPAT_CLIENT_INSTALL_PATH"] + "\" \\\n") + if "WINE_LARGE_ADDRESS_AWARE" in self.env: + f.write("\tWINE_LARGE_ADDRESS_AWARE=\"" + self.env["WINE_LARGE_ADDRESS_AWARE"] + "\" \\\n") + + def dump_dbg_scripts(self): + exe_name = os.path.basename(sys.argv[2]) + + tmpdir = self.env.get("PROTON_DEBUG_DIR", "/tmp") + "/proton_" + os.environ["USER"] + "/" + makedirs(tmpdir) + + with open(tmpdir + "winedbg", "w") as f: + f.write("#!/bin/bash\n") + f.write("#Run winedbg with args\n\n") + f.write("cd \"" + os.getcwd() + "\"\n") + self.dump_dbg_env(f) + f.write("\t\"" + g_proton.wine_bin + "\" winedbg \"$@\"\n") + os.chmod(tmpdir + "winedbg", 0o755) + + with open(tmpdir + "winedbg_run", "w") as f: + f.write("#!/bin/bash\n") + f.write("#Run winedbg and prepare to run game or given program\n\n") + f.write("cd \"" + os.getcwd() + "\"\n") + f.write("DEF_CMD=(") + first = True + for arg in sys.argv[2:]: + if first: + f.write("\"" + arg + "\"") + first = False + else: + f.write(" \"" + arg + "\"") + f.write(")\n") + self.dump_dbg_env(f) + f.write("\t\"" + g_proton.wine_bin + "\" winedbg \"${@:-${DEF_CMD[@]}}\"\n") + os.chmod(tmpdir + "winedbg_run", 0o755) + + with open(tmpdir + "gdb_attach", "w") as f: + f.write("#!/bin/bash\n") + f.write("#Run winedbg in gdb mode and auto-attach to already-running program\n\n") + f.write("cd \"" + os.getcwd() + "\"\n") + f.write("EXE_NAME=${1:-\"" + exe_name + "\"}\n") + f.write("WPID_HEX=$(\"" + tmpdir + "winedbg\" --command 'info process' | grep -i \"$EXE_NAME\" | cut -f2 -d' ' | tr -d '0')\n") + f.write("if [ -z \"$WPID_HEX\" ]; then \n") + f.write(" echo \"Program does not appear to be running: \\\"$EXE_NAME\\\"\"\n") + f.write(" exit 1\n") + f.write("fi\n") + f.write("WPID_DEC=$(printf %d 0x$WPID_HEX)\n") + self.dump_dbg_env(f) + f.write("\t\"" + g_proton.wine_bin + "\" winedbg --gdb $WPID_DEC\n") + os.chmod(tmpdir + "gdb_attach", 0o755) + + with open(tmpdir + "gdb_run", "w") as f: + f.write("#!/bin/bash\n") + f.write("#Run winedbg in gdb mode and prepare to run game or given program\n\n") + f.write("cd \"" + os.getcwd() + "\"\n") + f.write("DEF_CMD=(") + first = True + for arg in sys.argv[2:]: + if first: + f.write("\"" + arg + "\"") + first = False + else: + f.write(" \"" + arg + "\"") + f.write(")\n") + self.dump_dbg_env(f) + f.write("\t\"" + g_proton.wine_bin + "\" winedbg --gdb \"${@:-${DEF_CMD[@]}}\"\n") + os.chmod(tmpdir + "gdb_run", 0o755) + + with open(tmpdir + "run", "w") as f: + f.write("#!/bin/bash\n") + f.write("#Run game or given command in environment\n\n") + f.write("cd \"" + os.getcwd() + "\"\n") + f.write("DEF_CMD=(") + first = True + for arg in sys.argv[2:]: + if first: + f.write("\"" + arg + "\"") + first = False + else: + f.write(" \"" + arg + "\"") + f.write(")\n") + self.dump_dbg_env(f) + f.write("\t\"" + g_proton.wine_bin + "\" steam.exe \"${@:-${DEF_CMD[@]}}\"\n") + os.chmod(tmpdir + "run", 0o755) + + def run_proc(self, args, local_env=None): + if local_env is None: + local_env = self.env + subprocess.call(args, env=local_env, stderr=self.log_file, stdout=self.log_file) + + def run(self): + if "PROTON_DUMP_DEBUG_COMMANDS" in self.env and nonzero(self.env["PROTON_DUMP_DEBUG_COMMANDS"]): + try: + self.dump_dbg_scripts() + except OSError: + log("Unable to write debug scripts! " + str(sys.exc_info()[1])) + self.run_proc([g_proton.wine_bin, "steam"] + sys.argv[2:] + self.cmdlineappend) + + +if __name__ == "__main__": + if not "STEAM_COMPAT_DATA_PATH" in os.environ: + log("No compat data path?") + sys.exit(1) + + g_proton = Proton(os.path.dirname(sys.argv[0])) + +# g_proton.extract_tarball() + + g_compatdata = CompatData(os.environ["STEAM_COMPAT_DATA_PATH"]) + + g_session = Session() + + g_session.init_wine() + + g_proton.make_default_prefix() + + g_session.init_session() + + #determine mode + if sys.argv[1] == "run": + #start target app + g_session.run() + elif sys.argv[1] == "waitforexitandrun": + #wait for wineserver to shut down + g_session.run_proc([g_proton.wineserver_bin, "-w"]) + #then run + g_session.run() + elif sys.argv[1] == "getcompatpath": + #linux -> windows path + path = subprocess.check_output([g_proton.wine_bin, "winepath", "-w", sys.argv[2]], env=g_session.env, stderr=g_session.log_file) + sys.stdout.buffer.write(path) + elif sys.argv[1] == "getnativepath": + #windows -> linux path + path = subprocess.check_output([g_proton.wine_bin, "winepath", sys.argv[2]], env=g_session.env, stderr=g_session.log_file) + sys.stdout.buffer.write(path) + else: + log("Need a verb.") + sys.exit(1) + + sys.exit(0) + +#pylint --disable=C0301,C0326,C0330,C0111,C0103,R0902,C1801,R0914,R0912,R0915 +# vim: set syntax=python: diff --git a/portwine_run_scripts/debug b/data_from_portwine/scripts/debug similarity index 100% rename from portwine_run_scripts/debug rename to data_from_portwine/scripts/debug diff --git a/portwine_run_scripts/lang b/data_from_portwine/scripts/lang similarity index 100% rename from portwine_run_scripts/lang rename to data_from_portwine/scripts/lang diff --git a/portwine_run_scripts/port_update b/data_from_portwine/scripts/port_update similarity index 100% rename from portwine_run_scripts/port_update rename to data_from_portwine/scripts/port_update diff --git a/portwine_run_scripts/remove b/data_from_portwine/scripts/remove similarity index 100% rename from portwine_run_scripts/remove rename to data_from_portwine/scripts/remove diff --git a/portwine_run_scripts/restart b/data_from_portwine/scripts/restart similarity index 100% rename from portwine_run_scripts/restart rename to data_from_portwine/scripts/restart diff --git a/portwine_run_scripts/runlib b/data_from_portwine/scripts/runlib similarity index 100% rename from portwine_run_scripts/runlib rename to data_from_portwine/scripts/runlib diff --git a/portwine_run_scripts/setup b/data_from_portwine/scripts/setup similarity index 100% rename from portwine_run_scripts/setup rename to data_from_portwine/scripts/setup diff --git a/portwine_run_scripts/start b/data_from_portwine/scripts/start similarity index 100% rename from portwine_run_scripts/start rename to data_from_portwine/scripts/start diff --git a/portwine_run_scripts/vars b/data_from_portwine/scripts/vars similarity index 100% rename from portwine_run_scripts/vars rename to data_from_portwine/scripts/vars diff --git a/portwine_run_scripts/wineboot b/data_from_portwine/scripts/wineboot similarity index 100% rename from portwine_run_scripts/wineboot rename to data_from_portwine/scripts/wineboot diff --git a/portwine_run_scripts/winecfg b/data_from_portwine/scripts/winecfg similarity index 100% rename from portwine_run_scripts/winecfg rename to data_from_portwine/scripts/winecfg diff --git a/portwine_run_scripts/winecmd b/data_from_portwine/scripts/winecmd similarity index 100% rename from portwine_run_scripts/winecmd rename to data_from_portwine/scripts/winecmd diff --git a/portwine_run_scripts/winefile b/data_from_portwine/scripts/winefile similarity index 100% rename from portwine_run_scripts/winefile rename to data_from_portwine/scripts/winefile diff --git a/portwine_run_scripts/winereg b/data_from_portwine/scripts/winereg similarity index 100% rename from portwine_run_scripts/winereg rename to data_from_portwine/scripts/winereg diff --git a/portwine_run_scripts/winetricks b/data_from_portwine/scripts/winetricks similarity index 100% rename from portwine_run_scripts/winetricks rename to data_from_portwine/scripts/winetricks diff --git a/portwine_run_scripts/winetricks-q-force b/data_from_portwine/scripts/winetricks-q-force similarity index 100% rename from portwine_run_scripts/winetricks-q-force rename to data_from_portwine/scripts/winetricks-q-force