static size_t file_write(const void * const p, size_t len, stream_t *stream) { PHYSFS_sint64 count; int error; PHYSFS_File *file; if (file_check_context(stream)) return 0; file = stream->context.pfs.file; count = PHYSFS_writeBytes(file, p, len); if (count < len && (error = PHYSFS_getLastErrorCode())) { s_log_error("Error writing to file stream (pfs: %s). (File: %s)", PHYSFS_getErrorByCode(error), stream->context.pfs.file_path); stream->error = STREAM_ERROR_FAILURE; if (count == -1) return 0; } return (size_t)count; }
OFileStreambuf::OFileStreambuf(const std::string& filename) : file() { file = PHYSFS_openWrite(filename.c_str()); if(file == nullptr) { std::stringstream msg; msg << "Couldn't open file '" << filename << "': " << PHYSFS_getLastErrorCode(); throw std::runtime_error(msg.str()); } setp(buf, buf+sizeof(buf)); }
void FS_Init(const char *argv0) { int err = PHYSFS_init(argv0); if (err == 0) { Con_Errorf(ERR_FATAL, "Error in PHYSFS_init: %s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode())); return; } const char *baseDir = PHYSFS_getBaseDir(); fs_basepath = Con_GetVarDefault("fs.basepath", baseDir, CONVAR_STARTUP); fs_basegame = Con_GetVarDefault("fs.basegame", "base", CONVAR_STARTUP); fs_game = Con_GetVarDefault("fs.game", DEFAULT_GAME, CONVAR_STARTUP); bool modLoaded = fs_game->string[0] != '\0'; char **baseFiles, **gameFiles; // get the file listing for the basegame dir, then immediately unmount const char *fullBasePath = tempstr("%s/%s", fs_basepath->string, fs_basegame->string); PHYSFS_mount(fullBasePath, "/", 1); baseFiles = PHYSFS_enumerateFiles("/"); PHYSFS_removeFromSearchPath(fullBasePath); // if fs_game is set, do the same thing for the fs_game dir if (modLoaded) { const char *fullGamePath = tempstr("%s/%s", fs_basepath->string, fs_game->string); PHYSFS_mount(fullGamePath, "/", 1); gameFiles = PHYSFS_enumerateFiles("/"); PHYSFS_removeFromSearchPath(fullGamePath); // mount the mod dir first, then mount mod PK3s PHYSFS_mount(tempstr("%s/%s", fs_basepath->string, fs_game->string), "/", 1); FS_AddPaksFromList(gameFiles, fs_basepath->string, fs_game->string); PHYSFS_freeList(gameFiles); } // then mount the base game dir, then the mount base game PK3s PHYSFS_mount(tempstr("%s/%s", fs_basepath->string, fs_basegame->string), "/", 1); FS_AddPaksFromList(baseFiles, fs_basepath->string, fs_basegame->string); PHYSFS_freeList(baseFiles); // print all the files we've found in order of priority Con_Printf("Current filesystem search path:\n"); PHYSFS_getSearchPathCallback(printSearchPath, NULL); Con_Printf("\n"); // add command handler for dir to view virtual filesystem Con_AddCommand("dir", Cmd_Dir_f); }
IFileStreambuf::IFileStreambuf(const std::string& filename) : file(), buf() { // check this as PHYSFS seems to be buggy and still returns a // valid pointer in this case if(filename.empty()) { throw std::runtime_error("Couldn't open file: empty filename"); } file = PHYSFS_openRead(filename.c_str()); if(file == nullptr) { std::stringstream msg; msg << "Couldn't open file '" << filename << "': " << PHYSFS_getLastErrorCode(); throw std::runtime_error(msg.str()); } }
Transfer(Downloader& downloader, TransferId id, const std::string& url, const std::string& outfile) : m_downloader(downloader), m_id(id), m_url(url), m_handle(), m_error_buffer({{'\0'}}), m_status(new TransferStatus(m_downloader, id)), m_fout(PHYSFS_openWrite(outfile.c_str()), PHYSFS_close) { if (!m_fout) { std::ostringstream out; out << "PHYSFS_openRead() failed: " << PHYSFS_getLastErrorCode(); throw std::runtime_error(out.str()); } m_handle = curl_easy_init(); if (!m_handle) { throw std::runtime_error("curl_easy_init() failed"); } else { curl_easy_setopt(m_handle, CURLOPT_URL, url.c_str()); curl_easy_setopt(m_handle, CURLOPT_USERAGENT, "SuperTux/" PACKAGE_VERSION " libcURL"); curl_easy_setopt(m_handle, CURLOPT_WRITEDATA, this); curl_easy_setopt(m_handle, CURLOPT_WRITEFUNCTION, &Transfer::on_data_wrap); curl_easy_setopt(m_handle, CURLOPT_ERRORBUFFER, m_error_buffer.data()); curl_easy_setopt(m_handle, CURLOPT_NOSIGNAL, 1); curl_easy_setopt(m_handle, CURLOPT_FAILONERROR, 1); curl_easy_setopt(m_handle, CURLOPT_FOLLOWLOCATION, 1); curl_easy_setopt(m_handle, CURLOPT_NOPROGRESS, 0); curl_easy_setopt(m_handle, CURLOPT_PROGRESSDATA, this); curl_easy_setopt(m_handle, CURLOPT_PROGRESSFUNCTION, &Transfer::on_progress_wrap); } }
PhysfsSubsystem(const char* argv0, boost::optional<std::string> forced_datadir, boost::optional<std::string> forced_userdir) : m_forced_datadir(forced_datadir), m_forced_userdir(forced_userdir) { if (!PHYSFS_init(argv0)) { std::stringstream msg; msg << "Couldn't initialize physfs: " << PHYSFS_getLastErrorCode(); throw std::runtime_error(msg.str()); } else { // allow symbolic links PHYSFS_permitSymbolicLinks(1); find_userdir(); find_datadir(); } }
void find_datadir() const { std::string datadir; if (m_forced_datadir) { datadir = *m_forced_datadir; } else if (const char* env_datadir = getenv("SUPERTUX2_DATA_DIR")) { datadir = env_datadir; } else { // check if we run from source dir char* basepath_c = SDL_GetBasePath(); std::string basepath = basepath_c ? basepath_c : "./"; SDL_free(basepath_c); if (FileSystem::exists(FileSystem::join(BUILD_DATA_DIR, "credits.stxt"))) { datadir = BUILD_DATA_DIR; // Add config dir for supplemental files PHYSFS_mount(boost::filesystem::canonical(BUILD_CONFIG_DATA_DIR).string().c_str(), NULL, 1); } else { // if the game is not run from the source directory, try to find // the global install location datadir = basepath.substr(0, basepath.rfind(INSTALL_SUBDIR_BIN)); datadir = FileSystem::join(datadir, INSTALL_SUBDIR_SHARE); } } if (!PHYSFS_mount(boost::filesystem::canonical(datadir).string().c_str(), NULL, 1)) { log_warning << "Couldn't add '" << datadir << "' to physfs searchpath: " << PHYSFS_getLastErrorCode() << std::endl; } }
FileSystem::FileSystem(std::vector<UString> paths) { // FIXME: Is this the right thing to do that? LogInfo("Registering external archivers..."); PHYSFS_registerArchiver(getCueArchiver()); // Paths are supplied in inverse-search order (IE the last in 'paths' should be the first // searched) for (auto &p : paths) { if (!PHYSFS_mount(p.cStr(), "/", 0)) { LogInfo("Failed to add resource dir \"%s\", error: %s", p, PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode())); continue; } else LogInfo("Resource dir \"%s\" mounted to \"%s\"", p, PHYSFS_getMountPoint(p.cStr())); } this->writeDir = PHYSFS_getPrefDir(PROGRAM_ORGANISATION, PROGRAM_NAME); LogInfo("Setting write directory to \"%s\"", this->writeDir); PHYSFS_setWriteDir(this->writeDir.cStr()); // Finally, the write directory trumps all PHYSFS_mount(this->writeDir.cStr(), "/", 0); }
void Level::save(const std::string& filepath, bool retry) { //FIXME: It tests for directory in supertux/data, but saves into .supertux2. try { { // make sure the level directory exists std::string dirname = FileSystem::dirname(filepath); if(!PHYSFS_exists(dirname.c_str())) { if(!PHYSFS_mkdir(dirname.c_str())) { std::ostringstream msg; msg << "Couldn't create directory for level '" << dirname << "': " <<PHYSFS_getLastErrorCode(); throw std::runtime_error(msg.str()); } } if(!PhysFSFileSystem::is_directory(dirname)) { std::ostringstream msg; msg << "Level path '" << dirname << "' is not a directory"; throw std::runtime_error(msg.str()); } } Writer writer(filepath); writer.start_list("supertux-level"); // Starts writing to supertux level file. Keep this at the very beginning. writer.write("version", 2); writer.write("name", m_name, true); writer.write("author", m_author, false); writer.write("tileset", m_tileset, false); if (m_contact != "") { writer.write("contact", m_contact, false); } if (m_license != "") { writer.write("license", m_license, false); } if (m_target_time != 0.0f){ writer.write("target-time", m_target_time); } for(auto& sector : m_sectors) { sector->save(writer); } // Ends writing to supertux level file. Keep this at the very end. writer.end_list("supertux-level"); log_warning << "Level saved as " << filepath << "." << std::endl; } catch(std::exception& e) { if (retry) { std::stringstream msg; msg << "Problem when saving level '" << filepath << "': " << e.what(); throw std::runtime_error(msg.str()); } else { log_warning << "Failed to save the level, retrying..." << std::endl; { // create the level directory again std::string dirname = FileSystem::dirname(filepath); if(!PHYSFS_mkdir(dirname.c_str())) { std::ostringstream msg; msg << "Couldn't create directory for level '" << dirname << "': " <<PHYSFS_getLastErrorCode(); throw std::runtime_error(msg.str()); } } save(filepath, true); } } }
void find_userdir() const { std::string userdir; if (m_forced_userdir) { userdir = *m_forced_userdir; } else if (const char* env_userdir = getenv("SUPERTUX2_USER_DIR")) { userdir = env_userdir; } else { userdir = PHYSFS_getPrefDir("SuperTux","supertux2"); } //Kept for backwards-compatability only, hence the silence #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" std::string physfs_userdir = PHYSFS_getUserDir(); #pragma GCC diagnostic pop #ifdef _WIN32 std::string olduserdir = FileSystem::join(physfs_userdir, PACKAGE_NAME); #else std::string olduserdir = FileSystem::join(physfs_userdir, "." PACKAGE_NAME); #endif if (FileSystem::is_directory(olduserdir)) { boost::filesystem::path olduserpath(olduserdir); boost::filesystem::path userpath(userdir); boost::filesystem::directory_iterator end_itr; bool success = true; // cycle through the directory for (boost::filesystem::directory_iterator itr(olduserpath); itr != end_itr; ++itr) { try { boost::filesystem::rename(itr->path().string().c_str(), userpath / itr->path().filename()); } catch (const boost::filesystem::filesystem_error& err) { success = false; log_warning << "Failed to move contents of config directory: " << err.what() << std::endl; } } if (success) { try { boost::filesystem::remove_all(olduserpath); } catch (const boost::filesystem::filesystem_error& err) { success = false; log_warning << "Failed to remove old config directory: " << err.what(); } } if (success) { log_info << "Moved old config dir " << olduserdir << " to " << userdir << std::endl; } } if (!FileSystem::is_directory(userdir)) { FileSystem::mkdir(userdir); log_info << "Created SuperTux userdir: " << userdir << std::endl; } if (!PHYSFS_setWriteDir(userdir.c_str())) { std::ostringstream msg; msg << "Failed to use userdir directory '" << userdir << "': " << PHYSFS_getLastErrorCode(); throw std::runtime_error(msg.str()); } PHYSFS_mount(userdir.c_str(), NULL, 0); }