/*---------------------------------------------------------------------------* Project: archiver extractor for Revolution dvd File: extract.c Copyright (C) 2001-2006 Nintendo. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Log: extract.c,v $ Revision 1.1 2006/04/20 01:41:22 hiratsu Initial check-in. 1 7/02/01 11:34p Hashida Initial revision. $NoKeywords: $ *---------------------------------------------------------------------------*/ #include "darch.h" struct DirInfo_t { struct DirInfo_t* child; struct DirInfo_t* parent; char fullPath[FILENAME_MAX]; int nextEntry; }; typedef struct DirInfo_t DirInfo; static DirInfo RootDir; static DirInfo* CurrDir = &RootDir; DarchHandle* OpenArc(char* fileName) { ARCHeader header; DarchHandle* handle; int fstLength; if ( NULL == (handle = malloc(sizeof(DarchHandle))) ) { fprintf(stderr, "malloc failed\n"); exit(1); } strcpy(handle->name, fileName); if( (handle->fid = open(fileName, O_BINARY | O_RDONLY)) == -1 ) { fprintf(stderr, "error opening %s\n", fileName); exit(1); } if (sizeof(ARCHeader) != read(handle->fid, &header, sizeof(ARCHeader))) { fprintf(stderr, "error reading %s\n", fileName); exit(1); } if (header.magic != REV32(DARCH_MAGIC)) { fprintf(stderr, "%s is not an archive\n", fileName); exit(1); } fstLength = REV32(header.fstSize); handle->fileStart = REV32(header.fileStart); if ( NULL == (handle->fst = malloc(fstLength)) ) { fprintf(stderr, "malloc failed\n"); exit(1); } if ( -1 == lseek(handle->fid, REV32(header.fstStart), SEEK_SET) ) { fprintf(stderr, "lseek failed on %s\n", fileName); exit(1); } if (fstLength != read(handle->fid, handle->fst, fstLength)) { fprintf(stderr, "error reading %s\n", fileName); exit(1); } handle->entryNum = nextDir(handle->fst); handle->stringStartOffset = handle->entryNum * sizeof(FSTEntry); if (debugMode) { fprintf(stderr, "entry num is %d\n", handle->entryNum); fprintf(stderr, "fst length is %d\n", fstLength); } handle->currEntry = 0; RootDir.child = NULL; RootDir.parent = NULL; RootDir.fullPath[0] = '\0'; RootDir.nextEntry = handle->entryNum; return handle; } static char* GetName(DarchHandle* handle, FSTEntry* entry) { char* stringStart; stringStart = (char*)handle->fst + handle->stringStartOffset; return stringStart + stringOff(entry); } BOOL GetNextEntry(DarchHandle* handle, FSTEntryInfo* entryInfo) { FSTEntry* fstEntry; DirInfo* dirInfo; handle->currEntry++; if (handle->currEntry >= handle->entryNum) { return FALSE; } fstEntry = &handle->fst[handle->currEntry]; // determine current directory while(CurrDir->nextEntry == handle->currEntry) { CurrDir = CurrDir->parent; free(CurrDir->child); CurrDir->child = NULL; } entryInfo->next = NULL; entryInfo->entryNum = handle->currEntry; strcpy(entryInfo->pathName, CurrDir->fullPath); entryInfo->nameOffset = strlen(entryInfo->pathName); entryInfo->name = (char*)entryInfo->pathName + entryInfo->nameOffset; strcat(entryInfo->pathName, GetName(handle, fstEntry)); if (debugMode) { fprintf(stderr, "full path name is %s\n", entryInfo->pathName); fprintf(stderr, "name is %s\n", entryInfo->name); } if (entryIsDir(fstEntry)) { if (debugMode) { fprintf(stderr, "entry is directory\n"); } entryInfo->isDir = TRUE; entryInfo->parentEntry = parentDir(fstEntry); entryInfo->nextEntry = nextDir(fstEntry); entryInfo->filePosition = 0; entryInfo->fileLength = 0; if ( NULL == (dirInfo = malloc(sizeof(DirInfo))) ) { fprintf(stderr, "malloc failed\n"); exit(1); } CurrDir->child = dirInfo; dirInfo->child = NULL; dirInfo->parent = CurrDir; strcpy(dirInfo->fullPath, entryInfo->pathName); strcat(dirInfo->fullPath, "/"); dirInfo->nextEntry = entryInfo->nextEntry; CurrDir = dirInfo; } else { entryInfo->isDir = FALSE; entryInfo->parentEntry = 0; entryInfo->nextEntry = 0; entryInfo->filePosition = filePosition(fstEntry); entryInfo->fileLength = fileLength(fstEntry); } return TRUE; } BOOL CloseArc(DarchHandle* handle) { free(handle->fst); if (close(handle->fid) == -1) { fprintf(stderr, "error closing %s\n", handle->name); exit(1); } free(handle); return TRUE; } void Diff(int fid, FSTEntryInfo* entryInfo) { struct stat sb; int fileLength; int fidB; if(stat(entryInfo->pathName, &sb)) { if (entryInfo->isDir) { fprintf(stdout, "%s: Directory does not exist\n", entryInfo->pathName); } else { fprintf(stdout, "%s: File does not exist\n", entryInfo->pathName); } return; } if (entryInfo->isDir) { if ( !(sb.st_mode & _S_IFDIR) ) { fprintf(stdout, "%s: No longer a directory\n", entryInfo->pathName); return; } } else { fileLength = entryInfo->fileLength; if ( sb.st_mode & _S_IFDIR ) { fprintf(stdout, "%s: Not a regular file\n", entryInfo->pathName); return; } // Check size if (sb.st_size != fileLength) { fprintf(stdout, "%s: Size differs\n", entryInfo->pathName); return; } if( (fidB = open(entryInfo->pathName, O_BINARY | O_RDONLY)) == -1 ) { fprintf(stderr, "%s: Error opening %s\n", progName, entryInfo->pathName); exit(1); } if (DiffUtility(fid, entryInfo->filePosition, fidB, 0, fileLength)) { if (verbose) { fprintf(stdout, "%s: Same\n", entryInfo->pathName); } } else { fprintf(stdout, "%s: Data differs\n", entryInfo->pathName); } close(fidB); return; } } void Extract(int fid, FSTEntryInfo* entryInfo) { int outid; int filePosition; int fileLength; if (entryInfo->isDir) { CreateDirectory(entryInfo->pathName, NULL); } else { filePosition = entryInfo->filePosition; fileLength = entryInfo->fileLength; if( (outid = open(entryInfo->pathName, O_BINARY | O_TRUNC | O_CREAT | O_WRONLY, 0666)) == -1 ) { fprintf(stderr, "Cannot open %s\n", entryInfo->pathName); exit(1); } CopyUtility(fid, filePosition, outid, 0, fileLength); close(outid); } } void ListArc(char* name) { DarchHandle* handle; FSTEntryInfo entryInfo; handle = OpenArc(name); if (verbose) { fprintf(stdout, " Position Length name\n"); fprintf(stdout, "-----------------------\n"); } while(GetNextEntry(handle, &entryInfo)) { if (verbose) { fprintf(stdout, "%s ", entryInfo.isDir? "d" : "-"); fprintf(stdout, "%7d %7d ", entryInfo.filePosition, entryInfo.fileLength); } fprintf(stdout, "%s", entryInfo.pathName); if (entryInfo.isDir) { fprintf(stdout, "/\n"); } else { fprintf(stdout, "\n"); } } CloseArc(handle); } static void CreateExtractDir(char* extract) { if (CreateDirectory(extract, NULL) == 0) { if (GetLastError() == ERROR_ALREADY_EXISTS) { fprintf(stderr, "%s: Directory %s already exists. Can't extract.\n", progName, extract); exit(1); } else { fprintf(stderr, "%s: Failed to create directory %s\n", progName, extract); fprintf(stderr, "last error: %d\n", GetLastError()); exit(1); } } } void ExtractArc(char* name, char* root) { DarchHandle* handle; FSTEntryInfo entryInfo; handle = OpenArc(name); CreateExtractDir(root); if (SetCurrentDirectory(root) == 0) { fprintf(stderr, "%s: Cannot change directory to %s\n", progName, root); fprintf(stderr, "%s: Error code is %d\n", progName, GetLastError()); exit(1); } fprintf(stdout, " Position Length name\n"); fprintf(stdout, "-----------------------\n"); while(GetNextEntry(handle, &entryInfo)) { fprintf(stdout, "%s ", entryInfo.isDir? "d" : "-"); fprintf(stdout, "%7d %7d ", entryInfo.filePosition, entryInfo.fileLength); fprintf(stdout, "%s", entryInfo.pathName); if (entryInfo.isDir) { fprintf(stdout, "/\n"); } else { fprintf(stdout, "\n"); } Extract(handle->fid, &entryInfo); } CloseArc(handle); } void DiffArc(char* name, char* root) { DarchHandle* handle; FSTEntryInfo entryInfo; handle = OpenArc(name); if (SetCurrentDirectory(root) == 0) { fprintf(stderr, "%s: Cannot change directory to %s\n", progName, root); fprintf(stderr, "%s: Error code is %d\n", progName, GetLastError()); exit(1); } while(GetNextEntry(handle, &entryInfo)) { fprintf(stdout, "%s", entryInfo.pathName); if (entryInfo.isDir) { fprintf(stdout, "/\n"); } else { fprintf(stdout, "\n"); } Diff(handle->fid, &entryInfo); } CloseArc(handle); }