| 1 |
/** $MirOS: src/bin/pax/tar.c,v 1.4 2007/02/17 04:52:41 tg Exp $ */ |
| 2 |
/* $OpenBSD: tar.c,v 1.41 2006/03/04 20:24:55 otto Exp $ */ |
| 3 |
/* $NetBSD: tar.c,v 1.5 1995/03/21 09:07:49 cgd Exp $ */ |
| 4 |
|
| 5 |
/*- |
| 6 |
* Copyright (c) 2006 Thorsten Glaser. |
| 7 |
* Copyright (c) 1992 Keith Muller. |
| 8 |
* Copyright (c) 1992, 1993 |
| 9 |
* The Regents of the University of California. All rights reserved. |
| 10 |
* |
| 11 |
* This code is derived from software contributed to Berkeley by |
| 12 |
* Keith Muller of the University of California, San Diego. |
| 13 |
* |
| 14 |
* Redistribution and use in source and binary forms, with or without |
| 15 |
* modification, are permitted provided that the following conditions |
| 16 |
* are met: |
| 17 |
* 1. Redistributions of source code must retain the above copyright |
| 18 |
* notice, this list of conditions and the following disclaimer. |
| 19 |
* 2. Redistributions in binary form must reproduce the above copyright |
| 20 |
* notice, this list of conditions and the following disclaimer in the |
| 21 |
* documentation and/or other materials provided with the distribution. |
| 22 |
* 3. Neither the name of the University nor the names of its contributors |
| 23 |
* may be used to endorse or promote products derived from this software |
| 24 |
* without specific prior written permission. |
| 25 |
* |
| 26 |
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
| 27 |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 28 |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| 29 |
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
| 30 |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| 31 |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
| 32 |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| 33 |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| 34 |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
| 35 |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| 36 |
* SUCH DAMAGE. |
| 37 |
*/ |
| 38 |
|
| 39 |
#include <sys/param.h> |
| 40 |
#include <sys/time.h> |
| 41 |
#include <sys/stat.h> |
| 42 |
#include <string.h> |
| 43 |
#include <stdio.h> |
| 44 |
#include <unistd.h> |
| 45 |
#include <stdlib.h> |
| 46 |
#include "pax.h" |
| 47 |
#include "extern.h" |
| 48 |
#include "tar.h" |
| 49 |
#include "options.h" |
| 50 |
|
| 51 |
__SCCSID("@(#)tar.c 8.2 (Berkeley) 4/18/94"); |
| 52 |
__RCSID("$MirOS: src/bin/pax/tar.c,v 1.4 2007/02/17 04:52:41 tg Exp $"); |
| 53 |
|
| 54 |
/* |
| 55 |
* Routines for reading, writing and header identify of various versions of tar |
| 56 |
*/ |
| 57 |
|
| 58 |
static size_t expandname(char *, size_t, char **, const char *, size_t); |
| 59 |
static u_long tar_chksm(char *, int); |
| 60 |
static char *name_split(char *, int); |
| 61 |
static int ul_oct(u_long, char *, int, int); |
| 62 |
#ifndef LONG_OFF_T |
| 63 |
static int uqd_oct(u_quad_t, char *, int, int); |
| 64 |
#endif |
| 65 |
|
| 66 |
static void tar_dbgfld(const char *, const char *, size_t); |
| 67 |
|
| 68 |
static uid_t uid_nobody; |
| 69 |
static uid_t uid_warn; |
| 70 |
static gid_t gid_nobody; |
| 71 |
static gid_t gid_warn; |
| 72 |
|
| 73 |
/* |
| 74 |
* Routines common to all versions of tar |
| 75 |
*/ |
| 76 |
|
| 77 |
static int tar_nodir; /* do not write dirs under old tar */ |
| 78 |
char *gnu_name_string; /* GNU ././@LongLink hackery name */ |
| 79 |
char *gnu_link_string; /* GNU ././@LongLink hackery link */ |
| 80 |
|
| 81 |
/* |
| 82 |
* tar_endwr() |
| 83 |
* add the tar trailer of two null blocks |
| 84 |
* Return: |
| 85 |
* 0 if ok, -1 otherwise (what wr_skip returns) |
| 86 |
*/ |
| 87 |
|
| 88 |
int |
| 89 |
tar_endwr(void) |
| 90 |
{ |
| 91 |
return(wr_skip((off_t)(NULLCNT*BLKMULT))); |
| 92 |
} |
| 93 |
|
| 94 |
/* |
| 95 |
* tar_endrd() |
| 96 |
* no cleanup needed here, just return size of trailer (for append) |
| 97 |
* Return: |
| 98 |
* size of trailer (2 * BLKMULT) |
| 99 |
*/ |
| 100 |
|
| 101 |
off_t |
| 102 |
tar_endrd(void) |
| 103 |
{ |
| 104 |
return((off_t)(NULLCNT*BLKMULT)); |
| 105 |
} |
| 106 |
|
| 107 |
/* |
| 108 |
* tar_trail() |
| 109 |
* Called to determine if a header block is a valid trailer. We are passed |
| 110 |
* the block, the in_sync flag (which tells us we are in resync mode; |
| 111 |
* looking for a valid header), and cnt (which starts at zero) which is |
| 112 |
* used to count the number of empty blocks we have seen so far. |
| 113 |
* Return: |
| 114 |
* 0 if a valid trailer, -1 if not a valid trailer, or 1 if the block |
| 115 |
* could never contain a header. |
| 116 |
*/ |
| 117 |
|
| 118 |
int |
| 119 |
tar_trail(ARCHD *ignore __attribute__((unused)), char *buf, int in_resync, |
| 120 |
int *cnt) |
| 121 |
{ |
| 122 |
int i; |
| 123 |
|
| 124 |
/* |
| 125 |
* look for all zero, trailer is two consecutive blocks of zero |
| 126 |
*/ |
| 127 |
for (i = 0; i < BLKMULT; ++i) { |
| 128 |
if (buf[i] != '\0') |
| 129 |
break; |
| 130 |
} |
| 131 |
|
| 132 |
/* |
| 133 |
* if not all zero it is not a trailer, but MIGHT be a header. |
| 134 |
*/ |
| 135 |
if (i != BLKMULT) |
| 136 |
return(-1); |
| 137 |
|
| 138 |
/* |
| 139 |
* When given a zero block, we must be careful! |
| 140 |
* If we are not in resync mode, check for the trailer. Have to watch |
| 141 |
* out that we do not mis-identify file data as the trailer, so we do |
| 142 |
* NOT try to id a trailer during resync mode. During resync mode we |
| 143 |
* might as well throw this block out since a valid header can NEVER be |
| 144 |
* a block of all 0 (we must have a valid file name). |
| 145 |
*/ |
| 146 |
if (!in_resync && (++*cnt >= NULLCNT)) |
| 147 |
return(0); |
| 148 |
return(1); |
| 149 |
} |
| 150 |
|
| 151 |
/* |
| 152 |
* ul_oct() |
| 153 |
* convert an unsigned long to an octal string. many oddball field |
| 154 |
* termination characters are used by the various versions of tar in the |
| 155 |
* different fields. term selects which kind to use. str is '0' padded |
| 156 |
* at the front to len. we are unable to use only one format as many old |
| 157 |
* tar readers are very cranky about this. |
| 158 |
* Return: |
| 159 |
* 0 if the number fit into the string, -1 otherwise |
| 160 |
*/ |
| 161 |
|
| 162 |
static int |
| 163 |
ul_oct(u_long val, char *str, int len, int term) |
| 164 |
{ |
| 165 |
char *pt; |
| 166 |
|
| 167 |
/* |
| 168 |
* term selects the appropriate character(s) for the end of the string |
| 169 |
*/ |
| 170 |
pt = str + len - 1; |
| 171 |
switch (term) { |
| 172 |
case 3: |
| 173 |
*pt-- = '\0'; |
| 174 |
break; |
| 175 |
case 2: |
| 176 |
*pt-- = ' '; |
| 177 |
*pt-- = '\0'; |
| 178 |
break; |
| 179 |
case 1: |
| 180 |
*pt-- = ' '; |
| 181 |
break; |
| 182 |
case 0: |
| 183 |
default: |
| 184 |
*pt-- = '\0'; |
| 185 |
*pt-- = ' '; |
| 186 |
break; |
| 187 |
} |
| 188 |
|
| 189 |
/* |
| 190 |
* convert and blank pad if there is space |
| 191 |
*/ |
| 192 |
while (pt >= str) { |
| 193 |
*pt-- = '0' + (char)(val & 0x7); |
| 194 |
if ((val = val >> 3) == (u_long)0) |
| 195 |
break; |
| 196 |
} |
| 197 |
|
| 198 |
while (pt >= str) |
| 199 |
*pt-- = '0'; |
| 200 |
if (val != (u_long)0) |
| 201 |
return(-1); |
| 202 |
return(0); |
| 203 |
} |
| 204 |
|
| 205 |
#ifndef LONG_OFF_T |
| 206 |
/* |
| 207 |
* uqd_oct() |
| 208 |
* convert an u_quad_t to an octal string. one of many oddball field |
| 209 |
* termination characters are used by the various versions of tar in the |
| 210 |
* different fields. term selects which kind to use. str is '0' padded |
| 211 |
* at the front to len. we are unable to use only one format as many old |
| 212 |
* tar readers are very cranky about this. |
| 213 |
* Return: |
| 214 |
* 0 if the number fit into the string, -1 otherwise |
| 215 |
*/ |
| 216 |
|
| 217 |
static int |
| 218 |
uqd_oct(u_quad_t val, char *str, int len, int term) |
| 219 |
{ |
| 220 |
char *pt; |
| 221 |
|
| 222 |
/* |
| 223 |
* term selects the appropriate character(s) for the end of the string |
| 224 |
*/ |
| 225 |
pt = str + len - 1; |
| 226 |
switch (term) { |
| 227 |
case 3: |
| 228 |
*pt-- = '\0'; |
| 229 |
break; |
| 230 |
case 2: |
| 231 |
*pt-- = ' '; |
| 232 |
*pt-- = '\0'; |
| 233 |
break; |
| 234 |
case 1: |
| 235 |
*pt-- = ' '; |
| 236 |
break; |
| 237 |
case 0: |
| 238 |
default: |
| 239 |
*pt-- = '\0'; |
| 240 |
*pt-- = ' '; |
| 241 |
break; |
| 242 |
} |
| 243 |
|
| 244 |
/* |
| 245 |
* convert and blank pad if there is space |
| 246 |
*/ |
| 247 |
while (pt >= str) { |
| 248 |
*pt-- = '0' + (char)(val & 0x7); |
| 249 |
if ((val = val >> 3) == 0) |
| 250 |
break; |
| 251 |
} |
| 252 |
|
| 253 |
while (pt >= str) |
| 254 |
*pt-- = '0'; |
| 255 |
if (val != (u_quad_t)0) |
| 256 |
return(-1); |
| 257 |
return(0); |
| 258 |
} |
| 259 |
#endif |
| 260 |
|
| 261 |
/* |
| 262 |
* tar_chksm() |
| 263 |
* calculate the checksum for a tar block counting the checksum field as |
| 264 |
* all blanks (BLNKSUM is that value pre-calculated, the sum of 8 blanks). |
| 265 |
* NOTE: we use len to short circuit summing 0's on write since we ALWAYS |
| 266 |
* pad headers with 0. |
| 267 |
* Return: |
| 268 |
* unsigned long checksum |
| 269 |
*/ |
| 270 |
|
| 271 |
static u_long |
| 272 |
tar_chksm(char *blk, int len) |
| 273 |
{ |
| 274 |
char *stop; |
| 275 |
char *pt; |
| 276 |
u_long chksm = BLNKSUM; /* initial value is checksum field sum */ |
| 277 |
|
| 278 |
/* |
| 279 |
* add the part of the block before the checksum field |
| 280 |
*/ |
| 281 |
pt = blk; |
| 282 |
stop = blk + CHK_OFFSET; |
| 283 |
while (pt < stop) |
| 284 |
chksm += (u_long)(*pt++ & 0xff); |
| 285 |
/* |
| 286 |
* move past the checksum field and keep going, spec counts the |
| 287 |
* checksum field as the sum of 8 blanks (which is pre-computed as |
| 288 |
* BLNKSUM). |
| 289 |
* ASSUMED: len is greater than CHK_OFFSET. (len is where our 0 padding |
| 290 |
* starts, no point in summing zero's) |
| 291 |
*/ |
| 292 |
pt += CHK_LEN; |
| 293 |
stop = blk + len; |
| 294 |
while (pt < stop) |
| 295 |
chksm += (u_long)(*pt++ & 0xff); |
| 296 |
return(chksm); |
| 297 |
} |
| 298 |
|
| 299 |
/* |
| 300 |
* Routines for old BSD style tar (also made portable to sysV tar) |
| 301 |
*/ |
| 302 |
|
| 303 |
/* |
| 304 |
* tar_id() |
| 305 |
* determine if a block given to us is a valid tar header (and not a USTAR |
| 306 |
* header). We have to be on the lookout for those pesky blocks of all |
| 307 |
* zero's. |
| 308 |
* Return: |
| 309 |
* 0 if a tar header, -1 otherwise |
| 310 |
*/ |
| 311 |
|
| 312 |
int |
| 313 |
tar_id(char *blk, int size) |
| 314 |
{ |
| 315 |
HD_TAR *hd; |
| 316 |
HD_USTAR *uhd; |
| 317 |
|
| 318 |
if (size < BLKMULT) |
| 319 |
return(-1); |
| 320 |
hd = (HD_TAR *)blk; |
| 321 |
uhd = (HD_USTAR *)blk; |
| 322 |
|
| 323 |
/* |
| 324 |
* check for block of zero's first, a simple and fast test, then make |
| 325 |
* sure this is not a ustar header by looking for the ustar magic |
| 326 |
* cookie. We should use TMAGLEN, but some USTAR archive programs are |
| 327 |
* wrong and create archives missing the \0. Last we check the |
| 328 |
* checksum. If this is ok we have to assume it is a valid header. |
| 329 |
*/ |
| 330 |
if (hd->name[0] == '\0') |
| 331 |
return(-1); |
| 332 |
if (strncmp(uhd->magic, TMAGIC, TMAGLEN - 1) == 0) |
| 333 |
return(-1); |
| 334 |
if (asc_ul(hd->chksum,sizeof(hd->chksum),OCT) != tar_chksm(blk,BLKMULT)) |
| 335 |
return(-1); |
| 336 |
force_one_volume = 1; |
| 337 |
return(0); |
| 338 |
} |
| 339 |
|
| 340 |
/* |
| 341 |
* tar_opt() |
| 342 |
* handle tar format specific -o options |
| 343 |
* Return: |
| 344 |
* 0 if ok -1 otherwise |
| 345 |
*/ |
| 346 |
|
| 347 |
int |
| 348 |
tar_opt(void) |
| 349 |
{ |
| 350 |
OPLIST *opt; |
| 351 |
|
| 352 |
while ((opt = opt_next()) != NULL) { |
| 353 |
if (strcmp(opt->name, TAR_OPTION) || |
| 354 |
strcmp(opt->value, TAR_NODIR)) { |
| 355 |
paxwarn(1, "Unknown tar format -o option/value pair %s=%s", |
| 356 |
opt->name, opt->value); |
| 357 |
paxwarn(1,"%s=%s is the only supported tar format option", |
| 358 |
TAR_OPTION, TAR_NODIR); |
| 359 |
return(-1); |
| 360 |
} |
| 361 |
|
| 362 |
/* |
| 363 |
* we only support one option, and only when writing |
| 364 |
*/ |
| 365 |
if ((act != APPND) && (act != ARCHIVE)) { |
| 366 |
paxwarn(1, "%s=%s is only supported when writing.", |
| 367 |
opt->name, opt->value); |
| 368 |
return(-1); |
| 369 |
} |
| 370 |
tar_nodir = 1; |
| 371 |
} |
| 372 |
return(0); |
| 373 |
} |
| 374 |
|
| 375 |
|
| 376 |
/* |
| 377 |
* tar_rd() |
| 378 |
* extract the values out of block already determined to be a tar header. |
| 379 |
* store the values in the ARCHD parameter. |
| 380 |
* Return: |
| 381 |
* 0 |
| 382 |
*/ |
| 383 |
|
| 384 |
int |
| 385 |
tar_rd(ARCHD *arcn, char *buf) |
| 386 |
{ |
| 387 |
HD_TAR *hd; |
| 388 |
char *pt; |
| 389 |
|
| 390 |
/* |
| 391 |
* we only get proper sized buffers passed to us |
| 392 |
*/ |
| 393 |
if (tar_id(buf, BLKMULT) < 0) |
| 394 |
return(-1); |
| 395 |
memset(arcn, 0, sizeof(*arcn)); |
| 396 |
arcn->org_name = arcn->name; |
| 397 |
arcn->sb.st_nlink = 1; |
| 398 |
|
| 399 |
/* |
| 400 |
* copy out the name and values in the stat buffer |
| 401 |
*/ |
| 402 |
hd = (HD_TAR *)buf; |
| 403 |
if (hd->linkflag != LONGLINKTYPE && hd->linkflag != LONGNAMETYPE) { |
| 404 |
arcn->nlen = expandname(arcn->name, sizeof(arcn->name), |
| 405 |
&gnu_name_string, hd->name, sizeof(hd->name)); |
| 406 |
arcn->ln_nlen = expandname(arcn->ln_name, sizeof(arcn->ln_name), |
| 407 |
&gnu_link_string, hd->linkname, sizeof(hd->linkname)); |
| 408 |
} |
| 409 |
arcn->sb.st_mode = (mode_t)(asc_ul(hd->mode,sizeof(hd->mode),OCT) & |
| 410 |
0xfff); |
| 411 |
arcn->sb.st_uid = (uid_t)asc_ul(hd->uid, sizeof(hd->uid), OCT); |
| 412 |
arcn->sb.st_gid = (gid_t)asc_ul(hd->gid, sizeof(hd->gid), OCT); |
| 413 |
#ifdef LONG_OFF_T |
| 414 |
arcn->sb.st_size = (off_t)asc_ul(hd->size, sizeof(hd->size), OCT); |
| 415 |
#else |
| 416 |
arcn->sb.st_size = (off_t)asc_uqd(hd->size, sizeof(hd->size), OCT); |
| 417 |
#endif |
| 418 |
arcn->sb.st_mtime = (time_t)asc_ul(hd->mtime, sizeof(hd->mtime), OCT); |
| 419 |
arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime; |
| 420 |
|
| 421 |
/* |
| 422 |
* have to look at the last character, it may be a '/' and that is used |
| 423 |
* to encode this as a directory |
| 424 |
*/ |
| 425 |
pt = &(arcn->name[arcn->nlen - 1]); |
| 426 |
arcn->pad = 0; |
| 427 |
arcn->skip = 0; |
| 428 |
switch (hd->linkflag) { |
| 429 |
case SYMTYPE: |
| 430 |
/* |
| 431 |
* symbolic link, need to get the link name and set the type in |
| 432 |
* the st_mode so -v printing will look correct. |
| 433 |
*/ |
| 434 |
arcn->type = PAX_SLK; |
| 435 |
arcn->sb.st_mode |= S_IFLNK; |
| 436 |
break; |
| 437 |
case LNKTYPE: |
| 438 |
/* |
| 439 |
* hard link, need to get the link name, set the type in the |
| 440 |
* st_mode and st_nlink so -v printing will look better. |
| 441 |
*/ |
| 442 |
arcn->type = PAX_HLK; |
| 443 |
arcn->sb.st_nlink = 2; |
| 444 |
|
| 445 |
/* |
| 446 |
* no idea of what type this thing really points at, but |
| 447 |
* we set something for printing only. |
| 448 |
*/ |
| 449 |
arcn->sb.st_mode |= S_IFREG; |
| 450 |
break; |
| 451 |
case LONGLINKTYPE: |
| 452 |
case LONGNAMETYPE: |
| 453 |
/* |
| 454 |
* GNU long link/file; we tag these here and let the |
| 455 |
* pax internals deal with it -- too ugly otherwise. |
| 456 |
*/ |
| 457 |
arcn->type = |
| 458 |
hd->linkflag == LONGLINKTYPE ? PAX_GLL : PAX_GLF; |
| 459 |
arcn->pad = TAR_PAD(arcn->sb.st_size); |
| 460 |
arcn->skip = arcn->sb.st_size; |
| 461 |
break; |
| 462 |
case DIRTYPE: |
| 463 |
/* |
| 464 |
* It is a directory, set the mode for -v printing |
| 465 |
*/ |
| 466 |
arcn->type = PAX_DIR; |
| 467 |
arcn->sb.st_mode |= S_IFDIR; |
| 468 |
arcn->sb.st_nlink = 2; |
| 469 |
break; |
| 470 |
case AREGTYPE: |
| 471 |
case REGTYPE: |
| 472 |
default: |
| 473 |
/* |
| 474 |
* If we have a trailing / this is a directory and NOT a file. |
| 475 |
*/ |
| 476 |
arcn->ln_name[0] = '\0'; |
| 477 |
arcn->ln_nlen = 0; |
| 478 |
if (*pt == '/') { |
| 479 |
/* |
| 480 |
* it is a directory, set the mode for -v printing |
| 481 |
*/ |
| 482 |
arcn->type = PAX_DIR; |
| 483 |
arcn->sb.st_mode |= S_IFDIR; |
| 484 |
arcn->sb.st_nlink = 2; |
| 485 |
} else { |
| 486 |
/* |
| 487 |
* have a file that will be followed by data. Set the |
| 488 |
* skip value to the size field and calculate the size |
| 489 |
* of the padding. |
| 490 |
*/ |
| 491 |
arcn->type = PAX_REG; |
| 492 |
arcn->sb.st_mode |= S_IFREG; |
| 493 |
arcn->pad = TAR_PAD(arcn->sb.st_size); |
| 494 |
arcn->skip = arcn->sb.st_size; |
| 495 |
} |
| 496 |
break; |
| 497 |
} |
| 498 |
|
| 499 |
/* |
| 500 |
* strip off any trailing slash. |
| 501 |
*/ |
| 502 |
if (*pt == '/') { |
| 503 |
*pt = '\0'; |
| 504 |
--arcn->nlen; |
| 505 |
} |
| 506 |
return(0); |
| 507 |
} |
| 508 |
|
| 509 |
/* |
| 510 |
* tar_wr() |
| 511 |
* write a tar header for the file specified in the ARCHD to the archive. |
| 512 |
* Have to check for file types that cannot be stored and file names that |
| 513 |
* are too long. Be careful of the term (last arg) to ul_oct, each field |
| 514 |
* of tar has it own spec for the termination character(s). |
| 515 |
* ASSUMED: space after header in header block is zero filled |
| 516 |
* Return: |
| 517 |
* 0 if file has data to be written after the header, 1 if file has NO |
| 518 |
* data to write after the header, -1 if archive write failed |
| 519 |
*/ |
| 520 |
|
| 521 |
int |
| 522 |
tar_wr(ARCHD *arcn) |
| 523 |
{ |
| 524 |
HD_TAR *hd; |
| 525 |
int len; |
| 526 |
char hdblk[sizeof(HD_TAR)]; |
| 527 |
|
| 528 |
/* |
| 529 |
* check for those file system types which tar cannot store |
| 530 |
*/ |
| 531 |
switch (arcn->type) { |
| 532 |
case PAX_DIR: |
| 533 |
/* |
| 534 |
* user asked that dirs not be written to the archive |
| 535 |
*/ |
| 536 |
if (tar_nodir) |
| 537 |
return(1); |
| 538 |
break; |
| 539 |
case PAX_CHR: |
| 540 |
paxwarn(1, "Tar cannot archive a character device %s", |
| 541 |
arcn->org_name); |
| 542 |
return(1); |
| 543 |
case PAX_BLK: |
| 544 |
paxwarn(1, "Tar cannot archive a block device %s", arcn->org_name); |
| 545 |
return(1); |
| 546 |
case PAX_SCK: |
| 547 |
paxwarn(1, "Tar cannot archive a socket %s", arcn->org_name); |
| 548 |
return(1); |
| 549 |
case PAX_FIF: |
| 550 |
paxwarn(1, "Tar cannot archive a fifo %s", arcn->org_name); |
| 551 |
return(1); |
| 552 |
case PAX_SLK: |
| 553 |
case PAX_HLK: |
| 554 |
case PAX_HRG: |
| 555 |
if ((size_t)arcn->ln_nlen > sizeof(hd->linkname)) { |
| 556 |
paxwarn(1, "Link name too long for tar %s", |
| 557 |
arcn->ln_name); |
| 558 |
return(1); |
| 559 |
} |
| 560 |
break; |
| 561 |
case PAX_REG: |
| 562 |
case PAX_CTG: |
| 563 |
default: |
| 564 |
break; |
| 565 |
} |
| 566 |
|
| 567 |
/* |
| 568 |
* check file name len, remember extra char for dirs (the / at the end) |
| 569 |
*/ |
| 570 |
len = arcn->nlen; |
| 571 |
if (arcn->type == PAX_DIR) |
| 572 |
++len; |
| 573 |
if ((size_t)len > sizeof(hd->name)) { |
| 574 |
paxwarn(1, "File name too long for tar %s", arcn->name); |
| 575 |
return(1); |
| 576 |
} |
| 577 |
|
| 578 |
/* |
| 579 |
* Copy the data out of the ARCHD into the tar header based on the type |
| 580 |
* of the file. Remember, many tar readers want all fields to be |
| 581 |
* padded with zero so we zero the header first. We then set the |
| 582 |
* linkflag field (type), the linkname, the size, and set the padding |
| 583 |
* (if any) to be added after the file data (0 for all other types, |
| 584 |
* as they only have a header). |
| 585 |
*/ |
| 586 |
memset(hdblk, 0, sizeof(hdblk)); |
| 587 |
hd = (HD_TAR *)hdblk; |
| 588 |
fieldcpy(hd->name, sizeof(hd->name), arcn->name, sizeof(arcn->name)); |
| 589 |
arcn->pad = 0; |
| 590 |
|
| 591 |
if (arcn->type == PAX_DIR) { |
| 592 |
/* |
| 593 |
* directories are the same as files, except have a filename |
| 594 |
* that ends with a /, we add the slash here. No data follows |
| 595 |
* dirs, so no pad. |
| 596 |
*/ |
| 597 |
hd->linkflag = AREGTYPE; |
| 598 |
hd->name[len-1] = '/'; |
| 599 |
if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 1)) |
| 600 |
goto out; |
| 601 |
} else if (arcn->type == PAX_SLK) { |
| 602 |
/* |
| 603 |
* no data follows this file, so no pad |
| 604 |
*/ |
| 605 |
hd->linkflag = SYMTYPE; |
| 606 |
fieldcpy(hd->linkname, sizeof(hd->linkname), arcn->ln_name, |
| 607 |
sizeof(arcn->ln_name)); |
| 608 |
if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 1)) |
| 609 |
goto out; |
| 610 |
} else if ((arcn->type == PAX_HLK) || (arcn->type == PAX_HRG)) { |
| 611 |
/* |
| 612 |
* no data follows this file, so no pad |
| 613 |
*/ |
| 614 |
hd->linkflag = LNKTYPE; |
| 615 |
fieldcpy(hd->linkname, sizeof(hd->linkname), arcn->ln_name, |
| 616 |
sizeof(arcn->ln_name)); |
| 617 |
if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 1)) |
| 618 |
goto out; |
| 619 |
} else { |
| 620 |
/* |
| 621 |
* data follows this file, so set the pad |
| 622 |
*/ |
| 623 |
hd->linkflag = AREGTYPE; |
| 624 |
# ifdef LONG_OFF_T |
| 625 |
if (ul_oct((u_long)arcn->sb.st_size, hd->size, |
| 626 |
sizeof(hd->size), 1)) { |
| 627 |
# else |
| 628 |
if (uqd_oct((u_quad_t)arcn->sb.st_size, hd->size, |
| 629 |
sizeof(hd->size), 1)) { |
| 630 |
# endif |
| 631 |
paxwarn(1,"File is too large for tar %s", arcn->org_name); |
| 632 |
return(1); |
| 633 |
} |
| 634 |
arcn->pad = TAR_PAD(arcn->sb.st_size); |
| 635 |
} |
| 636 |
|
| 637 |
/* |
| 638 |
* copy those fields that are independent of the type |
| 639 |
*/ |
| 640 |
if (ul_oct((u_long)arcn->sb.st_mode, hd->mode, sizeof(hd->mode), 0) || |
| 641 |
ul_oct((u_long)arcn->sb.st_uid, hd->uid, sizeof(hd->uid), 0) || |
| 642 |
ul_oct((u_long)arcn->sb.st_gid, hd->gid, sizeof(hd->gid), 0) || |
| 643 |
ul_oct((u_long)(u_int)arcn->sb.st_mtime, hd->mtime, sizeof(hd->mtime), 1)) |
| 644 |
goto out; |
| 645 |
|
| 646 |
/* |
| 647 |
* calculate and add the checksum, then write the header. A return of |
| 648 |
* 0 tells the caller to now write the file data, 1 says no data needs |
| 649 |
* to be written |
| 650 |
*/ |
| 651 |
if (ul_oct(tar_chksm(hdblk, sizeof(HD_TAR)), hd->chksum, |
| 652 |
sizeof(hd->chksum), 3)) |
| 653 |
goto out; |
| 654 |
if (wr_rdbuf(hdblk, sizeof(HD_TAR)) < 0) |
| 655 |
return(-1); |
| 656 |
if (wr_skip((off_t)(BLKMULT - sizeof(HD_TAR))) < 0) |
| 657 |
return(-1); |
| 658 |
if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG)) |
| 659 |
return(0); |
| 660 |
return(1); |
| 661 |
|
| 662 |
out: |
| 663 |
/* |
| 664 |
* header field is out of range |
| 665 |
*/ |
| 666 |
paxwarn(1, "Tar header field is too small for %s", arcn->org_name); |
| 667 |
return(1); |
| 668 |
} |
| 669 |
|
| 670 |
/* |
| 671 |
* Routines for POSIX ustar |
| 672 |
*/ |
| 673 |
|
| 674 |
/* |
| 675 |
* ustar_strd() |
| 676 |
* initialization for ustar read |
| 677 |
* Return: |
| 678 |
* 0 if ok, -1 otherwise |
| 679 |
*/ |
| 680 |
|
| 681 |
int |
| 682 |
ustar_strd(void) |
| 683 |
{ |
| 684 |
if ((usrtb_start() < 0) || (grptb_start() < 0)) |
| 685 |
return(-1); |
| 686 |
return(0); |
| 687 |
} |
| 688 |
|
| 689 |
/* |
| 690 |
* ustar_stwr() |
| 691 |
* initialization for ustar write |
| 692 |
* Return: |
| 693 |
* 0 if ok, -1 otherwise |
| 694 |
*/ |
| 695 |
|
| 696 |
int |
| 697 |
ustar_stwr(void) |
| 698 |
{ |
| 699 |
if ((uidtb_start() < 0) || (gidtb_start() < 0)) |
| 700 |
return(-1); |
| 701 |
return(0); |
| 702 |
} |
| 703 |
|
| 704 |
/* |
| 705 |
* ustar_id() |
| 706 |
* determine if a block given to us is a valid ustar header. We have to |
| 707 |
* be on the lookout for those pesky blocks of all zero's |
| 708 |
* Return: |
| 709 |
* 0 if a ustar header, -1 otherwise |
| 710 |
*/ |
| 711 |
|
| 712 |
int |
| 713 |
ustar_id(char *blk, int size) |
| 714 |
{ |
| 715 |
HD_USTAR *hd; |
| 716 |
|
| 717 |
if (size < BLKMULT) |
| 718 |
return(-1); |
| 719 |
hd = (HD_USTAR *)blk; |
| 720 |
|
| 721 |
/* |
| 722 |
* check for block of zero's first, a simple and fast test then check |
| 723 |
* ustar magic cookie. We should use TMAGLEN, but some USTAR archive |
| 724 |
* programs are fouled up and create archives missing the \0. Last we |
| 725 |
* check the checksum. If ok we have to assume it is a valid header. |
| 726 |
*/ |
| 727 |
if (hd->prefix[0] == '\0' && hd->name[0] == '\0') |
| 728 |
return(-1); |
| 729 |
if (strncmp(hd->magic, TMAGIC, TMAGLEN - 1) != 0) |
| 730 |
return(-1); |
| 731 |
if (asc_ul(hd->chksum,sizeof(hd->chksum),OCT) != tar_chksm(blk,BLKMULT)) |
| 732 |
return(-1); |
| 733 |
return(0); |
| 734 |
} |
| 735 |
|
| 736 |
/* |
| 737 |
* ustar_rd() |
| 738 |
* extract the values out of block already determined to be a ustar header. |
| 739 |
* store the values in the ARCHD parameter. |
| 740 |
* Return: |
| 741 |
* 0 |
| 742 |
*/ |
| 743 |
|
| 744 |
int |
| 745 |
ustar_rd(ARCHD *arcn, char *buf) |
| 746 |
{ |
| 747 |
HD_USTAR *hd; |
| 748 |
char *dest; |
| 749 |
int cnt = 0; |
| 750 |
dev_t devmajor; |
| 751 |
dev_t devminor; |
| 752 |
|
| 753 |
/* |
| 754 |
* we only get proper sized buffers |
| 755 |
*/ |
| 756 |
if (ustar_id(buf, BLKMULT) < 0) |
| 757 |
return(-1); |
| 758 |
memset(arcn, 0, sizeof(*arcn)); |
| 759 |
arcn->org_name = arcn->name; |
| 760 |
arcn->sb.st_nlink = 1; |
| 761 |
hd = (HD_USTAR *)buf; |
| 762 |
|
| 763 |
/* |
| 764 |
* see if the filename is split into two parts. if, so joint the parts. |
| 765 |
* we copy the prefix first and add a / between the prefix and name. |
| 766 |
*/ |
| 767 |
dest = arcn->name; |
| 768 |
if (*(hd->prefix) != '\0') { |
| 769 |
cnt = fieldcpy(dest, sizeof(arcn->name) - 1, hd->prefix, |
| 770 |
sizeof(hd->prefix)); |
| 771 |
dest += cnt; |
| 772 |
*dest++ = '/'; |
| 773 |
cnt++; |
| 774 |
} else { |
| 775 |
cnt = 0; |
| 776 |
} |
| 777 |
|
| 778 |
if (hd->typeflag != LONGLINKTYPE && hd->typeflag != LONGNAMETYPE) { |
| 779 |
arcn->nlen = cnt + expandname(dest, sizeof(arcn->name) - cnt, |
| 780 |
&gnu_name_string, hd->name, sizeof(hd->name)); |
| 781 |
arcn->ln_nlen = expandname(arcn->ln_name, sizeof(arcn->ln_name), |
| 782 |
&gnu_link_string, hd->linkname, sizeof(hd->linkname)); |
| 783 |
} |
| 784 |
|
| 785 |
/* |
| 786 |
* follow the spec to the letter. we should only have mode bits, strip |
| 787 |
* off all other crud we may be passed. |
| 788 |
*/ |
| 789 |
arcn->sb.st_mode = (mode_t)(asc_ul(hd->mode, sizeof(hd->mode), OCT) & |
| 790 |
0xfff); |
| 791 |
#ifdef LONG_OFF_T |
| 792 |
arcn->sb.st_size = (off_t)asc_ul(hd->size, sizeof(hd->size), OCT); |
| 793 |
#else |
| 794 |
arcn->sb.st_size = (off_t)asc_uqd(hd->size, sizeof(hd->size), OCT); |
| 795 |
#endif |
| 796 |
arcn->sb.st_mtime = (time_t)asc_ul(hd->mtime, sizeof(hd->mtime), OCT); |
| 797 |
arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime; |
| 798 |
|
| 799 |
/* |
| 800 |
* If we can find the ascii names for gname and uname in the password |
| 801 |
* and group files we will use the uid's and gid they bind. Otherwise |
| 802 |
* we use the uid and gid values stored in the header. (This is what |
| 803 |
* the posix spec wants). |
| 804 |
*/ |
| 805 |
hd->gname[sizeof(hd->gname) - 1] = '\0'; |
| 806 |
if (gid_name(hd->gname, &(arcn->sb.st_gid)) < 0) |
| 807 |
arcn->sb.st_gid = (gid_t)asc_ul(hd->gid, sizeof(hd->gid), OCT); |
| 808 |
hd->uname[sizeof(hd->uname) - 1] = '\0'; |
| 809 |
if (uid_name(hd->uname, &(arcn->sb.st_uid)) < 0) |
| 810 |
arcn->sb.st_uid = (uid_t)asc_ul(hd->uid, sizeof(hd->uid), OCT); |
| 811 |
|
| 812 |
/* |
| 813 |
* set the defaults, these may be changed depending on the file type |
| 814 |
*/ |
| 815 |
arcn->pad = 0; |
| 816 |
arcn->skip = 0; |
| 817 |
arcn->sb.st_rdev = (dev_t)0; |
| 818 |
|
| 819 |
/* |
| 820 |
* set the mode and PAX type according to the typeflag in the header |
| 821 |
*/ |
| 822 |
switch (hd->typeflag) { |
| 823 |
case FIFOTYPE: |
| 824 |
arcn->type = PAX_FIF; |
| 825 |
arcn->sb.st_mode |= S_IFIFO; |
| 826 |
break; |
| 827 |
case DIRTYPE: |
| 828 |
arcn->type = PAX_DIR; |
| 829 |
arcn->sb.st_mode |= S_IFDIR; |
| 830 |
arcn->sb.st_nlink = 2; |
| 831 |
|
| 832 |
/* |
| 833 |
* Some programs that create ustar archives append a '/' |
| 834 |
* to the pathname for directories. This clearly violates |
| 835 |
* ustar specs, but we will silently strip it off anyway. |
| 836 |
*/ |
| 837 |
if (arcn->name[arcn->nlen - 1] == '/') |
| 838 |
arcn->name[--arcn->nlen] = '\0'; |
| 839 |
break; |
| 840 |
case BLKTYPE: |
| 841 |
case CHRTYPE: |
| 842 |
/* |
| 843 |
* this type requires the rdev field to be set. |
| 844 |
*/ |
| 845 |
if (hd->typeflag == BLKTYPE) { |
| 846 |
arcn->type = PAX_BLK; |
| 847 |
arcn->sb.st_mode |= S_IFBLK; |
| 848 |
} else { |
| 849 |
arcn->type = PAX_CHR; |
| 850 |
arcn->sb.st_mode |= S_IFCHR; |
| 851 |
} |
| 852 |
devmajor = (dev_t)asc_ul(hd->devmajor,sizeof(hd->devmajor),OCT); |
| 853 |
devminor = (dev_t)asc_ul(hd->devminor,sizeof(hd->devminor),OCT); |
| 854 |
arcn->sb.st_rdev = TODEV(devmajor, devminor); |
| 855 |
break; |
| 856 |
case SYMTYPE: |
| 857 |
case LNKTYPE: |
| 858 |
if (hd->typeflag == SYMTYPE) { |
| 859 |
arcn->type = PAX_SLK; |
| 860 |
arcn->sb.st_mode |= S_IFLNK; |
| 861 |
} else { |
| 862 |
arcn->type = PAX_HLK; |
| 863 |
/* |
| 864 |
* so printing looks better |
| 865 |
*/ |
| 866 |
arcn->sb.st_mode |= S_IFREG; |
| 867 |
arcn->sb.st_nlink = 2; |
| 868 |
} |
| 869 |
break; |
| 870 |
case LONGLINKTYPE: |
| 871 |
case LONGNAMETYPE: |
| 872 |
/* |
| 873 |
* GNU long link/file; we tag these here and let the |
| 874 |
* pax internals deal with it -- too ugly otherwise. |
| 875 |
*/ |
| 876 |
arcn->type = |
| 877 |
hd->typeflag == LONGLINKTYPE ? PAX_GLL : PAX_GLF; |
| 878 |
arcn->pad = TAR_PAD(arcn->sb.st_size); |
| 879 |
arcn->skip = arcn->sb.st_size; |
| 880 |
break; |
| 881 |
case CONTTYPE: |
| 882 |
case AREGTYPE: |
| 883 |
case REGTYPE: |
| 884 |
default: |
| 885 |
/* |
| 886 |
* these types have file data that follows. Set the skip and |
| 887 |
* pad fields. |
| 888 |
*/ |
| 889 |
arcn->type = PAX_REG; |
| 890 |
arcn->pad = TAR_PAD(arcn->sb.st_size); |
| 891 |
arcn->skip = arcn->sb.st_size; |
| 892 |
arcn->sb.st_mode |= S_IFREG; |
| 893 |
break; |
| 894 |
} |
| 895 |
return(0); |
| 896 |
} |
| 897 |
|
| 898 |
/* |
| 899 |
* ustar_wr() |
| 900 |
* write a ustar header for the file specified in the ARCHD to the archive |
| 901 |
* Have to check for file types that cannot be stored and file names that |
| 902 |
* are too long. Be careful of the term (last arg) to ul_oct, we only use |
| 903 |
* '\0' for the termination character (this is different than picky tar) |
| 904 |
* ASSUMED: space after header in header block is zero filled |
| 905 |
* Return: |
| 906 |
* 0 if file has data to be written after the header, 1 if file has NO |
| 907 |
* data to write after the header, -1 if archive write failed |
| 908 |
*/ |
| 909 |
|
| 910 |
int |
| 911 |
ustar_wr(ARCHD *arcn) |
| 912 |
{ |
| 913 |
HD_USTAR *hd; |
| 914 |
char *pt; |
| 915 |
char hdblk[sizeof(HD_USTAR)]; |
| 916 |
|
| 917 |
u_long t_uid, t_gid, t_mtime; |
| 918 |
|
| 919 |
anonarch_init(); |
| 920 |
|
| 921 |
/* |
| 922 |
* check for those file system types ustar cannot store |
| 923 |
*/ |
| 924 |
if (arcn->type == PAX_SCK) { |
| 925 |
paxwarn(1, "Ustar cannot archive a socket %s", arcn->org_name); |
| 926 |
return(1); |
| 927 |
} |
| 928 |
|
| 929 |
/* |
| 930 |
* check the length of the linkname |
| 931 |
*/ |
| 932 |
if (((arcn->type == PAX_SLK) || (arcn->type == PAX_HLK) || |
| 933 |
(arcn->type == PAX_HRG)) && |
| 934 |
((size_t)arcn->ln_nlen > sizeof(hd->linkname))) { |
| 935 |
paxwarn(1, "Link name too long for ustar %s", arcn->ln_name); |
| 936 |
return(1); |
| 937 |
} |
| 938 |
|
| 939 |
/* |
| 940 |
* split the path name into prefix and name fields (if needed). if |
| 941 |
* pt != arcn->name, the name has to be split |
| 942 |
*/ |
| 943 |
if ((pt = name_split(arcn->name, arcn->nlen)) == NULL) { |
| 944 |
paxwarn(1, "File name too long for ustar %s", arcn->name); |
| 945 |
return(1); |
| 946 |
} |
| 947 |
|
| 948 |
/* |
| 949 |
* zero out the header so we don't have to worry about zero fill below |
| 950 |
*/ |
| 951 |
memset(hdblk, 0, sizeof(hdblk)); |
| 952 |
hd = (HD_USTAR *)hdblk; |
| 953 |
arcn->pad = 0L; |
| 954 |
|
| 955 |
/* |
| 956 |
* split the name, or zero out the prefix |
| 957 |
*/ |
| 958 |
if (pt != arcn->name) { |
| 959 |
/* |
| 960 |
* name was split, pt points at the / where the split is to |
| 961 |
* occur, we remove the / and copy the first part to the prefix |
| 962 |
*/ |
| 963 |
*pt = '\0'; |
| 964 |
fieldcpy(hd->prefix, sizeof(hd->prefix), arcn->name, |
| 965 |
sizeof(arcn->name)); |
| 966 |
*pt++ = '/'; |
| 967 |
} |
| 968 |
|
| 969 |
/* |
| 970 |
* copy the name part. this may be the whole path or the part after |
| 971 |
* the prefix |
| 972 |
*/ |
| 973 |
fieldcpy(hd->name, sizeof(hd->name), pt, |
| 974 |
sizeof(arcn->name) - (pt - arcn->name)); |
| 975 |
|
| 976 |
t_uid = (anonarch & ANON_UIDGID) ? 0UL : (u_long)arcn->sb.st_uid; |
| 977 |
t_gid = (anonarch & ANON_UIDGID) ? 0UL : (u_long)arcn->sb.st_gid; |
| 978 |
t_mtime = (anonarch & ANON_MTIME) ? 0UL : (u_long)(u_int)arcn->sb.st_mtime; |
| 979 |
|
| 980 |
/* |
| 981 |
* set the fields in the header that are type dependent |
| 982 |
*/ |
| 983 |
switch (arcn->type) { |
| 984 |
case PAX_DIR: |
| 985 |
hd->typeflag = DIRTYPE; |
| 986 |
if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3)) |
| 987 |
goto out; |
| 988 |
break; |
| 989 |
case PAX_CHR: |
| 990 |
case PAX_BLK: |
| 991 |
if (arcn->type == PAX_CHR) |
| 992 |
hd->typeflag = CHRTYPE; |
| 993 |
else |
| 994 |
hd->typeflag = BLKTYPE; |
| 995 |
if (ul_oct((u_long)MAJOR(arcn->sb.st_rdev), hd->devmajor, |
| 996 |
sizeof(hd->devmajor), 3) || |
| 997 |
ul_oct((u_long)MINOR(arcn->sb.st_rdev), hd->devminor, |
| 998 |
sizeof(hd->devminor), 3) || |
| 999 |
ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3)) |
| 1000 |
goto out; |
| 1001 |
break; |
| 1002 |
case PAX_FIF: |
| 1003 |
hd->typeflag = FIFOTYPE; |
| 1004 |
if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3)) |
| 1005 |
goto out; |
| 1006 |
break; |
| 1007 |
case PAX_SLK: |
| 1008 |
case PAX_HLK: |
| 1009 |
case PAX_HRG: |
| 1010 |
if (arcn->type == PAX_SLK) |
| 1011 |
hd->typeflag = SYMTYPE; |
| 1012 |
else |
| 1013 |
hd->typeflag = LNKTYPE; |
| 1014 |
fieldcpy(hd->linkname, sizeof(hd->linkname), arcn->ln_name, |
| 1015 |
sizeof(arcn->ln_name)); |
| 1016 |
if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3)) |
| 1017 |
goto out; |
| 1018 |
break; |
| 1019 |
case PAX_REG: |
| 1020 |
case PAX_CTG: |
| 1021 |
default: |
| 1022 |
/* |
| 1023 |
* file data with this type, set the padding |
| 1024 |
*/ |
| 1025 |
if (arcn->type == PAX_CTG) |
| 1026 |
hd->typeflag = CONTTYPE; |
| 1027 |
else |
| 1028 |
hd->typeflag = REGTYPE; |
| 1029 |
arcn->pad = TAR_PAD(arcn->sb.st_size); |
| 1030 |
# ifdef LONG_OFF_T |
| 1031 |
if (ul_oct((u_long)arcn->sb.st_size, hd->size, |
| 1032 |
sizeof(hd->size), 3)) { |
| 1033 |
# else |
| 1034 |
if (uqd_oct((u_quad_t)arcn->sb.st_size, hd->size, |
| 1035 |
sizeof(hd->size), 3)) { |
| 1036 |
# endif |
| 1037 |
paxwarn(1,"File is too long for ustar %s",arcn->org_name); |
| 1038 |
return(1); |
| 1039 |
} |
| 1040 |
break; |
| 1041 |
} |
| 1042 |
|
| 1043 |
strncpy(hd->magic, TMAGIC, TMAGLEN); |
| 1044 |
strncpy(hd->version, TVERSION, TVERSLEN); |
| 1045 |
|
| 1046 |
/* |
| 1047 |
* set the remaining fields. Some versions want all 16 bits of mode |
| 1048 |
* we better humor them (they really do not meet spec though).... |
| 1049 |
*/ |
| 1050 |
if (ul_oct(t_uid, hd->uid, sizeof(hd->uid), 3)) { |
| 1051 |
if (uid_nobody == 0) { |
| 1052 |
if (uid_name("nobody", &uid_nobody) == -1) |
| 1053 |
goto out; |
| 1054 |
} |
| 1055 |
if (uid_warn != t_uid) { |
| 1056 |
uid_warn = t_uid; |
| 1057 |
paxwarn(1, |
| 1058 |
"Ustar header field is too small for uid %lu, " |
| 1059 |
"using nobody", t_uid); |
| 1060 |
} |
| 1061 |
if (ul_oct((u_long)uid_nobody, hd->uid, sizeof(hd->uid), 3)) |
| 1062 |
goto out; |
| 1063 |
} |
| 1064 |
if (ul_oct(t_gid, hd->gid, sizeof(hd->gid), 3)) { |
| 1065 |
if (gid_nobody == 0) { |
| 1066 |
if (gid_name("nobody", &gid_nobody) == -1) |
| 1067 |
goto out; |
| 1068 |
} |
| 1069 |
if (gid_warn != t_gid) { |
| 1070 |
gid_warn = t_gid; |
| 1071 |
paxwarn(1, |
| 1072 |
"Ustar header field is too small for gid %lu, " |
| 1073 |
"using nobody", t_gid); |
| 1074 |
} |
| 1075 |
if (ul_oct((u_long)gid_nobody, hd->gid, sizeof(hd->gid), 3)) |
| 1076 |
goto out; |
| 1077 |
} |
| 1078 |
if (ul_oct((u_long)arcn->sb.st_mode, hd->mode, sizeof(hd->mode), 3) || |
| 1079 |
ul_oct(t_mtime,hd->mtime,sizeof(hd->mtime),3)) |
| 1080 |
goto out; |
| 1081 |
strncpy(hd->uname, name_uid(t_uid, 0), sizeof(hd->uname)); |
| 1082 |
strncpy(hd->gname, name_gid(t_gid, 0), sizeof(hd->gname)); |
| 1083 |
|
| 1084 |
/* |
| 1085 |
* calculate and store the checksum write the header to the archive |
| 1086 |
* return 0 tells the caller to now write the file data, 1 says no data |
| 1087 |
* needs to be written |
| 1088 |
*/ |
| 1089 |
if (ul_oct(tar_chksm(hdblk, sizeof(HD_USTAR)), hd->chksum, |
| 1090 |
sizeof(hd->chksum), 3)) |
| 1091 |
goto out; |
| 1092 |
|
| 1093 |
if (anonarch & ANON_DEBUG) { |
| 1094 |
tar_dbgfld(NULL, NULL, 0); |
| 1095 |
tar_dbgfld("writing name '", hd->name, TNMSZ); |
| 1096 |
tar_dbgfld("' mode ", hd->mode, 8); |
| 1097 |
tar_dbgfld(" uid ", hd->uid, 8); |
| 1098 |
tar_dbgfld(" (", hd->uname, 32); |
| 1099 |
tar_dbgfld(") gid ", hd->gid, 8); |
| 1100 |
tar_dbgfld(" (", hd->gname, 32); |
| 1101 |
tar_dbgfld(") size ", hd->size, 12); |
| 1102 |
tar_dbgfld(" mtime ", hd->mtime, 12); |
| 1103 |
tar_dbgfld(" type ", &(hd->typeflag), 1); |
| 1104 |
tar_dbgfld(" linked to '", hd->linkname, TNMSZ); |
| 1105 |
tar_dbgfld("' magic '", hd->magic, TMAGLEN); |
| 1106 |
tar_dbgfld("' v", hd->version, TVERSLEN); |
| 1107 |
tar_dbgfld(" device '", hd->devmajor, 8); |
| 1108 |
tar_dbgfld(":", hd->devminor, 8); |
| 1109 |
tar_dbgfld("' prefix '", hd->prefix, TPFSZ); |
| 1110 |
tar_dbgfld("' checksum ", hd->chksum, CHK_LEN); |
| 1111 |
tar_dbgfld(NULL, NULL, 1); |
| 1112 |
} |
| 1113 |
|
| 1114 |
if (wr_rdbuf(hdblk, sizeof(HD_USTAR)) < 0) |
| 1115 |
return(-1); |
| 1116 |
if (wr_skip((off_t)(BLKMULT - sizeof(HD_USTAR))) < 0) |
| 1117 |
return(-1); |
| 1118 |
if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG)) |
| 1119 |
return(0); |
| 1120 |
return(1); |
| 1121 |
|
| 1122 |
out: |
| 1123 |
/* |
| 1124 |
* header field is out of range |
| 1125 |
*/ |
| 1126 |
paxwarn(1, "Ustar header field is too small for %s", arcn->org_name); |
| 1127 |
return(1); |
| 1128 |
} |
| 1129 |
|
| 1130 |
/* |
| 1131 |
* name_split() |
| 1132 |
* see if the name has to be split for storage in a ustar header. We try |
| 1133 |
* to fit the entire name in the name field without splitting if we can. |
| 1134 |
* The split point is always at a / |
| 1135 |
* Return |
| 1136 |
* character pointer to split point (always the / that is to be removed |
| 1137 |
* if the split is not needed, the points is set to the start of the file |
| 1138 |
* name (it would violate the spec to split there). A NULL is returned if |
| 1139 |
* the file name is too long |
| 1140 |
*/ |
| 1141 |
|
| 1142 |
static char * |
| 1143 |
name_split(char *name, int len) |
| 1144 |
{ |
| 1145 |
char *start; |
| 1146 |
|
| 1147 |
/* |
| 1148 |
* check to see if the file name is small enough to fit in the name |
| 1149 |
* field. if so just return a pointer to the name. |
| 1150 |
* The strings can fill the complete name and prefix fields |
| 1151 |
* without a NUL terminator. |
| 1152 |
*/ |
| 1153 |
if (len <= TNMSZ) |
| 1154 |
return(name); |
| 1155 |
if (len > (TPFSZ + TNMSZ + 1)) |
| 1156 |
return(NULL); |
| 1157 |
|
| 1158 |
/* |
| 1159 |
* we start looking at the biggest sized piece that fits in the name |
| 1160 |
* field. We walk forward looking for a slash to split at. The idea is |
| 1161 |
* to find the biggest piece to fit in the name field (or the smallest |
| 1162 |
* prefix we can find) (the -1 is correct the biggest piece would |
| 1163 |
* include the slash between the two parts that gets thrown away) |
| 1164 |
*/ |
| 1165 |
start = name + len - TNMSZ - 1; |
| 1166 |
while ((*start != '\0') && (*start != '/')) |
| 1167 |
++start; |
| 1168 |
|
| 1169 |
/* |
| 1170 |
* if we hit the end of the string, this name cannot be split, so we |
| 1171 |
* cannot store this file. |
| 1172 |
*/ |
| 1173 |
if (*start == '\0') |
| 1174 |
return(NULL); |
| 1175 |
len = start - name; |
| 1176 |
|
| 1177 |
/* |
| 1178 |
* NOTE: /str where the length of str == TNMSZ can not be stored under |
| 1179 |
* the p1003.1-1990 spec for ustar. We could force a prefix of / and |
| 1180 |
* the file would then expand on extract to //str. The len == 0 below |
| 1181 |
* makes this special case follow the spec to the letter. |
| 1182 |
*/ |
| 1183 |
if ((len > TPFSZ) || (len == 0)) |
| 1184 |
return(NULL); |
| 1185 |
|
| 1186 |
/* |
| 1187 |
* ok have a split point, return it to the caller |
| 1188 |
*/ |
| 1189 |
return(start); |
| 1190 |
} |
| 1191 |
|
| 1192 |
static size_t |
| 1193 |
expandname(char *buf, size_t len, char **gnu_name, const char *name, |
| 1194 |
size_t limit) |
| 1195 |
{ |
| 1196 |
size_t nlen; |
| 1197 |
|
| 1198 |
if (*gnu_name) { |
| 1199 |
/* *gnu_name is NUL terminated */ |
| 1200 |
if ((nlen = strlcpy(buf, *gnu_name, len)) >= len) |
| 1201 |
nlen = len - 1; |
| 1202 |
free(*gnu_name); |
| 1203 |
*gnu_name = NULL; |
| 1204 |
} else |
| 1205 |
nlen = fieldcpy(buf, len, name, limit); |
| 1206 |
return(nlen); |
| 1207 |
} |
| 1208 |
|
| 1209 |
static void |
| 1210 |
tar_dbgfld(const char *pfx, const char *sp, size_t len) |
| 1211 |
{ |
| 1212 |
static char fbuf[256]; |
| 1213 |
char tbuf[256], *s; |
| 1214 |
|
| 1215 |
if ((pfx == NULL) || (sp == NULL)) { |
| 1216 |
if ((pfx == NULL) && (sp == NULL)) { |
| 1217 |
if (len == 0) { |
| 1218 |
*fbuf = 0; |
| 1219 |
} else { |
| 1220 |
paxwarn(0, fbuf); |
| 1221 |
} |
| 1222 |
} else |
| 1223 |
paxwarn(0, "tar_dbgfld: wrong call"); |
| 1224 |
return; |
| 1225 |
} |
| 1226 |
|
| 1227 |
strlcat(fbuf, pfx, sizeof (fbuf)); |
| 1228 |
|
| 1229 |
if (len == 0) |
| 1230 |
return; |
| 1231 |
|
| 1232 |
if (len > (sizeof (tbuf) - 1)) |
| 1233 |
len = sizeof (tbuf) - 1; |
| 1234 |
|
| 1235 |
memmove(s = tbuf, sp, len); |
| 1236 |
tbuf[len] = 0; |
| 1237 |
while (*s == ' ') |
| 1238 |
++s; |
| 1239 |
while (s[strlen(s) - 1] == ' ') |
| 1240 |
s[strlen(s) - 1] = 0; |
| 1241 |
|
| 1242 |
strlcat(fbuf, tbuf, sizeof (fbuf)); |
| 1243 |
} |