/* 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.OARcorp.com/rtems/license.html. * * $Id$ */ #include #include #include #include #include #include #include "untar.h" /************************************************************************** * 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 167 bytes Padding * 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 LF_OLDNORMAL '\0' /* Normal disk file, Unix compatible */ #define LF_NORMAL '0' /* Normal disk file */ #define LF_LINK '1' /* Link to previously dumped file */ #define LF_SYMLINK '2' /* Symbolic link */ #define LF_CHR '3' /* Character special file */ #define LF_BLK '4' /* Block special file */ #define LF_DIR '5' /* Directory */ #define LF_FIFO '6' /* FIFO special file */ #define LF_CONFIG '7' /* Contiguous file */ #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. *************************************************************************/ static unsigned long octal2ulong(char *octascii, int len) { int 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: * * * * unsigned char *tar_buf - Pointer to TAR buffer. * * unsigned long 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(unsigned char *tar_buf, unsigned long 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 = 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 = (int)octal2ulong(&bufr[148], 8); sum = 0; for (i=0; i<512; i++) { if ((i >= 148) && (i < 156)) { sum += 0xff & ' '; } else { sum += 0xff & bufr[i]; } } 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 == LF_SYMLINK) { strncpy(linkname, &bufr[157], MAX_NAME_FIELD_SIZE); linkname[MAX_NAME_FIELD_SIZE] = '\0'; /* symlink(fname, linkname); */ } else if (linkflag == LF_NORMAL) { nblocks = (((file_size) + 511) & ~511) / 512; if ((fp = fopen(fname, "w")) == NULL) { printf("Untar failed to create file %s\n", fname); ptr += 512 * nblocks; } else { unsigned long sizeToGo = file_size; unsigned long 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]; } } 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 == LF_SYMLINK) { strncpy(linkname, &bufr[157], MAX_NAME_FIELD_SIZE); linkname[MAX_NAME_FIELD_SIZE] = '\0'; } else if (linkflag == LF_NORMAL) { int out_fd; /****************************************************************** * Read out the data. There are nblocks of data where nblocks * is the size rounded to the nearest 512-byte boundary. *****************************************************************/ nblocks = (((size) + 511) & ~511) / 512; if ((out_fd = creat(fname, 0644)) == -1) { for (i=0; i