Beispiel #1
0
void DataDirLocater::AddPortableDir()
{
	const std::string dd_curWorkDir = GetBinaryLocation();

	// This is useful in case of multiple engine/unitsync versions installed
	// together in a sub-dir of the data-dir
	// The data-dir structure then might look similar to this:
	// maps/
	// games/
	// engines/engine-0.83.0.0.exe
	// engines/engine-0.83.1.0.exe
	// unitsyncs/unitsync-0.83.0.0.exe
	// unitsyncs/unitsync-0.83.1.0.exe
	const std::string curWorkDirParent = FileSystem::GetParent(dd_curWorkDir);

	if ((curWorkDirParent != "") && LooksLikeMultiVersionDataDir(curWorkDirParent)) {
		AddDirs(curWorkDirParent); // "../"
	}
	AddDirs(dd_curWorkDir);
}
Beispiel #2
0
void DataDirLocater::AddCwdOrParentDir(const std::string& curWorkDir, bool forceAdd)
{
	// This is useful in case of multiple engine/unitsync versions installed
	// together in a sub-dir of the data-dir
	// The data-dir structure then might look similar to this:
	// maps/
	// games/
	// engines/engine-0.83.0.0.exe
	// engines/engine-0.83.1.0.exe
	// unitsyncs/unitsync-0.83.0.0.exe
	// unitsyncs/unitsync-0.83.1.0.exe
	const std::string curWorkDirParent = FileSystem::GetParent(curWorkDir);

	// we can not add both ./ and ../ as data-dir
	if ((curWorkDirParent != "") && LooksLikeMultiVersionDataDir(curWorkDirParent)) {
		AddDirs(curWorkDirParent); // "../"
	} else if (IsPortableMode() || forceAdd) {
		// always using this would be unclean, because spring and unitsync
		// would end up with different sets of data-dirs
		AddDirs(curWorkDir); // "./"
	}
}
void DataDirLocater::LocateDataDirs()
{
    // Prepare the data-dirs defined in different places

    // environment variable
    std::string dd_env = "";
    {
        char* env = getenv("SPRING_DATADIR");
        if (env && *env) {
            dd_env = SubstEnvVars(env);
        }
    }

#if       defined(UNITSYNC)
    const std::string dd_curWorkDir = Platform::GetModulePath();
#else  // defined(UNITSYNC)
    const std::string dd_curWorkDir = Platform::GetProcessExecutablePath();
#endif // defined(UNITSYNC)

    // This is useful in case of multiple engine/unitsync versions installed
    // together in a sub-dir of the data-dir
    // The data-dir structure then might look similar to this:
    // maps/
    // games/
    // engines/engine-0.83.0.0.exe
    // engines/engine-0.83.1.0.exe
    // unitsyncs/unitsync-0.83.0.0.exe
    // unitsyncs/unitsync-0.83.1.0.exe
    const std::string dd_curWorkDirParent = FileSystemHandler::GetParent(dd_curWorkDir);

#if    defined(WIN32)
    // fetch my documents path
    TCHAR pathMyDocs[MAX_PATH];
    SHGetFolderPath( NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, pathMyDocs);

    // fetch app-data path
    TCHAR pathAppData[MAX_PATH];
    SHGetFolderPath( NULL, CSIDL_COMMON_APPDATA, NULL, SHGFP_TYPE_CURRENT, pathAppData);

    std::string dd_myDocs = pathMyDocs;
    // e.g. F:\Dokumente und Einstellungen\Karl-Robert\Eigene Dateien\Spring
    dd_myDocs += "\\Spring";

    std::string dd_myDocsMyGames = pathMyDocs;
    // My Documents\My Games seems to be the MS standard even if no official guidelines exist
    // most if not all new Games For Windows(TM) games use this dir
    dd_myDocsMyGames += "\\My Games\\Spring";

    std::string dd_appData = pathAppData;
    // e.g. F:\Dokumente und Einstellungen\All Users\Anwendungsdaten\Spring
    dd_appData += "\\Spring";
#elif     defined(MACOSX_BUNDLE)
    const std::string dd_curWorkDirData = dd_curWorkDir + "/" + SubstEnvVars(DATADIR);
    const std::string dd_curWorkDirLib  = dd_curWorkDir + "/" + SubstEnvVars(LIBDIR);
#else // *nix (-OSX)
    // settings in /etc
    std::string dd_etc = "";
    {
        FILE* fileH = ::fopen("/etc/spring/datadir", "r");
        if (fileH) {
            const char whiteSpaces[3] = {'\t', ' ', '\0'};
            char lineBuf[1024];
            while (fgets(lineBuf, sizeof(lineBuf), fileH)) {
                char* newLineCharPos = strchr(lineBuf, '\n');
                if (newLineCharPos) {
                    // remove the new line char
                    *newLineCharPos = '\0';
                }
                // ignore lines consisting of only whitespaces
                if ((strlen(lineBuf) > 0) && strspn(lineBuf, whiteSpaces) != strlen(lineBuf)) {
                    // append, separated by sPD (depending on OS): ';' or ':'
                    dd_etc = dd_etc + (dd_etc.empty() ? "" : sPD) + SubstEnvVars(lineBuf);
                }
            }
            fclose(fileH);
        }
    }
#endif // defined(WIN32), defined(MACOSX_BUNDLE), else

    // Construct the list of datadirs from various sources.
    datadirs.clear();
    // The first dir added will be the writeable data dir.

    // same on all platforms
    AddDirs(dd_env);    // ENV{SPRING_DATADIR}
    // user defined in spring config handler
    // (Linux: ~/.springrc, Windows: .\springsettings.cfg)
    AddDirs(SubstEnvVars(configHandler->GetString("SpringData", "")));

#ifdef WIN32
    // All MS Windows variants

    if ((dd_curWorkDirParent != "") && LooksLikeMultiVersionDataDir(dd_curWorkDirParent)) {
        AddDirs(dd_curWorkDirParent); // "../"
    } else if (IsPortableMode()) { // we can not add both ./ and ../ as data-dir
        AddDirs(dd_curWorkDir); // "./"
    }
    AddDirs(dd_myDocsMyGames);  // "C:/.../My Documents/My Games/Spring/"
    AddDirs(dd_myDocs);         // "C:/.../My Documents/Spring/"
    AddDirs(dd_appData);        // "C:/.../All Users/Applications/Spring/"

#elif defined(MACOSX_BUNDLE)
    // Mac OS X

    // Maps and mods are supposed to be located in spring's executable location on Mac, but unitsync
    // cannot find them since it does not know spring binary path. I have no idea but to force users
    // to locate lobby executables in the same as spring's dir and add its location to search dirs.
#ifdef UNITSYNC
    AddDirs(dd_curWorkDir);     // "./"
#endif

    // libs and data are supposed to be located in subdirectories of spring executable, so they
    // sould be added instead of SPRING_DATADIR definition.
    AddDirs(dd_curWorkDirData); // "./data/"
    AddDirs(dd_curWorkDirLib);  // "./lib/"

#else
    // Linux, FreeBSD, Solaris, Apple non-bundle

    if ((dd_curWorkDirParent != "") && LooksLikeMultiVersionDataDir(dd_curWorkDirParent)) {
        AddDirs(dd_curWorkDirParent); // "../"
    } else if (IsPortableMode()) { // we can not add both ./ and ../ as data-dir
        // always using this would be unclean, because spring and unitsync
        // would end up with different sets of data-dirs
        AddDirs(dd_curWorkDir); // "./"
    }
    AddDirs(SubstEnvVars("$HOME/.spring")); // "~/.spring/"
    AddDirs(dd_etc);            // from /etc/spring/datadir
#endif

#ifdef SPRING_DATADIR
    AddDirs(SubstEnvVars(SPRING_DATADIR)); // from -DSPRING_DATADIR
#endif

    // Figure out permissions of all datadirs
    DeterminePermissions();

    if (!writedir) {
        // bail out
        const std::string errstr = "Not a single writable data directory found!\n\n"
                                   "Configure a writable data directory using either:\n"
                                   "- the SPRING_DATADIR environment variable,\n"
#ifdef WIN32
                                   "- a SpringData=C:/path/to/data declaration in spring's config file ./springsettings.cfg\n"
                                   "- by giving you write access to the installation directory";
#else
                                   "- a SpringData=/path/to/data declaration in ~/.springrc or\n"
                                   "- the configuration file /etc/spring/datadir";
#endif
        throw content_error(errstr);
    }

    // for now, chdir to the data directory as a safety measure:
    // Not only safety anymore, it's just easier if other code can safely assume that
    // writedir == current working directory
    FileSystemHandler::GetInstance().Chdir(GetWriteDir()->path.c_str());

    // Initialize the log. Only after this moment log will be written to file.
    logOutput.Initialize();
    // Logging MAY NOT start before the chdir, otherwise the logfile ends up
    // in the wrong directory.
    // Update: now it actually may start before, log has preInitLog.
    for (std::vector<DataDir>::const_iterator d = datadirs.begin(); d != datadirs.end(); ++d) {
        if (d->writable) {
            logOutput.Print("Using read-write data directory: %s", d->path.c_str());

            // tag the cache dir
            const std::string cacheDir = d->path + "cache";
            if (filesystem.CreateDirectory(cacheDir)) {
                CacheDir::SetCacheDir(cacheDir, true);
            }
        } else {
            logOutput.Print("Using read-only data directory: %s",  d->path.c_str());
        }
    }
}