1 1.1 joerg /*- 2 1.1.1.5 christos * SPDX-License-Identifier: BSD-2-Clause 3 1.1.1.5 christos * 4 1.1 joerg * Copyright (c) 2003-2007 Tim Kientzle 5 1.1 joerg * All rights reserved. 6 1.1 joerg */ 7 1.1 joerg 8 1.1 joerg #include "bsdtar_platform.h" 9 1.1 joerg 10 1.1 joerg #ifdef HAVE_SYS_STAT_H 11 1.1 joerg #include <sys/stat.h> 12 1.1 joerg #endif 13 1.1 joerg #ifdef HAVE_SYS_TYPES_H 14 1.1 joerg #include <sys/types.h> /* Linux doesn't define mode_t, etc. in sys/stat.h. */ 15 1.1 joerg #endif 16 1.1 joerg #include <ctype.h> 17 1.1 joerg #ifdef HAVE_ERRNO_H 18 1.1 joerg #include <errno.h> 19 1.1 joerg #endif 20 1.1.1.2 joerg #ifdef HAVE_IO_H 21 1.1.1.2 joerg #include <io.h> 22 1.1.1.2 joerg #endif 23 1.1 joerg #ifdef HAVE_STDARG_H 24 1.1 joerg #include <stdarg.h> 25 1.1 joerg #endif 26 1.1.1.2 joerg #ifdef HAVE_STDINT_H 27 1.1.1.2 joerg #include <stdint.h> 28 1.1.1.2 joerg #endif 29 1.1 joerg #include <stdio.h> 30 1.1 joerg #ifdef HAVE_STDLIB_H 31 1.1 joerg #include <stdlib.h> 32 1.1 joerg #endif 33 1.1 joerg #ifdef HAVE_STRING_H 34 1.1 joerg #include <string.h> 35 1.1 joerg #endif 36 1.1.1.2 joerg #ifdef HAVE_WCTYPE_H 37 1.1.1.2 joerg #include <wctype.h> 38 1.1.1.2 joerg #else 39 1.1.1.2 joerg /* If we don't have wctype, we need to hack up some version of iswprint(). */ 40 1.1.1.3 joerg #define iswprint isprint 41 1.1.1.2 joerg #endif 42 1.1 joerg 43 1.1 joerg #include "bsdtar.h" 44 1.1.1.6 christos #include "lafe_err.h" 45 1.1.1.3 joerg #include "passphrase.h" 46 1.1.1.2 joerg 47 1.1.1.4 christos static size_t bsdtar_expand_char(char *, size_t, size_t, char); 48 1.1.1.2 joerg static const char *strip_components(const char *path, int elements); 49 1.1.1.2 joerg 50 1.1.1.2 joerg #if defined(_WIN32) && !defined(__CYGWIN__) 51 1.1.1.3 joerg #define read _read 52 1.1.1.2 joerg #endif 53 1.1 joerg 54 1.1.1.2 joerg /* TODO: Hack up a version of mbtowc for platforms with no wide 55 1.1.1.2 joerg * character support at all. I think the following might suffice, 56 1.1.1.2 joerg * but it needs careful testing. 57 1.1.1.2 joerg * #if !HAVE_MBTOWC 58 1.1.1.3 joerg * #define mbtowc(wcp, p, n) ((*wcp = *p), 1) 59 1.1.1.2 joerg * #endif 60 1.1.1.2 joerg */ 61 1.1 joerg 62 1.1 joerg /* 63 1.1 joerg * Print a string, taking care with any non-printable characters. 64 1.1.1.2 joerg * 65 1.1.1.2 joerg * Note that we use a stack-allocated buffer to receive the formatted 66 1.1.1.2 joerg * string if we can. This is partly performance (avoiding a call to 67 1.1.1.2 joerg * malloc()), partly out of expedience (we have to call vsnprintf() 68 1.1.1.2 joerg * before malloc() anyway to find out how big a buffer we need; we may 69 1.1.1.2 joerg * as well point that first call at a small local buffer in case it 70 1.1.1.6 christos * works). 71 1.1 joerg */ 72 1.1 joerg 73 1.1 joerg void 74 1.1.1.6 christos safe_fprintf(FILE * restrict f, const char * restrict fmt, ...) 75 1.1 joerg { 76 1.1.1.2 joerg char fmtbuff_stack[256]; /* Place to format the printf() string. */ 77 1.1.1.2 joerg char outbuff[256]; /* Buffer for outgoing characters. */ 78 1.1.1.2 joerg char *fmtbuff_heap; /* If fmtbuff_stack is too small, we use malloc */ 79 1.1.1.2 joerg char *fmtbuff; /* Pointer to fmtbuff_stack or fmtbuff_heap. */ 80 1.1.1.6 christos size_t fmtbuff_length; 81 1.1.1.2 joerg int length, n; 82 1.1 joerg va_list ap; 83 1.1.1.2 joerg const char *p; 84 1.1.1.6 christos size_t i; 85 1.1.1.2 joerg wchar_t wc; 86 1.1.1.2 joerg char try_wc; 87 1.1 joerg 88 1.1 joerg /* Use a stack-allocated buffer if we can, for speed and safety. */ 89 1.1.1.6 christos memset(fmtbuff_stack, '\0', sizeof(fmtbuff_stack)); 90 1.1.1.2 joerg fmtbuff_heap = NULL; 91 1.1.1.2 joerg fmtbuff_length = sizeof(fmtbuff_stack); 92 1.1.1.2 joerg fmtbuff = fmtbuff_stack; 93 1.1 joerg 94 1.1.1.2 joerg /* Try formatting into the stack buffer. */ 95 1.1 joerg va_start(ap, fmt); 96 1.1.1.2 joerg length = vsnprintf(fmtbuff, fmtbuff_length, fmt, ap); 97 1.1 joerg va_end(ap); 98 1.1.1.2 joerg 99 1.1.1.6 christos /* If vsnprintf will always fail, stop early. */ 100 1.1.1.6 christos if (length < 0 && errno == EOVERFLOW) 101 1.1.1.6 christos return; 102 1.1.1.6 christos 103 1.1.1.2 joerg /* If the result was too large, allocate a buffer on the heap. */ 104 1.1.1.6 christos while (length < 0 || (size_t)length >= fmtbuff_length) { 105 1.1.1.6 christos if (length >= 0 && (size_t)length >= fmtbuff_length) 106 1.1.1.6 christos fmtbuff_length = (size_t)length + 1; 107 1.1.1.3 joerg else if (fmtbuff_length < 8192) 108 1.1.1.3 joerg fmtbuff_length *= 2; 109 1.1.1.3 joerg else if (fmtbuff_length < 1000000) 110 1.1.1.3 joerg fmtbuff_length += fmtbuff_length / 4; 111 1.1.1.3 joerg else { 112 1.1.1.6 christos fmtbuff[fmtbuff_length - 1] = '\0'; 113 1.1.1.6 christos length = (int)strlen(fmtbuff); 114 1.1.1.3 joerg break; 115 1.1.1.3 joerg } 116 1.1.1.3 joerg free(fmtbuff_heap); 117 1.1.1.2 joerg fmtbuff_heap = malloc(fmtbuff_length); 118 1.1.1.2 joerg 119 1.1.1.2 joerg /* Reformat the result into the heap buffer if we can. */ 120 1.1.1.2 joerg if (fmtbuff_heap != NULL) { 121 1.1.1.2 joerg fmtbuff = fmtbuff_heap; 122 1.1 joerg va_start(ap, fmt); 123 1.1.1.2 joerg length = vsnprintf(fmtbuff, fmtbuff_length, fmt, ap); 124 1.1 joerg va_end(ap); 125 1.1.1.2 joerg } else { 126 1.1.1.2 joerg /* Leave fmtbuff pointing to the truncated 127 1.1.1.2 joerg * string in fmtbuff_stack. */ 128 1.1.1.6 christos fmtbuff_stack[sizeof(fmtbuff_stack) - 1] = '\0'; 129 1.1.1.3 joerg fmtbuff = fmtbuff_stack; 130 1.1.1.6 christos length = (int)strlen(fmtbuff); 131 1.1.1.3 joerg break; 132 1.1 joerg } 133 1.1 joerg } 134 1.1 joerg 135 1.1.1.2 joerg /* Note: mbrtowc() has a cleaner API, but mbtowc() seems a bit 136 1.1.1.2 joerg * more portable, so we use that here instead. */ 137 1.1.1.3 joerg if (mbtowc(NULL, NULL, 1) == -1) { /* Reset the shift state. */ 138 1.1.1.3 joerg /* mbtowc() should never fail in practice, but 139 1.1.1.3 joerg * handle the theoretical error anyway. */ 140 1.1.1.3 joerg free(fmtbuff_heap); 141 1.1.1.3 joerg return; 142 1.1.1.3 joerg } 143 1.1.1.2 joerg 144 1.1 joerg /* Write data, expanding unprintable characters. */ 145 1.1.1.2 joerg p = fmtbuff; 146 1.1 joerg i = 0; 147 1.1.1.2 joerg try_wc = 1; 148 1.1 joerg while (*p != '\0') { 149 1.1 joerg 150 1.1.1.2 joerg /* Convert to wide char, test if the wide 151 1.1.1.2 joerg * char is printable in the current locale. */ 152 1.1.1.2 joerg if (try_wc && (n = mbtowc(&wc, p, length)) != -1) { 153 1.1.1.2 joerg length -= n; 154 1.1.1.2 joerg if (iswprint(wc) && wc != L'\\') { 155 1.1.1.2 joerg /* Printable, copy the bytes through. */ 156 1.1.1.2 joerg while (n-- > 0) 157 1.1.1.2 joerg outbuff[i++] = *p++; 158 1.1.1.2 joerg } else { 159 1.1.1.2 joerg /* Not printable, format the bytes. */ 160 1.1.1.2 joerg while (n-- > 0) 161 1.1.1.6 christos i += bsdtar_expand_char( 162 1.1.1.4 christos outbuff, sizeof(outbuff), i, *p++); 163 1.1 joerg } 164 1.1.1.2 joerg } else { 165 1.1.1.2 joerg /* After any conversion failure, don't bother 166 1.1.1.2 joerg * trying to convert the rest. */ 167 1.1.1.6 christos i += bsdtar_expand_char(outbuff, sizeof(outbuff), i, *p++); 168 1.1.1.2 joerg try_wc = 0; 169 1.1 joerg } 170 1.1 joerg 171 1.1.1.2 joerg /* If our output buffer is full, dump it and keep going. */ 172 1.1.1.3 joerg if (i > (sizeof(outbuff) - 128)) { 173 1.1.1.2 joerg outbuff[i] = '\0'; 174 1.1.1.2 joerg fprintf(f, "%s", outbuff); 175 1.1 joerg i = 0; 176 1.1 joerg } 177 1.1 joerg } 178 1.1.1.2 joerg outbuff[i] = '\0'; 179 1.1.1.2 joerg fprintf(f, "%s", outbuff); 180 1.1 joerg 181 1.1.1.2 joerg /* If we allocated a heap-based formatting buffer, free it now. */ 182 1.1.1.3 joerg free(fmtbuff_heap); 183 1.1 joerg } 184 1.1 joerg 185 1.1.1.2 joerg /* 186 1.1.1.2 joerg * Render an arbitrary sequence of bytes into printable ASCII characters. 187 1.1.1.2 joerg */ 188 1.1.1.2 joerg static size_t 189 1.1.1.4 christos bsdtar_expand_char(char *buff, size_t buffsize, size_t offset, char c) 190 1.1 joerg { 191 1.1.1.2 joerg size_t i = offset; 192 1.1 joerg 193 1.1.1.2 joerg if (isprint((unsigned char)c) && c != '\\') 194 1.1.1.2 joerg buff[i++] = c; 195 1.1.1.2 joerg else { 196 1.1.1.2 joerg buff[i++] = '\\'; 197 1.1.1.2 joerg switch (c) { 198 1.1.1.2 joerg case '\a': buff[i++] = 'a'; break; 199 1.1.1.2 joerg case '\b': buff[i++] = 'b'; break; 200 1.1.1.2 joerg case '\f': buff[i++] = 'f'; break; 201 1.1.1.2 joerg case '\n': buff[i++] = 'n'; break; 202 1.1.1.2 joerg #if '\r' != '\n' 203 1.1.1.2 joerg /* On some platforms, \n and \r are the same. */ 204 1.1.1.2 joerg case '\r': buff[i++] = 'r'; break; 205 1.1.1.2 joerg #endif 206 1.1.1.2 joerg case '\t': buff[i++] = 't'; break; 207 1.1.1.2 joerg case '\v': buff[i++] = 'v'; break; 208 1.1.1.2 joerg case '\\': buff[i++] = '\\'; break; 209 1.1.1.2 joerg default: 210 1.1.1.6 christos snprintf(buff + i, buffsize - i, "%03o", 211 1.1.1.6 christos 0xFF & (unsigned int)c); 212 1.1.1.2 joerg i += 3; 213 1.1.1.2 joerg } 214 1.1.1.2 joerg } 215 1.1 joerg 216 1.1.1.2 joerg return (i - offset); 217 1.1 joerg } 218 1.1 joerg 219 1.1 joerg int 220 1.1 joerg yes(const char *fmt, ...) 221 1.1 joerg { 222 1.1 joerg char buff[32]; 223 1.1 joerg char *p; 224 1.1 joerg ssize_t l; 225 1.1.1.5 christos int read_fd = 2; /* stderr */ 226 1.1 joerg 227 1.1 joerg va_list ap; 228 1.1 joerg va_start(ap, fmt); 229 1.1 joerg vfprintf(stderr, fmt, ap); 230 1.1 joerg va_end(ap); 231 1.1 joerg fprintf(stderr, " (y/N)? "); 232 1.1 joerg fflush(stderr); 233 1.1 joerg 234 1.1.1.5 christos #if defined(_WIN32) && !defined(__CYGWIN__) 235 1.1.1.5 christos /* To be resilient when stdin is a pipe, bsdtar prefers to read from 236 1.1.1.5 christos * stderr. On Windows, stderr cannot be read. The nearest "piping 237 1.1.1.5 christos * resilient" equivalent is reopening the console input handle. 238 1.1.1.5 christos */ 239 1.1.1.5 christos read_fd = _open("CONIN$", O_RDONLY); 240 1.1.1.5 christos if (read_fd < 0) { 241 1.1.1.5 christos fprintf(stderr, "Keyboard read failed\n"); 242 1.1.1.5 christos exit(1); 243 1.1.1.5 christos } 244 1.1.1.5 christos #endif 245 1.1.1.5 christos 246 1.1.1.5 christos l = read(read_fd, buff, sizeof(buff) - 1); 247 1.1.1.5 christos 248 1.1.1.5 christos #if defined(_WIN32) && !defined(__CYGWIN__) 249 1.1.1.5 christos _close(read_fd); 250 1.1.1.5 christos #endif 251 1.1.1.5 christos 252 1.1.1.3 joerg if (l < 0) { 253 1.1.1.3 joerg fprintf(stderr, "Keyboard read failed\n"); 254 1.1.1.3 joerg exit(1); 255 1.1.1.3 joerg } 256 1.1.1.3 joerg if (l == 0) 257 1.1 joerg return (0); 258 1.1 joerg buff[l] = 0; 259 1.1 joerg 260 1.1 joerg for (p = buff; *p != '\0'; p++) { 261 1.1.1.2 joerg if (isspace((unsigned char)*p)) 262 1.1 joerg continue; 263 1.1 joerg switch(*p) { 264 1.1 joerg case 'y': case 'Y': 265 1.1 joerg return (1); 266 1.1 joerg case 'n': case 'N': 267 1.1 joerg return (0); 268 1.1 joerg default: 269 1.1 joerg return (0); 270 1.1 joerg } 271 1.1 joerg } 272 1.1 joerg 273 1.1 joerg return (0); 274 1.1 joerg } 275 1.1 joerg 276 1.1 joerg /*- 277 1.1 joerg * The logic here for -C <dir> attempts to avoid 278 1.1 joerg * chdir() as long as possible. For example: 279 1.1 joerg * "-C /foo -C /bar file" needs chdir("/bar") but not chdir("/foo") 280 1.1 joerg * "-C /foo -C bar file" needs chdir("/foo/bar") 281 1.1 joerg * "-C /foo -C bar /file1" does not need chdir() 282 1.1 joerg * "-C /foo -C bar /file1 file2" needs chdir("/foo/bar") before file2 283 1.1 joerg * 284 1.1 joerg * The only correct way to handle this is to record a "pending" chdir 285 1.1 joerg * request and combine multiple requests intelligently until we 286 1.1 joerg * need to process a non-absolute file. set_chdir() adds the new dir 287 1.1 joerg * to the pending list; do_chdir() actually executes any pending chdir. 288 1.1 joerg * 289 1.1 joerg * This way, programs that build tar command lines don't have to worry 290 1.1 joerg * about -C with non-existent directories; such requests will only 291 1.1 joerg * fail if the directory must be accessed. 292 1.1.1.2 joerg * 293 1.1 joerg */ 294 1.1 joerg void 295 1.1 joerg set_chdir(struct bsdtar *bsdtar, const char *newdir) 296 1.1 joerg { 297 1.1.1.3 joerg #if defined(_WIN32) && !defined(__CYGWIN__) 298 1.1.1.3 joerg if (newdir[0] == '/' || newdir[0] == '\\' || 299 1.1.1.3 joerg /* Detect this type, for example, "C:\" or "C:/" */ 300 1.1.1.3 joerg (((newdir[0] >= 'a' && newdir[0] <= 'z') || 301 1.1.1.3 joerg (newdir[0] >= 'A' && newdir[0] <= 'Z')) && 302 1.1.1.3 joerg newdir[1] == ':' && (newdir[2] == '/' || newdir[2] == '\\'))) { 303 1.1.1.3 joerg #else 304 1.1 joerg if (newdir[0] == '/') { 305 1.1.1.3 joerg #endif 306 1.1 joerg /* The -C /foo -C /bar case; dump first one. */ 307 1.1 joerg free(bsdtar->pending_chdir); 308 1.1 joerg bsdtar->pending_chdir = NULL; 309 1.1 joerg } 310 1.1 joerg if (bsdtar->pending_chdir == NULL) 311 1.1 joerg /* Easy case: no previously-saved dir. */ 312 1.1 joerg bsdtar->pending_chdir = strdup(newdir); 313 1.1 joerg else { 314 1.1 joerg /* The -C /foo -C bar case; concatenate */ 315 1.1 joerg char *old_pending = bsdtar->pending_chdir; 316 1.1 joerg size_t old_len = strlen(old_pending); 317 1.1.1.6 christos size_t newdir_len = strlen(newdir); 318 1.1.1.6 christos size_t new_len = old_len + newdir_len + 2; 319 1.1.1.6 christos if (old_len > SIZE_MAX - newdir_len - 2) 320 1.1.1.6 christos lafe_errc(1, errno, "Path too long"); 321 1.1.1.4 christos bsdtar->pending_chdir = malloc(new_len); 322 1.1 joerg if (old_pending[old_len - 1] == '/') 323 1.1 joerg old_pending[old_len - 1] = '\0'; 324 1.1 joerg if (bsdtar->pending_chdir != NULL) 325 1.1.1.4 christos snprintf(bsdtar->pending_chdir, new_len, "%s/%s", 326 1.1 joerg old_pending, newdir); 327 1.1 joerg free(old_pending); 328 1.1 joerg } 329 1.1 joerg if (bsdtar->pending_chdir == NULL) 330 1.1.1.2 joerg lafe_errc(1, errno, "No memory"); 331 1.1 joerg } 332 1.1 joerg 333 1.1 joerg void 334 1.1 joerg do_chdir(struct bsdtar *bsdtar) 335 1.1 joerg { 336 1.1 joerg if (bsdtar->pending_chdir == NULL) 337 1.1 joerg return; 338 1.1 joerg 339 1.1 joerg if (chdir(bsdtar->pending_chdir) != 0) { 340 1.1.1.6 christos lafe_errc(1, 0, "could not chdir to '%s'", 341 1.1 joerg bsdtar->pending_chdir); 342 1.1 joerg } 343 1.1 joerg free(bsdtar->pending_chdir); 344 1.1 joerg bsdtar->pending_chdir = NULL; 345 1.1 joerg } 346 1.1 joerg 347 1.1.1.2 joerg static const char * 348 1.1.1.2 joerg strip_components(const char *p, int elements) 349 1.1.1.2 joerg { 350 1.1.1.2 joerg /* Skip as many elements as necessary. */ 351 1.1.1.2 joerg while (elements > 0) { 352 1.1.1.2 joerg switch (*p++) { 353 1.1.1.2 joerg case '/': 354 1.1.1.2 joerg #if defined(_WIN32) && !defined(__CYGWIN__) 355 1.1.1.2 joerg case '\\': /* Support \ path sep on Windows ONLY. */ 356 1.1.1.2 joerg #endif 357 1.1.1.2 joerg elements--; 358 1.1.1.2 joerg break; 359 1.1.1.2 joerg case '\0': 360 1.1.1.2 joerg /* Path is too short, skip it. */ 361 1.1.1.2 joerg return (NULL); 362 1.1.1.2 joerg } 363 1.1.1.2 joerg } 364 1.1.1.2 joerg 365 1.1.1.2 joerg /* Skip any / characters. This handles short paths that have 366 1.1.1.2 joerg * additional / termination. This also handles the case where 367 1.1.1.2 joerg * the logic above stops in the middle of a duplicate // 368 1.1.1.2 joerg * sequence (which would otherwise get converted to an 369 1.1.1.2 joerg * absolute path). */ 370 1.1.1.2 joerg for (;;) { 371 1.1.1.2 joerg switch (*p) { 372 1.1.1.2 joerg case '/': 373 1.1.1.2 joerg #if defined(_WIN32) && !defined(__CYGWIN__) 374 1.1.1.2 joerg case '\\': /* Support \ path sep on Windows ONLY. */ 375 1.1.1.2 joerg #endif 376 1.1.1.2 joerg ++p; 377 1.1.1.2 joerg break; 378 1.1.1.2 joerg case '\0': 379 1.1.1.2 joerg return (NULL); 380 1.1.1.2 joerg default: 381 1.1.1.2 joerg return (p); 382 1.1.1.2 joerg } 383 1.1.1.2 joerg } 384 1.1.1.2 joerg } 385 1.1.1.2 joerg 386 1.1.1.3 joerg static void 387 1.1.1.3 joerg warn_strip_leading_char(struct bsdtar *bsdtar, const char *c) 388 1.1.1.3 joerg { 389 1.1.1.3 joerg if (!bsdtar->warned_lead_slash) { 390 1.1.1.3 joerg lafe_warnc(0, 391 1.1.1.3 joerg "Removing leading '%c' from member names", 392 1.1.1.3 joerg c[0]); 393 1.1.1.3 joerg bsdtar->warned_lead_slash = 1; 394 1.1.1.3 joerg } 395 1.1.1.3 joerg } 396 1.1.1.3 joerg 397 1.1.1.3 joerg static void 398 1.1.1.3 joerg warn_strip_drive_letter(struct bsdtar *bsdtar) 399 1.1.1.3 joerg { 400 1.1.1.3 joerg if (!bsdtar->warned_lead_slash) { 401 1.1.1.3 joerg lafe_warnc(0, 402 1.1.1.3 joerg "Removing leading drive letter from " 403 1.1.1.3 joerg "member names"); 404 1.1.1.3 joerg bsdtar->warned_lead_slash = 1; 405 1.1.1.3 joerg } 406 1.1.1.3 joerg } 407 1.1.1.3 joerg 408 1.1.1.3 joerg /* 409 1.1.1.3 joerg * Convert absolute path to non-absolute path by skipping leading 410 1.1.1.3 joerg * absolute path prefixes. 411 1.1.1.3 joerg */ 412 1.1.1.3 joerg static const char* 413 1.1.1.3 joerg strip_absolute_path(struct bsdtar *bsdtar, const char *p) 414 1.1.1.3 joerg { 415 1.1.1.3 joerg const char *rp; 416 1.1.1.3 joerg 417 1.1.1.3 joerg /* Remove leading "//./" or "//?/" or "//?/UNC/" 418 1.1.1.3 joerg * (absolute path prefixes used by Windows API) */ 419 1.1.1.3 joerg if ((p[0] == '/' || p[0] == '\\') && 420 1.1.1.3 joerg (p[1] == '/' || p[1] == '\\') && 421 1.1.1.3 joerg (p[2] == '.' || p[2] == '?') && 422 1.1.1.3 joerg (p[3] == '/' || p[3] == '\\')) 423 1.1.1.3 joerg { 424 1.1.1.3 joerg if (p[2] == '?' && 425 1.1.1.3 joerg (p[4] == 'U' || p[4] == 'u') && 426 1.1.1.3 joerg (p[5] == 'N' || p[5] == 'n') && 427 1.1.1.3 joerg (p[6] == 'C' || p[6] == 'c') && 428 1.1.1.3 joerg (p[7] == '/' || p[7] == '\\')) 429 1.1.1.3 joerg p += 8; 430 1.1.1.3 joerg else 431 1.1.1.3 joerg p += 4; 432 1.1.1.3 joerg warn_strip_drive_letter(bsdtar); 433 1.1.1.3 joerg } 434 1.1.1.3 joerg 435 1.1.1.3 joerg /* Remove multiple leading slashes and Windows drive letters. */ 436 1.1.1.3 joerg do { 437 1.1.1.3 joerg rp = p; 438 1.1.1.3 joerg if (((p[0] >= 'a' && p[0] <= 'z') || 439 1.1.1.3 joerg (p[0] >= 'A' && p[0] <= 'Z')) && 440 1.1.1.3 joerg p[1] == ':') { 441 1.1.1.3 joerg p += 2; 442 1.1.1.3 joerg warn_strip_drive_letter(bsdtar); 443 1.1.1.3 joerg } 444 1.1.1.3 joerg 445 1.1.1.3 joerg /* Remove leading "/../", "/./", "//", etc. */ 446 1.1.1.3 joerg while (p[0] == '/' || p[0] == '\\') { 447 1.1.1.3 joerg if (p[1] == '.' && 448 1.1.1.3 joerg p[2] == '.' && 449 1.1.1.3 joerg (p[3] == '/' || p[3] == '\\')) { 450 1.1.1.3 joerg p += 3; /* Remove "/..", leave "/" for next pass. */ 451 1.1.1.3 joerg } else if (p[1] == '.' && 452 1.1.1.3 joerg (p[2] == '/' || p[2] == '\\')) { 453 1.1.1.3 joerg p += 2; /* Remove "/.", leave "/" for next pass. */ 454 1.1.1.3 joerg } else 455 1.1.1.3 joerg p += 1; /* Remove "/". */ 456 1.1.1.3 joerg warn_strip_leading_char(bsdtar, rp); 457 1.1.1.3 joerg } 458 1.1.1.3 joerg } while (rp != p); 459 1.1.1.3 joerg 460 1.1.1.3 joerg return (p); 461 1.1.1.3 joerg } 462 1.1.1.3 joerg 463 1.1 joerg /* 464 1.1 joerg * Handle --strip-components and any future path-rewriting options. 465 1.1 joerg * Returns non-zero if the pathname should not be extracted. 466 1.1 joerg * 467 1.1.1.3 joerg * Note: The rewrites are applied uniformly to pathnames and hardlink 468 1.1.1.3 joerg * names but not to symlink bodies. This is deliberate: Symlink 469 1.1.1.3 joerg * bodies are not necessarily filenames. Even when they are, they 470 1.1.1.3 joerg * need to be interpreted relative to the directory containing them, 471 1.1.1.3 joerg * so simple rewrites like this are rarely appropriate. 472 1.1.1.3 joerg * 473 1.1 joerg * TODO: Support pax-style regex path rewrites. 474 1.1 joerg */ 475 1.1 joerg int 476 1.1 joerg edit_pathname(struct bsdtar *bsdtar, struct archive_entry *entry) 477 1.1 joerg { 478 1.1 joerg const char *name = archive_entry_pathname(entry); 479 1.1.1.3 joerg const char *original_name = name; 480 1.1.1.3 joerg const char *hardlinkname = archive_entry_hardlink(entry); 481 1.1.1.3 joerg const char *original_hardlinkname = hardlinkname; 482 1.1.1.4 christos #if defined(HAVE_REGEX_H) || defined(HAVE_PCREPOSIX_H) || defined(HAVE_PCRE2POSIX_H) 483 1.1 joerg char *subst_name; 484 1.1 joerg int r; 485 1.1 joerg 486 1.1.1.3 joerg /* Apply user-specified substitution to pathname. */ 487 1.1.1.3 joerg r = apply_substitution(bsdtar, name, &subst_name, 0, 0); 488 1.1 joerg if (r == -1) { 489 1.1.1.2 joerg lafe_warnc(0, "Invalid substitution, skipping entry"); 490 1.1 joerg return 1; 491 1.1 joerg } 492 1.1 joerg if (r == 1) { 493 1.1 joerg archive_entry_copy_pathname(entry, subst_name); 494 1.1 joerg if (*subst_name == '\0') { 495 1.1 joerg free(subst_name); 496 1.1 joerg return -1; 497 1.1 joerg } else 498 1.1 joerg free(subst_name); 499 1.1 joerg name = archive_entry_pathname(entry); 500 1.1.1.3 joerg original_name = name; 501 1.1 joerg } 502 1.1 joerg 503 1.1.1.3 joerg /* Apply user-specified substitution to hardlink target. */ 504 1.1.1.3 joerg if (hardlinkname != NULL) { 505 1.1.1.3 joerg r = apply_substitution(bsdtar, hardlinkname, &subst_name, 0, 1); 506 1.1 joerg if (r == -1) { 507 1.1.1.2 joerg lafe_warnc(0, "Invalid substitution, skipping entry"); 508 1.1 joerg return 1; 509 1.1 joerg } 510 1.1 joerg if (r == 1) { 511 1.1 joerg archive_entry_copy_hardlink(entry, subst_name); 512 1.1 joerg free(subst_name); 513 1.1 joerg } 514 1.1.1.3 joerg hardlinkname = archive_entry_hardlink(entry); 515 1.1.1.3 joerg original_hardlinkname = hardlinkname; 516 1.1 joerg } 517 1.1.1.3 joerg 518 1.1.1.3 joerg /* Apply user-specified substitution to symlink body. */ 519 1.1 joerg if (archive_entry_symlink(entry) != NULL) { 520 1.1.1.3 joerg r = apply_substitution(bsdtar, archive_entry_symlink(entry), &subst_name, 1, 0); 521 1.1 joerg if (r == -1) { 522 1.1.1.2 joerg lafe_warnc(0, "Invalid substitution, skipping entry"); 523 1.1 joerg return 1; 524 1.1 joerg } 525 1.1 joerg if (r == 1) { 526 1.1 joerg archive_entry_copy_symlink(entry, subst_name); 527 1.1 joerg free(subst_name); 528 1.1 joerg } 529 1.1 joerg } 530 1.1 joerg #endif 531 1.1 joerg 532 1.1 joerg /* Strip leading dir names as per --strip-components option. */ 533 1.1.1.2 joerg if (bsdtar->strip_components > 0) { 534 1.1.1.2 joerg name = strip_components(name, bsdtar->strip_components); 535 1.1.1.2 joerg if (name == NULL) 536 1.1.1.2 joerg return (1); 537 1.1 joerg 538 1.1.1.3 joerg if (hardlinkname != NULL) { 539 1.1.1.3 joerg hardlinkname = strip_components(hardlinkname, 540 1.1.1.2 joerg bsdtar->strip_components); 541 1.1.1.3 joerg if (hardlinkname == NULL) 542 1.1 joerg return (1); 543 1.1 joerg } 544 1.1 joerg } 545 1.1 joerg 546 1.1.1.3 joerg if ((bsdtar->flags & OPTFLAG_ABSOLUTE_PATHS) == 0) { 547 1.1.1.3 joerg /* By default, don't write or restore absolute pathnames. */ 548 1.1.1.3 joerg name = strip_absolute_path(bsdtar, name); 549 1.1.1.3 joerg if (*name == '\0') 550 1.1.1.3 joerg name = "."; 551 1.1.1.2 joerg 552 1.1.1.3 joerg if (hardlinkname != NULL) { 553 1.1.1.3 joerg hardlinkname = strip_absolute_path(bsdtar, hardlinkname); 554 1.1.1.3 joerg if (*hardlinkname == '\0') 555 1.1.1.3 joerg return (1); 556 1.1 joerg } 557 1.1.1.2 joerg } else { 558 1.1.1.2 joerg /* Strip redundant leading '/' characters. */ 559 1.1.1.2 joerg while (name[0] == '/' && name[1] == '/') 560 1.1.1.2 joerg name++; 561 1.1 joerg } 562 1.1 joerg 563 1.1.1.3 joerg /* Replace name in archive_entry. */ 564 1.1.1.3 joerg if (name != original_name) { 565 1.1.1.3 joerg archive_entry_copy_pathname(entry, name); 566 1.1.1.3 joerg } 567 1.1.1.3 joerg if (hardlinkname != original_hardlinkname) { 568 1.1.1.3 joerg archive_entry_copy_hardlink(entry, hardlinkname); 569 1.1 joerg } 570 1.1 joerg return (0); 571 1.1 joerg } 572 1.1 joerg 573 1.1 joerg /* 574 1.1.1.6 christos * Apply --mtime and --clamp-mtime options. 575 1.1.1.6 christos */ 576 1.1.1.6 christos void 577 1.1.1.6 christos edit_mtime(struct bsdtar *bsdtar, struct archive_entry *entry) 578 1.1.1.6 christos { 579 1.1.1.6 christos if (!bsdtar->has_mtime) 580 1.1.1.6 christos return; 581 1.1.1.6 christos 582 1.1.1.6 christos __LA_TIME_T entry_mtime = archive_entry_mtime(entry); 583 1.1.1.6 christos if (!bsdtar->clamp_mtime || entry_mtime > bsdtar->mtime) 584 1.1.1.6 christos archive_entry_set_mtime(entry, bsdtar->mtime, 0); 585 1.1.1.6 christos } 586 1.1.1.6 christos 587 1.1.1.6 christos /* 588 1.1.1.2 joerg * It would be nice to just use printf() for formatting large numbers, 589 1.1.1.2 joerg * but the compatibility problems are quite a headache. Hence the 590 1.1.1.2 joerg * following simple utility function. 591 1.1.1.2 joerg */ 592 1.1.1.2 joerg const char * 593 1.1.1.2 joerg tar_i64toa(int64_t n0) 594 1.1.1.2 joerg { 595 1.1.1.2 joerg static char buff[24]; 596 1.1.1.3 joerg uint64_t n = n0 < 0 ? -n0 : n0; 597 1.1.1.2 joerg char *p = buff + sizeof(buff); 598 1.1.1.2 joerg 599 1.1.1.2 joerg *--p = '\0'; 600 1.1.1.2 joerg do { 601 1.1.1.2 joerg *--p = '0' + (int)(n % 10); 602 1.1.1.3 joerg } while (n /= 10); 603 1.1.1.2 joerg if (n0 < 0) 604 1.1.1.2 joerg *--p = '-'; 605 1.1.1.2 joerg return p; 606 1.1.1.2 joerg } 607 1.1.1.2 joerg 608 1.1.1.2 joerg /* 609 1.1 joerg * Like strcmp(), but try to be a little more aware of the fact that 610 1.1 joerg * we're comparing two paths. Right now, it just handles leading 611 1.1 joerg * "./" and trailing '/' specially, so that "a/b/" == "./a/b" 612 1.1 joerg * 613 1.1 joerg * TODO: Make this better, so that "./a//b/./c/" == "a/b/c" 614 1.1 joerg * TODO: After this works, push it down into libarchive. 615 1.1 joerg * TODO: Publish the path normalization routines in libarchive so 616 1.1 joerg * that bsdtar can normalize paths and use fast strcmp() instead 617 1.1 joerg * of this. 618 1.1.1.2 joerg * 619 1.1.1.2 joerg * Note: This is currently only used within write.c, so should 620 1.1.1.2 joerg * not handle \ path separators. 621 1.1 joerg */ 622 1.1 joerg 623 1.1 joerg int 624 1.1 joerg pathcmp(const char *a, const char *b) 625 1.1 joerg { 626 1.1 joerg /* Skip leading './' */ 627 1.1 joerg if (a[0] == '.' && a[1] == '/' && a[2] != '\0') 628 1.1 joerg a += 2; 629 1.1 joerg if (b[0] == '.' && b[1] == '/' && b[2] != '\0') 630 1.1 joerg b += 2; 631 1.1 joerg /* Find the first difference, or return (0) if none. */ 632 1.1 joerg while (*a == *b) { 633 1.1 joerg if (*a == '\0') 634 1.1 joerg return (0); 635 1.1 joerg a++; 636 1.1 joerg b++; 637 1.1 joerg } 638 1.1 joerg /* 639 1.1 joerg * If one ends in '/' and the other one doesn't, 640 1.1 joerg * they're the same. 641 1.1 joerg */ 642 1.1 joerg if (a[0] == '/' && a[1] == '\0' && b[0] == '\0') 643 1.1 joerg return (0); 644 1.1 joerg if (a[0] == '\0' && b[0] == '/' && b[1] == '\0') 645 1.1 joerg return (0); 646 1.1 joerg /* They're really different, return the correct sign. */ 647 1.1 joerg return (*(const unsigned char *)a - *(const unsigned char *)b); 648 1.1 joerg } 649 1.1.1.3 joerg 650 1.1.1.3 joerg #define PPBUFF_SIZE 1024 651 1.1.1.3 joerg const char * 652 1.1.1.3 joerg passphrase_callback(struct archive *a, void *_client_data) 653 1.1.1.3 joerg { 654 1.1.1.3 joerg struct bsdtar *bsdtar = (struct bsdtar *)_client_data; 655 1.1.1.3 joerg (void)a; /* UNUSED */ 656 1.1.1.3 joerg 657 1.1.1.3 joerg if (bsdtar->ppbuff == NULL) { 658 1.1.1.3 joerg bsdtar->ppbuff = malloc(PPBUFF_SIZE); 659 1.1.1.3 joerg if (bsdtar->ppbuff == NULL) 660 1.1.1.3 joerg lafe_errc(1, errno, "Out of memory"); 661 1.1.1.3 joerg } 662 1.1.1.3 joerg return lafe_readpassphrase("Enter passphrase:", 663 1.1.1.3 joerg bsdtar->ppbuff, PPBUFF_SIZE); 664 1.1.1.3 joerg } 665 1.1.1.3 joerg 666 1.1.1.3 joerg void 667 1.1.1.3 joerg passphrase_free(char *ppbuff) 668 1.1.1.3 joerg { 669 1.1.1.3 joerg if (ppbuff != NULL) { 670 1.1.1.3 joerg memset(ppbuff, 0, PPBUFF_SIZE); 671 1.1.1.3 joerg free(ppbuff); 672 1.1.1.3 joerg } 673 1.1.1.3 joerg } 674 1.1.1.3 joerg 675 1.1.1.3 joerg /* 676 1.1.1.3 joerg * Display information about the current file. 677 1.1.1.3 joerg * 678 1.1.1.3 joerg * The format here roughly duplicates the output of 'ls -l'. 679 1.1.1.3 joerg * This is based on SUSv2, where 'tar tv' is documented as 680 1.1.1.3 joerg * listing additional information in an "unspecified format," 681 1.1.1.3 joerg * and 'pax -l' is documented as using the same format as 'ls -l'. 682 1.1.1.3 joerg */ 683 1.1.1.3 joerg void 684 1.1.1.3 joerg list_item_verbose(struct bsdtar *bsdtar, FILE *out, struct archive_entry *entry) 685 1.1.1.3 joerg { 686 1.1.1.3 joerg char tmp[100]; 687 1.1.1.3 joerg size_t w; 688 1.1.1.6 christos size_t sw; 689 1.1.1.3 joerg const char *p; 690 1.1.1.3 joerg const char *fmt; 691 1.1.1.3 joerg time_t tim; 692 1.1.1.3 joerg static time_t now; 693 1.1.1.4 christos struct tm *ltime; 694 1.1.1.4 christos #if defined(HAVE_LOCALTIME_R) || defined(HAVE_LOCALTIME_S) 695 1.1.1.4 christos struct tm tmbuf; 696 1.1.1.4 christos #endif 697 1.1.1.3 joerg 698 1.1.1.3 joerg /* 699 1.1.1.3 joerg * We avoid collecting the entire list in memory at once by 700 1.1.1.3 joerg * listing things as we see them. However, that also means we can't 701 1.1.1.3 joerg * just pre-compute the field widths. Instead, we start with guesses 702 1.1.1.3 joerg * and just widen them as necessary. These numbers are completely 703 1.1.1.3 joerg * arbitrary. 704 1.1.1.3 joerg */ 705 1.1.1.3 joerg if (!bsdtar->u_width) { 706 1.1.1.3 joerg bsdtar->u_width = 6; 707 1.1.1.3 joerg bsdtar->gs_width = 13; 708 1.1.1.3 joerg } 709 1.1.1.3 joerg if (!now) 710 1.1.1.3 joerg time(&now); 711 1.1.1.6 christos fprintf(out, "%s %u ", 712 1.1.1.3 joerg archive_entry_strmode(entry), 713 1.1.1.3 joerg archive_entry_nlink(entry)); 714 1.1.1.3 joerg 715 1.1.1.3 joerg /* Use uname if it's present, else uid. */ 716 1.1.1.3 joerg p = archive_entry_uname(entry); 717 1.1.1.3 joerg if ((p == NULL) || (*p == '\0')) { 718 1.1.1.4 christos snprintf(tmp, sizeof(tmp), "%lu ", 719 1.1.1.3 joerg (unsigned long)archive_entry_uid(entry)); 720 1.1.1.3 joerg p = tmp; 721 1.1.1.3 joerg } 722 1.1.1.3 joerg w = strlen(p); 723 1.1.1.3 joerg if (w > bsdtar->u_width) 724 1.1.1.3 joerg bsdtar->u_width = w; 725 1.1.1.3 joerg fprintf(out, "%-*s ", (int)bsdtar->u_width, p); 726 1.1.1.3 joerg 727 1.1.1.3 joerg /* Use gname if it's present, else gid. */ 728 1.1.1.3 joerg p = archive_entry_gname(entry); 729 1.1.1.3 joerg if (p != NULL && p[0] != '\0') { 730 1.1.1.3 joerg fprintf(out, "%s", p); 731 1.1.1.3 joerg w = strlen(p); 732 1.1.1.3 joerg } else { 733 1.1.1.4 christos snprintf(tmp, sizeof(tmp), "%lu", 734 1.1.1.3 joerg (unsigned long)archive_entry_gid(entry)); 735 1.1.1.3 joerg w = strlen(tmp); 736 1.1.1.3 joerg fprintf(out, "%s", tmp); 737 1.1.1.3 joerg } 738 1.1.1.3 joerg 739 1.1.1.3 joerg /* 740 1.1.1.3 joerg * Print device number or file size, right-aligned so as to make 741 1.1.1.3 joerg * total width of group and devnum/filesize fields be gs_width. 742 1.1.1.3 joerg * If gs_width is too small, grow it. 743 1.1.1.3 joerg */ 744 1.1.1.3 joerg if (archive_entry_filetype(entry) == AE_IFCHR 745 1.1.1.3 joerg || archive_entry_filetype(entry) == AE_IFBLK) { 746 1.1.1.4 christos snprintf(tmp, sizeof(tmp), "%lu,%lu", 747 1.1.1.3 joerg (unsigned long)archive_entry_rdevmajor(entry), 748 1.1.1.3 joerg (unsigned long)archive_entry_rdevminor(entry)); 749 1.1.1.3 joerg } else { 750 1.1.1.3 joerg strcpy(tmp, tar_i64toa(archive_entry_size(entry))); 751 1.1.1.3 joerg } 752 1.1.1.3 joerg if (w + strlen(tmp) >= bsdtar->gs_width) 753 1.1.1.3 joerg bsdtar->gs_width = w+strlen(tmp)+1; 754 1.1.1.3 joerg fprintf(out, "%*s", (int)(bsdtar->gs_width - w), tmp); 755 1.1.1.3 joerg 756 1.1.1.3 joerg /* Format the time using 'ls -l' conventions. */ 757 1.1.1.3 joerg tim = archive_entry_mtime(entry); 758 1.1.1.3 joerg #define HALF_YEAR (time_t)365 * 86400 / 2 759 1.1.1.3 joerg #if defined(_WIN32) && !defined(__CYGWIN__) 760 1.1.1.3 joerg #define DAY_FMT "%d" /* Windows' strftime function does not support %e format. */ 761 1.1.1.3 joerg #else 762 1.1.1.3 joerg #define DAY_FMT "%e" /* Day number without leading zeros */ 763 1.1.1.3 joerg #endif 764 1.1.1.3 joerg if (tim < now - HALF_YEAR || tim > now + HALF_YEAR) 765 1.1.1.3 joerg fmt = bsdtar->day_first ? DAY_FMT " %b %Y" : "%b " DAY_FMT " %Y"; 766 1.1.1.3 joerg else 767 1.1.1.3 joerg fmt = bsdtar->day_first ? DAY_FMT " %b %H:%M" : "%b " DAY_FMT " %H:%M"; 768 1.1.1.4 christos #if defined(HAVE_LOCALTIME_S) 769 1.1.1.4 christos ltime = localtime_s(&tmbuf, &tim) ? NULL : &tmbuf; 770 1.1.1.4 christos #elif defined(HAVE_LOCALTIME_R) 771 1.1.1.4 christos ltime = localtime_r(&tim, &tmbuf); 772 1.1.1.4 christos #else 773 1.1.1.4 christos ltime = localtime(&tim); 774 1.1.1.4 christos #endif 775 1.1.1.6 christos if (ltime) 776 1.1.1.6 christos sw = strftime(tmp, sizeof(tmp), fmt, ltime); 777 1.1.1.6 christos if (!ltime || !sw) 778 1.1.1.6 christos sprintf(tmp, "-- -- ----"); 779 1.1.1.3 joerg fprintf(out, " %s ", tmp); 780 1.1.1.3 joerg safe_fprintf(out, "%s", archive_entry_pathname(entry)); 781 1.1.1.3 joerg 782 1.1.1.3 joerg /* Extra information for links. */ 783 1.1.1.3 joerg if (archive_entry_hardlink(entry)) /* Hard link */ 784 1.1.1.3 joerg safe_fprintf(out, " link to %s", 785 1.1.1.3 joerg archive_entry_hardlink(entry)); 786 1.1.1.3 joerg else if (archive_entry_symlink(entry)) /* Symbolic link */ 787 1.1.1.3 joerg safe_fprintf(out, " -> %s", archive_entry_symlink(entry)); 788 1.1.1.3 joerg } 789