FS.cpp 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. /*
  2. * Copyright (c) 2013-2016, The PurpleI2P Project
  3. *
  4. * This file is part of Purple i2pd project and licensed under BSD3
  5. *
  6. * See full license text in LICENSE file at top of project tree
  7. */
  8. #include <algorithm>
  9. #include <boost/filesystem.hpp>
  10. #ifdef _WIN32
  11. #include <shlobj.h>
  12. #include <windows.h>
  13. #endif
  14. #include "Base.h"
  15. #include "FS.h"
  16. #include "Log.h"
  17. #include "Garlic.h"
  18. namespace i2p {
  19. namespace fs {
  20. std::string appName = "i2pd";
  21. std::string dataDir = "";
  22. #ifdef _WIN32
  23. std::string dirSep = "\\";
  24. #else
  25. std::string dirSep = "/";
  26. #endif
  27. const std::string & GetAppName () {
  28. return appName;
  29. }
  30. void SetAppName (const std::string& name) {
  31. appName = name;
  32. }
  33. const std::string & GetDataDir () {
  34. return dataDir;
  35. }
  36. void DetectDataDir(const std::string & cmdline_param, bool isService) {
  37. if (cmdline_param != "") {
  38. dataDir = cmdline_param;
  39. return;
  40. }
  41. #if defined(WIN32) || defined(_WIN32)
  42. char localAppData[MAX_PATH];
  43. // check executable directory first
  44. if(!GetModuleFileName(NULL, localAppData, MAX_PATH))
  45. {
  46. #if defined(WIN32_APP)
  47. MessageBox(NULL, TEXT("Unable to get application path!"), TEXT("I2Pd: error"), MB_ICONERROR | MB_OK);
  48. #else
  49. fprintf(stderr, "Error: Unable to get application path!");
  50. #endif
  51. exit(1);
  52. }
  53. else
  54. {
  55. auto execPath = boost::filesystem::path(localAppData).parent_path();
  56. // if config file exists in .exe's folder use it
  57. if(boost::filesystem::exists(execPath/"i2pd.conf")) // TODO: magic string
  58. dataDir = execPath.string ();
  59. else // otherwise %appdata%
  60. {
  61. if(SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, 0, localAppData) != S_OK)
  62. {
  63. #if defined(WIN32_APP)
  64. MessageBox(NULL, TEXT("Unable to get AppData path!"), TEXT("I2Pd: error"), MB_ICONERROR | MB_OK);
  65. #else
  66. fprintf(stderr, "Error: Unable to get AppData path!");
  67. #endif
  68. exit(1);
  69. }
  70. else
  71. dataDir = std::string(localAppData) + "\\" + appName;
  72. }
  73. }
  74. return;
  75. #elif defined(MAC_OSX)
  76. char *home = getenv("HOME");
  77. dataDir = (home != NULL && strlen(home) > 0) ? home : "";
  78. dataDir += "/Library/Application Support/" + appName;
  79. return;
  80. #else /* other unix */
  81. #if defined(ANDROID)
  82. const char * ext = getenv("EXTERNAL_STORAGE");
  83. if (!ext) ext = "/sdcard";
  84. if (boost::filesystem::exists(ext))
  85. {
  86. dataDir = std::string (ext) + "/" + appName;
  87. return;
  88. }
  89. #endif
  90. // otherwise use /data/files
  91. char *home = getenv("HOME");
  92. if (isService) {
  93. dataDir = "/var/lib/" + appName;
  94. } else if (home != NULL && strlen(home) > 0) {
  95. dataDir = std::string(home) + "/." + appName;
  96. } else {
  97. dataDir = "/tmp/" + appName;
  98. }
  99. return;
  100. #endif
  101. }
  102. bool Init() {
  103. if (!boost::filesystem::exists(dataDir))
  104. boost::filesystem::create_directory(dataDir);
  105. std::string destinations = DataDirPath("destinations");
  106. if (!boost::filesystem::exists(destinations))
  107. boost::filesystem::create_directory(destinations);
  108. std::string tags = DataDirPath("tags");
  109. if (!boost::filesystem::exists(tags))
  110. boost::filesystem::create_directory(tags);
  111. else
  112. i2p::garlic::CleanUpTagsFiles ();
  113. return true;
  114. }
  115. bool ReadDir(const std::string & path, std::vector<std::string> & files) {
  116. if (!boost::filesystem::exists(path))
  117. return false;
  118. boost::filesystem::directory_iterator it(path);
  119. boost::filesystem::directory_iterator end;
  120. for ( ; it != end; it++) {
  121. if (!boost::filesystem::is_regular_file(it->status()))
  122. continue;
  123. files.push_back(it->path().string());
  124. }
  125. return true;
  126. }
  127. bool Exists(const std::string & path) {
  128. return boost::filesystem::exists(path);
  129. }
  130. uint32_t GetLastUpdateTime (const std::string & path)
  131. {
  132. if (!boost::filesystem::exists(path))
  133. return 0;
  134. boost::system::error_code ec;
  135. auto t = boost::filesystem::last_write_time (path, ec);
  136. return ec ? 0 : t;
  137. }
  138. bool Remove(const std::string & path) {
  139. if (!boost::filesystem::exists(path))
  140. return false;
  141. return boost::filesystem::remove(path);
  142. }
  143. bool CreateDirectory (const std::string& path)
  144. {
  145. if (boost::filesystem::exists(path) && boost::filesystem::is_directory (boost::filesystem::status (path)))
  146. return true;
  147. return boost::filesystem::create_directory(path);
  148. }
  149. void HashedStorage::SetPlace(const std::string &path) {
  150. root = path + i2p::fs::dirSep + name;
  151. }
  152. bool HashedStorage::Init(const char * chars, size_t count) {
  153. if (!boost::filesystem::exists(root)) {
  154. boost::filesystem::create_directories(root);
  155. }
  156. for (size_t i = 0; i < count; i++) {
  157. auto p = root + i2p::fs::dirSep + prefix1 + chars[i];
  158. if (boost::filesystem::exists(p))
  159. continue;
  160. if (boost::filesystem::create_directory(p))
  161. continue; /* ^ throws exception on failure */
  162. return false;
  163. }
  164. return true;
  165. }
  166. std::string HashedStorage::Path(const std::string & ident) const {
  167. std::string safe_ident = ident;
  168. std::replace(safe_ident.begin(), safe_ident.end(), '/', '-');
  169. std::replace(safe_ident.begin(), safe_ident.end(), '\\', '-');
  170. std::stringstream t("");
  171. t << this->root << i2p::fs::dirSep;
  172. t << prefix1 << safe_ident[0] << i2p::fs::dirSep;
  173. t << prefix2 << safe_ident << "." << suffix;
  174. return t.str();
  175. }
  176. void HashedStorage::Remove(const std::string & ident) {
  177. std::string path = Path(ident);
  178. if (!boost::filesystem::exists(path))
  179. return;
  180. boost::filesystem::remove(path);
  181. }
  182. void HashedStorage::Traverse(std::vector<std::string> & files) {
  183. Iterate([&files] (const std::string & fname) {
  184. files.push_back(fname);
  185. });
  186. }
  187. void HashedStorage::Iterate(FilenameVisitor v)
  188. {
  189. boost::filesystem::path p(root);
  190. boost::filesystem::recursive_directory_iterator it(p);
  191. boost::filesystem::recursive_directory_iterator end;
  192. for ( ; it != end; it++) {
  193. if (!boost::filesystem::is_regular_file( it->status() ))
  194. continue;
  195. const std::string & t = it->path().string();
  196. v(t);
  197. }
  198. }
  199. } // fs
  200. } // i2p