From: Stefan E. <se...@us...> - 2002-04-26 18:24:59
|
Update of /cvsroot/blob/blob/src/lib In directory usw-pr-cvs1:/tmp/cvs-serv26183 Added Files: tar.c Log Message: - first revision of minimal tar archive support. - this module will be used to get a blob/ramdisk/kernel update mechanism from e.g. CF cards using raw tar archives. For ex. do a "tar -c --posix -f /def/hda zImage blob initrd.gz cramfs.img" with /dev/hda a mounted CF card, ship the CF card to your customer and off you go. - Missing so far: * only posix tar format * no zlib support (do we need this?) * only "t" and "x" are supported, i.e. no creation of tar archives so far. - This is WIP .... --- NEW FILE: tar.c --- /********************************************************************** * tar archive framework * * Copyright (C) 2002, Stefan Eletzhofer <ste...@el...> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: tar.c,v 1.1 2002/04/26 18:24:54 seletz Exp $ * * $Log: tar.c,v $ * Revision 1.1 2002/04/26 18:24:54 seletz * - first revision of minimal tar archive support. * - this module will be used to get a blob/ramdisk/kernel * update mechanism from e.g. CF cards using raw tar archives. * For ex. do a "tar -c --posix -f /def/hda zImage blob initrd.gz cramfs.img" * with /dev/hda a mounted CF card, ship the CF card to your customer * and off you go. * - Missing so far: * * only posix tar format * * no zlib support (do we need this?) * * only "t" and "x" are supported, i.e. no creation of tar * archives so far. * - This is WIP .... * * Revision 1.2 2002/04/24 14:27:08 seletz * - first round of bugfixing. Now at last one can read 512 byte sectors * of a CF in true-ide mode. See system3.c::pcmciatest(). * * Still WIP. YMMV, and so on.... * * Revision 1.1 2002/04/18 19:52:49 seletz * - Added PCMCIA and IDE framework. Based on Brad Parker's code. * NOTE NOTE NOTE: * This is all Work-In-Progress (you have been warned) * */ /********************************************************************** * Includes */ #ifdef HAVE_CONFIG_H # include <blob/config.h> #endif #include <blob/types.h> #include <blob/errno.h> #include <blob/util.h> #include <blob/command.h> #include <blob/tar.h> /********************************************************************** * defines */ #define TAR_DEBUG 0 #if TAR_DEBUG # define DBG( x, args... ) if ( tar_dbg>x ) printf( args ); #else # define DBG( x, args... ) #endif /********************************************************************** * module globals */ #if TAR_DEBUG static int tar_dbg = 1; #else static int tar_dbg = 0; #endif static char module_version[] = "$Id: tar.c,v 1.1 2002/04/26 18:24:54 seletz Exp $"; /********************************************************************** * static functions */ static int tar_skip_file( tar_arch_t *arch ); static int tar_file_search( tar_arch_t *arch, char *file ); static int tar_xtract_blocks( tar_arch_t *arch, char *dest ); static int tar_fileinfo_get( tar_arch_t *arch ); static int tar_hdr_chk( tar_hdr_posix_t *hdr ); static int tar_hdr_fname_get( tar_hdr_posix_t *hdr, char **fname ); static int tar_hdr_fsize_get( tar_hdr_posix_t *hdr, unsigned long *size ); static int tar_from_oct( unsigned char *start, size_t digits, unsigned long *value ); /**********************************************************************/ /**********************************************************************/ /**********************************************************************/ /* simple memory block getter */ int mem_block_get( unsigned char *buffer, void *priv ) { struct mem *mp= (struct mem *)priv; DBG( 15, "%s: priv=%p\n", __FUNCTION__, priv ); if ( !mp ) return -EINVAL; if ( !mp->curr ) mp->curr=mp->start; DBG( 15, "%s: start=%p, curr=%p\n", __FUNCTION__, mp->start, mp->curr ); memcpy( buffer, mp->curr, 512 ); mp->curr += 512; return 0; } /* memory block reset */ int mem_block_reset( void *priv ) { struct mem *mp= (struct mem *)priv; DBG( 15, "%s: priv=%p\n", __FUNCTION__, priv ); if ( !mp ) return -EINVAL; DBG( 15, "%s: start=%p, curr=%p\n", __FUNCTION__, mp->start, mp->curr ); mp->curr=mp->start; return 0; } /* set debug level */ void tar_dbg_set( int lvl ) { tar_dbg = lvl; } /* init archive struct */ int tar_init( tar_arch_t *arch, block_get_fn get, block_reset_fn reset, void *priv ) { DBG( 1, "%s: arch=%p, get=%p, reset=%p, priv=%p\n", __FUNCTION__, arch, get, reset, priv ); DBG( 1, "tar: version %s\n", module_version ); if ( !arch ) { return -EINVAL; } arch->block_get = get; arch->block_reset=reset; arch->block_get_priv = priv; arch->size=0l; arch->blocks=0l; arch->filename[0]=0; return 0; } /* do a "tar tv" */ int tar_tell( tar_arch_t *arch ) { int ret = 0; int fini = 0; int files = 0; DBG( 1, "%s: arch=%p\n", __FUNCTION__, arch ); if ( !arch ) return -EINVAL; /* reset to block 0 */ ret = arch->block_reset( arch->block_get_priv ); if ( ret ) { printf( "tar: cant reset to block 0: %d\n", ret ); return ret; } while ( !fini ) { ret = tar_fileinfo_get( arch ); if ( ret ) { fini = 1; continue; } files++; printf( "%s %ld bytes, %d blocks\n", arch->filename, arch->size, arch->blocks ); /* skip file */ ret = tar_skip_file( arch ); if ( ret ) { printf( "tar: tar_skip_file: %d\n", ret ); return -EINVAL; } } printf( "tar: %d files.\n", files ); return 0; } /* do a "tar xv" */ int tar_xtract( tar_arch_t *arch, char *filename, char *dest ) { int ret = 0; DBG( 1, "%s: arch=%p, filename=%p, dest=%p\n", __FUNCTION__, arch, filename, dest ); if ( !arch || !filename ) return -EINVAL; /* reset to block 0 */ ret = arch->block_reset( arch->block_get_priv ); if ( ret ) { printf( "tar: cant reset to block 0: %d\n", ret ); return ret; } ret = tar_file_search( arch, filename ); if ( ret ) { printf( "tar: cant find file '%s' in archive (%d).\n", filename, ret ); return -EINVAL; } ret = tar_xtract_blocks( arch, dest ); if ( ret ) { printf( "tar: cant extract file '%s' from archive (%d).\n", filename, ret ); return -EINVAL; } printf( "tar: extracted file '%s', %ld bytes (%d blocks).\n", arch->filename, arch->size, arch->blocks ); return 0; } /********************************************************************** * Static functions */ static int tar_file_search( tar_arch_t *arch, char *file ) { int ret = 0; int fini = 0; int found = 0; DBG( 1, "%s: arch=%p, file=%p\n", __FUNCTION__, arch, file ); if ( !arch || !file ) return -EINVAL; while ( !fini ) { ret = tar_fileinfo_get( arch ); if ( ret ) { fini = 1; continue; } DBG( 5, "%s %ld bytes, %d blocks\n", arch->filename, arch->size, arch->blocks ); if ( strncmp( arch->filename, file, 255 ) == 0 ) { found = 1; fini = 1; continue; } /* skip file */ ret = tar_skip_file( arch ); if ( ret ) { printf( "tar: tar_skip_file: %d\n", ret ); return -EINVAL; } } return found?0:1; } /* skip to next file, if any */ static int tar_skip_file( tar_arch_t *arch ) { int ret = 0; int block; DBG( 1, "%s: arch=%p\n", __FUNCTION__, arch ); if ( !arch ) return -EINVAL; /* skip data */ for ( block=0; block<arch->blocks; block++ ) { ret = arch->block_get( arch->buffer, arch->block_get_priv ); if ( ret ) { printf( "tar: cant get block %d: %d\n", block, ret ); return ret; } } return 0; } /* extract current file to memory. */ static int tar_xtract_blocks( tar_arch_t *arch, char *dest ) { int ret = 0; int block; unsigned long size; DBG( 1, "%s: arch=%p, dest=%p\n", __FUNCTION__, arch, dest ); if ( !arch || !dest ) return -EINVAL; size = arch->size; if ( !size ) return -EINVAL; /* extract data */ for ( block=0; block<arch->blocks; block++ ) { ret = arch->block_get( arch->buffer, arch->block_get_priv ); if ( ret ) { printf( "tar: cant get block %d: %d\n", block, ret ); return ret; } DBG( 5, "%s: %ld bytes to go\n", __FUNCTION__, size ); if ( size>512 ) { memcpy( dest, arch->buffer, 512 ); size -= 512; dest += 512; } else { memcpy( dest, arch->buffer, size ); dest += size; } } return 0; } /* get current file infos out of tar header */ static int tar_fileinfo_get( tar_arch_t *arch ) { int ret = 0; tar_hdr_posix_t *phdr = NULL; if ( !arch ) return -EINVAL; /* get header */ ret = arch->block_get( arch->buffer, arch->block_get_priv ); if ( ret ) { printf( "tar: cant get block: %d\n", ret ); goto DONE; } /* and decode infos */ phdr = (tar_hdr_posix_t*)arch->buffer; ret = tar_hdr_chk( phdr ); if ( ret ) { printf( "tar: no posix tar header: %d\n", ret ); ret = -EINVAL; goto DONE; } ret = tar_hdr_fsize_get( phdr, &arch->size ); if ( ret ) { printf( "tar: cant decode file size: %d\n", ret ); ret = ret; goto DONE; } arch->blocks = (arch->size/512) + (arch->size%512?1:0); printf( "tar: %s %ld bytes, %d blocks\n", phdr->name, arch->size, arch->blocks ); strncpy( arch->filename, phdr->name, 100 ); arch->filename[100] = 0; ret = 0; DONE: /* reset fileinfos on error */ if ( ret ) { arch->size=0; arch->blocks=0; arch->filename[0]=0; } return ret; } /* check wether or not we have a posix tar header */ static int tar_hdr_chk( tar_hdr_posix_t *hdr ) { int ret = 0; if ( !hdr ) return -EINVAL; /* check magic */ ret = strncmp( hdr->magic, TMAGIC, TMAGLEN ); if ( ret != 0 ) return -EINVAL; return 0; } /* get file size from header */ static int tar_hdr_fsize_get( tar_hdr_posix_t *hdr, unsigned long *size ) { return tar_from_oct( hdr->size, 11, size ); } /* get filename from header */ static int tar_hdr_fname_get( tar_hdr_posix_t *hdr, char **fname ) { if ( !hdr || !fname ) return -EINVAL; *fname = hdr->name; return 0; } /* decode octal BCD data from header */ static int tar_from_oct( unsigned char *start, size_t digits, unsigned long *value ) { unsigned long val = 0l; DBG( 5, "%s: start=%p, digits=%d, value=%p\n", __FUNCTION__, start, digits, value ); if ( !start || !value ) return -EINVAL; while ( digits ) { if ( (*start > '7') || (*start < '0') ) return -EINVAL; DBG( 5, "%s: %c, val=%ld\n", __FUNCTION__, *start, val ); val = ( val << 3 ) | (*start - '0'); --digits; ++start; } *value = val; return 0; } |