PageRenderTime 100ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/indra/llvfs/lldir.cpp

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