lldir.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:17k
源码类别:

游戏引擎

开发平台:

C++ Builder

  1. /** 
  2.  * @file lldir.cpp
  3.  * @brief implementation of directory utilities base class
  4.  *
  5.  * $LicenseInfo:firstyear=2002&license=viewergpl$
  6.  * 
  7.  * Copyright (c) 2002-2010, Linden Research, Inc.
  8.  * 
  9.  * Second Life Viewer Source Code
  10.  * The source code in this file ("Source Code") is provided by Linden Lab
  11.  * to you under the terms of the GNU General Public License, version 2.0
  12.  * ("GPL"), unless you have obtained a separate licensing agreement
  13.  * ("Other License"), formally executed by you and Linden Lab.  Terms of
  14.  * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15.  * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16.  * 
  17.  * There are special exceptions to the terms and conditions of the GPL as
  18.  * it is applied to this Source Code. View the full text of the exception
  19.  * in the file doc/FLOSS-exception.txt in this software distribution, or
  20.  * online at
  21.  * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22.  * 
  23.  * By copying, modifying or distributing this software, you acknowledge
  24.  * that you have read and understood your obligations described above,
  25.  * and agree to abide by those obligations.
  26.  * 
  27.  * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28.  * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29.  * COMPLETENESS OR PERFORMANCE.
  30.  * $/LicenseInfo$
  31.  */
  32. #include "linden_common.h"
  33. #if !LL_WINDOWS
  34. #include <sys/stat.h>
  35. #include <sys/types.h>
  36. #include <errno.h>
  37. #else
  38. #include <direct.h>
  39. #endif
  40. #include "lldir.h"
  41. #include "llerror.h"
  42. #include "lltimer.h" // ms_sleep()
  43. #include "lluuid.h"
  44. #if LL_WINDOWS
  45. #include "lldir_win32.h"
  46. LLDir_Win32 gDirUtil;
  47. #elif LL_DARWIN
  48. #include "lldir_mac.h"
  49. LLDir_Mac gDirUtil;
  50. #elif LL_SOLARIS
  51. #include "lldir_solaris.h"
  52. LLDir_Solaris gDirUtil;
  53. #else
  54. #include "lldir_linux.h"
  55. LLDir_Linux gDirUtil;
  56. #endif
  57. LLDir *gDirUtilp = (LLDir *)&gDirUtil;
  58. LLDir::LLDir()
  59. : mAppName(""),
  60. mExecutablePathAndName(""),
  61. mExecutableFilename(""),
  62. mExecutableDir(""),
  63. mAppRODataDir(""),
  64. mOSUserDir(""),
  65. mOSUserAppDir(""),
  66. mLindenUserDir(""),
  67. mOSCacheDir(""),
  68. mCAFile(""),
  69. mTempDir(""),
  70. mDirDelimiter("/") // fallback to forward slash if not overridden
  71. {
  72. }
  73. LLDir::~LLDir()
  74. {
  75. }
  76. S32 LLDir::deleteFilesInDir(const std::string &dirname, const std::string &mask)
  77. {
  78. S32 count = 0;
  79. std::string filename; 
  80. std::string fullpath;
  81. S32 result;
  82. while (getNextFileInDir(dirname, mask, filename, FALSE))
  83. {
  84. if ((filename == ".") || (filename == ".."))
  85. {
  86. // skipping directory traversal filenames
  87. count++;
  88. continue;
  89. }
  90. fullpath = dirname;
  91. fullpath += getDirDelimiter();
  92. fullpath += filename;
  93. S32 retry_count = 0;
  94. while (retry_count < 5)
  95. {
  96. if (0 != LLFile::remove(fullpath))
  97. {
  98. result = errno;
  99. llwarns << "Problem removing " << fullpath << " - errorcode: "
  100. << result << " attempt " << retry_count << llendl;
  101. ms_sleep(1000);
  102. }
  103. else
  104. {
  105. if (retry_count)
  106. {
  107. llwarns << "Successfully removed " << fullpath << llendl;
  108. }
  109. break;
  110. }
  111. retry_count++;
  112. }
  113. count++;
  114. }
  115. return count;
  116. }
  117. const std::string LLDir::findFile(const std::string &filename, 
  118.    const std::string& searchPath1, 
  119.    const std::string& searchPath2, 
  120.    const std::string& searchPath3) const
  121. {
  122. std::vector<std::string> search_paths;
  123. search_paths.push_back(searchPath1);
  124. search_paths.push_back(searchPath2);
  125. search_paths.push_back(searchPath3);
  126. return findFile(filename, search_paths);
  127. }
  128. const std::string LLDir::findFile(const std::string& filename, const std::vector<std::string> search_paths) const
  129. {
  130. std::vector<std::string>::const_iterator search_path_iter;
  131. for (search_path_iter = search_paths.begin();
  132. search_path_iter != search_paths.end();
  133. ++search_path_iter)
  134. {
  135. if (!search_path_iter->empty())
  136. {
  137. std::string filename_and_path = (*search_path_iter) + getDirDelimiter() + filename;
  138. if (fileExists(filename_and_path))
  139. {
  140. return filename_and_path;
  141. }
  142. }
  143. }
  144. return "";
  145. }
  146. const std::string &LLDir::getExecutablePathAndName() const
  147. {
  148. return mExecutablePathAndName;
  149. }
  150. const std::string &LLDir::getExecutableFilename() const
  151. {
  152. return mExecutableFilename;
  153. }
  154. const std::string &LLDir::getExecutableDir() const
  155. {
  156. return mExecutableDir;
  157. }
  158. const std::string &LLDir::getWorkingDir() const
  159. {
  160. return mWorkingDir;
  161. }
  162. const std::string &LLDir::getAppName() const
  163. {
  164. return mAppName;
  165. }
  166. const std::string &LLDir::getAppRODataDir() const
  167. {
  168. return mAppRODataDir;
  169. }
  170. const std::string &LLDir::getOSUserDir() const
  171. {
  172. return mOSUserDir;
  173. }
  174. const std::string &LLDir::getOSUserAppDir() const
  175. {
  176. return mOSUserAppDir;
  177. }
  178. const std::string &LLDir::getLindenUserDir() const
  179. {
  180. if (mLindenUserDir.empty())
  181. {
  182. lldebugs << "getLindenUserDir() called early, we don't have the user name yet - returning empty string to caller" << llendl;
  183. }
  184. return mLindenUserDir;
  185. }
  186. const std::string &LLDir::getChatLogsDir() const
  187. {
  188. return mChatLogsDir;
  189. }
  190. const std::string &LLDir::getPerAccountChatLogsDir() const
  191. {
  192. return mPerAccountChatLogsDir;
  193. }
  194. const std::string &LLDir::getTempDir() const
  195. {
  196. return mTempDir;
  197. }
  198. const std::string  LLDir::getCacheDir(bool get_default) const
  199. {
  200. if (mCacheDir.empty() || get_default)
  201. {
  202. if (!mDefaultCacheDir.empty())
  203. { // Set at startup - can't set here due to const API
  204. return mDefaultCacheDir;
  205. }
  206. std::string res = buildSLOSCacheDir();
  207. return res;
  208. }
  209. else
  210. {
  211. return mCacheDir;
  212. }
  213. }
  214. // Return the default cache directory
  215. std::string LLDir::buildSLOSCacheDir() const
  216. {
  217. std::string res;
  218. if (getOSCacheDir().empty())
  219. {
  220. if (getOSUserAppDir().empty())
  221. {
  222. res = "data";
  223. }
  224. else
  225. {
  226. res = getOSUserAppDir() + mDirDelimiter + "cache";
  227. }
  228. }
  229. else
  230. {
  231. res = getOSCacheDir() + mDirDelimiter + "SecondLife";
  232. }
  233. return res;
  234. }
  235. const std::string &LLDir::getOSCacheDir() const
  236. {
  237. return mOSCacheDir;
  238. }
  239. const std::string &LLDir::getCAFile() const
  240. {
  241. return mCAFile;
  242. }
  243. const std::string &LLDir::getDirDelimiter() const
  244. {
  245. return mDirDelimiter;
  246. }
  247. const std::string &LLDir::getSkinDir() const
  248. {
  249. return mSkinDir;
  250. }
  251. const std::string &LLDir::getUserSkinDir() const
  252. {
  253. return mUserSkinDir;
  254. }
  255. const std::string& LLDir::getDefaultSkinDir() const
  256. {
  257. return mDefaultSkinDir;
  258. }
  259. const std::string LLDir::getSkinBaseDir() const
  260. {
  261. return mSkinBaseDir;
  262. }
  263. const std::string &LLDir::getLLPluginDir() const
  264. {
  265. return mLLPluginDir;
  266. }
  267. std::string LLDir::getExpandedFilename(ELLPath location, const std::string& filename) const
  268. {
  269. return getExpandedFilename(location, "", filename);
  270. }
  271. std::string LLDir::getExpandedFilename(ELLPath location, const std::string& subdir, const std::string& filename) const
  272. {
  273. return getExpandedFilename(location, "", subdir, filename);
  274. }
  275. std::string LLDir::getExpandedFilename(ELLPath location, const std::string& subdir1, const std::string& subdir2, const std::string& in_filename) const
  276. {
  277. std::string prefix;
  278. switch (location)
  279. {
  280. case LL_PATH_NONE:
  281. // Do nothing
  282. break;
  283. case LL_PATH_APP_SETTINGS:
  284. prefix = getAppRODataDir();
  285. prefix += mDirDelimiter;
  286. prefix += "app_settings";
  287. break;
  288. case LL_PATH_CHARACTER:
  289. prefix = getAppRODataDir();
  290. prefix += mDirDelimiter;
  291. prefix += "character";
  292. break;
  293. case LL_PATH_HELP:
  294. prefix = "help";
  295. break;
  296. case LL_PATH_CACHE:
  297. prefix = getCacheDir();
  298. break;
  299. case LL_PATH_USER_SETTINGS:
  300. prefix = getOSUserAppDir();
  301. prefix += mDirDelimiter;
  302. prefix += "user_settings";
  303. break;
  304. case LL_PATH_PER_SL_ACCOUNT:
  305. prefix = getLindenUserDir();
  306. if (prefix.empty())
  307. {
  308. // if we're asking for the per-SL-account directory but we haven't logged in yet (or otherwise don't know the account name from which to build this string), then intentionally return a blank string to the caller and skip the below warning about a blank prefix.
  309. return std::string();
  310. }
  311. break;
  312. case LL_PATH_CHAT_LOGS:
  313. prefix = getChatLogsDir();
  314. break;
  315. case LL_PATH_PER_ACCOUNT_CHAT_LOGS:
  316. prefix = getPerAccountChatLogsDir();
  317. break;
  318. case LL_PATH_LOGS:
  319. prefix = getOSUserAppDir();
  320. prefix += mDirDelimiter;
  321. prefix += "logs";
  322. break;
  323. case LL_PATH_TEMP:
  324. prefix = getTempDir();
  325. break;
  326. case LL_PATH_TOP_SKIN:
  327. prefix = getSkinDir();
  328. break;
  329. case LL_PATH_DEFAULT_SKIN:
  330. prefix = getDefaultSkinDir();
  331. break;
  332. case LL_PATH_USER_SKIN:
  333. prefix = getOSUserAppDir();
  334. prefix += mDirDelimiter;
  335. prefix += "user_settings";
  336. prefix += mDirDelimiter;
  337. prefix += "skins";
  338. break;
  339. case LL_PATH_SKINS:
  340. prefix = getSkinBaseDir();
  341. break;
  342. case LL_PATH_LOCAL_ASSETS:
  343. prefix = getAppRODataDir();
  344. prefix += mDirDelimiter;
  345. prefix += "local_assets";
  346. break;
  347. case LL_PATH_EXECUTABLE:
  348. prefix = getExecutableDir();
  349. break;
  350. case LL_PATH_FONTS:
  351. prefix = getAppRODataDir();
  352. prefix += mDirDelimiter;
  353. prefix += "fonts";
  354. break;
  355. default:
  356. llassert(0);
  357. }
  358. std::string filename = in_filename;
  359. if (!subdir2.empty())
  360. {
  361. filename = subdir2 + mDirDelimiter + filename;
  362. }
  363. if (!subdir1.empty())
  364. {
  365. filename = subdir1 + mDirDelimiter + filename;
  366. }
  367. if (prefix.empty())
  368. {
  369. llwarns << "prefix is empty, possible bad filename" << llendl;
  370. }
  371. std::string expanded_filename;
  372. if (!filename.empty())
  373. {
  374. if (!prefix.empty())
  375. {
  376. expanded_filename += prefix;
  377. expanded_filename += mDirDelimiter;
  378. expanded_filename += filename;
  379. }
  380. else
  381. {
  382. expanded_filename = filename;
  383. }
  384. }
  385. else if (!prefix.empty())
  386. {
  387. // Directory only, no file name.
  388. expanded_filename = prefix;
  389. }
  390. else
  391. {
  392. expanded_filename.assign("");
  393. }
  394. //llinfos << "*** EXPANDED FILENAME: <" << expanded_filename << ">" << llendl;
  395. return expanded_filename;
  396. }
  397. std::string LLDir::getBaseFileName(const std::string& filepath, bool strip_exten) const
  398. {
  399. std::size_t offset = filepath.find_last_of(getDirDelimiter());
  400. offset = (offset == std::string::npos) ? 0 : offset+1;
  401. std::string res = filepath.substr(offset, std::string::npos);
  402. if (strip_exten)
  403. {
  404. offset = res.find_last_of('.');
  405. if (offset != std::string::npos &&
  406.     offset != 0) // if basename STARTS with '.', don't strip
  407. {
  408. res = res.substr(0, offset);
  409. }
  410. }
  411. return res;
  412. }
  413. std::string LLDir::getDirName(const std::string& filepath) const
  414. {
  415. std::size_t offset = filepath.find_last_of(getDirDelimiter());
  416. S32 len = (offset == std::string::npos) ? 0 : offset;
  417. std::string dirname = filepath.substr(0, len);
  418. return dirname;
  419. }
  420. std::string LLDir::getExtension(const std::string& filepath) const
  421. {
  422. if (filepath.empty())
  423. return std::string();
  424. std::string basename = getBaseFileName(filepath, false);
  425. std::size_t offset = basename.find_last_of('.');
  426. std::string exten = (offset == std::string::npos || offset == 0) ? "" : basename.substr(offset+1);
  427. LLStringUtil::toLower(exten);
  428. return exten;
  429. }
  430. std::string LLDir::findSkinnedFilename(const std::string &filename) const
  431. {
  432. return findSkinnedFilename("", "", filename);
  433. }
  434. std::string LLDir::findSkinnedFilename(const std::string &subdir, const std::string &filename) const
  435. {
  436. return findSkinnedFilename("", subdir, filename);
  437. }
  438. std::string LLDir::findSkinnedFilename(const std::string &subdir1, const std::string &subdir2, const std::string &filename) const
  439. {
  440. // generate subdirectory path fragment, e.g. "/foo/bar", "/foo", ""
  441. std::string subdirs = ((subdir1.empty() ? "" : mDirDelimiter) + subdir1)
  442.  + ((subdir2.empty() ? "" : mDirDelimiter) + subdir2);
  443. std::vector<std::string> search_paths;
  444. search_paths.push_back(getUserSkinDir() + subdirs); // first look in user skin override
  445. search_paths.push_back(getSkinDir() + subdirs); // then in current skin
  446. search_paths.push_back(getDefaultSkinDir() + subdirs);  // then default skin
  447. search_paths.push_back(getCacheDir() + subdirs); // and last in preload directory
  448. std::string found_file = findFile(filename, search_paths);
  449. return found_file;
  450. }
  451. std::string LLDir::getTempFilename() const
  452. {
  453. LLUUID random_uuid;
  454. std::string uuid_str;
  455. random_uuid.generate();
  456. random_uuid.toString(uuid_str);
  457. std::string temp_filename = getTempDir();
  458. temp_filename += mDirDelimiter;
  459. temp_filename += uuid_str;
  460. temp_filename += ".tmp";
  461. return temp_filename;
  462. }
  463. // static
  464. std::string LLDir::getScrubbedFileName(const std::string uncleanFileName)
  465. {
  466. std::string name(uncleanFileName);
  467. const std::string illegalChars(getForbiddenFileChars());
  468. // replace any illegal file chars with and underscore '_'
  469. for( unsigned int i = 0; i < illegalChars.length(); i++ )
  470. {
  471. int j = -1;
  472. while((j = name.find(illegalChars[i])) > -1)
  473. {
  474. name[j] = '_';
  475. }
  476. }
  477. return name;
  478. }
  479. // static
  480. std::string LLDir::getForbiddenFileChars()
  481. {
  482. return "\/:*?"<>|";
  483. }
  484. void LLDir::setLindenUserDir(const std::string &first, const std::string &last)
  485. {
  486. // if both first and last aren't set, that's bad.
  487. if (!first.empty() && !last.empty())
  488. {
  489. // some platforms have case-sensitive filesystems, so be
  490. // utterly consistent with our firstname/lastname case.
  491. std::string firstlower(first);
  492. LLStringUtil::toLower(firstlower);
  493. std::string lastlower(last);
  494. LLStringUtil::toLower(lastlower);
  495. mLindenUserDir = getOSUserAppDir();
  496. mLindenUserDir += mDirDelimiter;
  497. mLindenUserDir += firstlower;
  498. mLindenUserDir += "_";
  499. mLindenUserDir += lastlower;
  500. llinfos << "Got name for LLDir::setLindenUserDir(first='" << first << "', last='" << last << "')" << llendl;
  501. }
  502. else
  503. {
  504. llerrs << "Invalid name for LLDir::setLindenUserDir(first='" << first << "', last='" << last << "')" << llendl;
  505. }
  506. dumpCurrentDirectories();
  507. }
  508. void LLDir::setChatLogsDir(const std::string &path)
  509. {
  510. if (!path.empty() )
  511. {
  512. mChatLogsDir = path;
  513. }
  514. else
  515. {
  516. llwarns << "Invalid name for LLDir::setChatLogsDir" << llendl;
  517. }
  518. }
  519. void LLDir::setPerAccountChatLogsDir(const std::string &first, const std::string &last)
  520. {
  521. // if both first and last aren't set, assume we're grabbing the cached dir
  522. if (!first.empty() && !last.empty())
  523. {
  524. // some platforms have case-sensitive filesystems, so be
  525. // utterly consistent with our firstname/lastname case.
  526. std::string firstlower(first);
  527. LLStringUtil::toLower(firstlower);
  528. std::string lastlower(last);
  529. LLStringUtil::toLower(lastlower);
  530. mPerAccountChatLogsDir = getChatLogsDir();
  531. mPerAccountChatLogsDir += mDirDelimiter;
  532. mPerAccountChatLogsDir += firstlower;
  533. mPerAccountChatLogsDir += "_";
  534. mPerAccountChatLogsDir += lastlower;
  535. }
  536. else
  537. {
  538. llwarns << "Invalid name for LLDir::setPerAccountChatLogsDir" << llendl;
  539. }
  540. }
  541. void LLDir::setSkinFolder(const std::string &skin_folder)
  542. {
  543. mSkinDir = getSkinBaseDir();
  544. mSkinDir += mDirDelimiter;
  545. mSkinDir += skin_folder;
  546. // user modifications to current skin
  547. // e.g. c:documents and settingsusersusernameapplication datasecond lifeskinsdazzle
  548. mUserSkinDir = getOSUserAppDir();
  549. mUserSkinDir += mDirDelimiter;
  550. mUserSkinDir += "skins";
  551. mUserSkinDir += mDirDelimiter;
  552. mUserSkinDir += skin_folder;
  553. // base skin which is used as fallback for all skinned files
  554. // e.g. c:program filessecondlifeskinsdefault
  555. mDefaultSkinDir = getSkinBaseDir();
  556. mDefaultSkinDir += mDirDelimiter;
  557. mDefaultSkinDir += "default";
  558. }
  559. bool LLDir::setCacheDir(const std::string &path)
  560. {
  561. if (path.empty() )
  562. {
  563. // reset to default
  564. mCacheDir = "";
  565. return true;
  566. }
  567. else
  568. {
  569. LLFile::mkdir(path);
  570. std::string tempname = path + mDirDelimiter + "temp";
  571. LLFILE* file = LLFile::fopen(tempname,"wt");
  572. if (file)
  573. {
  574. fclose(file);
  575. LLFile::remove(tempname);
  576. mCacheDir = path;
  577. return true;
  578. }
  579. return false;
  580. }
  581. }
  582. void LLDir::dumpCurrentDirectories()
  583. {
  584. LL_DEBUGS2("AppInit","Directories") << "Current Directories:" << LL_ENDL;
  585. LL_DEBUGS2("AppInit","Directories") << "  CurPath:               " << getCurPath() << LL_ENDL;
  586. LL_DEBUGS2("AppInit","Directories") << "  AppName:               " << getAppName() << LL_ENDL;
  587. LL_DEBUGS2("AppInit","Directories") << "  ExecutableFilename:    " << getExecutableFilename() << LL_ENDL;
  588. LL_DEBUGS2("AppInit","Directories") << "  ExecutableDir:         " << getExecutableDir() << LL_ENDL;
  589. LL_DEBUGS2("AppInit","Directories") << "  ExecutablePathAndName: " << getExecutablePathAndName() << LL_ENDL;
  590. LL_DEBUGS2("AppInit","Directories") << "  WorkingDir:            " << getWorkingDir() << LL_ENDL;
  591. LL_DEBUGS2("AppInit","Directories") << "  AppRODataDir:          " << getAppRODataDir() << LL_ENDL;
  592. LL_DEBUGS2("AppInit","Directories") << "  OSUserDir:             " << getOSUserDir() << LL_ENDL;
  593. LL_DEBUGS2("AppInit","Directories") << "  OSUserAppDir:          " << getOSUserAppDir() << LL_ENDL;
  594. LL_DEBUGS2("AppInit","Directories") << "  LindenUserDir:         " << getLindenUserDir() << LL_ENDL;
  595. LL_DEBUGS2("AppInit","Directories") << "  TempDir:               " << getTempDir() << LL_ENDL;
  596. LL_DEBUGS2("AppInit","Directories") << "  CAFile:  " << getCAFile() << LL_ENDL;
  597. LL_DEBUGS2("AppInit","Directories") << "  SkinBaseDir:           " << getSkinBaseDir() << LL_ENDL;
  598. LL_DEBUGS2("AppInit","Directories") << "  SkinDir:               " << getSkinDir() << LL_ENDL;
  599. }
  600. void dir_exists_or_crash(const std::string &dir_name)
  601. {
  602. #if LL_WINDOWS
  603. // *FIX: lame - it doesn't do the same thing on windows. not so
  604. // important since we don't deploy simulator to windows boxes.
  605. LLFile::mkdir(dir_name, 0700);
  606. #else
  607. struct stat dir_stat;
  608. if(0 != LLFile::stat(dir_name, &dir_stat))
  609. {
  610. S32 stat_rv = errno;
  611. if(ENOENT == stat_rv)
  612. {
  613.    if(0 != LLFile::mkdir(dir_name, 0700)) // octal
  614.    {
  615.    llerrs << "Unable to create directory: " << dir_name << llendl;
  616.    }
  617. }
  618. else
  619. {
  620. llerrs << "Unable to stat: " << dir_name << " errno = " << stat_rv
  621.    << llendl;
  622. }
  623. }
  624. else
  625. {
  626. // data_dir exists, make sure it's a directory.
  627. if(!S_ISDIR(dir_stat.st_mode))
  628. {
  629. llerrs << "Data directory collision: " << dir_name << llendl;
  630. }
  631. }
  632. #endif
  633. }