archive_util.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704
  1. /*-
  2. * Copyright (c) 2009-2012,2014 Michihiro NAKAJIMA
  3. * Copyright (c) 2003-2007 Tim Kientzle
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions
  8. * are met:
  9. * 1. Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. *
  15. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
  16. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  17. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  18. * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
  19. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  20. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  21. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  22. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  23. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  24. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25. */
  26. #include "archive_platform.h"
  27. __FBSDID("$FreeBSD: head/lib/libarchive/archive_util.c 201098 2009-12-28 02:58:14Z kientzle $");
  28. #ifdef HAVE_SYS_TYPES_H
  29. #include <sys/types.h>
  30. #endif
  31. #ifdef HAVE_ERRNO_H
  32. #include <errno.h>
  33. #endif
  34. #ifdef HAVE_FCNTL_H
  35. #include <fcntl.h>
  36. #endif
  37. #ifdef HAVE_STDLIB_H
  38. #include <stdlib.h>
  39. #endif
  40. #ifdef HAVE_STRING_H
  41. #include <string.h>
  42. #endif
  43. #if defined(_WIN32) && !defined(__CYGWIN__)
  44. #if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
  45. /* don't use bcrypt when XP needs to be supported */
  46. #include <bcrypt.h>
  47. /* Common in other bcrypt implementations, but missing from VS2008. */
  48. #ifndef BCRYPT_SUCCESS
  49. #define BCRYPT_SUCCESS(r) ((NTSTATUS)(r) == STATUS_SUCCESS)
  50. #endif
  51. #elif defined(HAVE_WINCRYPT_H)
  52. #include <wincrypt.h>
  53. #endif
  54. #endif
  55. #ifdef HAVE_ZLIB_H
  56. #include <cm3p/zlib.h>
  57. #endif
  58. #ifdef HAVE_LZMA_H
  59. #include <cm3p/lzma.h>
  60. #endif
  61. #ifdef HAVE_BZLIB_H
  62. #include <cm3p/bzlib.h>
  63. #endif
  64. #ifdef HAVE_LZ4_H
  65. #include <lz4.h>
  66. #endif
  67. #include "archive.h"
  68. #include "archive_private.h"
  69. #include "archive_random_private.h"
  70. #include "archive_string.h"
  71. #ifndef O_CLOEXEC
  72. #define O_CLOEXEC 0
  73. #endif
  74. static int archive_utility_string_sort_helper(char **, unsigned int);
  75. /* Generic initialization of 'struct archive' objects. */
  76. int
  77. __archive_clean(struct archive *a)
  78. {
  79. archive_string_conversion_free(a);
  80. return (ARCHIVE_OK);
  81. }
  82. int
  83. archive_version_number(void)
  84. {
  85. return (ARCHIVE_VERSION_NUMBER);
  86. }
  87. const char *
  88. archive_version_string(void)
  89. {
  90. return (ARCHIVE_VERSION_STRING);
  91. }
  92. int
  93. archive_errno(struct archive *a)
  94. {
  95. return (a->archive_error_number);
  96. }
  97. const char *
  98. archive_error_string(struct archive *a)
  99. {
  100. if (a->error != NULL && *a->error != '\0')
  101. return (a->error);
  102. else
  103. return (NULL);
  104. }
  105. int
  106. archive_file_count(struct archive *a)
  107. {
  108. return (a->file_count);
  109. }
  110. int
  111. archive_format(struct archive *a)
  112. {
  113. return (a->archive_format);
  114. }
  115. const char *
  116. archive_format_name(struct archive *a)
  117. {
  118. return (a->archive_format_name);
  119. }
  120. int
  121. archive_compression(struct archive *a)
  122. {
  123. return archive_filter_code(a, 0);
  124. }
  125. const char *
  126. archive_compression_name(struct archive *a)
  127. {
  128. return archive_filter_name(a, 0);
  129. }
  130. /*
  131. * Return a count of the number of compressed bytes processed.
  132. */
  133. la_int64_t
  134. archive_position_compressed(struct archive *a)
  135. {
  136. return archive_filter_bytes(a, -1);
  137. }
  138. /*
  139. * Return a count of the number of uncompressed bytes processed.
  140. */
  141. la_int64_t
  142. archive_position_uncompressed(struct archive *a)
  143. {
  144. return archive_filter_bytes(a, 0);
  145. }
  146. void
  147. archive_clear_error(struct archive *a)
  148. {
  149. archive_string_empty(&a->error_string);
  150. a->error = NULL;
  151. a->archive_error_number = 0;
  152. }
  153. void
  154. archive_set_error(struct archive *a, int error_number, const char *fmt, ...)
  155. {
  156. va_list ap;
  157. a->archive_error_number = error_number;
  158. if (fmt == NULL) {
  159. a->error = NULL;
  160. return;
  161. }
  162. archive_string_empty(&(a->error_string));
  163. va_start(ap, fmt);
  164. archive_string_vsprintf(&(a->error_string), fmt, ap);
  165. va_end(ap);
  166. a->error = a->error_string.s;
  167. }
  168. void
  169. archive_copy_error(struct archive *dest, struct archive *src)
  170. {
  171. dest->archive_error_number = src->archive_error_number;
  172. archive_string_copy(&dest->error_string, &src->error_string);
  173. dest->error = dest->error_string.s;
  174. }
  175. void
  176. __archive_errx(int retvalue, const char *msg)
  177. {
  178. static const char msg1[] = "Fatal Internal Error in libarchive: ";
  179. size_t s;
  180. s = write(2, msg1, strlen(msg1));
  181. (void)s; /* UNUSED */
  182. s = write(2, msg, strlen(msg));
  183. (void)s; /* UNUSED */
  184. s = write(2, "\n", 1);
  185. (void)s; /* UNUSED */
  186. exit(retvalue);
  187. }
  188. /*
  189. * Create a temporary file
  190. */
  191. #if defined(_WIN32) && !defined(__CYGWIN__)
  192. /*
  193. * Do not use Windows tmpfile() function.
  194. * It will make a temporary file under the root directory
  195. * and it'll cause permission error if a user who is
  196. * non-Administrator creates temporary files.
  197. * Also Windows version of mktemp family including _mktemp_s
  198. * are not secure.
  199. */
  200. static int
  201. __archive_mktempx(const char *tmpdir, wchar_t *template)
  202. {
  203. static const wchar_t prefix[] = L"libarchive_";
  204. static const wchar_t suffix[] = L"XXXXXXXXXX";
  205. static const wchar_t num[] = {
  206. L'0', L'1', L'2', L'3', L'4', L'5', L'6', L'7',
  207. L'8', L'9', L'A', L'B', L'C', L'D', L'E', L'F',
  208. L'G', L'H', L'I', L'J', L'K', L'L', L'M', L'N',
  209. L'O', L'P', L'Q', L'R', L'S', L'T', L'U', L'V',
  210. L'W', L'X', L'Y', L'Z', L'a', L'b', L'c', L'd',
  211. L'e', L'f', L'g', L'h', L'i', L'j', L'k', L'l',
  212. L'm', L'n', L'o', L'p', L'q', L'r', L's', L't',
  213. L'u', L'v', L'w', L'x', L'y', L'z'
  214. };
  215. struct archive_wstring temp_name;
  216. wchar_t *ws;
  217. DWORD attr;
  218. wchar_t *xp, *ep;
  219. int fd;
  220. #if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
  221. BCRYPT_ALG_HANDLE hAlg = NULL;
  222. #else
  223. HCRYPTPROV hProv = (HCRYPTPROV)NULL;
  224. #endif
  225. fd = -1;
  226. ws = NULL;
  227. if (template == NULL) {
  228. archive_string_init(&temp_name);
  229. /* Get a temporary directory. */
  230. if (tmpdir == NULL) {
  231. size_t l;
  232. wchar_t *tmp;
  233. l = GetTempPathW(0, NULL);
  234. if (l == 0) {
  235. la_dosmaperr(GetLastError());
  236. goto exit_tmpfile;
  237. }
  238. tmp = malloc(l*sizeof(wchar_t));
  239. if (tmp == NULL) {
  240. errno = ENOMEM;
  241. goto exit_tmpfile;
  242. }
  243. GetTempPathW((DWORD)l, tmp);
  244. archive_wstrcpy(&temp_name, tmp);
  245. free(tmp);
  246. } else {
  247. if (archive_wstring_append_from_mbs(&temp_name, tmpdir,
  248. strlen(tmpdir)) < 0)
  249. goto exit_tmpfile;
  250. if (temp_name.s[temp_name.length-1] != L'/')
  251. archive_wstrappend_wchar(&temp_name, L'/');
  252. }
  253. /* Check if temp_name is a directory. */
  254. attr = GetFileAttributesW(temp_name.s);
  255. if (attr == (DWORD)-1) {
  256. if (GetLastError() != ERROR_FILE_NOT_FOUND) {
  257. la_dosmaperr(GetLastError());
  258. goto exit_tmpfile;
  259. }
  260. ws = __la_win_permissive_name_w(temp_name.s);
  261. if (ws == NULL) {
  262. errno = EINVAL;
  263. goto exit_tmpfile;
  264. }
  265. attr = GetFileAttributesW(ws);
  266. if (attr == (DWORD)-1) {
  267. la_dosmaperr(GetLastError());
  268. goto exit_tmpfile;
  269. }
  270. }
  271. if (!(attr & FILE_ATTRIBUTE_DIRECTORY)) {
  272. errno = ENOTDIR;
  273. goto exit_tmpfile;
  274. }
  275. /*
  276. * Create a temporary file.
  277. */
  278. archive_wstrcat(&temp_name, prefix);
  279. archive_wstrcat(&temp_name, suffix);
  280. ep = temp_name.s + archive_strlen(&temp_name);
  281. xp = ep - wcslen(suffix);
  282. template = temp_name.s;
  283. } else {
  284. xp = wcschr(template, L'X');
  285. if (xp == NULL) /* No X, programming error */
  286. abort();
  287. for (ep = xp; *ep == L'X'; ep++)
  288. continue;
  289. if (*ep) /* X followed by non X, programming error */
  290. abort();
  291. }
  292. #if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
  293. if (!BCRYPT_SUCCESS(BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_RNG_ALGORITHM,
  294. NULL, 0))) {
  295. la_dosmaperr(GetLastError());
  296. goto exit_tmpfile;
  297. }
  298. #else
  299. if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL,
  300. CRYPT_VERIFYCONTEXT)) {
  301. la_dosmaperr(GetLastError());
  302. goto exit_tmpfile;
  303. }
  304. #endif
  305. for (;;) {
  306. wchar_t *p;
  307. HANDLE h;
  308. # if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */
  309. CREATEFILE2_EXTENDED_PARAMETERS createExParams;
  310. #endif
  311. /* Generate a random file name through CryptGenRandom(). */
  312. p = xp;
  313. #if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
  314. if (!BCRYPT_SUCCESS(BCryptGenRandom(hAlg, (PUCHAR)p,
  315. (DWORD)(ep - p)*sizeof(wchar_t), 0))) {
  316. la_dosmaperr(GetLastError());
  317. goto exit_tmpfile;
  318. }
  319. #else
  320. if (!CryptGenRandom(hProv, (DWORD)(ep - p)*sizeof(wchar_t),
  321. (BYTE*)p)) {
  322. la_dosmaperr(GetLastError());
  323. goto exit_tmpfile;
  324. }
  325. #endif
  326. for (; p < ep; p++)
  327. *p = num[((DWORD)*p) % (sizeof(num)/sizeof(num[0]))];
  328. free(ws);
  329. ws = __la_win_permissive_name_w(template);
  330. if (ws == NULL) {
  331. errno = EINVAL;
  332. goto exit_tmpfile;
  333. }
  334. if (template == temp_name.s) {
  335. attr = FILE_ATTRIBUTE_TEMPORARY |
  336. FILE_FLAG_DELETE_ON_CLOSE;
  337. } else {
  338. /* mkstemp */
  339. attr = FILE_ATTRIBUTE_NORMAL;
  340. }
  341. # if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */
  342. ZeroMemory(&createExParams, sizeof(createExParams));
  343. createExParams.dwSize = sizeof(createExParams);
  344. createExParams.dwFileAttributes = attr & 0xFFFF;
  345. createExParams.dwFileFlags = attr & 0xFFF00000;
  346. h = CreateFile2(ws,
  347. GENERIC_READ | GENERIC_WRITE | DELETE,
  348. 0,/* Not share */
  349. CREATE_NEW,
  350. &createExParams);
  351. #else
  352. h = CreateFileW(ws,
  353. GENERIC_READ | GENERIC_WRITE | DELETE,
  354. 0,/* Not share */
  355. NULL,
  356. CREATE_NEW,/* Create a new file only */
  357. attr,
  358. NULL);
  359. #endif
  360. if (h == INVALID_HANDLE_VALUE) {
  361. /* The same file already exists. retry with
  362. * a new filename. */
  363. if (GetLastError() == ERROR_FILE_EXISTS)
  364. continue;
  365. /* Otherwise, fail creation temporary file. */
  366. la_dosmaperr(GetLastError());
  367. goto exit_tmpfile;
  368. }
  369. fd = _open_osfhandle((intptr_t)h, _O_BINARY | _O_RDWR);
  370. if (fd == -1) {
  371. la_dosmaperr(GetLastError());
  372. CloseHandle(h);
  373. goto exit_tmpfile;
  374. } else
  375. break;/* success! */
  376. }
  377. exit_tmpfile:
  378. #if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
  379. if (hAlg != NULL)
  380. BCryptCloseAlgorithmProvider(hAlg, 0);
  381. #else
  382. if (hProv != (HCRYPTPROV)NULL)
  383. CryptReleaseContext(hProv, 0);
  384. #endif
  385. free(ws);
  386. if (template == temp_name.s)
  387. archive_wstring_free(&temp_name);
  388. return (fd);
  389. }
  390. int
  391. __archive_mktemp(const char *tmpdir)
  392. {
  393. return __archive_mktempx(tmpdir, NULL);
  394. }
  395. int
  396. __archive_mkstemp(wchar_t *template)
  397. {
  398. return __archive_mktempx(NULL, template);
  399. }
  400. #else
  401. static int
  402. get_tempdir(struct archive_string *temppath)
  403. {
  404. const char *tmp;
  405. tmp = getenv("TMPDIR");
  406. if (tmp == NULL)
  407. #ifdef _PATH_TMP
  408. tmp = _PATH_TMP;
  409. #else
  410. tmp = "/tmp";
  411. #endif
  412. archive_strcpy(temppath, tmp);
  413. if (temppath->s[temppath->length-1] != '/')
  414. archive_strappend_char(temppath, '/');
  415. return (ARCHIVE_OK);
  416. }
  417. #if defined(HAVE_MKSTEMP)
  418. /*
  419. * We can use mkstemp().
  420. */
  421. int
  422. __archive_mktemp(const char *tmpdir)
  423. {
  424. struct archive_string temp_name;
  425. int fd = -1;
  426. archive_string_init(&temp_name);
  427. if (tmpdir == NULL) {
  428. if (get_tempdir(&temp_name) != ARCHIVE_OK)
  429. goto exit_tmpfile;
  430. } else {
  431. archive_strcpy(&temp_name, tmpdir);
  432. if (temp_name.s[temp_name.length-1] != '/')
  433. archive_strappend_char(&temp_name, '/');
  434. }
  435. #ifdef O_TMPFILE
  436. fd = open(temp_name.s, O_RDWR|O_CLOEXEC|O_TMPFILE|O_EXCL, 0600);
  437. if(fd >= 0)
  438. goto exit_tmpfile;
  439. #endif
  440. archive_strcat(&temp_name, "libarchive_XXXXXX");
  441. fd = mkstemp(temp_name.s);
  442. if (fd < 0)
  443. goto exit_tmpfile;
  444. __archive_ensure_cloexec_flag(fd);
  445. unlink(temp_name.s);
  446. exit_tmpfile:
  447. archive_string_free(&temp_name);
  448. return (fd);
  449. }
  450. int
  451. __archive_mkstemp(char *template)
  452. {
  453. int fd = -1;
  454. fd = mkstemp(template);
  455. if (fd >= 0)
  456. __archive_ensure_cloexec_flag(fd);
  457. return (fd);
  458. }
  459. #else /* !HAVE_MKSTEMP */
  460. /*
  461. * We use a private routine.
  462. */
  463. static int
  464. __archive_mktempx(const char *tmpdir, char *template)
  465. {
  466. static const char num[] = {
  467. '0', '1', '2', '3', '4', '5', '6', '7',
  468. '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
  469. 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
  470. 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
  471. 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
  472. 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
  473. 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
  474. 'u', 'v', 'w', 'x', 'y', 'z'
  475. };
  476. struct archive_string temp_name;
  477. struct stat st;
  478. int fd;
  479. char *tp, *ep;
  480. fd = -1;
  481. if (template == NULL) {
  482. archive_string_init(&temp_name);
  483. if (tmpdir == NULL) {
  484. if (get_tempdir(&temp_name) != ARCHIVE_OK)
  485. goto exit_tmpfile;
  486. } else
  487. archive_strcpy(&temp_name, tmpdir);
  488. if (temp_name.s[temp_name.length-1] == '/') {
  489. temp_name.s[temp_name.length-1] = '\0';
  490. temp_name.length --;
  491. }
  492. if (la_stat(temp_name.s, &st) < 0)
  493. goto exit_tmpfile;
  494. if (!S_ISDIR(st.st_mode)) {
  495. errno = ENOTDIR;
  496. goto exit_tmpfile;
  497. }
  498. archive_strcat(&temp_name, "/libarchive_");
  499. tp = temp_name.s + archive_strlen(&temp_name);
  500. archive_strcat(&temp_name, "XXXXXXXXXX");
  501. ep = temp_name.s + archive_strlen(&temp_name);
  502. template = temp_name.s;
  503. } else {
  504. tp = strchr(template, 'X');
  505. if (tp == NULL) /* No X, programming error */
  506. abort();
  507. for (ep = tp; *ep == 'X'; ep++)
  508. continue;
  509. if (*ep) /* X followed by non X, programming error */
  510. abort();
  511. }
  512. do {
  513. char *p;
  514. p = tp;
  515. archive_random(p, ep - p);
  516. while (p < ep) {
  517. int d = *((unsigned char *)p) % sizeof(num);
  518. *p++ = num[d];
  519. }
  520. fd = open(template, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC,
  521. 0600);
  522. } while (fd < 0 && errno == EEXIST);
  523. if (fd < 0)
  524. goto exit_tmpfile;
  525. __archive_ensure_cloexec_flag(fd);
  526. if (template == temp_name.s)
  527. unlink(temp_name.s);
  528. exit_tmpfile:
  529. if (template == temp_name.s)
  530. archive_string_free(&temp_name);
  531. return (fd);
  532. }
  533. int
  534. __archive_mktemp(const char *tmpdir)
  535. {
  536. return __archive_mktempx(tmpdir, NULL);
  537. }
  538. int
  539. __archive_mkstemp(char *template)
  540. {
  541. return __archive_mktempx(NULL, template);
  542. }
  543. #endif /* !HAVE_MKSTEMP */
  544. #endif /* !_WIN32 || __CYGWIN__ */
  545. /*
  546. * Set FD_CLOEXEC flag to a file descriptor if it is not set.
  547. * We have to set the flag if the platform does not provide O_CLOEXEC
  548. * or F_DUPFD_CLOEXEC flags.
  549. *
  550. * Note: This function is absolutely called after creating a new file
  551. * descriptor even if the platform seemingly provides O_CLOEXEC or
  552. * F_DUPFD_CLOEXEC macros because it is possible that the platform
  553. * merely declares those macros, especially Linux 2.6.18 - 2.6.24 do it.
  554. */
  555. void
  556. __archive_ensure_cloexec_flag(int fd)
  557. {
  558. #if defined(_WIN32) && !defined(__CYGWIN__)
  559. (void)fd; /* UNUSED */
  560. #else
  561. int flags;
  562. if (fd >= 0) {
  563. flags = fcntl(fd, F_GETFD);
  564. if (flags != -1 && (flags & FD_CLOEXEC) == 0)
  565. fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
  566. }
  567. #endif
  568. }
  569. /*
  570. * Utility function to sort a group of strings using quicksort.
  571. */
  572. static int
  573. archive_utility_string_sort_helper(char **strings, unsigned int n)
  574. {
  575. unsigned int i, lesser_count, greater_count;
  576. char **lesser, **greater, **tmp, *pivot;
  577. int retval1, retval2;
  578. /* A list of 0 or 1 elements is already sorted */
  579. if (n <= 1)
  580. return (ARCHIVE_OK);
  581. lesser_count = greater_count = 0;
  582. lesser = greater = NULL;
  583. pivot = strings[0];
  584. for (i = 1; i < n; i++)
  585. {
  586. if (strcmp(strings[i], pivot) < 0)
  587. {
  588. lesser_count++;
  589. tmp = (char **)realloc(lesser,
  590. lesser_count * sizeof(char *));
  591. if (!tmp) {
  592. free(greater);
  593. free(lesser);
  594. return (ARCHIVE_FATAL);
  595. }
  596. lesser = tmp;
  597. lesser[lesser_count - 1] = strings[i];
  598. }
  599. else
  600. {
  601. greater_count++;
  602. tmp = (char **)realloc(greater,
  603. greater_count * sizeof(char *));
  604. if (!tmp) {
  605. free(greater);
  606. free(lesser);
  607. return (ARCHIVE_FATAL);
  608. }
  609. greater = tmp;
  610. greater[greater_count - 1] = strings[i];
  611. }
  612. }
  613. /* quicksort(lesser) */
  614. retval1 = archive_utility_string_sort_helper(lesser, lesser_count);
  615. for (i = 0; i < lesser_count; i++)
  616. strings[i] = lesser[i];
  617. free(lesser);
  618. /* pivot */
  619. strings[lesser_count] = pivot;
  620. /* quicksort(greater) */
  621. retval2 = archive_utility_string_sort_helper(greater, greater_count);
  622. for (i = 0; i < greater_count; i++)
  623. strings[lesser_count + 1 + i] = greater[i];
  624. free(greater);
  625. return (retval1 < retval2) ? retval1 : retval2;
  626. }
  627. int
  628. archive_utility_string_sort(char **strings)
  629. {
  630. unsigned int size = 0;
  631. while (strings[size] != NULL)
  632. size++;
  633. return archive_utility_string_sort_helper(strings, size);
  634. }