llfile.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807
  1. /**
  2. * @file llfile.cpp
  3. * @author Michael Schlachter
  4. * @date 2006-03-23
  5. * @brief Implementation of cross-platform POSIX file buffer and c++
  6. * stream classes.
  7. *
  8. * $LicenseInfo:firstyear=2006&license=viewergpl$
  9. *
  10. * Copyright (c) 2006-2009, Linden Research, Inc.
  11. *
  12. * Second Life Viewer Source Code
  13. * The source code in this file ("Source Code") is provided by Linden Lab
  14. * to you under the terms of the GNU General Public License, version 2.0
  15. * ("GPL"), unless you have obtained a separate licensing agreement
  16. * ("Other License"), formally executed by you and Linden Lab. Terms of
  17. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  18. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  19. *
  20. * There are special exceptions to the terms and conditions of the GPL as
  21. * it is applied to this Source Code. View the full text of the exception
  22. * in the file doc/FLOSS-exception.txt in this software distribution, or
  23. * online at
  24. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  25. *
  26. * By copying, modifying or distributing this software, you acknowledge
  27. * that you have read and understood your obligations described above,
  28. * and agree to abide by those obligations.
  29. *
  30. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  31. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  32. * COMPLETENESS OR PERFORMANCE.
  33. * $/LicenseInfo$
  34. */
  35. #include "linden_common.h" // Also includes llfile.h
  36. #if LL_WINDOWS
  37. # include <stdlib.h> // Windows errno
  38. # include <io.h> // _get_osfhandle()
  39. // There is no symlink() C function for Windows: use C++17 instead.
  40. # include <filesystem>
  41. #else
  42. # include <errno.h>
  43. # include <fcntl.h>
  44. # include <unistd.h>
  45. #endif
  46. #include <stdio.h>
  47. #include <utility>
  48. #include "zlib.h"
  49. #include "llstring.h"
  50. using namespace std;
  51. //static
  52. bool LLFile::sWriteError = false;
  53. bool LLFile::sFlushOnWrite = false;
  54. // Many of the methods below use OS-level functions that mess with errno. Wrap
  55. // variants of strerror() to report errors.
  56. #if LL_WINDOWS
  57. // On Windows, use strerror_s().
  58. std::string strerr(int errn)
  59. {
  60. char buffer[256];
  61. strerror_s(buffer, errn); // infers sizeof(buffer) -- love it !
  62. return buffer;
  63. }
  64. typedef std::basic_ios<char, std::char_traits<char> > _Myios;
  65. #else
  66. // On POSIX we want to call strerror_r(), but alarmingly, there are two
  67. // different variants. The one that returns int always populates the passed
  68. // buffer (except in case of error), whereas the other one always returns a
  69. // valid char* but might or might not populate the passed buffer. How do we
  70. // know which one we are getting ? Define adapters for each and let the
  71. // compiler select the applicable adapter.
  72. // strerror_r() returns char*
  73. std::string message_from(int orig_errno, const char* buffer, size_t bufflen,
  74. const char* strerror_ret)
  75. {
  76. return strerror_ret;
  77. }
  78. // strerror_r() returns int
  79. std::string message_from(int orig_errno, const char* buffer, size_t bufflen,
  80. int strerror_ret)
  81. {
  82. if (strerror_ret == 0)
  83. {
  84. return buffer;
  85. }
  86. // Here strerror_r() has set errno. Since strerror_r() has already failed,
  87. // seems like a poor bet to call it again to diagnose its own error...
  88. int stre_errno = errno;
  89. if (stre_errno == ERANGE)
  90. {
  91. return llformat("strerror_r() cannot explain errno %d (%d-byte buffer too small)",
  92. orig_errno, bufflen);
  93. }
  94. if (stre_errno == EINVAL)
  95. {
  96. return llformat("unknown errno %d", orig_errno);
  97. }
  98. // Here we do not even understand the errno from strerror_r() !
  99. return llformat("strerror_r() cannot explain errno %d (error %d)",
  100. orig_errno, stre_errno);
  101. }
  102. std::string strerr(int errn)
  103. {
  104. char buffer[256];
  105. // Select message_from() function matching the strerror_r() we have on hand
  106. return message_from(errn, buffer, sizeof(buffer),
  107. strerror_r(errn, buffer, sizeof(buffer)));
  108. }
  109. #endif // LL_WINDOWS
  110. // On either system, shorthand call just infers global 'errno'.
  111. std::string strerr()
  112. {
  113. return strerr(errno);
  114. }
  115. LLFile::LLFile(const std::string& filename, const char* mode, S64* size)
  116. {
  117. if (size)
  118. {
  119. llstat st;
  120. *size = LLFile::stat(filename, &st) == 0 &&
  121. S_ISREG(st.st_mode) ? (S64)st.st_size : 0;
  122. }
  123. mFile = LLFile::open(filename, mode);
  124. }
  125. LLFile::~LLFile()
  126. {
  127. if (mFile)
  128. {
  129. fclose(mFile);
  130. }
  131. }
  132. LLFile& LLFile::operator=(LLFILE* f)
  133. {
  134. if (mFile)
  135. {
  136. fclose(mFile);
  137. }
  138. mFile = f;
  139. return *this;
  140. }
  141. LLFile& LLFile::operator=(LLFile&& other)
  142. {
  143. if (mFile)
  144. {
  145. fclose(mFile);
  146. }
  147. std::swap(mFile, other.mFile);
  148. return *this;
  149. }
  150. S64 LLFile::read(U8* buffer, S64 bytes)
  151. {
  152. if (!mFile)
  153. {
  154. return 0;
  155. }
  156. return fread((void*)buffer, 1, bytes, mFile);
  157. }
  158. S64 LLFile::write(const U8* buffer, S64 bytes)
  159. {
  160. if (!mFile)
  161. {
  162. return 0;
  163. }
  164. S64 written = fwrite((const void*)buffer, 1, bytes, mFile);
  165. if (sFlushOnWrite)
  166. {
  167. fflush(mFile);
  168. }
  169. if (written < bytes)
  170. {
  171. sWriteError = true;
  172. }
  173. return written;
  174. }
  175. bool LLFile::flush()
  176. {
  177. return mFile && fflush(mFile) == 0;
  178. }
  179. S64 LLFile::seek(S64 position, bool delta)
  180. {
  181. if (!mFile)
  182. {
  183. return -1;
  184. }
  185. if (position < 0)
  186. {
  187. fseek(mFile, 0, SEEK_END);
  188. }
  189. else if (delta)
  190. {
  191. fseek(mFile, position, SEEK_CUR);
  192. }
  193. else
  194. {
  195. fseek(mFile, position, SEEK_SET);
  196. }
  197. return ftell(mFile);
  198. }
  199. bool LLFile::eof()
  200. {
  201. return !mFile || feof(mFile) != 0;
  202. }
  203. // Implementation borrowed/adapted from APR. HB
  204. bool LLFile::lock(bool exclusive)
  205. {
  206. if (!mFile)
  207. {
  208. return false;
  209. }
  210. #if LL_WINDOWS
  211. // Windows does not work like POSIX OSes... An exclusive lock on a file
  212. // prevents any read access to it from another process and a shared lock
  213. // prevents writes by anyone, including the lock holder. HB
  214. DWORD flags = LOCKFILE_FAIL_IMMEDIATELY;
  215. if (exclusive)
  216. {
  217. flags |= LOCKFILE_EXCLUSIVE_LOCK;
  218. }
  219. constexpr DWORD len = 0xffffffff;
  220. OVERLAPPED offset;
  221. memset(&offset, 0, sizeof(offset));
  222. HANDLE h = (HANDLE)_get_osfhandle(_fileno(mFile));
  223. memset(&offset, 0, sizeof(offset));
  224. return LockFileEx(h, flags, 0, len, len, &offset);
  225. #else
  226. // With POSIX OSes a write lock still allows the lock holder to write to
  227. // the file, while all others can still read from it. We therefore can use
  228. // the write lock and ignore entirely the 'exclusive' boolean. HB
  229. struct flock l = { 0 };
  230. l.l_whence = SEEK_SET; // Lock from start of file
  231. l.l_start = 0; // Begin lock at this offset
  232. l.l_len = 0; // Lock to end of file
  233. l.l_type = F_WRLCK; // Write lock ('exclusive' ignored).
  234. constexpr int fc = F_SETLK; // Non-blocking lock.
  235. // Keep trying if fcntl() gets interrupted (by a signal)
  236. int rc;
  237. while ((rc = fcntl(fileno(mFile), fc, &l)) < 0 && errno == EINTR) ;
  238. return rc != -1;
  239. #endif
  240. }
  241. bool LLFile::unlock()
  242. {
  243. if (!mFile)
  244. {
  245. return false;
  246. }
  247. #if LL_WINDOWS
  248. constexpr DWORD len = 0xffffffff;
  249. OVERLAPPED offset;
  250. memset(&offset, 0, sizeof(offset));
  251. HANDLE h = (HANDLE)_get_osfhandle(_fileno(mFile));
  252. memset(&offset, 0, sizeof(offset));
  253. return UnlockFileEx(h, 0, len, len, &offset);
  254. #else
  255. struct flock l = { 0 };
  256. l.l_whence = SEEK_SET; // Lock from start of file
  257. l.l_start = 0; // Begin lock at this offset
  258. l.l_len = 0; // Lock to end of file
  259. l.l_type = F_UNLCK; // Unlock.
  260. constexpr int fc = F_SETLK; // Non-blocking lock.
  261. // Keep trying if fcntl() gets interrupted (by a signal)
  262. int rc;
  263. while ((rc = fcntl(fileno(mFile), fc, &l)) < 0 && errno == EINTR) ;
  264. return rc != -1;
  265. #endif
  266. }
  267. //static
  268. bool LLFile::mkdir(const std::string& dirname, U16 perms)
  269. {
  270. #if LL_WINDOWS
  271. // Permissions are ignored on Windows
  272. int rc = _wmkdir(ll_convert_string_to_wide(dirname).c_str());
  273. #else
  274. int rc = ::mkdir(dirname.c_str(), (mode_t)perms);
  275. #endif
  276. if (rc < 0)
  277. {
  278. // Capture errno before we start emitting output
  279. int errn = errno;
  280. // We often use mkdir() to ensure the existence of a directory that
  281. // might already exist. Consider it a success when that directory
  282. // already exists.
  283. if (errn != EEXIST)
  284. {
  285. llwarns << "Failed on '" << dirname << "' (errno " << errn
  286. << "): " << strerr(errn) << llendl;
  287. return false;
  288. }
  289. }
  290. return true;
  291. }
  292. //static
  293. bool LLFile::rmdir(const std::string& dirname)
  294. {
  295. #if LL_WINDOWS
  296. // Permissions are ignored on Windows
  297. int rc = _wrmdir(ll_convert_string_to_wide(dirname).c_str());
  298. #else
  299. int rc = ::rmdir(dirname.c_str());
  300. #endif
  301. if (rc < 0)
  302. {
  303. // Capture errno before we start emitting output
  304. int errn = errno;
  305. llwarns << "Failed on '" << dirname << "' (errno " << errn
  306. << "): " << strerr(errn) << llendl;
  307. return false;
  308. }
  309. return true;
  310. }
  311. //static
  312. LLFILE* LLFile::open(const std::string& filename, const char* mode)
  313. {
  314. #if LL_WINDOWS
  315. return _wfopen(ll_convert_string_to_wide(filename).c_str(),
  316. ll_convert_string_to_wide(mode).c_str());
  317. #else
  318. return fopen(filename.c_str(), mode);
  319. #endif
  320. }
  321. //static
  322. LLFILE* LLFile::open(const char* filename, const char* mode)
  323. {
  324. #if LL_WINDOWS
  325. return _wfopen(ll_convert_string_to_wide(filename).c_str(),
  326. ll_convert_string_to_wide(mode).c_str());
  327. #else
  328. return fopen(filename, mode);
  329. #endif
  330. }
  331. void LLFile::close(LLFILE* file)
  332. {
  333. if (file)
  334. {
  335. // Note: we do not care about errors when closing
  336. fclose(file);
  337. }
  338. }
  339. bool LLFile::remove(const std::string& filename)
  340. {
  341. #if LL_WINDOWS
  342. int rc = _wremove(ll_convert_string_to_wide(filename).c_str());
  343. #else
  344. int rc = ::remove(filename.c_str());
  345. #endif
  346. if (rc)
  347. {
  348. // We do not care if the file to be removed does not exist.
  349. // Do not spam the log with such warnings either.
  350. if (errno != ENOENT)
  351. {
  352. // Capture errno before we start emitting output
  353. int errn = errno;
  354. llwarns << "Failed on '" << filename << "' (errno " << errn
  355. << "): " << strerr(errn) << llendl;
  356. return false;
  357. }
  358. }
  359. return true;
  360. }
  361. bool LLFile::rename(const std::string& filename, const std::string& newname,
  362. bool ignore_cross_linking)
  363. {
  364. #if LL_WINDOWS
  365. int rc = _wrename(ll_convert_string_to_wide(filename).c_str(),
  366. ll_convert_string_to_wide(newname).c_str());
  367. // Capture errno before we (possibly) start emitting output
  368. int errn = errno;
  369. #else
  370. int rc = ::rename(filename.c_str(), newname.c_str());
  371. int errn = errno; // Capture errno before it (possibly) changes
  372. if (rc && errn == EXDEV)
  373. {
  374. if (LLFile::copy(filename, newname))
  375. {
  376. if (!ignore_cross_linking)
  377. {
  378. llinfos << "Rename across mounts detected; moving "
  379. << filename << " to " << newname << " instead."
  380. << llendl;
  381. }
  382. unlink(filename.c_str());
  383. return true;
  384. }
  385. }
  386. #endif
  387. if (rc)
  388. {
  389. llwarns << "Failed to rename \""<< filename << "\" to \"" << newname
  390. << " \" (errno " << errn << "): " << strerr(errn) << llendl;
  391. return false;
  392. }
  393. return true;
  394. }
  395. bool LLFile::copy(const std::string from, const std::string to)
  396. {
  397. bool copied = false;
  398. LLFILE* in = LLFile::open(from, "rb");
  399. if (in)
  400. {
  401. LLFILE* out = LLFile::open(to, "wb");
  402. if (out)
  403. {
  404. char buf[16384];
  405. size_t readbytes;
  406. bool write_ok = true;
  407. while (write_ok && (readbytes = fread(buf, 1, 16384, in)))
  408. {
  409. if (fwrite(buf, 1, readbytes, out) != readbytes)
  410. {
  411. llwarns << "Short write to: " << to << llendl;
  412. write_ok = false;
  413. sWriteError = true;
  414. }
  415. }
  416. if (write_ok)
  417. {
  418. copied = true;
  419. }
  420. fclose(out);
  421. }
  422. fclose(in);
  423. }
  424. return copied;
  425. }
  426. // Returns the OS stat error code (with errno reflecting the actual error, when
  427. // it occurs): we do not warn on failures here, since this call is used in
  428. // places where the appropriate action will be taken when a failure occurs
  429. // (most of the time, we use stat to just check that a file exists). HB
  430. S32 LLFile::stat(const std::string& filename, llstat* filestatus)
  431. {
  432. #if LL_WINDOWS
  433. return _wstat(ll_convert_string_to_wide(filename).c_str(), filestatus);
  434. #else
  435. return ::stat(filename.c_str(), filestatus);
  436. #endif
  437. }
  438. bool LLFile::exists(const std::string& filename)
  439. {
  440. llstat st;
  441. return LLFile::stat(filename, &st) == 0;
  442. }
  443. bool LLFile::isdir(const std::string& filename)
  444. {
  445. llstat st;
  446. return LLFile::stat(filename, &st) == 0 && S_ISDIR(st.st_mode);
  447. }
  448. bool LLFile::isfile(const std::string& filename)
  449. {
  450. llstat st;
  451. return LLFile::stat(filename, &st) == 0 && S_ISREG(st.st_mode);
  452. }
  453. size_t LLFile::getFileSize(const std::string& filename)
  454. {
  455. llstat st;
  456. return LLFile::stat(filename, &st) == 0 &&
  457. S_ISREG(st.st_mode) ? st.st_size : 0;
  458. }
  459. time_t LLFile::lastModidied(const std::string& filename)
  460. {
  461. llstat st;
  462. return LLFile::stat(filename, &st) == 0 ? st.st_mtime : 0;
  463. }
  464. const char* LLFile::tmpdir()
  465. {
  466. static std::string utf8path;
  467. if (utf8path.empty())
  468. {
  469. char sep;
  470. #if LL_WINDOWS
  471. sep = '\\';
  472. std::vector<wchar_t> utf16path(MAX_PATH + 1);
  473. GetTempPathW(utf16path.size(), &utf16path[0]);
  474. utf8path = ll_convert_wide_to_string(&utf16path[0]);
  475. #else
  476. sep = '/';
  477. char* env = getenv("TMP");
  478. if (!env)
  479. {
  480. env = getenv("TMPDIR");
  481. }
  482. utf8path = env ? env : "/tmp/";
  483. #endif
  484. if (utf8path[utf8path.size() - 1] != sep)
  485. {
  486. utf8path += sep;
  487. }
  488. }
  489. return utf8path.c_str();
  490. }
  491. //static
  492. S32 LLFile::readEx(const std::string& filename, void* buf, S32 offset,
  493. S32 nbytes)
  494. {
  495. if (offset < 0)
  496. {
  497. llwarns << "Negative offset passed to read: " << filename << llendl;
  498. llassert(false);
  499. return 0;
  500. }
  501. LLFile infile(filename, "rb");
  502. if (!infile)
  503. {
  504. llwarns << "Failed to open for reading: " << filename << llendl;
  505. return 0;
  506. }
  507. if (offset > 0 && infile.seek(offset) != offset)
  508. {
  509. llwarns << "Failed to seek at offset " << offset << " in file: "
  510. << filename << llendl;
  511. return 0;
  512. }
  513. S32 bytes_read = infile.read((U8*)buf, nbytes);
  514. if (bytes_read != nbytes)
  515. {
  516. llwarns << "Failed to read " << nbytes << " bytes from file: "
  517. << filename << llendl;
  518. return 0;
  519. }
  520. llassert_always(bytes_read <= 0x7fffffff);
  521. return bytes_read;
  522. }
  523. //static
  524. S32 LLFile::writeEx(const std::string& filename, void* buf, S32 offset,
  525. S32 nbytes)
  526. {
  527. bool exists = LLFile::exists(filename);
  528. const char* flags = exists ? (offset < 0 ? "ab" : "r+b") : "wb";
  529. LLFile outfile(filename, flags);
  530. if (!outfile)
  531. {
  532. llwarns << "Failed to open for writing: " << filename << llendl;
  533. return 0;
  534. }
  535. if (offset > 0 && outfile.seek(offset) != offset)
  536. {
  537. llwarns << "Failed to seek at offset " << offset << " in file: "
  538. << filename << llendl;
  539. return 0;
  540. }
  541. S32 bytes_written = outfile.write((U8*)buf, nbytes);
  542. if (bytes_written != nbytes)
  543. {
  544. llwarns << "Failed to write " << nbytes << " bytes to file: "
  545. << filename << llendl;
  546. sWriteError = true;
  547. return 0;
  548. }
  549. llassert_always(bytes_written <= 0x7fffffff);
  550. return bytes_written;
  551. }
  552. //static
  553. std::string LLFile::getContents(const std::string& filename)
  554. {
  555. std::string contents;
  556. LLFILE* fp = LLFile::open(filename, "rb");
  557. if (fp)
  558. {
  559. fseek(fp, 0, SEEK_END);
  560. size_t length = (size_t)ftell(fp);
  561. if (length > 0)
  562. {
  563. fseek(fp, 0, SEEK_SET);
  564. std::vector<char> buffer(length);
  565. size_t nread = fread(buffer.data(), 1, length, fp);
  566. if (nread > 0)
  567. {
  568. contents.assign(buffer.data(), nread);
  569. }
  570. }
  571. fclose(fp);
  572. }
  573. return contents;
  574. }
  575. //static
  576. bool LLFile::createFileSymlink(const std::string& filename,
  577. const std::string& link)
  578. {
  579. if (filename.empty() || link.empty())
  580. {
  581. return false;
  582. }
  583. if (!LLFile::exists(filename))
  584. {
  585. // Create an empty file
  586. llofstream outfile(filename);
  587. if (!outfile.is_open())
  588. {
  589. llwarns << "Failed to create an empty file for non-existent "
  590. << filename << " to link to: " << link << llendl;
  591. return false;
  592. }
  593. }
  594. if (!isfile(filename))
  595. {
  596. llwarns << "Target " << filename
  597. << " is not a regular file. Cannot link it as: " << link
  598. << llendl;
  599. return false;
  600. }
  601. // Note: we could use C++17 std::filesystem too for Linux and macOS, if
  602. // only gcc 8 or older and clang v9 or older did not need a special add-on
  603. // stdc++fs library... On its side, Windows does not have the symlink() C
  604. // function. An alternative would be using boost::filesystem for everyone,
  605. // but I want to keep llcommon indepedendant from the boost_filesystem
  606. // library (which is only used by llfilesystem). HB
  607. #if LL_WINDOWS
  608. std::error_code ec;
  609. std::filesystem::create_symlink(filename, link, ec);
  610. #else
  611. int ec = symlink(filename.c_str(), link.c_str());
  612. #endif
  613. if (ec)
  614. {
  615. llwarns << "Failed to create symbolic link " << link << " for file "
  616. << filename << llendl;
  617. }
  618. return true;
  619. }
  620. //static
  621. bool LLFile::gzip(const std::string& srcfile, const std::string& dstfile)
  622. {
  623. constexpr S32 COMPRESS_BUFFER_SIZE = 32768;
  624. U8 buffer[COMPRESS_BUFFER_SIZE];
  625. std::string tmpfile = dstfile + ".tmp";
  626. #if LL_WINDOWS
  627. gzFile dst = gzopen_w(ll_convert_string_to_wide(tmpfile).c_str(), "wb");
  628. #else
  629. gzFile dst = gzopen(tmpfile.c_str(), "wb");
  630. #endif
  631. if (!dst)
  632. {
  633. return false;
  634. }
  635. LLFILE* src = LLFile::open(srcfile, "rb");
  636. if (!src)
  637. {
  638. gzclose(dst);
  639. return false;
  640. }
  641. do
  642. {
  643. size_t bytes = fread(buffer, sizeof(U8), COMPRESS_BUFFER_SIZE, src);
  644. gzwrite(dst, buffer, bytes);
  645. }
  646. while (!feof(src));
  647. LLFile::close(src);
  648. gzclose(dst);
  649. LLFile::remove(dstfile);
  650. return LLFile::rename(tmpfile, dstfile);
  651. }
  652. //static
  653. bool LLFile::gunzip(const std::string& srcfile, const std::string& dstfile)
  654. {
  655. constexpr S32 UNCOMPRESS_BUFFER_SIZE = 32768;
  656. U8 buffer[UNCOMPRESS_BUFFER_SIZE];
  657. #if LL_WINDOWS
  658. gzFile src = gzopen_w(ll_convert_string_to_wide(srcfile).c_str(), "rb");
  659. #else
  660. gzFile src = gzopen(srcfile.c_str(), "rb");
  661. #endif
  662. if (!src)
  663. {
  664. return false;
  665. }
  666. std::string tmpfile = dstfile + ".tmp";
  667. LLFILE* dst = LLFile::open(tmpfile, "wb");
  668. if (!dst)
  669. {
  670. gzclose(src);
  671. return false;
  672. }
  673. do
  674. {
  675. size_t bytes = gzread(src, buffer, UNCOMPRESS_BUFFER_SIZE);
  676. size_t nwrit = fwrite(buffer, sizeof(U8), bytes, dst);
  677. if (nwrit < bytes)
  678. {
  679. llwarns << "Short write on " << tmpfile << ": Wrote " << nwrit
  680. << " of " << bytes << " bytes." << llendl;
  681. LLFile::setWriteError();
  682. gzclose(src);
  683. LLFile::close(dst);
  684. return false;
  685. }
  686. }
  687. while (!gzeof(src));
  688. gzclose(src);
  689. LLFile::close(dst);
  690. LLFile::remove(dstfile);
  691. return LLFile::rename(tmpfile, dstfile);
  692. }
  693. #if LL_WINDOWS
  694. ///////////////////////////////////////////////////////////////////////////////
  695. // Modified file stream created to overcome the incorrect behaviour of POSIX
  696. // fopen in windows
  697. ///////////////////////////////////////////////////////////////////////////////
  698. // Input file stream
  699. llifstream::llifstream()
  700. {
  701. }
  702. //explicit
  703. llifstream::llifstream(const std::string& filename, ios_base::openmode mode)
  704. : std::ifstream(ll_convert_string_to_wide(filename).c_str(),
  705. mode | ios_base::in)
  706. {
  707. }
  708. void llifstream::open(const std::string& filename, ios_base::openmode mode)
  709. {
  710. std::ifstream::open(ll_convert_string_to_wide(filename).c_str(),
  711. mode | ios_base::in);
  712. }
  713. // Output file stream
  714. llofstream::llofstream()
  715. {
  716. }
  717. //explicit
  718. llofstream::llofstream(const std::string& filename, ios_base::openmode mode)
  719. : std::ofstream(ll_convert_string_to_wide(filename), mode | ios_base::out)
  720. {
  721. }
  722. void llofstream::open(const std::string& filename, ios_base::openmode mode)
  723. {
  724. std::ofstream::open(ll_convert_string_to_wide(filename).c_str(),
  725. mode | ios_base::out);
  726. }
  727. #endif // LL_WINDOWS