1228753Smm/*- 2302001Smm * Copyright (c) 2009-2012,2014 Michihiro NAKAJIMA 3228753Smm * Copyright (c) 2003-2007 Tim Kientzle 4228753Smm * All rights reserved. 5228753Smm * 6228753Smm * Redistribution and use in source and binary forms, with or without 7228753Smm * modification, are permitted provided that the following conditions 8228753Smm * are met: 9228753Smm * 1. Redistributions of source code must retain the above copyright 10228753Smm * notice, this list of conditions and the following disclaimer. 11228753Smm * 2. Redistributions in binary form must reproduce the above copyright 12228753Smm * notice, this list of conditions and the following disclaimer in the 13228753Smm * documentation and/or other materials provided with the distribution. 14228753Smm * 15228753Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 16228753Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17228753Smm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18228753Smm * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 19228753Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20228753Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21228753Smm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22228753Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23228753Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24228753Smm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25228753Smm */ 26228753Smm 27228753Smm#include "archive_platform.h" 28228763Smm__FBSDID("$FreeBSD: stable/10/contrib/libarchive/libarchive/archive_util.c 368708 2020-12-16 22:25:40Z mm $"); 29228753Smm 30228753Smm#ifdef HAVE_SYS_TYPES_H 31228753Smm#include <sys/types.h> 32228753Smm#endif 33232153Smm#ifdef HAVE_ERRNO_H 34232153Smm#include <errno.h> 35232153Smm#endif 36232153Smm#ifdef HAVE_FCNTL_H 37232153Smm#include <fcntl.h> 38232153Smm#endif 39228753Smm#ifdef HAVE_STDLIB_H 40228753Smm#include <stdlib.h> 41228753Smm#endif 42228753Smm#ifdef HAVE_STRING_H 43228753Smm#include <string.h> 44228753Smm#endif 45232153Smm#if defined(HAVE_WINCRYPT_H) && !defined(__CYGWIN__) 46232153Smm#include <wincrypt.h> 47232153Smm#endif 48302001Smm#ifdef HAVE_ZLIB_H 49302001Smm#include <zlib.h> 50302001Smm#endif 51302001Smm#ifdef HAVE_LZMA_H 52302001Smm#include <lzma.h> 53302001Smm#endif 54302001Smm#ifdef HAVE_BZLIB_H 55302001Smm#include <bzlib.h> 56302001Smm#endif 57302001Smm#ifdef HAVE_LZ4_H 58302001Smm#include <lz4.h> 59302001Smm#endif 60228753Smm 61228753Smm#include "archive.h" 62228753Smm#include "archive_private.h" 63302001Smm#include "archive_random_private.h" 64228753Smm#include "archive_string.h" 65228753Smm 66248616Smm#ifndef O_CLOEXEC 67248616Smm#define O_CLOEXEC 0 68248616Smm#endif 69248616Smm 70302001Smmstatic int archive_utility_string_sort_helper(char **, unsigned int); 71302001Smm 72232153Smm/* Generic initialization of 'struct archive' objects. */ 73228753Smmint 74232153Smm__archive_clean(struct archive *a) 75228753Smm{ 76232153Smm archive_string_conversion_free(a); 77232153Smm return (ARCHIVE_OK); 78228753Smm} 79228753Smm 80228753Smmint 81228753Smmarchive_version_number(void) 82228753Smm{ 83228753Smm return (ARCHIVE_VERSION_NUMBER); 84228753Smm} 85228753Smm 86228753Smmconst char * 87228753Smmarchive_version_string(void) 88228753Smm{ 89228753Smm return (ARCHIVE_VERSION_STRING); 90228753Smm} 91228753Smm 92228753Smmint 93228753Smmarchive_errno(struct archive *a) 94228753Smm{ 95228753Smm return (a->archive_error_number); 96228753Smm} 97228753Smm 98228753Smmconst char * 99228753Smmarchive_error_string(struct archive *a) 100228753Smm{ 101228753Smm 102228753Smm if (a->error != NULL && *a->error != '\0') 103228753Smm return (a->error); 104228753Smm else 105232153Smm return (NULL); 106228753Smm} 107228753Smm 108228753Smmint 109228753Smmarchive_file_count(struct archive *a) 110228753Smm{ 111228753Smm return (a->file_count); 112228753Smm} 113228753Smm 114228753Smmint 115228753Smmarchive_format(struct archive *a) 116228753Smm{ 117228753Smm return (a->archive_format); 118228753Smm} 119228753Smm 120228753Smmconst char * 121228753Smmarchive_format_name(struct archive *a) 122228753Smm{ 123228753Smm return (a->archive_format_name); 124228753Smm} 125228753Smm 126228753Smm 127228753Smmint 128228753Smmarchive_compression(struct archive *a) 129228753Smm{ 130232153Smm return archive_filter_code(a, 0); 131228753Smm} 132228753Smm 133228753Smmconst char * 134228753Smmarchive_compression_name(struct archive *a) 135228753Smm{ 136232153Smm return archive_filter_name(a, 0); 137228753Smm} 138228753Smm 139228753Smm 140228753Smm/* 141228753Smm * Return a count of the number of compressed bytes processed. 142228753Smm */ 143328828Smmla_int64_t 144228753Smmarchive_position_compressed(struct archive *a) 145228753Smm{ 146232153Smm return archive_filter_bytes(a, -1); 147228753Smm} 148228753Smm 149228753Smm/* 150228753Smm * Return a count of the number of uncompressed bytes processed. 151228753Smm */ 152328828Smmla_int64_t 153228753Smmarchive_position_uncompressed(struct archive *a) 154228753Smm{ 155232153Smm return archive_filter_bytes(a, 0); 156228753Smm} 157228753Smm 158228753Smmvoid 159228753Smmarchive_clear_error(struct archive *a) 160228753Smm{ 161228753Smm archive_string_empty(&a->error_string); 162228753Smm a->error = NULL; 163228753Smm a->archive_error_number = 0; 164228753Smm} 165228753Smm 166228753Smmvoid 167228753Smmarchive_set_error(struct archive *a, int error_number, const char *fmt, ...) 168228753Smm{ 169228753Smm va_list ap; 170228753Smm 171228753Smm a->archive_error_number = error_number; 172228753Smm if (fmt == NULL) { 173228753Smm a->error = NULL; 174228753Smm return; 175228753Smm } 176228753Smm 177232153Smm archive_string_empty(&(a->error_string)); 178228753Smm va_start(ap, fmt); 179228753Smm archive_string_vsprintf(&(a->error_string), fmt, ap); 180228753Smm va_end(ap); 181228753Smm a->error = a->error_string.s; 182228753Smm} 183228753Smm 184228753Smmvoid 185228753Smmarchive_copy_error(struct archive *dest, struct archive *src) 186228753Smm{ 187228753Smm dest->archive_error_number = src->archive_error_number; 188228753Smm 189228753Smm archive_string_copy(&dest->error_string, &src->error_string); 190228753Smm dest->error = dest->error_string.s; 191228753Smm} 192228753Smm 193228753Smmvoid 194228753Smm__archive_errx(int retvalue, const char *msg) 195228753Smm{ 196316338Smm static const char msg1[] = "Fatal Internal Error in libarchive: "; 197228753Smm size_t s; 198228753Smm 199228753Smm s = write(2, msg1, strlen(msg1)); 200228753Smm (void)s; /* UNUSED */ 201228753Smm s = write(2, msg, strlen(msg)); 202228753Smm (void)s; /* UNUSED */ 203228753Smm s = write(2, "\n", 1); 204228753Smm (void)s; /* UNUSED */ 205228753Smm exit(retvalue); 206228753Smm} 207228753Smm 208228753Smm/* 209232153Smm * Create a temporary file 210228753Smm */ 211232153Smm#if defined(_WIN32) && !defined(__CYGWIN__) 212232153Smm 213232153Smm/* 214232153Smm * Do not use Windows tmpfile() function. 215232153Smm * It will make a temporary file under the root directory 216232153Smm * and it'll cause permission error if a user who is 217232153Smm * non-Administrator creates temporary files. 218232153Smm * Also Windows version of mktemp family including _mktemp_s 219232153Smm * are not secure. 220232153Smm */ 221358090Smmstatic int 222358090Smm__archive_mktempx(const char *tmpdir, wchar_t *template) 223228753Smm{ 224316338Smm static const wchar_t prefix[] = L"libarchive_"; 225316338Smm static const wchar_t suffix[] = L"XXXXXXXXXX"; 226232153Smm static const wchar_t num[] = { 227232153Smm L'0', L'1', L'2', L'3', L'4', L'5', L'6', L'7', 228232153Smm L'8', L'9', L'A', L'B', L'C', L'D', L'E', L'F', 229232153Smm L'G', L'H', L'I', L'J', L'K', L'L', L'M', L'N', 230232153Smm L'O', L'P', L'Q', L'R', L'S', L'T', L'U', L'V', 231232153Smm L'W', L'X', L'Y', L'Z', L'a', L'b', L'c', L'd', 232232153Smm L'e', L'f', L'g', L'h', L'i', L'j', L'k', L'l', 233232153Smm L'm', L'n', L'o', L'p', L'q', L'r', L's', L't', 234232153Smm L'u', L'v', L'w', L'x', L'y', L'z' 235232153Smm }; 236232153Smm HCRYPTPROV hProv; 237232153Smm struct archive_wstring temp_name; 238232153Smm wchar_t *ws; 239232153Smm DWORD attr; 240232153Smm wchar_t *xp, *ep; 241232153Smm int fd; 242228753Smm 243232153Smm hProv = (HCRYPTPROV)NULL; 244232153Smm fd = -1; 245232153Smm ws = NULL; 246232153Smm 247358090Smm if (template == NULL) { 248358090Smm archive_string_init(&temp_name); 249232153Smm 250358090Smm /* Get a temporary directory. */ 251358090Smm if (tmpdir == NULL) { 252358090Smm size_t l; 253358090Smm wchar_t *tmp; 254358090Smm 255358090Smm l = GetTempPathW(0, NULL); 256358090Smm if (l == 0) { 257358090Smm la_dosmaperr(GetLastError()); 258358090Smm goto exit_tmpfile; 259358090Smm } 260358090Smm tmp = malloc(l*sizeof(wchar_t)); 261358090Smm if (tmp == NULL) { 262358090Smm errno = ENOMEM; 263358090Smm goto exit_tmpfile; 264358090Smm } 265358090Smm GetTempPathW((DWORD)l, tmp); 266358090Smm archive_wstrcpy(&temp_name, tmp); 267358090Smm free(tmp); 268358090Smm } else { 269358090Smm if (archive_wstring_append_from_mbs(&temp_name, tmpdir, 270358090Smm strlen(tmpdir)) < 0) 271358090Smm goto exit_tmpfile; 272358090Smm if (temp_name.s[temp_name.length-1] != L'/') 273358090Smm archive_wstrappend_wchar(&temp_name, L'/'); 274232153Smm } 275228753Smm 276358090Smm /* Check if temp_name is a directory. */ 277358090Smm attr = GetFileAttributesW(temp_name.s); 278358090Smm if (attr == (DWORD)-1) { 279358090Smm if (GetLastError() != ERROR_FILE_NOT_FOUND) { 280358090Smm la_dosmaperr(GetLastError()); 281358090Smm goto exit_tmpfile; 282358090Smm } 283358090Smm ws = __la_win_permissive_name_w(temp_name.s); 284358090Smm if (ws == NULL) { 285358090Smm errno = EINVAL; 286358090Smm goto exit_tmpfile; 287358090Smm } 288358090Smm attr = GetFileAttributesW(ws); 289358090Smm if (attr == (DWORD)-1) { 290358090Smm la_dosmaperr(GetLastError()); 291358090Smm goto exit_tmpfile; 292358090Smm } 293228753Smm } 294358090Smm if (!(attr & FILE_ATTRIBUTE_DIRECTORY)) { 295358090Smm errno = ENOTDIR; 296232153Smm goto exit_tmpfile; 297232153Smm } 298358090Smm 299358090Smm /* 300358090Smm * Create a temporary file. 301358090Smm */ 302358090Smm archive_wstrcat(&temp_name, prefix); 303358090Smm archive_wstrcat(&temp_name, suffix); 304358090Smm ep = temp_name.s + archive_strlen(&temp_name); 305358090Smm xp = ep - wcslen(suffix); 306358090Smm template = temp_name.s; 307358090Smm } else { 308358090Smm xp = wcschr(template, L'X'); 309358090Smm if (xp == NULL) /* No X, programming error */ 310358090Smm abort(); 311358090Smm for (ep = xp; *ep == L'X'; ep++) 312358090Smm continue; 313358090Smm if (*ep) /* X followed by non X, programming error */ 314358090Smm abort(); 315228753Smm } 316228753Smm 317232153Smm if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 318232153Smm CRYPT_VERIFYCONTEXT)) { 319232153Smm la_dosmaperr(GetLastError()); 320232153Smm goto exit_tmpfile; 321232153Smm } 322232153Smm 323232153Smm for (;;) { 324232153Smm wchar_t *p; 325232153Smm HANDLE h; 326232153Smm 327232153Smm /* Generate a random file name through CryptGenRandom(). */ 328232153Smm p = xp; 329248616Smm if (!CryptGenRandom(hProv, (DWORD)(ep - p)*sizeof(wchar_t), 330248616Smm (BYTE*)p)) { 331232153Smm la_dosmaperr(GetLastError()); 332232153Smm goto exit_tmpfile; 333232153Smm } 334232153Smm for (; p < ep; p++) 335232153Smm *p = num[((DWORD)*p) % (sizeof(num)/sizeof(num[0]))]; 336232153Smm 337232153Smm free(ws); 338358090Smm ws = __la_win_permissive_name_w(template); 339232153Smm if (ws == NULL) { 340232153Smm errno = EINVAL; 341232153Smm goto exit_tmpfile; 342232153Smm } 343358090Smm if (template == temp_name.s) { 344358090Smm attr = FILE_ATTRIBUTE_TEMPORARY | 345358090Smm FILE_FLAG_DELETE_ON_CLOSE; 346358090Smm } else { 347358090Smm /* mkstemp */ 348358090Smm attr = FILE_ATTRIBUTE_NORMAL; 349358090Smm } 350232153Smm h = CreateFileW(ws, 351232153Smm GENERIC_READ | GENERIC_WRITE | DELETE, 352232153Smm 0,/* Not share */ 353232153Smm NULL, 354232153Smm CREATE_NEW,/* Create a new file only */ 355358090Smm attr, 356232153Smm NULL); 357232153Smm if (h == INVALID_HANDLE_VALUE) { 358232153Smm /* The same file already exists. retry with 359232153Smm * a new filename. */ 360232153Smm if (GetLastError() == ERROR_FILE_EXISTS) 361232153Smm continue; 362232153Smm /* Otherwise, fail creation temporary file. */ 363232153Smm la_dosmaperr(GetLastError()); 364232153Smm goto exit_tmpfile; 365232153Smm } 366232153Smm fd = _open_osfhandle((intptr_t)h, _O_BINARY | _O_RDWR); 367232153Smm if (fd == -1) { 368358927Smm la_dosmaperr(GetLastError()); 369232153Smm CloseHandle(h); 370232153Smm goto exit_tmpfile; 371232153Smm } else 372232153Smm break;/* success! */ 373232153Smm } 374232153Smmexit_tmpfile: 375232153Smm if (hProv != (HCRYPTPROV)NULL) 376232153Smm CryptReleaseContext(hProv, 0); 377232153Smm free(ws); 378358090Smm if (template == temp_name.s) 379358090Smm archive_wstring_free(&temp_name); 380232153Smm return (fd); 381228753Smm} 382232153Smm 383358090Smmint 384358090Smm__archive_mktemp(const char *tmpdir) 385358090Smm{ 386358090Smm return __archive_mktempx(tmpdir, NULL); 387358090Smm} 388358090Smm 389358090Smmint 390358090Smm__archive_mkstemp(wchar_t *template) 391358090Smm{ 392358090Smm return __archive_mktempx(NULL, template); 393358090Smm} 394358090Smm 395232153Smm#else 396232153Smm 397232153Smmstatic int 398232153Smmget_tempdir(struct archive_string *temppath) 399232153Smm{ 400232153Smm const char *tmp; 401232153Smm 402232153Smm tmp = getenv("TMPDIR"); 403232153Smm if (tmp == NULL) 404232153Smm#ifdef _PATH_TMP 405232153Smm tmp = _PATH_TMP; 406232153Smm#else 407232153Smm tmp = "/tmp"; 408232153Smm#endif 409232153Smm archive_strcpy(temppath, tmp); 410232153Smm if (temppath->s[temppath->length-1] != '/') 411232153Smm archive_strappend_char(temppath, '/'); 412232153Smm return (ARCHIVE_OK); 413232153Smm} 414232153Smm 415232153Smm#if defined(HAVE_MKSTEMP) 416232153Smm 417232153Smm/* 418232153Smm * We can use mkstemp(). 419232153Smm */ 420232153Smm 421232153Smmint 422232153Smm__archive_mktemp(const char *tmpdir) 423232153Smm{ 424232153Smm struct archive_string temp_name; 425232153Smm int fd = -1; 426232153Smm 427232153Smm archive_string_init(&temp_name); 428232153Smm if (tmpdir == NULL) { 429232153Smm if (get_tempdir(&temp_name) != ARCHIVE_OK) 430232153Smm goto exit_tmpfile; 431232153Smm } else { 432232153Smm archive_strcpy(&temp_name, tmpdir); 433232153Smm if (temp_name.s[temp_name.length-1] != '/') 434232153Smm archive_strappend_char(&temp_name, '/'); 435232153Smm } 436368708Smm#ifdef O_TMPFILE 437368708Smm fd = open(temp_name.s, O_RDWR|O_CLOEXEC|O_TMPFILE|O_EXCL, 0600); 438368708Smm if(fd >= 0) 439368708Smm goto exit_tmpfile; 440368708Smm#endif 441232153Smm archive_strcat(&temp_name, "libarchive_XXXXXX"); 442232153Smm fd = mkstemp(temp_name.s); 443232153Smm if (fd < 0) 444232153Smm goto exit_tmpfile; 445248616Smm __archive_ensure_cloexec_flag(fd); 446232153Smm unlink(temp_name.s); 447232153Smmexit_tmpfile: 448232153Smm archive_string_free(&temp_name); 449232153Smm return (fd); 450232153Smm} 451232153Smm 452358090Smmint 453358090Smm__archive_mkstemp(char *template) 454358090Smm{ 455358090Smm int fd = -1; 456358090Smm fd = mkstemp(template); 457358090Smm if (fd >= 0) 458358090Smm __archive_ensure_cloexec_flag(fd); 459358090Smm return (fd); 460358090Smm} 461232153Smm 462358090Smm#else /* !HAVE_MKSTEMP */ 463358090Smm 464232153Smm/* 465232153Smm * We use a private routine. 466232153Smm */ 467232153Smm 468358090Smmstatic int 469358090Smm__archive_mktempx(const char *tmpdir, char *template) 470232153Smm{ 471232153Smm static const char num[] = { 472232153Smm '0', '1', '2', '3', '4', '5', '6', '7', 473232153Smm '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 474232153Smm 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 475232153Smm 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 476232153Smm 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 477232153Smm 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 478232153Smm 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 479232153Smm 'u', 'v', 'w', 'x', 'y', 'z' 480232153Smm }; 481232153Smm struct archive_string temp_name; 482232153Smm struct stat st; 483232153Smm int fd; 484232153Smm char *tp, *ep; 485232153Smm 486232153Smm fd = -1; 487358090Smm if (template == NULL) { 488358090Smm archive_string_init(&temp_name); 489358090Smm if (tmpdir == NULL) { 490358090Smm if (get_tempdir(&temp_name) != ARCHIVE_OK) 491358090Smm goto exit_tmpfile; 492358090Smm } else 493358090Smm archive_strcpy(&temp_name, tmpdir); 494358090Smm if (temp_name.s[temp_name.length-1] == '/') { 495358090Smm temp_name.s[temp_name.length-1] = '\0'; 496358090Smm temp_name.length --; 497358090Smm } 498358090Smm if (la_stat(temp_name.s, &st) < 0) 499232153Smm goto exit_tmpfile; 500358090Smm if (!S_ISDIR(st.st_mode)) { 501358090Smm errno = ENOTDIR; 502358090Smm goto exit_tmpfile; 503358090Smm } 504358090Smm archive_strcat(&temp_name, "/libarchive_"); 505358090Smm tp = temp_name.s + archive_strlen(&temp_name); 506358090Smm archive_strcat(&temp_name, "XXXXXXXXXX"); 507358090Smm ep = temp_name.s + archive_strlen(&temp_name); 508358090Smm template = temp_name.s; 509358090Smm } else { 510358090Smm tp = strchr(template, 'X'); 511358090Smm if (tp == NULL) /* No X, programming error */ 512358090Smm abort(); 513358090Smm for (ep = tp; *ep == 'X'; ep++) 514358090Smm continue; 515358090Smm if (*ep) /* X followed by non X, programming error */ 516358090Smm abort(); 517232153Smm } 518232153Smm 519232153Smm do { 520232153Smm char *p; 521232153Smm 522232153Smm p = tp; 523302001Smm archive_random(p, ep - p); 524302001Smm while (p < ep) { 525302001Smm int d = *((unsigned char *)p) % sizeof(num); 526302001Smm *p++ = num[d]; 527302001Smm } 528358090Smm fd = open(template, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, 529248616Smm 0600); 530232153Smm } while (fd < 0 && errno == EEXIST); 531232153Smm if (fd < 0) 532232153Smm goto exit_tmpfile; 533248616Smm __archive_ensure_cloexec_flag(fd); 534358090Smm if (template == temp_name.s) 535358090Smm unlink(temp_name.s); 536232153Smmexit_tmpfile: 537358090Smm if (template == temp_name.s) 538358090Smm archive_string_free(&temp_name); 539232153Smm return (fd); 540232153Smm} 541232153Smm 542358090Smmint 543358090Smm__archive_mktemp(const char *tmpdir) 544358090Smm{ 545358090Smm return __archive_mktempx(tmpdir, NULL); 546358090Smm} 547358090Smm 548358090Smmint 549358090Smm__archive_mkstemp(char *template) 550358090Smm{ 551358090Smm return __archive_mktempx(NULL, template); 552358090Smm} 553358090Smm 554358090Smm#endif /* !HAVE_MKSTEMP */ 555232153Smm#endif /* !_WIN32 || __CYGWIN__ */ 556248616Smm 557248616Smm/* 558248616Smm * Set FD_CLOEXEC flag to a file descriptor if it is not set. 559248616Smm * We have to set the flag if the platform does not provide O_CLOEXEC 560248616Smm * or F_DUPFD_CLOEXEC flags. 561248616Smm * 562248616Smm * Note: This function is absolutely called after creating a new file 563248616Smm * descriptor even if the platform seemingly provides O_CLOEXEC or 564248616Smm * F_DUPFD_CLOEXEC macros because it is possible that the platform 565248616Smm * merely declares those macros, especially Linux 2.6.18 - 2.6.24 do it. 566248616Smm */ 567248616Smmvoid 568248616Smm__archive_ensure_cloexec_flag(int fd) 569248616Smm{ 570248616Smm#if defined(_WIN32) && !defined(__CYGWIN__) 571305192Smm (void)fd; /* UNUSED */ 572248616Smm#else 573248616Smm int flags; 574248616Smm 575248616Smm if (fd >= 0) { 576248616Smm flags = fcntl(fd, F_GETFD); 577248616Smm if (flags != -1 && (flags & FD_CLOEXEC) == 0) 578248616Smm fcntl(fd, F_SETFD, flags | FD_CLOEXEC); 579248616Smm } 580248616Smm#endif 581248616Smm} 582302001Smm 583302001Smm/* 584302001Smm * Utility function to sort a group of strings using quicksort. 585302001Smm */ 586302001Smmstatic int 587302001Smmarchive_utility_string_sort_helper(char **strings, unsigned int n) 588302001Smm{ 589302001Smm unsigned int i, lesser_count, greater_count; 590302001Smm char **lesser, **greater, **tmp, *pivot; 591302001Smm int retval1, retval2; 592302001Smm 593302001Smm /* A list of 0 or 1 elements is already sorted */ 594302001Smm if (n <= 1) 595302001Smm return (ARCHIVE_OK); 596302001Smm 597302001Smm lesser_count = greater_count = 0; 598302001Smm lesser = greater = NULL; 599302001Smm pivot = strings[0]; 600302001Smm for (i = 1; i < n; i++) 601302001Smm { 602302001Smm if (strcmp(strings[i], pivot) < 0) 603302001Smm { 604302001Smm lesser_count++; 605302001Smm tmp = (char **)realloc(lesser, 606302001Smm lesser_count * sizeof(char *)); 607302001Smm if (!tmp) { 608302001Smm free(greater); 609302001Smm free(lesser); 610302001Smm return (ARCHIVE_FATAL); 611302001Smm } 612302001Smm lesser = tmp; 613302001Smm lesser[lesser_count - 1] = strings[i]; 614302001Smm } 615302001Smm else 616302001Smm { 617302001Smm greater_count++; 618302001Smm tmp = (char **)realloc(greater, 619302001Smm greater_count * sizeof(char *)); 620302001Smm if (!tmp) { 621302001Smm free(greater); 622302001Smm free(lesser); 623302001Smm return (ARCHIVE_FATAL); 624302001Smm } 625302001Smm greater = tmp; 626302001Smm greater[greater_count - 1] = strings[i]; 627302001Smm } 628302001Smm } 629302001Smm 630302001Smm /* quicksort(lesser) */ 631302001Smm retval1 = archive_utility_string_sort_helper(lesser, lesser_count); 632302001Smm for (i = 0; i < lesser_count; i++) 633302001Smm strings[i] = lesser[i]; 634302001Smm free(lesser); 635302001Smm 636302001Smm /* pivot */ 637302001Smm strings[lesser_count] = pivot; 638302001Smm 639302001Smm /* quicksort(greater) */ 640302001Smm retval2 = archive_utility_string_sort_helper(greater, greater_count); 641302001Smm for (i = 0; i < greater_count; i++) 642302001Smm strings[lesser_count + 1 + i] = greater[i]; 643302001Smm free(greater); 644302001Smm 645302001Smm return (retval1 < retval2) ? retval1 : retval2; 646302001Smm} 647302001Smm 648302001Smmint 649302001Smmarchive_utility_string_sort(char **strings) 650302001Smm{ 651302001Smm unsigned int size = 0; 652302001Smm while (strings[size] != NULL) 653302001Smm size++; 654302001Smm return archive_utility_string_sort_helper(strings, size); 655302001Smm} 656