| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384 |
- /*
- ** Copyright 1998-2003 University of Illinois Board of Trustees
- ** Copyright 1998-2003 Mark D. Roth
- ** All rights reserved.
- **
- ** block.c - libtar code to handle tar archive header blocks
- **
- ** Mark D. Roth <[email protected]>
- ** Campus Information Technologies and Educational Services
- ** University of Illinois at Urbana-Champaign
- */
- #include <libtarint/internal.h>
- #include <errno.h>
- #ifdef STDC_HEADERS
- # include <string.h>
- # include <stdlib.h>
- #endif
- #define BIT_ISSET(bitmask, bit) ((bitmask) & (bit))
- /* read a header block */
- int
- th_read_internal(TAR *t)
- {
- int i;
- int num_zero_blocks = 0;
- #ifdef DEBUG
- printf("==> th_read_internal(TAR=\"%s\")\n", t->pathname);
- #endif
- while ((i = tar_block_read(t, &(t->th_buf))) == T_BLOCKSIZE)
- {
- /* two all-zero blocks mark EOF */
- if (t->th_buf.name[0] == '\0')
- {
- num_zero_blocks++;
- if (!BIT_ISSET(t->options, TAR_IGNORE_EOT)
- && num_zero_blocks >= 2)
- return 0; /* EOF */
- else
- continue;
- }
- /* verify magic and version */
- if (BIT_ISSET(t->options, TAR_CHECK_MAGIC)
- && strncmp(t->th_buf.magic, TMAGIC, TMAGLEN - 1) != 0)
- {
- #ifdef DEBUG
- puts("!!! unknown magic value in tar header");
- #endif
- return -2;
- }
- if (BIT_ISSET(t->options, TAR_CHECK_VERSION)
- && strncmp(t->th_buf.version, TVERSION, TVERSLEN) != 0)
- {
- #ifdef DEBUG
- puts("!!! unknown version value in tar header");
- #endif
- return -2;
- }
- /* check chksum */
- if (!BIT_ISSET(t->options, TAR_IGNORE_CRC)
- && !th_crc_ok(t))
- {
- #ifdef DEBUG
- puts("!!! tar header checksum error");
- #endif
- return -2;
- }
- break;
- }
- #ifdef DEBUG
- printf("<== th_read_internal(): returning %d\n", i);
- #endif
- return i;
- }
- /* wrapper function for th_read_internal() to handle GNU extensions */
- int
- th_read(TAR *t)
- {
- int i, j;
- size_t sz;
- char *ptr;
- #ifdef DEBUG
- printf("==> th_read(t=0x%lx)\n", t);
- #endif
- if (t->th_buf.gnu_longname != NULL)
- free(t->th_buf.gnu_longname);
- if (t->th_buf.gnu_longlink != NULL)
- free(t->th_buf.gnu_longlink);
- memset(&(t->th_buf), 0, sizeof(struct tar_header));
- i = th_read_internal(t);
- if (i == 0)
- return 1;
- else if (i != T_BLOCKSIZE)
- {
- if (i != -1)
- errno = EINVAL;
- return -1;
- }
- /* check for GNU long link extention */
- if (TH_ISLONGLINK(t))
- {
- sz = th_get_size(t);
- j = (sz / T_BLOCKSIZE) + (sz % T_BLOCKSIZE ? 1 : 0);
- #ifdef DEBUG
- printf(" th_read(): GNU long linkname detected "
- "(%ld bytes, %d blocks)\n", sz, j);
- #endif
- t->th_buf.gnu_longlink = (char *)malloc(j * T_BLOCKSIZE);
- if (t->th_buf.gnu_longlink == NULL)
- return -1;
- for (ptr = t->th_buf.gnu_longlink; j > 0;
- j--, ptr += T_BLOCKSIZE)
- {
- #ifdef DEBUG
- printf(" th_read(): reading long linkname "
- "(%d blocks left, ptr == %ld)\n", j, ptr);
- #endif
- i = tar_block_read(t, ptr);
- if (i != T_BLOCKSIZE)
- {
- if (i != -1)
- errno = EINVAL;
- return -1;
- }
- #ifdef DEBUG
- printf(" th_read(): read block == \"%s\"\n", ptr);
- #endif
- }
- #ifdef DEBUG
- printf(" th_read(): t->th_buf.gnu_longlink == \"%s\"\n",
- t->th_buf.gnu_longlink);
- #endif
- i = th_read_internal(t);
- if (i != T_BLOCKSIZE)
- {
- if (i != -1)
- errno = EINVAL;
- return -1;
- }
- }
- /* check for GNU long name extention */
- if (TH_ISLONGNAME(t))
- {
- sz = th_get_size(t);
- j = (sz / T_BLOCKSIZE) + (sz % T_BLOCKSIZE ? 1 : 0);
- #ifdef DEBUG
- printf(" th_read(): GNU long filename detected "
- "(%ld bytes, %d blocks)\n", sz, j);
- #endif
- t->th_buf.gnu_longname = (char *)malloc(j * T_BLOCKSIZE);
- if (t->th_buf.gnu_longname == NULL)
- return -1;
- for (ptr = t->th_buf.gnu_longname; j > 0;
- j--, ptr += T_BLOCKSIZE)
- {
- #ifdef DEBUG
- printf(" th_read(): reading long filename "
- "(%d blocks left, ptr == %ld)\n", j, ptr);
- #endif
- i = tar_block_read(t, ptr);
- if (i != T_BLOCKSIZE)
- {
- if (i != -1)
- errno = EINVAL;
- return -1;
- }
- #ifdef DEBUG
- printf(" th_read(): read block == \"%s\"\n", ptr);
- #endif
- }
- #ifdef DEBUG
- printf(" th_read(): t->th_buf.gnu_longname == \"%s\"\n",
- t->th_buf.gnu_longname);
- #endif
- i = th_read_internal(t);
- if (i != T_BLOCKSIZE)
- {
- if (i != -1)
- errno = EINVAL;
- return -1;
- }
- }
- #if 0
- /*
- ** work-around for old archive files with broken typeflag fields
- ** NOTE: I fixed this in the TH_IS*() macros instead
- */
- /*
- ** (directories are signified with a trailing '/')
- */
- if (t->th_buf.typeflag == AREGTYPE
- && t->th_buf.name[strlen(t->th_buf.name) - 1] == '/')
- t->th_buf.typeflag = DIRTYPE;
- /*
- ** fallback to using mode bits
- */
- if (t->th_buf.typeflag == AREGTYPE)
- {
- mode = (mode_t)oct_to_int(t->th_buf.mode);
- if (S_ISREG(mode))
- t->th_buf.typeflag = REGTYPE;
- else if (S_ISDIR(mode))
- t->th_buf.typeflag = DIRTYPE;
- else if (S_ISFIFO(mode))
- t->th_buf.typeflag = FIFOTYPE;
- else if (S_ISCHR(mode))
- t->th_buf.typeflag = CHRTYPE;
- else if (S_ISBLK(mode))
- t->th_buf.typeflag = BLKTYPE;
- else if (S_ISLNK(mode))
- t->th_buf.typeflag = SYMTYPE;
- }
- #endif
- return 0;
- }
- /* write a header block */
- int
- th_write(TAR *t)
- {
- int i, j;
- char type2;
- size_t sz, sz2;
- char *ptr;
- char buf[T_BLOCKSIZE];
- #ifdef DEBUG
- printf("==> th_write(TAR=\"%s\")\n", t->pathname);
- th_print(t);
- #endif
- if ((t->options & TAR_GNU) && t->th_buf.gnu_longlink != NULL)
- {
- #ifdef DEBUG
- printf("th_write(): using gnu_longlink (\"%s\")\n",
- t->th_buf.gnu_longlink);
- #endif
- /* save old size and type */
- type2 = t->th_buf.typeflag;
- sz2 = th_get_size(t);
- /* write out initial header block with fake size and type */
- t->th_buf.typeflag = GNU_LONGLINK_TYPE;
- sz = strlen(t->th_buf.gnu_longlink);
- th_set_size(t, sz);
- th_finish(t);
- i = tar_block_write(t, &(t->th_buf));
- if (i != T_BLOCKSIZE)
- {
- if (i != -1)
- errno = EINVAL;
- return -1;
- }
- /* write out extra blocks containing long name */
- for (j = (sz / T_BLOCKSIZE) + (sz % T_BLOCKSIZE ? 1 : 0),
- ptr = t->th_buf.gnu_longlink; j > 1;
- j--, ptr += T_BLOCKSIZE)
- {
- i = tar_block_write(t, ptr);
- if (i != T_BLOCKSIZE)
- {
- if (i != -1)
- errno = EINVAL;
- return -1;
- }
- }
- memset(buf, 0, T_BLOCKSIZE);
- strncpy(buf, ptr, T_BLOCKSIZE);
- i = tar_block_write(t, &buf);
- if (i != T_BLOCKSIZE)
- {
- if (i != -1)
- errno = EINVAL;
- return -1;
- }
- /* reset type and size to original values */
- t->th_buf.typeflag = type2;
- th_set_size(t, sz2);
- }
- if ((t->options & TAR_GNU) && t->th_buf.gnu_longname != NULL)
- {
- #ifdef DEBUG
- printf("th_write(): using gnu_longname (\"%s\")\n",
- t->th_buf.gnu_longname);
- #endif
- /* save old size and type */
- type2 = t->th_buf.typeflag;
- sz2 = th_get_size(t);
- /* write out initial header block with fake size and type */
- t->th_buf.typeflag = GNU_LONGNAME_TYPE;
- sz = strlen(t->th_buf.gnu_longname);
- th_set_size(t, sz);
- th_finish(t);
- i = tar_block_write(t, &(t->th_buf));
- if (i != T_BLOCKSIZE)
- {
- if (i != -1)
- errno = EINVAL;
- return -1;
- }
- /* write out extra blocks containing long name */
- for (j = (sz / T_BLOCKSIZE) + (sz % T_BLOCKSIZE ? 1 : 0),
- ptr = t->th_buf.gnu_longname; j > 1;
- j--, ptr += T_BLOCKSIZE)
- {
- i = tar_block_write(t, ptr);
- if (i != T_BLOCKSIZE)
- {
- if (i != -1)
- errno = EINVAL;
- return -1;
- }
- }
- memset(buf, 0, T_BLOCKSIZE);
- strncpy(buf, ptr, T_BLOCKSIZE);
- i = tar_block_write(t, &buf);
- if (i != T_BLOCKSIZE)
- {
- if (i != -1)
- errno = EINVAL;
- return -1;
- }
- /* reset type and size to original values */
- t->th_buf.typeflag = type2;
- th_set_size(t, sz2);
- }
- th_finish(t);
- #ifdef DEBUG
- /* print tar header */
- th_print(t);
- #endif
- i = tar_block_write(t, &(t->th_buf));
- if (i != T_BLOCKSIZE)
- {
- if (i != -1)
- errno = EINVAL;
- return -1;
- }
- #ifdef DEBUG
- puts("th_write(): returning 0");
- #endif
- return 0;
- }
|