sane filesystem code

master
darkrose 2017-05-10 22:22:41 +10:00
parent 258a6ed465
commit 1b88f95b25
13 changed files with 16 additions and 542 deletions

View File

@ -210,7 +210,6 @@ set(common_SRCS
debug.cpp
serialization.cpp
light.cpp
filesys.cpp
connection.cpp
environment.cpp
plantgrowth.cpp

View File

@ -24,7 +24,6 @@
************************************************************************/
#include "environment.h"
#include "filesys.h"
#include "porting.h"
#include "collision.h"
#include "content_mapnode.h"

View File

@ -1,298 +0,0 @@
/************************************************************************
* Minetest-c55
* Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
*
* filesys.cpp
* voxelands - 3d voxel world sandbox game
* Copyright (C) Lisa 'darkrose' Milne 2014 <lisa@ltmnet.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
* License updated from GPLv2 or later to GPLv3 or later by Lisa Milne
* for Voxelands.
************************************************************************/
#include <stdio.h>
#include "filesys.h"
#include "strfnd.h"
#include <iostream>
#include <string.h>
namespace fs
{
#ifdef _WIN32 // WINDOWS
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <stdio.h>
#include <malloc.h>
#include <tchar.h>
#include <wchar.h>
#define BUFSIZE MAX_PATH
std::vector<DirListNode> GetDirListing(std::string pathstring)
{
std::vector<DirListNode> listing;
WIN32_FIND_DATA FindFileData;
HANDLE hFind = INVALID_HANDLE_VALUE;
DWORD dwError;
LPTSTR DirSpec;
INT retval;
DirSpec = (LPTSTR) malloc (BUFSIZE);
if( DirSpec == NULL )
{
printf( "Insufficient memory available\n" );
retval = 1;
goto Cleanup;
}
// Check that the input is not larger than allowed.
if (pathstring.size() > (BUFSIZE - 2))
{
_tprintf(TEXT("Input directory is too large.\n"));
retval = 3;
goto Cleanup;
}
//_tprintf (TEXT("Target directory is %s.\n"), pathstring.c_str());
sprintf(DirSpec, "%s", (pathstring + "\\*").c_str());
// Find the first file in the directory.
hFind = FindFirstFile(DirSpec, &FindFileData);
if (hFind == INVALID_HANDLE_VALUE)
{
_tprintf (TEXT("Invalid file handle. Error is %u.\n"),
GetLastError());
retval = (-1);
}
else
{
// NOTE:
// Be very sure to not include '..' in the results, it will
// result in an epic failure when deleting stuff.
DirListNode node;
node.name = FindFileData.cFileName;
node.dir = FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
if(node.name != "." && node.name != "..")
listing.push_back(node);
// List all the other files in the directory.
while (FindNextFile(hFind, &FindFileData) != 0)
{
DirListNode node;
node.name = FindFileData.cFileName;
node.dir = FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
if(node.name != "." && node.name != "..")
listing.push_back(node);
}
dwError = GetLastError();
FindClose(hFind);
if (dwError != ERROR_NO_MORE_FILES)
{
_tprintf (TEXT("FindNextFile error. Error is %u.\n"),
dwError);
retval = (-1);
goto Cleanup;
}
}
retval = 0;
Cleanup:
free(DirSpec);
if(retval != 0) listing.clear();
//for(unsigned int i=0; i<listing.size(); i++){
// std::cout<<listing[i].name<<(listing[i].dir?" (dir)":" (file)")<<std::endl;
//}
return listing;
}
bool CreateDir(std::string path)
{
bool r = CreateDirectory(path.c_str(), NULL);
if(r == true)
return true;
if(GetLastError() == ERROR_ALREADY_EXISTS)
return true;
return false;
}
bool PathExists(std::string path)
{
return (GetFileAttributes(path.c_str()) != INVALID_FILE_ATTRIBUTES);
}
bool RecursiveDelete(std::string path)
{
std::cerr<<"Removing \""<<path<<"\""<<std::endl;
DWORD attributes = GetFileAttributes(path.c_str());
// Delete if it's a file, or call recursive delete if a directory
if(attributes == INVALID_FILE_ATTRIBUTES) {
std::cerr<<"Could not remove \""<<path<<"\""<<std::endl;
return false;
} else {
if(attributes == FILE_ATTRIBUTE_DIRECTORY) {
std::vector<DirListNode> dir_list = GetDirListing(path);
for(int i = 0; i < dir_list.size(); i++) {
DirListNode &node = dir_list[i];
std::string fpath = path + DIR_DELIM + node.name;
if(!RecursiveDelete(fpath)) {
std::cerr<<"Could not remove contents of \""<<fpath<<"\""<<std::endl;
return false;
}
}
if(!RemoveDirectory(path.c_str())) {
std::cerr<<"Could not remove \""<<path<<"\""<<std::endl;
return false;
}
} else {
if(!DeleteFile(path.c_str())) {
std::cerr<<"Could not remove \""<<path<<"\""<<std::endl;
return false;
}
}
}
return true;
}
#else // POSIX
#include <sys/time.h>
#include <unistd.h>
#include <sys/types.h>
#include <dirent.h>
#include <errno.h>
#include <sys/stat.h>
#include <ftw.h>
std::vector<DirListNode> GetDirListing(std::string pathstring)
{
std::vector<DirListNode> listing;
DIR *dp;
struct dirent *dirp;
if ((dp = opendir(pathstring.c_str())) == NULL) {
//std::cout<<"Error("<<errno<<") opening "<<pathstring<<std::endl;
return listing;
}
while ((dirp = readdir(dp)) != NULL) {
// NOTE:
// Be very sure to not include '..' in the results, it will
// result in an epic failure when deleting stuff.
if (dirp->d_name[0]!='.') {
DirListNode node;
node.name = dirp->d_name;
if (dirp->d_type == DT_DIR) {
node.dir = true;
}else{
node.dir = false;
}
if (node.name != "." && node.name != "..")
listing.push_back(node);
}
}
closedir(dp);
return listing;
}
bool CreateDir(std::string path)
{
int r = mkdir(path.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
if (r == 0)
return true;
// If already exists, return true
if (errno == EEXIST)
return true;
return false;
}
bool PathExists(std::string path)
{
struct stat st;
return (stat(path.c_str(),&st) == 0);
}
int unlink_cb(const char* fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf)
{
return remove(fpath);
}
bool RecursiveDelete(std::string path)
{
// because fuck that
if (path.substr(0,1) != "/" || path == "/")
return false;
// file tree walk, calls the unlink_cb function on every file/directory
int ret = nftw(path.c_str(), unlink_cb, 64, FTW_DEPTH | FTW_PHYS);
return (ret == 0);
}
#endif
bool RecursiveDeleteContent(std::string path)
{
std::cerr<<"Removing content of \""<<path<<"\""<<std::endl;
std::vector<DirListNode> list = GetDirListing(path);
for(unsigned int i=0; i<list.size(); i++)
{
if(trim(list[i].name) == "." || trim(list[i].name) == "..")
continue;
std::string childpath = path + DIR_DELIM + list[i].name;
bool r = RecursiveDelete(childpath);
if(r == false)
{
std::cerr<<"Removing \""<<childpath<<"\" failed"<<std::endl;
return false;
}
}
return true;
}
bool CreateAllDirs(std::string path)
{
size_t pos;
std::vector<std::string> tocreate;
std::string basepath = path;
while(!PathExists(basepath))
{
tocreate.push_back(basepath);
pos = basepath.rfind(DIR_DELIM_C);
if(pos == std::string::npos)
return false;
basepath = basepath.substr(0,pos);
}
for(int i=tocreate.size()-1;i>=0;i--)
CreateDir(tocreate[i]);
return true;
}
} // namespace fs

View File

@ -1,70 +0,0 @@
/************************************************************************
* Minetest-c55
* Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
*
* filesys.h
* voxelands - 3d voxel world sandbox game
* Copyright (C) Lisa 'darkrose' Milne 2014 <lisa@ltmnet.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
* License updated from GPLv2 or later to GPLv3 or later by Lisa Milne
* for Voxelands.
************************************************************************/
#ifndef FILESYS_HEADER
#define FILESYS_HEADER
#include <string>
#include <vector>
#include "exceptions.h"
#ifdef _WIN32 // WINDOWS
#define DIR_DELIM "\\"
#define DIR_DELIM_C '\\'
#else // POSIX
#define DIR_DELIM "/"
#define DIR_DELIM_C '/'
#endif
namespace fs
{
struct DirListNode
{
std::string name;
bool dir;
};
std::vector<DirListNode> GetDirListing(std::string path);
// Returns true if already exists
bool CreateDir(std::string path);
// Create all directories on the given path that don't already exist.
bool CreateAllDirs(std::string path);
bool PathExists(std::string path);
// Only pass full paths to this one. True on success.
// NOTE: The WIN32 version returns always true.
bool RecursiveDelete(std::string path);
// Only pass full paths to this one. True on success.
bool RecursiveDeleteContent(std::string path);
}//fs
#endif

View File

@ -46,7 +46,6 @@
#include "mainmenumanager.h"
#include "intl.h"
#include "log.h"
#include "filesys.h"
#include "path.h"
#include "sound.h"
#ifndef SERVER
@ -1164,20 +1163,24 @@ void the_game(
}else if(input->wasKeyDown(getKeySetting(VLKC_SCREENSHOT))) {
irr::video::IImage* const image = driver->createScreenShot();
if (image) {
irr::c8 filename[256];
snprintf(filename, 256, "%s" DIR_DELIM "screenshot_%u.png",
g_settings->get("screenshot_path").c_str(),
device->getTimer()->getRealTime());
if (driver->writeImageToFile(image, io::path(filename))) {
char buff[512];
snprintf(buff, 512, gettext("Saved screenshot to '%s'"), filename);
infostream << "Saved screenshot to '" << filename << "'" << std::endl;
statustext = narrow_to_wide(buff);
statustext_time = 0;
char fn[256];
char path[1024];
if (snprintf(fn,256,"screenshot_%u.png", device->getTimer()->getRealTime()) >= 256) {
infostream << "Failed to save screenshot"<<std::endl;
}else{
infostream << "Failed to save screenshot '" << filename << "'"<<std::endl;
if (path_get((char*)"screenshot",fn,0,path,1024)) {
if (driver->writeImageToFile(image, io::path(path))) {
char buff[512];
snprintf(buff, 512, gettext("Saved screenshot to '%s'"), path);
infostream << "Saved screenshot to '" << fn << "'" << std::endl;
statustext = narrow_to_wide(buff);
statustext_time = 0;
}else{
infostream << "Failed to save screenshot '" << fn << "'"<<std::endl;
}
image->drop();
}
}
image->drop();
}
}else if (input->wasKeyDown(getKeySetting(VLKC_TOGGLE_HUD))) {
show_hud = !show_hud;

View File

@ -23,7 +23,6 @@
#include "http.h"
#include "main.h"
#include "settings.h"
#include "filesys.h"
#include "debug.h"
#include <stdio.h>
#include <iostream>

View File

@ -55,7 +55,6 @@
#include "porting.h"
#include "gettime.h"
#include "guiMessageMenu.h"
#include "filesys.h"
#include "config.h"
#include "guiMainMenu.h"
#include "mineral.h"

View File

@ -30,7 +30,6 @@
#ifndef SERVER
#include "client.h"
#endif
#include "filesys.h"
#include "utility.h"
#include "voxel.h"
#include "porting.h"
@ -2365,65 +2364,6 @@ sqlite3_int64 ServerMap::getBlockAsInteger(const v3s16 pos) {
(sqlite3_int64)pos.Y*4096 + (sqlite3_int64)pos.X;
}
void ServerMap::createDirs(std::string path)
{
if(fs::CreateAllDirs(path) == false)
{
m_dout<<DTIME<<"ServerMap: Failed to create directory "
<<"\""<<path<<"\""<<std::endl;
throw BaseException("ServerMap failed to create directory");
}
}
v2s16 ServerMap::getSectorPos(std::string dirname)
{
unsigned int x, y;
int r;
size_t spos = dirname.rfind(DIR_DELIM_C) + 1;
assert(spos != std::string::npos);
if(dirname.size() - spos == 8)
{
// Old layout
r = sscanf(dirname.substr(spos).c_str(), "%4x%4x", &x, &y);
}
else if(dirname.size() - spos == 3)
{
// New layout
r = sscanf(dirname.substr(spos-4).c_str(), "%3x" DIR_DELIM "%3x", &x, &y);
// Sign-extend the 12 bit values up to 16 bits...
if(x&0x800) x|=0xF000;
if(y&0x800) y|=0xF000;
}
else
{
assert(false);
}
assert(r == 2);
v2s16 pos((s16)x, (s16)y);
return pos;
}
v3s16 ServerMap::getBlockPos(std::string sectordir, std::string blockfile)
{
v2s16 p2d = getSectorPos(sectordir);
if(blockfile.size() != 4){
throw InvalidFilenameException("Invalid block filename");
}
unsigned int y;
int r = sscanf(blockfile.c_str(), "%4x", &y);
if(r != 1)
throw InvalidFilenameException("Invalid block filename");
return v3s16(p2d.X, y, p2d.Y);
}
std::string ServerMap::getBlockFilename(v3s16 p)
{
char cc[5];
snprintf(cc, 5, "%.4x", (unsigned int)p.Y&0xffff);
return cc;
}
void ServerMap::save(bool only_changed)
{
DSTACK(__FUNCTION_NAME);
@ -2705,85 +2645,6 @@ void ServerMap::saveBlock(MapBlock *block)
block->resetModified();
}
void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSector *sector, bool save_after_load)
{
DSTACK(__FUNCTION_NAME);
std::string fullpath = sectordir+DIR_DELIM+blockfile;
try{
std::ifstream is(fullpath.c_str(), std::ios_base::binary);
if(is.good() == false)
throw FileNotGoodException("Cannot open block file");
v3s16 p3d = getBlockPos(sectordir, blockfile);
v2s16 p2d(p3d.X, p3d.Z);
assert(sector->getPos() == p2d);
u8 version = SER_FMT_VER_INVALID;
is.read((char*)&version, 1);
if(is.fail())
throw SerializationError("ServerMap::loadBlock(): Failed"
" to read MapBlock version");
/*u32 block_size = MapBlock::serializedLength(version);
SharedBuffer<u8> data(block_size);
is.read((char*)*data, block_size);*/
// This will always return a sector because we're the server
//MapSector *sector = emergeSector(p2d);
MapBlock *block = NULL;
bool created_new = false;
block = sector->getBlockNoCreateNoEx(p3d.Y);
if(block == NULL)
{
block = sector->createBlankBlockNoInsert(p3d.Y);
created_new = true;
}
// Read basic data
block->deSerialize(is, version);
// Read extra data stored on disk
block->deSerializeDiskExtra(is, version);
// If it's a new block, insert it to the map
if(created_new)
sector->insertBlock(block);
/*
Save blocks loaded in old format in new format
*/
if(version < SER_FMT_VER_HIGHEST || save_after_load)
{
saveBlock(block);
// Should be in database now, so delete the old file
fs::RecursiveDelete(fullpath);
}
// We just loaded it from the disk, so it's up-to-date.
block->resetModified();
}
catch(SerializationError &e)
{
infostream<<"WARNING: Invalid block data on disk "
<<"fullpath="<<fullpath
<<" (SerializationError). "
<<"what()="<<e.what()
<<std::endl;
//" Ignoring. A new one will be generated.
assert(0);
// TODO: Backup file; name is in fullpath.
}
}
void ServerMap::loadBlock(std::string *blob, v3s16 p3d, MapSector *sector, bool save_after_load)
{
DSTACK(__FUNCTION_NAME);

View File

@ -369,18 +369,6 @@ public:
// Helper for placing objects on ground level
s16 findGroundLevel(v2s16 p2d);
/*
Misc. helper functions for fiddling with directory and file
names when saving
*/
void createDirs(std::string path);
// returns something like "map/sectors/xxxxxxxx"
std::string getSectorDir(v2s16 pos, int layout = 2);
// dirname: final directory name
v2s16 getSectorPos(std::string dirname);
v3s16 getBlockPos(std::string sectordir, std::string blockfile);
static std::string getBlockFilename(v3s16 p);
/*
Database functions
*/
@ -406,8 +394,6 @@ public:
void loadMapMeta();
void saveBlock(MapBlock *block);
// This will generate a sector with getSector if not found.
void loadBlock(std::string sectordir, std::string blockfile, MapSector *sector, bool save_after_load=false);
MapBlock* loadBlock(v3s16 p);
// Database version
void loadBlock(std::string *blob, v3s16 p3d, MapSector *sector, bool save_after_load=false);

View File

@ -32,7 +32,6 @@
#include "porting.h"
#include "config.h"
#include "debug.h"
#include "filesys.h"
#include "player.h"
#include "errno.h"

View File

@ -35,7 +35,6 @@
#include "mineral.h"
#include "config.h"
#include "servercommand.h"
#include "filesys.h"
#include "content_object.h"
#include "content_mapnode.h"
#include "content_craft.h"

View File

@ -69,7 +69,6 @@
#include "porting.h"
#include "config.h"
#include "mineral.h"
#include "filesys.h"
#include "defaultsettings.h"
#include "settings.h"
#include "profiler.h"

View File

@ -27,7 +27,6 @@
#include "debug.h"
#include "main.h" // for g_settings
#include "game.h"
#include "filesys.h"
#include "utility.h"
#include "settings.h"
#include "mesh.h"