mirror of
				https://github.com/PurpleI2P/i2pd.git
				synced 2025-11-04 08:30:46 +00:00 
			
		
		
		
	[windows] handle unexpected conditions (#1185)
This commit is contained in:
		
							parent
							
								
									83b5856a19
								
							
						
					
					
						commit
						7d0d421724
					
				
					 1 changed files with 171 additions and 146 deletions
				
			
		
							
								
								
									
										317
									
								
								libi2pd/FS.cpp
									
										
									
									
									
								
							
							
						
						
									
										317
									
								
								libi2pd/FS.cpp
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -11,6 +11,7 @@
 | 
			
		|||
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
#include <shlobj.h>
 | 
			
		||||
#include <windows.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "Base.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -20,187 +21,211 @@
 | 
			
		|||
 | 
			
		||||
namespace i2p {
 | 
			
		||||
namespace fs {
 | 
			
		||||
  std::string appName = "i2pd";
 | 
			
		||||
  std::string dataDir = "";
 | 
			
		||||
	std::string appName = "i2pd";
 | 
			
		||||
	std::string dataDir = "";
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
  std::string dirSep = "\\";
 | 
			
		||||
	std::string dirSep = "\\";
 | 
			
		||||
#else
 | 
			
		||||
  std::string dirSep = "/";
 | 
			
		||||
	std::string dirSep = "/";
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  const std::string & GetAppName () {
 | 
			
		||||
    return appName;
 | 
			
		||||
  }
 | 
			
		||||
	const std::string & GetAppName () {
 | 
			
		||||
		return appName;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
  void SetAppName (const std::string& name) {
 | 
			
		||||
    appName = name;
 | 
			
		||||
  }
 | 
			
		||||
	void SetAppName (const std::string& name) {
 | 
			
		||||
		appName = name;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
  const std::string & GetDataDir () {
 | 
			
		||||
    return dataDir;
 | 
			
		||||
  }
 | 
			
		||||
	const std::string & GetDataDir () {
 | 
			
		||||
		return dataDir;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
  void DetectDataDir(const std::string & cmdline_param, bool isService) {
 | 
			
		||||
    if (cmdline_param != "") {
 | 
			
		||||
      dataDir = cmdline_param;
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
	void DetectDataDir(const std::string & cmdline_param, bool isService) {
 | 
			
		||||
		if (cmdline_param != "") {
 | 
			
		||||
			dataDir = cmdline_param;
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
#if defined(WIN32) || defined(_WIN32)
 | 
			
		||||
    char localAppData[MAX_PATH];
 | 
			
		||||
    // check executable directory first
 | 
			
		||||
    GetModuleFileName (NULL, localAppData, MAX_PATH);
 | 
			
		||||
    auto execPath = boost::filesystem::path(localAppData).parent_path();
 | 
			
		||||
    // if config file exists in .exe's folder use it
 | 
			
		||||
    if(boost::filesystem::exists(execPath/"i2pd.conf")) // TODO: magic string
 | 
			
		||||
        dataDir = execPath.string ();
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        // otherwise %appdata%
 | 
			
		||||
        SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, 0, localAppData);
 | 
			
		||||
        dataDir = std::string(localAppData) + "\\" + appName;
 | 
			
		||||
    }
 | 
			
		||||
    return;
 | 
			
		||||
		char localAppData[MAX_PATH];
 | 
			
		||||
 | 
			
		||||
		// check executable directory first
 | 
			
		||||
		if(!GetModuleFileName(NULL, localAppData, MAX_PATH))
 | 
			
		||||
		{
 | 
			
		||||
#if defined(WIN32_APP)
 | 
			
		||||
			MessageBox(NULL, TEXT("Unable to get application path!"), TEXT("I2Pd: error"), MB_ICONERROR | MB_OK);
 | 
			
		||||
#else
 | 
			
		||||
			fprintf(stderr, "Error: Unable to get application path!");
 | 
			
		||||
#endif
 | 
			
		||||
			exit(1);
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			auto execPath = boost::filesystem::path(localAppData).parent_path();
 | 
			
		||||
 | 
			
		||||
			// if config file exists in .exe's folder use it
 | 
			
		||||
			if(boost::filesystem::exists(execPath/"i2pd.conf")) // TODO: magic string
 | 
			
		||||
				dataDir = execPath.string ();
 | 
			
		||||
			else // otherwise %appdata%
 | 
			
		||||
			{
 | 
			
		||||
				if(SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, 0, localAppData) != S_OK)
 | 
			
		||||
				{
 | 
			
		||||
#if defined(WIN32_APP)
 | 
			
		||||
					MessageBox(NULL, TEXT("Unable to get AppData path!"), TEXT("I2Pd: error"), MB_ICONERROR | MB_OK);
 | 
			
		||||
#else
 | 
			
		||||
					fprintf(stderr, "Error: Unable to get AppData path!");
 | 
			
		||||
#endif
 | 
			
		||||
					exit(1);
 | 
			
		||||
				}
 | 
			
		||||
				else
 | 
			
		||||
					dataDir = std::string(localAppData) + "\\" + appName;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return;
 | 
			
		||||
#elif defined(MAC_OSX)
 | 
			
		||||
    char *home = getenv("HOME");
 | 
			
		||||
    dataDir = (home != NULL && strlen(home) > 0) ? home : "";
 | 
			
		||||
    dataDir += "/Library/Application Support/" + appName;
 | 
			
		||||
    return;
 | 
			
		||||
		char *home = getenv("HOME");
 | 
			
		||||
		dataDir = (home != NULL && strlen(home) > 0) ? home : "";
 | 
			
		||||
		dataDir += "/Library/Application Support/" + appName;
 | 
			
		||||
		return;
 | 
			
		||||
#else /* other unix */
 | 
			
		||||
#if defined(ANDROID)
 | 
			
		||||
	const char * ext = getenv("EXTERNAL_STORAGE");
 | 
			
		||||
	if (!ext) ext = "/sdcard";
 | 
			
		||||
	if (boost::filesystem::exists(ext))
 | 
			
		||||
	{
 | 
			
		||||
		dataDir = std::string (ext) + "/" + appName;
 | 
			
		||||
		const char * ext = getenv("EXTERNAL_STORAGE");
 | 
			
		||||
		if (!ext) ext = "/sdcard";
 | 
			
		||||
		if (boost::filesystem::exists(ext))
 | 
			
		||||
		{
 | 
			
		||||
			dataDir = std::string (ext) + "/" + appName;
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
#endif
 | 
			
		||||
		// otherwise use /data/files
 | 
			
		||||
		char *home = getenv("HOME");
 | 
			
		||||
		if (isService) {
 | 
			
		||||
			dataDir = "/var/lib/" + appName;
 | 
			
		||||
		} else if (home != NULL && strlen(home) > 0) {
 | 
			
		||||
			dataDir = std::string(home) + "/." + appName;
 | 
			
		||||
		} else {
 | 
			
		||||
			dataDir = "/tmp/" + appName;
 | 
			
		||||
		}
 | 
			
		||||
		return;
 | 
			
		||||
#endif
 | 
			
		||||
	}
 | 
			
		||||
	// otherwise use /data/files
 | 
			
		||||
#endif
 | 
			
		||||
    char *home = getenv("HOME");
 | 
			
		||||
    if (isService) {
 | 
			
		||||
      dataDir = "/var/lib/" + appName;
 | 
			
		||||
    } else if (home != NULL && strlen(home) > 0) {
 | 
			
		||||
      dataDir = std::string(home) + "/." + appName;
 | 
			
		||||
    } else {
 | 
			
		||||
      dataDir = "/tmp/" + appName;
 | 
			
		||||
    }
 | 
			
		||||
    return;
 | 
			
		||||
#endif
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool Init() {
 | 
			
		||||
    if (!boost::filesystem::exists(dataDir))
 | 
			
		||||
      boost::filesystem::create_directory(dataDir);
 | 
			
		||||
    std::string destinations = DataDirPath("destinations");
 | 
			
		||||
    if (!boost::filesystem::exists(destinations))
 | 
			
		||||
      boost::filesystem::create_directory(destinations);
 | 
			
		||||
	std::string tags = DataDirPath("tags");
 | 
			
		||||
    if (!boost::filesystem::exists(tags))
 | 
			
		||||
	boost::filesystem::create_directory(tags);
 | 
			
		||||
	else
 | 
			
		||||
		i2p::garlic::CleanUpTagsFiles ();
 | 
			
		||||
	bool Init() {
 | 
			
		||||
		if (!boost::filesystem::exists(dataDir))
 | 
			
		||||
			boost::filesystem::create_directory(dataDir);
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
		std::string destinations = DataDirPath("destinations");
 | 
			
		||||
		if (!boost::filesystem::exists(destinations))
 | 
			
		||||
			boost::filesystem::create_directory(destinations);
 | 
			
		||||
 | 
			
		||||
  bool ReadDir(const std::string & path, std::vector<std::string> & files) {
 | 
			
		||||
    if (!boost::filesystem::exists(path))
 | 
			
		||||
      return false;
 | 
			
		||||
    boost::filesystem::directory_iterator it(path);
 | 
			
		||||
    boost::filesystem::directory_iterator end;
 | 
			
		||||
		std::string tags = DataDirPath("tags");
 | 
			
		||||
		if (!boost::filesystem::exists(tags))
 | 
			
		||||
			boost::filesystem::create_directory(tags);
 | 
			
		||||
		else
 | 
			
		||||
			i2p::garlic::CleanUpTagsFiles ();
 | 
			
		||||
 | 
			
		||||
    for ( ; it != end; it++) {
 | 
			
		||||
      if (!boost::filesystem::is_regular_file(it->status()))
 | 
			
		||||
        continue;
 | 
			
		||||
      files.push_back(it->path().string());
 | 
			
		||||
    }
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
	bool ReadDir(const std::string & path, std::vector<std::string> & files) {
 | 
			
		||||
		if (!boost::filesystem::exists(path))
 | 
			
		||||
			return false;
 | 
			
		||||
		boost::filesystem::directory_iterator it(path);
 | 
			
		||||
		boost::filesystem::directory_iterator end;
 | 
			
		||||
 | 
			
		||||
  bool Exists(const std::string & path) {
 | 
			
		||||
    return boost::filesystem::exists(path);
 | 
			
		||||
  }
 | 
			
		||||
		for ( ; it != end; it++) {
 | 
			
		||||
			if (!boost::filesystem::is_regular_file(it->status()))
 | 
			
		||||
				continue;
 | 
			
		||||
			files.push_back(it->path().string());
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
  uint32_t GetLastUpdateTime (const std::string & path)
 | 
			
		||||
  {
 | 
			
		||||
	 if (!boost::filesystem::exists(path)) return 0;
 | 
			
		||||
	 boost::system::error_code ec;
 | 
			
		||||
	 auto t = boost::filesystem::last_write_time (path, ec);
 | 
			
		||||
	 return ec ? 0 : t;
 | 
			
		||||
  }
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
  bool Remove(const std::string & path) {
 | 
			
		||||
    if (!boost::filesystem::exists(path))
 | 
			
		||||
      return false;
 | 
			
		||||
    return boost::filesystem::remove(path);
 | 
			
		||||
  }
 | 
			
		||||
	bool Exists(const std::string & path) {
 | 
			
		||||
		return boost::filesystem::exists(path);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uint32_t GetLastUpdateTime (const std::string & path)
 | 
			
		||||
	{
 | 
			
		||||
		if (!boost::filesystem::exists(path))
 | 
			
		||||
			return 0;
 | 
			
		||||
		boost::system::error_code ec;
 | 
			
		||||
		auto t = boost::filesystem::last_write_time (path, ec);
 | 
			
		||||
		return ec ? 0 : t;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool Remove(const std::string & path) {
 | 
			
		||||
		if (!boost::filesystem::exists(path))
 | 
			
		||||
			return false;
 | 
			
		||||
		return boost::filesystem::remove(path);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool CreateDirectory (const std::string& path)
 | 
			
		||||
	{
 | 
			
		||||
		if (boost::filesystem::exists(path) &&
 | 
			
		||||
			boost::filesystem::is_directory (boost::filesystem::status (path))) return true;
 | 
			
		||||
		if (boost::filesystem::exists(path) && boost::filesystem::is_directory (boost::filesystem::status (path)))
 | 
			
		||||
			return true;
 | 
			
		||||
		return boost::filesystem::create_directory(path);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
  void HashedStorage::SetPlace(const std::string &path) {
 | 
			
		||||
    root = path + i2p::fs::dirSep + name;
 | 
			
		||||
  }
 | 
			
		||||
	void HashedStorage::SetPlace(const std::string &path) {
 | 
			
		||||
		root = path + i2p::fs::dirSep + name;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
  bool HashedStorage::Init(const char * chars, size_t count) {
 | 
			
		||||
    if (!boost::filesystem::exists(root)) {
 | 
			
		||||
      boost::filesystem::create_directories(root);
 | 
			
		||||
    }
 | 
			
		||||
	bool HashedStorage::Init(const char * chars, size_t count) {
 | 
			
		||||
		if (!boost::filesystem::exists(root)) {
 | 
			
		||||
			boost::filesystem::create_directories(root);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
    for (size_t i = 0; i < count; i++) {
 | 
			
		||||
      auto p = root + i2p::fs::dirSep + prefix1 + chars[i];
 | 
			
		||||
      if (boost::filesystem::exists(p))
 | 
			
		||||
        continue;
 | 
			
		||||
      if (boost::filesystem::create_directory(p))
 | 
			
		||||
        continue; /* ^ throws exception on failure */
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
		for (size_t i = 0; i < count; i++) {
 | 
			
		||||
			auto p = root + i2p::fs::dirSep + prefix1 + chars[i];
 | 
			
		||||
			if (boost::filesystem::exists(p))
 | 
			
		||||
				continue;
 | 
			
		||||
			if (boost::filesystem::create_directory(p))
 | 
			
		||||
				continue; /* ^ throws exception on failure */
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
  std::string HashedStorage::Path(const std::string & ident) const {
 | 
			
		||||
    std::string safe_ident = ident;
 | 
			
		||||
    std::replace(safe_ident.begin(), safe_ident.end(), '/',  '-');
 | 
			
		||||
    std::replace(safe_ident.begin(), safe_ident.end(), '\\', '-');
 | 
			
		||||
	std::string HashedStorage::Path(const std::string & ident) const {
 | 
			
		||||
		std::string safe_ident = ident;
 | 
			
		||||
		std::replace(safe_ident.begin(), safe_ident.end(), '/',	'-');
 | 
			
		||||
		std::replace(safe_ident.begin(), safe_ident.end(), '\\', '-');
 | 
			
		||||
 | 
			
		||||
    std::stringstream t("");
 | 
			
		||||
    t << this->root << i2p::fs::dirSep;
 | 
			
		||||
    t << prefix1 << safe_ident[0] << i2p::fs::dirSep;
 | 
			
		||||
    t << prefix2 << safe_ident    << "." << suffix;
 | 
			
		||||
		std::stringstream t("");
 | 
			
		||||
		t << this->root << i2p::fs::dirSep;
 | 
			
		||||
		t << prefix1 << safe_ident[0] << i2p::fs::dirSep;
 | 
			
		||||
		t << prefix2 << safe_ident    << "." << suffix;
 | 
			
		||||
 | 
			
		||||
    return t.str();
 | 
			
		||||
  }
 | 
			
		||||
		return t.str();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
  void HashedStorage::Remove(const std::string & ident) {
 | 
			
		||||
    std::string path = Path(ident);
 | 
			
		||||
    if (!boost::filesystem::exists(path))
 | 
			
		||||
      return;
 | 
			
		||||
    boost::filesystem::remove(path);
 | 
			
		||||
  }
 | 
			
		||||
	void HashedStorage::Remove(const std::string & ident) {
 | 
			
		||||
		std::string path = Path(ident);
 | 
			
		||||
		if (!boost::filesystem::exists(path))
 | 
			
		||||
			return;
 | 
			
		||||
		boost::filesystem::remove(path);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
  void HashedStorage::Traverse(std::vector<std::string> & files) {
 | 
			
		||||
    Iterate([&files] (const std::string & fname) {
 | 
			
		||||
        files.push_back(fname);
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
	void HashedStorage::Traverse(std::vector<std::string> & files) {
 | 
			
		||||
		Iterate([&files] (const std::string & fname) {
 | 
			
		||||
			files.push_back(fname);
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
  void HashedStorage::Iterate(FilenameVisitor v)
 | 
			
		||||
  {
 | 
			
		||||
    boost::filesystem::path p(root);
 | 
			
		||||
    boost::filesystem::recursive_directory_iterator it(p);
 | 
			
		||||
    boost::filesystem::recursive_directory_iterator end;
 | 
			
		||||
	void HashedStorage::Iterate(FilenameVisitor v)
 | 
			
		||||
	{
 | 
			
		||||
		boost::filesystem::path p(root);
 | 
			
		||||
		boost::filesystem::recursive_directory_iterator it(p);
 | 
			
		||||
		boost::filesystem::recursive_directory_iterator end;
 | 
			
		||||
 | 
			
		||||
    for ( ; it != end; it++) {
 | 
			
		||||
      if (!boost::filesystem::is_regular_file( it->status() ))
 | 
			
		||||
        continue;
 | 
			
		||||
      const std::string & t = it->path().string();
 | 
			
		||||
      v(t);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
		for ( ; it != end; it++) {
 | 
			
		||||
			if (!boost::filesystem::is_regular_file( it->status() ))
 | 
			
		||||
				continue;
 | 
			
		||||
			const std::string & t = it->path().string();
 | 
			
		||||
			v(t);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
} // fs
 | 
			
		||||
} // i2p
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue