/** * @file block.c Tar block functions * * $Id: block.c,v 1.8 2003/01/01 06:22:32 chipx86 Exp $ * * @Copyright (C) 1999-2003 The GNUpdate Project. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include "tar.h" #define __readBlock(fp, block) \ cxRead((block)->buffer, 1, TAR_BLOCK_SIZE, (fp)) #define __writeBlock(fp, block) \ cxWrite((block)->buffer, 1, TAR_BLOCK_SIZE, (fp)) #define __getCrc(block) (cxTarOctalToInt((block)->header.checksum)) #define __checkCrc(block) (__getCrc(block) == __calcCrc(block)) static int __calcCrc(TarBlock *block) { int i, sum = 0; for (i = 0; i < 512; i++) sum += block->buffer[i]; for (i = 0; i < 8; i++) sum += (' ' - block->header.checksum[i]); return sum; } static int __readInternal(CxFP *fp, TarBlock *block) { int i = 0; int zeroBlockCount = 0; while ((i = __readBlock(fp, block)) == TAR_BLOCK_SIZE) { /* Two all-zero blocks mark EOF */ if (block->header.name[0] == '\0') { zeroBlockCount++; if (zeroBlockCount == 2) return 0; else continue; } /* Verify magic and version */ if (!strncmp(block->header.magic, TAR_MAGIC, TAR_MAGIC_LEN - 1)) { /* Ustar */ #if 0 if (strncmp(block->header.version, "00", 2)) { /* Unknown version. */ return -3; } #endif } else if (memcmp(block->header.magic, "\0\0\0\0\0\0\0\0", 8)) { return -2; } if (!__checkCrc(block)) { /* Checksum error. */ return -4; } break; } return i; } CxStatus cxTarReadBlock(CxFP *fp, TarBlock *block) { int i, j; size_t size; char *ptr; memset(block->buffer, 0, TAR_BLOCK_SIZE); block->header.gnu_longname = NULL; block->header.gnu_longlink = NULL; i = __readInternal(fp, block); if (i != TAR_BLOCK_SIZE) { if (i == 0) return CX_EOF; else if (i == -2) return CX_INVALID_FORMAT; else if (i == -3) return CX_INVALID_VERSION; else if (i == -4) return CX_CORRUPT; errno = EINVAL; return CX_ERROR; /* XXX */ } if (block->header.typeFlag == GNU_LONGLINK) { size = cxTarOctalToInt(block->header.size); j = (size / TAR_BLOCK_SIZE) + ((size % TAR_BLOCK_SIZE) ? 1 : 0); MEM_CHECK(block->header.gnu_longlink = (char *)malloc(j * TAR_BLOCK_SIZE)); for (ptr = block->header.gnu_longlink; j > 0; j--, ptr += TAR_BLOCK_SIZE) { i = __readBlock(fp, block); if (i != TAR_BLOCK_SIZE) { if (i != -1) errno = EINVAL; return CX_ERROR; } } i = __readInternal(fp, block); if (i != TAR_BLOCK_SIZE) { if (i != -1) errno = EINVAL; return CX_ERROR; } } if (block->header.typeFlag == GNU_LONGNAME) { size = cxTarOctalToInt(block->header.size); j = (size / TAR_BLOCK_SIZE) + ((size % TAR_BLOCK_SIZE) ? 1 : 0); MEM_CHECK(block->header.gnu_longname = (char *)malloc(j * TAR_BLOCK_SIZE)); for (ptr = block->header.gnu_longname; j > 0; j--, ptr += TAR_BLOCK_SIZE) { i = __readBlock(fp, block); if (i != TAR_BLOCK_SIZE) { if (i != -1) errno = EINVAL; return CX_CORRUPT; } } i = __readInternal(fp, block); if (i != TAR_BLOCK_SIZE) { if (i != -1) errno = EINVAL; return CX_CORRUPT; } } return CX_SUCCESS; }