]> Git Repo - VerusCoin.git/blob - src/util.cpp
Auto merge of #1300 - ThisIsNotOfficialCodeItsJustForks:t915-add-wformat-security...
[VerusCoin.git] / src / util.cpp
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2014 The Bitcoin Core developers
3 // Distributed under the MIT software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
6 #if defined(HAVE_CONFIG_H)
7 #include "config/bitcoin-config.h"
8 #endif
9
10 #include "util.h"
11
12 #include "chainparamsbase.h"
13 #include "random.h"
14 #include "serialize.h"
15 #include "sync.h"
16 #include "utilstrencodings.h"
17 #include "utiltime.h"
18
19 #include <stdarg.h>
20
21 #if (defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__))
22 #include <pthread.h>
23 #include <pthread_np.h>
24 #endif
25
26 #ifndef WIN32
27 // for posix_fallocate
28 #ifdef __linux__
29
30 #ifdef _POSIX_C_SOURCE
31 #undef _POSIX_C_SOURCE
32 #endif
33
34 #define _POSIX_C_SOURCE 200112L
35
36 #endif // __linux__
37
38 #include <algorithm>
39 #include <fcntl.h>
40 #include <sys/resource.h>
41 #include <sys/stat.h>
42
43 #else
44
45 #ifdef _MSC_VER
46 #pragma warning(disable:4786)
47 #pragma warning(disable:4804)
48 #pragma warning(disable:4805)
49 #pragma warning(disable:4717)
50 #endif
51
52 #ifdef _WIN32_WINNT
53 #undef _WIN32_WINNT
54 #endif
55 #define _WIN32_WINNT 0x0501
56
57 #ifdef _WIN32_IE
58 #undef _WIN32_IE
59 #endif
60 #define _WIN32_IE 0x0501
61
62 #define WIN32_LEAN_AND_MEAN 1
63 #ifndef NOMINMAX
64 #define NOMINMAX
65 #endif
66
67 #include <io.h> /* for _commit */
68 #include <shlobj.h>
69 #endif
70
71 #ifdef HAVE_SYS_PRCTL_H
72 #include <sys/prctl.h>
73 #endif
74
75 #include <boost/algorithm/string/case_conv.hpp> // for to_lower()
76 #include <boost/algorithm/string/join.hpp>
77 #include <boost/algorithm/string/predicate.hpp> // for startswith() and endswith()
78 #include <boost/filesystem.hpp>
79 #include <boost/filesystem/fstream.hpp>
80 #include <boost/foreach.hpp>
81 #include <boost/program_options/detail/config_file.hpp>
82 #include <boost/program_options/parsers.hpp>
83 #include <boost/thread.hpp>
84 #include <openssl/crypto.h>
85 #include <openssl/rand.h>
86 #include <openssl/conf.h>
87
88 // Work around clang compilation problem in Boost 1.46:
89 // /usr/include/boost/program_options/detail/config_file.hpp:163:17: error: call to function 'to_internal' that is neither visible in the template definition nor found by argument-dependent lookup
90 // See also: http://stackoverflow.com/questions/10020179/compilation-fail-in-boost-librairies-program-options
91 //           http://clang.debian.net/status.php?version=3.0&key=CANNOT_FIND_FUNCTION
92 namespace boost {
93
94     namespace program_options {
95         std::string to_internal(const std::string&);
96     }
97
98 } // namespace boost
99
100 using namespace std;
101
102 map<string, string> mapArgs;
103 map<string, vector<string> > mapMultiArgs;
104 bool fDebug = false;
105 bool fPrintToConsole = false;
106 bool fPrintToDebugLog = true;
107 bool fDaemon = false;
108 bool fServer = false;
109 string strMiscWarning;
110 bool fLogTimestamps = false;
111 bool fLogIPs = false;
112 volatile bool fReopenDebugLog = false;
113 CTranslationInterface translationInterface;
114
115 /** Init OpenSSL library multithreading support */
116 static CCriticalSection** ppmutexOpenSSL;
117 void locking_callback(int mode, int i, const char* file, int line) NO_THREAD_SAFETY_ANALYSIS
118 {
119     if (mode & CRYPTO_LOCK) {
120         ENTER_CRITICAL_SECTION(*ppmutexOpenSSL[i]);
121     } else {
122         LEAVE_CRITICAL_SECTION(*ppmutexOpenSSL[i]);
123     }
124 }
125
126 // Init
127 class CInit
128 {
129 public:
130     CInit()
131     {
132         // Init OpenSSL library multithreading support
133         ppmutexOpenSSL = (CCriticalSection**)OPENSSL_malloc(CRYPTO_num_locks() * sizeof(CCriticalSection*));
134         for (int i = 0; i < CRYPTO_num_locks(); i++)
135             ppmutexOpenSSL[i] = new CCriticalSection();
136         CRYPTO_set_locking_callback(locking_callback);
137
138         // OpenSSL can optionally load a config file which lists optional loadable modules and engines.
139         // We don't use them so we don't require the config. However some of our libs may call functions
140         // which attempt to load the config file, possibly resulting in an exit() or crash if it is missing
141         // or corrupt. Explicitly tell OpenSSL not to try to load the file. The result for our libs will be
142         // that the config appears to have been loaded and there are no modules/engines available.
143         OPENSSL_no_config();
144
145 #ifdef WIN32
146         // Seed OpenSSL PRNG with current contents of the screen
147         RAND_screen();
148 #endif
149
150         // Seed OpenSSL PRNG with performance counter
151         RandAddSeed();
152     }
153     ~CInit()
154     {
155         // Securely erase the memory used by the PRNG
156         RAND_cleanup();
157         // Shutdown OpenSSL library multithreading support
158         CRYPTO_set_locking_callback(NULL);
159         for (int i = 0; i < CRYPTO_num_locks(); i++)
160             delete ppmutexOpenSSL[i];
161         OPENSSL_free(ppmutexOpenSSL);
162     }
163 }
164 instance_of_cinit;
165
166 /**
167  * LogPrintf() has been broken a couple of times now
168  * by well-meaning people adding mutexes in the most straightforward way.
169  * It breaks because it may be called by global destructors during shutdown.
170  * Since the order of destruction of static/global objects is undefined,
171  * defining a mutex as a global object doesn't work (the mutex gets
172  * destroyed, and then some later destructor calls OutputDebugStringF,
173  * maybe indirectly, and you get a core dump at shutdown trying to lock
174  * the mutex).
175  */
176
177 static boost::once_flag debugPrintInitFlag = BOOST_ONCE_INIT;
178 /**
179  * We use boost::call_once() to make sure these are initialized
180  * in a thread-safe manner the first time called:
181  */
182 static FILE* fileout = NULL;
183 static boost::mutex* mutexDebugLog = NULL;
184
185 static void DebugPrintInit()
186 {
187     assert(fileout == NULL);
188     assert(mutexDebugLog == NULL);
189
190     boost::filesystem::path pathDebug = GetDataDir() / "debug.log";
191     fileout = fopen(pathDebug.string().c_str(), "a");
192     if (fileout) setbuf(fileout, NULL); // unbuffered
193
194     mutexDebugLog = new boost::mutex();
195 }
196
197 bool LogAcceptCategory(const char* category)
198 {
199     if (category != NULL)
200     {
201         if (!fDebug)
202             return false;
203
204         // Give each thread quick access to -debug settings.
205         // This helps prevent issues debugging global destructors,
206         // where mapMultiArgs might be deleted before another
207         // global destructor calls LogPrint()
208         static boost::thread_specific_ptr<set<string> > ptrCategory;
209         if (ptrCategory.get() == NULL)
210         {
211             const vector<string>& categories = mapMultiArgs["-debug"];
212             ptrCategory.reset(new set<string>(categories.begin(), categories.end()));
213             // thread_specific_ptr automatically deletes the set when the thread ends.
214         }
215         const set<string>& setCategories = *ptrCategory.get();
216
217         // if not debugging everything and not debugging specific category, LogPrint does nothing.
218         if (setCategories.count(string("")) == 0 &&
219             setCategories.count(string(category)) == 0)
220             return false;
221     }
222     return true;
223 }
224
225 int LogPrintStr(const std::string &str)
226 {
227     int ret = 0; // Returns total number of characters written
228     if (fPrintToConsole)
229     {
230         // print to console
231         ret = fwrite(str.data(), 1, str.size(), stdout);
232         fflush(stdout);
233     }
234     else if (fPrintToDebugLog && AreBaseParamsConfigured())
235     {
236         static bool fStartedNewLine = true;
237         boost::call_once(&DebugPrintInit, debugPrintInitFlag);
238
239         if (fileout == NULL)
240             return ret;
241
242         boost::mutex::scoped_lock scoped_lock(*mutexDebugLog);
243
244         // reopen the log file, if requested
245         if (fReopenDebugLog) {
246             fReopenDebugLog = false;
247             boost::filesystem::path pathDebug = GetDataDir() / "debug.log";
248             if (freopen(pathDebug.string().c_str(),"a",fileout) != NULL)
249                 setbuf(fileout, NULL); // unbuffered
250         }
251
252         // Debug print useful for profiling
253         if (fLogTimestamps && fStartedNewLine)
254             ret += fprintf(fileout, "%s ", DateTimeStrFormat("%Y-%m-%d %H:%M:%S", GetTime()).c_str());
255         if (!str.empty() && str[str.size()-1] == '\n')
256             fStartedNewLine = true;
257         else
258             fStartedNewLine = false;
259
260         ret = fwrite(str.data(), 1, str.size(), fileout);
261     }
262
263     return ret;
264 }
265
266 static void InterpretNegativeSetting(string name, map<string, string>& mapSettingsRet)
267 {
268     // interpret -nofoo as -foo=0 (and -nofoo=0 as -foo=1) as long as -foo not set
269     if (name.find("-no") == 0)
270     {
271         std::string positive("-");
272         positive.append(name.begin()+3, name.end());
273         if (mapSettingsRet.count(positive) == 0)
274         {
275             bool value = !GetBoolArg(name, false);
276             mapSettingsRet[positive] = (value ? "1" : "0");
277         }
278     }
279 }
280
281 void ParseParameters(int argc, const char* const argv[])
282 {
283     mapArgs.clear();
284     mapMultiArgs.clear();
285
286     for (int i = 1; i < argc; i++)
287     {
288         std::string str(argv[i]);
289         std::string strValue;
290         size_t is_index = str.find('=');
291         if (is_index != std::string::npos)
292         {
293             strValue = str.substr(is_index+1);
294             str = str.substr(0, is_index);
295         }
296 #ifdef WIN32
297         boost::to_lower(str);
298         if (boost::algorithm::starts_with(str, "/"))
299             str = "-" + str.substr(1);
300 #endif
301
302         if (str[0] != '-')
303             break;
304
305         // Interpret --foo as -foo.
306         // If both --foo and -foo are set, the last takes effect.
307         if (str.length() > 1 && str[1] == '-')
308             str = str.substr(1);
309
310         mapArgs[str] = strValue;
311         mapMultiArgs[str].push_back(strValue);
312     }
313
314     // New 0.6 features:
315     BOOST_FOREACH(const PAIRTYPE(string,string)& entry, mapArgs)
316     {
317         // interpret -nofoo as -foo=0 (and -nofoo=0 as -foo=1) as long as -foo not set
318         InterpretNegativeSetting(entry.first, mapArgs);
319     }
320 }
321
322 std::string GetArg(const std::string& strArg, const std::string& strDefault)
323 {
324     if (mapArgs.count(strArg))
325         return mapArgs[strArg];
326     return strDefault;
327 }
328
329 int64_t GetArg(const std::string& strArg, int64_t nDefault)
330 {
331     if (mapArgs.count(strArg))
332         return atoi64(mapArgs[strArg]);
333     return nDefault;
334 }
335
336 bool GetBoolArg(const std::string& strArg, bool fDefault)
337 {
338     if (mapArgs.count(strArg))
339     {
340         if (mapArgs[strArg].empty())
341             return true;
342         return (atoi(mapArgs[strArg]) != 0);
343     }
344     return fDefault;
345 }
346
347 bool SoftSetArg(const std::string& strArg, const std::string& strValue)
348 {
349     if (mapArgs.count(strArg))
350         return false;
351     mapArgs[strArg] = strValue;
352     return true;
353 }
354
355 bool SoftSetBoolArg(const std::string& strArg, bool fValue)
356 {
357     if (fValue)
358         return SoftSetArg(strArg, std::string("1"));
359     else
360         return SoftSetArg(strArg, std::string("0"));
361 }
362
363 static const int screenWidth = 79;
364 static const int optIndent = 2;
365 static const int msgIndent = 7;
366
367 std::string HelpMessageGroup(const std::string &message) {
368     return std::string(message) + std::string("\n\n");
369 }
370
371 std::string HelpMessageOpt(const std::string &option, const std::string &message) {
372     return std::string(optIndent,' ') + std::string(option) +
373            std::string("\n") + std::string(msgIndent,' ') +
374            FormatParagraph(message, screenWidth - msgIndent, msgIndent) +
375            std::string("\n\n");
376 }
377
378 static std::string FormatException(const std::exception* pex, const char* pszThread)
379 {
380 #ifdef WIN32
381     char pszModule[MAX_PATH] = "";
382     GetModuleFileNameA(NULL, pszModule, sizeof(pszModule));
383 #else
384     const char* pszModule = "Zcash";
385 #endif
386     if (pex)
387         return strprintf(
388             "EXCEPTION: %s       \n%s       \n%s in %s       \n", typeid(*pex).name(), pex->what(), pszModule, pszThread);
389     else
390         return strprintf(
391             "UNKNOWN EXCEPTION       \n%s in %s       \n", pszModule, pszThread);
392 }
393
394 void PrintExceptionContinue(const std::exception* pex, const char* pszThread)
395 {
396     std::string message = FormatException(pex, pszThread);
397     LogPrintf("\n\n************************\n%s\n", message);
398     fprintf(stderr, "\n\n************************\n%s\n", message.c_str());
399     strMiscWarning = message;
400 }
401
402 boost::filesystem::path GetDefaultDataDir()
403 {
404     namespace fs = boost::filesystem;
405     // Windows < Vista: C:\Documents and Settings\Username\Application Data\Zcash
406     // Windows >= Vista: C:\Users\Username\AppData\Roaming\Zcash
407     // Mac: ~/Library/Application Support/Zcash
408     // Unix: ~/.zcash
409 #ifdef WIN32
410     // Windows
411     return GetSpecialFolderPath(CSIDL_APPDATA) / "Zcash";
412 #else
413     fs::path pathRet;
414     char* pszHome = getenv("HOME");
415     if (pszHome == NULL || strlen(pszHome) == 0)
416         pathRet = fs::path("/");
417     else
418         pathRet = fs::path(pszHome);
419 #ifdef MAC_OSX
420     // Mac
421     pathRet /= "Library/Application Support";
422     TryCreateDirectory(pathRet);
423     return pathRet / "Zcash";
424 #else
425     // Unix
426     return pathRet / ".zcash";
427 #endif
428 #endif
429 }
430
431 static boost::filesystem::path pathCached;
432 static boost::filesystem::path pathCachedNetSpecific;
433 static boost::filesystem::path zc_paramsPathCached;
434 static CCriticalSection csPathCached;
435
436 static boost::filesystem::path ZC_GetBaseParamsDir()
437 {
438     // Copied from GetDefaultDataDir and adapter for zcash params.
439
440     namespace fs = boost::filesystem;
441     // Windows < Vista: C:\Documents and Settings\Username\Application Data\ZcashParams
442     // Windows >= Vista: C:\Users\Username\AppData\Roaming\ZcashParams
443     // Mac: ~/Library/Application Support/ZcashParams
444     // Unix: ~/.zcash-params
445 #ifdef WIN32
446     // Windows
447     return GetSpecialFolderPath(CSIDL_APPDATA) / "ZcashParams";
448 #else
449     fs::path pathRet;
450     char* pszHome = getenv("HOME");
451     if (pszHome == NULL || strlen(pszHome) == 0)
452         pathRet = fs::path("/");
453     else
454         pathRet = fs::path(pszHome);
455 #ifdef MAC_OSX
456     // Mac
457     pathRet /= "Library/Application Support";
458     TryCreateDirectory(pathRet);
459     return pathRet / "ZcashParams";
460 #else
461     // Unix
462     return pathRet / ".zcash-params";
463 #endif
464 #endif
465 }
466
467 const boost::filesystem::path &ZC_GetParamsDir()
468 {
469     namespace fs = boost::filesystem;
470
471     LOCK(csPathCached); // Reuse the same lock as upstream.
472
473     fs::path &path = zc_paramsPathCached;
474
475     // This can be called during exceptions by LogPrintf(), so we cache the
476     // value so we don't have to do memory allocations after that.
477     if (!path.empty())
478         return path;
479
480     path = ZC_GetBaseParamsDir();
481     path /= BaseParams().DataDir();
482
483     return path;
484 }
485
486 const boost::filesystem::path &GetDataDir(bool fNetSpecific)
487 {
488     namespace fs = boost::filesystem;
489
490     LOCK(csPathCached);
491
492     fs::path &path = fNetSpecific ? pathCachedNetSpecific : pathCached;
493
494     // This can be called during exceptions by LogPrintf(), so we cache the
495     // value so we don't have to do memory allocations after that.
496     if (!path.empty())
497         return path;
498
499     if (mapArgs.count("-datadir")) {
500         path = fs::system_complete(mapArgs["-datadir"]);
501         if (!fs::is_directory(path)) {
502             path = "";
503             return path;
504         }
505     } else {
506         path = GetDefaultDataDir();
507     }
508     if (fNetSpecific)
509         path /= BaseParams().DataDir();
510
511     fs::create_directories(path);
512
513     return path;
514 }
515
516 void ClearDatadirCache()
517 {
518     pathCached = boost::filesystem::path();
519     pathCachedNetSpecific = boost::filesystem::path();
520 }
521
522 boost::filesystem::path GetConfigFile()
523 {
524     boost::filesystem::path pathConfigFile(GetArg("-conf", "zcash.conf"));
525     if (!pathConfigFile.is_complete())
526         pathConfigFile = GetDataDir(false) / pathConfigFile;
527
528     return pathConfigFile;
529 }
530
531 void ReadConfigFile(map<string, string>& mapSettingsRet,
532                     map<string, vector<string> >& mapMultiSettingsRet)
533 {
534     boost::filesystem::ifstream streamConfig(GetConfigFile());
535     if (!streamConfig.good())
536         return; // No zcash.conf file is OK
537
538     set<string> setOptions;
539     setOptions.insert("*");
540
541     for (boost::program_options::detail::config_file_iterator it(streamConfig, setOptions), end; it != end; ++it)
542     {
543         // Don't overwrite existing settings so command line settings override zcash.conf
544         string strKey = string("-") + it->string_key;
545         if (mapSettingsRet.count(strKey) == 0)
546         {
547             mapSettingsRet[strKey] = it->value[0];
548             // interpret nofoo=1 as foo=0 (and nofoo=0 as foo=1) as long as foo not set)
549             InterpretNegativeSetting(strKey, mapSettingsRet);
550         }
551         mapMultiSettingsRet[strKey].push_back(it->value[0]);
552     }
553     // If datadir is changed in .conf file:
554     ClearDatadirCache();
555 }
556
557 #ifndef WIN32
558 boost::filesystem::path GetPidFile()
559 {
560     boost::filesystem::path pathPidFile(GetArg("-pid", "zcashd.pid"));
561     if (!pathPidFile.is_complete()) pathPidFile = GetDataDir() / pathPidFile;
562     return pathPidFile;
563 }
564
565 void CreatePidFile(const boost::filesystem::path &path, pid_t pid)
566 {
567     FILE* file = fopen(path.string().c_str(), "w");
568     if (file)
569     {
570         fprintf(file, "%d\n", pid);
571         fclose(file);
572     }
573 }
574 #endif
575
576 bool RenameOver(boost::filesystem::path src, boost::filesystem::path dest)
577 {
578 #ifdef WIN32
579     return MoveFileExA(src.string().c_str(), dest.string().c_str(),
580                        MOVEFILE_REPLACE_EXISTING) != 0;
581 #else
582     int rc = std::rename(src.string().c_str(), dest.string().c_str());
583     return (rc == 0);
584 #endif /* WIN32 */
585 }
586
587 /**
588  * Ignores exceptions thrown by Boost's create_directory if the requested directory exists.
589  * Specifically handles case where path p exists, but it wasn't possible for the user to
590  * write to the parent directory.
591  */
592 bool TryCreateDirectory(const boost::filesystem::path& p)
593 {
594     try
595     {
596         return boost::filesystem::create_directory(p);
597     } catch (const boost::filesystem::filesystem_error&) {
598         if (!boost::filesystem::exists(p) || !boost::filesystem::is_directory(p))
599             throw;
600     }
601
602     // create_directory didn't create the directory, it had to have existed already
603     return false;
604 }
605
606 void FileCommit(FILE *fileout)
607 {
608     fflush(fileout); // harmless if redundantly called
609 #ifdef WIN32
610     HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(fileout));
611     FlushFileBuffers(hFile);
612 #else
613     #if defined(__linux__) || defined(__NetBSD__)
614     fdatasync(fileno(fileout));
615     #elif defined(__APPLE__) && defined(F_FULLFSYNC)
616     fcntl(fileno(fileout), F_FULLFSYNC, 0);
617     #else
618     fsync(fileno(fileout));
619     #endif
620 #endif
621 }
622
623 bool TruncateFile(FILE *file, unsigned int length) {
624 #if defined(WIN32)
625     return _chsize(_fileno(file), length) == 0;
626 #else
627     return ftruncate(fileno(file), length) == 0;
628 #endif
629 }
630
631 /**
632  * this function tries to raise the file descriptor limit to the requested number.
633  * It returns the actual file descriptor limit (which may be more or less than nMinFD)
634  */
635 int RaiseFileDescriptorLimit(int nMinFD) {
636 #if defined(WIN32)
637     return 2048;
638 #else
639     struct rlimit limitFD;
640     if (getrlimit(RLIMIT_NOFILE, &limitFD) != -1) {
641         if (limitFD.rlim_cur < (rlim_t)nMinFD) {
642             limitFD.rlim_cur = nMinFD;
643             if (limitFD.rlim_cur > limitFD.rlim_max)
644                 limitFD.rlim_cur = limitFD.rlim_max;
645             setrlimit(RLIMIT_NOFILE, &limitFD);
646             getrlimit(RLIMIT_NOFILE, &limitFD);
647         }
648         return limitFD.rlim_cur;
649     }
650     return nMinFD; // getrlimit failed, assume it's fine
651 #endif
652 }
653
654 /**
655  * this function tries to make a particular range of a file allocated (corresponding to disk space)
656  * it is advisory, and the range specified in the arguments will never contain live data
657  */
658 void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length) {
659 #if defined(WIN32)
660     // Windows-specific version
661     HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(file));
662     LARGE_INTEGER nFileSize;
663     int64_t nEndPos = (int64_t)offset + length;
664     nFileSize.u.LowPart = nEndPos & 0xFFFFFFFF;
665     nFileSize.u.HighPart = nEndPos >> 32;
666     SetFilePointerEx(hFile, nFileSize, 0, FILE_BEGIN);
667     SetEndOfFile(hFile);
668 #elif defined(MAC_OSX)
669     // OSX specific version
670     fstore_t fst;
671     fst.fst_flags = F_ALLOCATECONTIG;
672     fst.fst_posmode = F_PEOFPOSMODE;
673     fst.fst_offset = 0;
674     fst.fst_length = (off_t)offset + length;
675     fst.fst_bytesalloc = 0;
676     if (fcntl(fileno(file), F_PREALLOCATE, &fst) == -1) {
677         fst.fst_flags = F_ALLOCATEALL;
678         fcntl(fileno(file), F_PREALLOCATE, &fst);
679     }
680     ftruncate(fileno(file), fst.fst_length);
681 #elif defined(__linux__)
682     // Version using posix_fallocate
683     off_t nEndPos = (off_t)offset + length;
684     posix_fallocate(fileno(file), 0, nEndPos);
685 #else
686     // Fallback version
687     // TODO: just write one byte per block
688     static const char buf[65536] = {};
689     fseek(file, offset, SEEK_SET);
690     while (length > 0) {
691         unsigned int now = 65536;
692         if (length < now)
693             now = length;
694         fwrite(buf, 1, now, file); // allowed to fail; this function is advisory anyway
695         length -= now;
696     }
697 #endif
698 }
699
700 void ShrinkDebugFile()
701 {
702     // Scroll debug.log if it's getting too big
703     boost::filesystem::path pathLog = GetDataDir() / "debug.log";
704     FILE* file = fopen(pathLog.string().c_str(), "r");
705     if (file && boost::filesystem::file_size(pathLog) > 10 * 1000000)
706     {
707         // Restart the file with some of the end
708         std::vector <char> vch(200000,0);
709         fseek(file, -((long)vch.size()), SEEK_END);
710         int nBytes = fread(begin_ptr(vch), 1, vch.size(), file);
711         fclose(file);
712
713         file = fopen(pathLog.string().c_str(), "w");
714         if (file)
715         {
716             fwrite(begin_ptr(vch), 1, nBytes, file);
717             fclose(file);
718         }
719     }
720     else if (file != NULL)
721         fclose(file);
722 }
723
724 #ifdef WIN32
725 boost::filesystem::path GetSpecialFolderPath(int nFolder, bool fCreate)
726 {
727     namespace fs = boost::filesystem;
728
729     char pszPath[MAX_PATH] = "";
730
731     if(SHGetSpecialFolderPathA(NULL, pszPath, nFolder, fCreate))
732     {
733         return fs::path(pszPath);
734     }
735
736     LogPrintf("SHGetSpecialFolderPathA() failed, could not obtain requested path.\n");
737     return fs::path("");
738 }
739 #endif
740
741 boost::filesystem::path GetTempPath() {
742 #if BOOST_FILESYSTEM_VERSION == 3
743     return boost::filesystem::temp_directory_path();
744 #else
745     // TODO: remove when we don't support filesystem v2 anymore
746     boost::filesystem::path path;
747 #ifdef WIN32
748     char pszPath[MAX_PATH] = "";
749
750     if (GetTempPathA(MAX_PATH, pszPath))
751         path = boost::filesystem::path(pszPath);
752 #else
753     path = boost::filesystem::path("/tmp");
754 #endif
755     if (path.empty() || !boost::filesystem::is_directory(path)) {
756         LogPrintf("GetTempPath(): failed to find temp path\n");
757         return boost::filesystem::path("");
758     }
759     return path;
760 #endif
761 }
762
763 void runCommand(std::string strCommand)
764 {
765     int nErr = ::system(strCommand.c_str());
766     if (nErr)
767         LogPrintf("runCommand error: system(%s) returned %d\n", strCommand, nErr);
768 }
769
770 void RenameThread(const char* name)
771 {
772 #if defined(PR_SET_NAME)
773     // Only the first 15 characters are used (16 - NUL terminator)
774     ::prctl(PR_SET_NAME, name, 0, 0, 0);
775 #elif (defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__))
776     pthread_set_name_np(pthread_self(), name);
777
778 #elif defined(MAC_OSX)
779     pthread_setname_np(name);
780 #else
781     // Prevent warnings for unused parameters...
782     (void)name;
783 #endif
784 }
785
786 void SetupEnvironment()
787 {
788     // On most POSIX systems (e.g. Linux, but not BSD) the environment's locale
789     // may be invalid, in which case the "C" locale is used as fallback.
790 #if !defined(WIN32) && !defined(MAC_OSX) && !defined(__FreeBSD__) && !defined(__OpenBSD__)
791     try {
792         std::locale(""); // Raises a runtime error if current locale is invalid
793     } catch (const std::runtime_error&) {
794         setenv("LC_ALL", "C", 1);
795     }
796 #endif
797     // The path locale is lazy initialized and to avoid deinitialization errors
798     // in multithreading environments, it is set explicitly by the main thread.
799     // A dummy locale is used to extract the internal default locale, used by
800     // boost::filesystem::path, which is then used to explicitly imbue the path.
801     std::locale loc = boost::filesystem::path::imbue(std::locale::classic());
802     boost::filesystem::path::imbue(loc);
803 }
804
805 void SetThreadPriority(int nPriority)
806 {
807 #ifdef WIN32
808     SetThreadPriority(GetCurrentThread(), nPriority);
809 #else // WIN32
810 #ifdef PRIO_THREAD
811     setpriority(PRIO_THREAD, 0, nPriority);
812 #else // PRIO_THREAD
813     setpriority(PRIO_PROCESS, 0, nPriority);
814 #endif // PRIO_THREAD
815 #endif // WIN32
816 }
This page took 0.070345 seconds and 4 git commands to generate.