/* FIXME: * 1. Symbolic links are not created. * 2. Untar_FromMemory has printfs. * 3. Untar_FromMemory uses FILE *fp. * 4. How to determine end of archive? * * Written by: Jake Janovetz * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at * http://www.rtems.com/license/LICENSE. * * $Id$ */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include /************************************************************************** * TAR file format: * * Offset Length Contents * 0 100 bytes File name ('\0' terminated, 99 maxmum length) * 100 8 bytes File mode (in octal ascii) * 108 8 bytes User ID (in octal ascii) * 116 8 bytes Group ID (in octal ascii) * 124 12 bytes File size (s) (in octal ascii) * 136 12 bytes Modify time (in octal ascii) * 148 8 bytes Header checksum (in octal ascii) * 156 1 bytes Link flag * 157 100 bytes Linkname ('\0' terminated, 99 maxmum length) * 257 8 bytes Magic ("ustar \0") * 265 32 bytes User name ('\0' terminated, 31 maxmum length) * 297 32 bytes Group name ('\0' terminated, 31 maxmum length) * 329 8 bytes Major device ID (in octal ascii) * 337 8 bytes Minor device ID (in octal ascii) * 345 155 bytes Prefix * 512 (s+p)bytes File contents (s+p) := (((s) + 511) & ~511), * round up to 512 bytes * * Checksum: * int i, sum; * char* header = tar_header_pointer; * sum = 0; * for(i = 0; i < 512; i++) * sum += 0xFF & header[i]; *************************************************************************/ #define MAX_NAME_FIELD_SIZE 99 #define MIN(a,b) ((a)>(b)?(b):(a)) /************************************************************************** * This converts octal ASCII number representations into an * unsigned long. Only support 32-bit numbers for now. *************************************************************************/ unsigned long _rtems_octal2ulong(const char *octascii, size_t len) { size_t i; unsigned long num; unsigned long mult; num = 0; mult = 1; for (i=len-1; i>=0; i--) { if ((octascii[i] < '0') || (octascii[i] > '9')) { continue; } num += mult*((unsigned long)(octascii[i] - '0')); mult *= 8; } return(num); } /************************************************************************** * Function: Untar_FromMemory * ************************************************************************** * Description: * * * * This is a simple subroutine used to rip links, directories, and * * files out of a block of memory. * * * * * * Inputs: * * * * char *tar_buf - Pointer to TAR buffer. * * size_t size - Length of TAR buffer. * * * * * * Output: * * * * int - UNTAR_SUCCESSFUL (0) on successful completion. * * UNTAR_INVALID_CHECKSUM for an invalid header checksum. * * UNTAR_INVALID_HEADER for an invalid header. * * * ************************************************************************** * Change History: * * 12/30/1998 - Creation (JWJ) * *************************************************************************/ int Untar_FromMemory(char *tar_buf, size_t size) { FILE *fp; char *bufr; size_t n; char fname[100]; char linkname[100]; int sum; int hdr_chksum; int retval; unsigned long ptr; unsigned long i; unsigned long nblocks; unsigned long file_size; unsigned char linkflag; ptr = 0; while (1) { if (ptr + 512 > size) { retval = UNTAR_SUCCESSFUL; break; } /* Read the header */ bufr = &tar_buf[ptr]; ptr += 512; if (strncmp(&bufr[257], "ustar ", 7)) { retval = UNTAR_SUCCESSFUL; break; } strncpy(fname, bufr, MAX_NAME_FIELD_SIZE); fname[MAX_NAME_FIELD_SIZE] = '\0'; linkflag = bufr[156]; file_size = _rtems_octal2ulong(&bufr[124], 12); /****************************************************************** * Compute the TAR checksum and check with the value in * the archive. The checksum is computed over the entire * header, but the checksum field is substituted with blanks. ******************************************************************/ hdr_chksum = _rtems_octal2ulong(&bufr[148], 8); sum = _rtems_tar_header_checksum(bufr); if (sum != hdr_chksum) { retval = UNTAR_INVALID_CHECKSUM; break; } /****************************************************************** * We've decoded the header, now figure out what it contains and * do something with it. *****************************************************************/ if (linkflag == SYMTYPE) { strncpy(linkname, &bufr[157], MAX_NAME_FIELD_SIZE); linkname[MAX_NAME_FIELD_SIZE] = '\0'; symlink(linkname, fname); } else if (linkflag == REGTYPE) { nblocks = (((file_size) + 511) & ~511) / 512; if ((fp = fopen(fname, "w")) == NULL) { fprintf(stdout,"Untar failed to create file %s\n", fname); ptr += 512 * nblocks; } else { unsigned long sizeToGo = file_size; size_t len; /*************************************************************** * Read out the data. There are nblocks of data where nblocks * is the file_size rounded to the nearest 512-byte boundary. **************************************************************/ for (i=0; i= 148) && (i < 156)) sum += 0xff & ' '; else sum += 0xff & bufr[i]; } return(sum); }