/** * @file cpio.c CPIO module * * $Id: cpio.c,v 1.9 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 #include "cpio.h" typedef struct { long startPos; long lastPos; } CxCpioFileData; #define __makePadding(fp, modulo) \ { \ int padlen = ((modulo) - cxTell(fp) % (modulo)) % (modulo); \ char pad[padlen]; \ memset(pad, 0, padlen); \ cxWrite(pad, 1, padlen, (fp)); \ } static size_t __readFunc(void *ptr, size_t size, size_t nmemb, CxFP *fp) { CxCpioFileData *fileData; CxFile *file; CxFP *parentFp; size_t readSize, remainingSize, result; file = fp->file; fileData = (CxCpioFileData *)fp->moduleData; parentFp = (CxFP *)cxGetFileArchive(file)->moduleData; if (cxTell(parentFp) != fileData->lastPos) cxSeek(parentFp, fileData->lastPos, SEEK_SET); readSize = size * nmemb; remainingSize = cxGetFileCompressedSize(file) - (fileData->lastPos - fileData->startPos); if (readSize > remainingSize) readSize = remainingSize; result = cxRead(ptr, 1, readSize, parentFp); fileData->lastPos = cxTell(parentFp); return result; } static size_t __writeFunc(const void *ptr, size_t size, size_t nmemb, CxFP *fp) { return 0; } static void __seekFunc(CxFP *fp, long offset, int whence) { CxCpioFileData *fileData; CxFile *file; file = fp->file; fileData = (CxCpioFileData *)fp->moduleData; switch (whence) { case SEEK_SET: fileData->lastPos = fileData->startPos + offset; break; case SEEK_CUR: fileData->lastPos += offset; break; case SEEK_END: fileData->lastPos = fileData->startPos + cxGetFileCompressedSize(fp->file) - offset; break; } } static void __closeFunc(CxFP *fp) { if (fp->moduleData != NULL) { free(fp->moduleData); fp->moduleData = NULL; } } static CxStatus readArchive(CxArchive *archive, CxFP *fp) { CxStatus status; CxDirectory *root; char foundBlock = 0; root = cxGetArchiveRoot(archive); while ((status = cxCpioReadHeader(fp, archive)) == CX_SUCCESS) foundBlock = 1; if (status != CX_EOF) { /* TODO: Free up memory. */ if (status == CX_INVALID_FORMAT && foundBlock == 1) return CX_CORRUPT; return status; } else if (foundBlock == 0) { return CX_EOF; } cxSetArchiveType(archive, CX_ARCHIVE_MULTI); archive->moduleData = fp; return CX_SUCCESS; } static CxStatus saveArchive(CxArchive *archive, CxFP *fp) { CxFsIterator *iter; CxFile *file; CxFP *inFp; char header[112]; char buffer[BUFSIZ]; size_t s; iter = cxNewFsIterator(archive, CX_FSITER_FILES); for (file = cxGetFsIterFirst(iter); file != NULL; file = cxGetFsIterNext(iter)) { const char *filename; int nameSize; if (cxGetFilePhysicalPath(file) == NULL || cxGetFilePath(file) == NULL) { continue; } /* Open the file. */ inFp = cxOpenFile(cxGetFilePhysicalPath(file), CX_MODE_READ_ONLY | CX_MODE_RAW); if (inFp == NULL) continue; filename = cxGetFilePath(file); nameSize = strlen(filename); /* Write the file header. */ snprintf(header, 111, "%6s%08lx%08lx%08lx%08lx%08lx%08lx" "%08lx%08lx%08lx%08lx%08lx%08lx%08lx", CPIO_MAGICS_ASCII, 0L, (unsigned long)cxGetFileMode(file), (unsigned long)cxGetFileUid(file), (unsigned long)cxGetFileGid(file), 1L, /* XXX */ (unsigned long)cxGetFileDate(file), (unsigned long)cxGetFileSize(file), 0L, 0L, 0L, 0L, (unsigned long)nameSize + 1, 0L); cxWrite(header, 1, 110, fp); /* Write the filename. */ cxWrite(filename, 1, nameSize, fp); /* Add the padding. */ __makePadding(fp, 4); /* Write the file. */ while ((s = cxRead(buffer, 1, BUFSIZ, inFp)) > 0) cxWrite(buffer, 1, s, fp); cxClose(inFp); __makePadding(fp, 2); } /* Write the trailer. */ snprintf(header, 111, "%6s%08lx%08lx%08lx%08lx%08lx%08lx" "%08lx%08lx%08lx%08lx%08lx%08lx%08lx", CPIO_MAGICS_ASCII, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, (unsigned long)strlen(CPIO_TRAILER) + 1, 0L); cxWrite(header, 1, 110, fp); cxWrite(CPIO_TRAILER, 1, strlen(CPIO_TRAILER), fp); /* Pad the file to a multiple of 512 bytes */ __makePadding(fp, 512); cxDestroyFsIterator(iter); return CX_SUCCESS; } static void closeArchive(CxArchive *archive) { archive->moduleData = NULL; } static CxFP * openFile(CxFile *file, CxAccessMode mode) { CxCpioFileData *fileData; CxArchive *archive; CxFP *fp; if (!CX_IS_MODE_READ_ONLY(mode)) return NULL; archive = cxGetFileArchive(file); fp = cxNewFp(); cxSetReadFunc(fp, __readFunc); cxSetWriteFunc(fp, __writeFunc); cxSetSeekFunc(fp, __seekFunc); cxSetCloseFunc(fp, __closeFunc); MEM_CHECK(fileData = (CxCpioFileData *)malloc(sizeof(CxCpioFileData))); fileData->startPos = (long)file->moduleData; fileData->lastPos = fileData->startPos; fp->moduleData = fileData; cxSeek((CxFP *)archive->moduleData, fileData->startPos, SEEK_SET); return fp; } static void destroyFile(CxFile *file) { file->moduleData = NULL; } static char supportsExtension(const char *ext) { if (!strcasecmp(ext, "cpio")) return 1; return 0; } static CxArchiveOps ops = { readArchive, /* openArchive */ saveArchive, /* saveArchive */ closeArchive, /* closeArchive */ openFile, /* openFile */ destroyFile, /* destroyFile */ supportsExtension /* supportsExtension */ }; static void __moduleInit(CxModuleType type) { } CX_INIT_ARCHIVE_MODULE(cpio, __moduleInit, ops)