1 /*---------------------------------------------------------------------------*
2   Project:  archiver extractor for Revolution dvd
3   File:     extract.c
4 
5   Copyright (C) 2001-2006 Nintendo. All rights reserved.
6 
7   These coded instructions, statements, and computer programs contain
8   proprietary information of Nintendo of America Inc. and/or Nintendo
9   Company Ltd., and are protected by Federal copyright law.  They may
10   not be disclosed to third parties or copied or duplicated in any form,
11   in whole or in part, without the prior written consent of Nintendo.
12 
13   $Log: extract.c,v $
14   Revision 1.1  2006/04/20 01:41:22  hiratsu
15   Initial check-in.
16 
17 
18     1     7/02/01 11:34p Hashida
19     Initial revision.
20 
21   $NoKeywords: $
22  *---------------------------------------------------------------------------*/
23 
24 #include "darch.h"
25 
26 struct DirInfo_t
27 {
28     struct DirInfo_t*   child;
29     struct DirInfo_t*   parent;
30     char                fullPath[FILENAME_MAX];
31     int                 nextEntry;
32 
33 };
34 
35 typedef struct DirInfo_t        DirInfo;
36 
37 
38 
39 static DirInfo          RootDir;
40 static DirInfo*         CurrDir = &RootDir;
41 
42 
OpenArc(char * fileName)43 DarchHandle* OpenArc(char* fileName)
44 {
45     ARCHeader               header;
46     DarchHandle*            handle;
47     int                     fstLength;
48 
49     if ( NULL == (handle = malloc(sizeof(DarchHandle))) )
50     {
51         fprintf(stderr, "malloc failed\n");
52         exit(1);
53     }
54 
55     strcpy(handle->name, fileName);
56 
57     if( (handle->fid = open(fileName, O_BINARY | O_RDONLY)) == -1 )
58     {
59         fprintf(stderr, "error opening %s\n", fileName);
60         exit(1);
61     }
62 
63     if (sizeof(ARCHeader) != read(handle->fid, &header, sizeof(ARCHeader)))
64     {
65         fprintf(stderr, "error reading %s\n", fileName);
66         exit(1);
67     }
68 
69     if (header.magic != REV32(DARCH_MAGIC))
70     {
71         fprintf(stderr, "%s is not an archive\n", fileName);
72         exit(1);
73     }
74 
75     fstLength = REV32(header.fstSize);
76     handle->fileStart = REV32(header.fileStart);
77 
78     if ( NULL == (handle->fst = malloc(fstLength)) )
79     {
80         fprintf(stderr, "malloc failed\n");
81         exit(1);
82     }
83 
84     if ( -1 == lseek(handle->fid, REV32(header.fstStart), SEEK_SET) )
85     {
86         fprintf(stderr, "lseek failed on %s\n", fileName);
87         exit(1);
88     }
89 
90     if (fstLength != read(handle->fid, handle->fst, fstLength))
91     {
92         fprintf(stderr, "error reading %s\n", fileName);
93         exit(1);
94     }
95 
96     handle->entryNum = nextDir(handle->fst);
97     handle->stringStartOffset = handle->entryNum * sizeof(FSTEntry);
98 
99     if (debugMode)
100     {
101         fprintf(stderr, "entry num is %d\n", handle->entryNum);
102         fprintf(stderr, "fst length is %d\n", fstLength);
103     }
104 
105     handle->currEntry = 0;
106 
107     RootDir.child = NULL;
108     RootDir.parent = NULL;
109     RootDir.fullPath[0] = '\0';
110     RootDir.nextEntry = handle->entryNum;
111 
112     return handle;
113 }
114 
GetName(DarchHandle * handle,FSTEntry * entry)115 static char* GetName(DarchHandle* handle, FSTEntry* entry)
116 {
117     char*           stringStart;
118 
119     stringStart = (char*)handle->fst + handle->stringStartOffset;
120 
121     return stringStart + stringOff(entry);
122 
123 }
124 
GetNextEntry(DarchHandle * handle,FSTEntryInfo * entryInfo)125 BOOL GetNextEntry(DarchHandle* handle, FSTEntryInfo* entryInfo)
126 {
127     FSTEntry*               fstEntry;
128     DirInfo*                dirInfo;
129 
130     handle->currEntry++;
131 
132     if (handle->currEntry >= handle->entryNum)
133     {
134         return FALSE;
135     }
136 
137     fstEntry = &handle->fst[handle->currEntry];
138 
139     // determine current directory
140     while(CurrDir->nextEntry == handle->currEntry)
141     {
142         CurrDir = CurrDir->parent;
143 
144         free(CurrDir->child);
145         CurrDir->child = NULL;
146     }
147 
148     entryInfo->next = NULL;
149     entryInfo->entryNum = handle->currEntry;
150     strcpy(entryInfo->pathName, CurrDir->fullPath);
151     entryInfo->nameOffset = strlen(entryInfo->pathName);
152     entryInfo->name = (char*)entryInfo->pathName + entryInfo->nameOffset;
153     strcat(entryInfo->pathName, GetName(handle, fstEntry));
154 
155     if (debugMode)
156     {
157         fprintf(stderr, "full path name is %s\n", entryInfo->pathName);
158         fprintf(stderr, "name is %s\n", entryInfo->name);
159     }
160 
161     if (entryIsDir(fstEntry))
162     {
163         if (debugMode)
164         {
165             fprintf(stderr, "entry is directory\n");
166         }
167 
168         entryInfo->isDir = TRUE;
169         entryInfo->parentEntry = parentDir(fstEntry);
170         entryInfo->nextEntry = nextDir(fstEntry);
171         entryInfo->filePosition = 0;
172         entryInfo->fileLength = 0;
173 
174         if ( NULL == (dirInfo = malloc(sizeof(DirInfo))) )
175         {
176             fprintf(stderr, "malloc failed\n");
177             exit(1);
178         }
179 
180         CurrDir->child = dirInfo;
181         dirInfo->child = NULL;
182         dirInfo->parent = CurrDir;
183         strcpy(dirInfo->fullPath, entryInfo->pathName);
184         strcat(dirInfo->fullPath, "/");
185         dirInfo->nextEntry = entryInfo->nextEntry;
186 
187         CurrDir = dirInfo;
188 
189     }
190     else
191     {
192         entryInfo->isDir = FALSE;
193         entryInfo->parentEntry = 0;
194         entryInfo->nextEntry = 0;
195         entryInfo->filePosition = filePosition(fstEntry);
196         entryInfo->fileLength = fileLength(fstEntry);
197     }
198 
199     return TRUE;
200 }
201 
CloseArc(DarchHandle * handle)202 BOOL CloseArc(DarchHandle* handle)
203 {
204     free(handle->fst);
205 
206     if (close(handle->fid) == -1)
207     {
208         fprintf(stderr, "error closing %s\n", handle->name);
209         exit(1);
210     }
211 
212     free(handle);
213 
214     return TRUE;
215 }
216 
217 
Diff(int fid,FSTEntryInfo * entryInfo)218 void Diff(int fid, FSTEntryInfo* entryInfo)
219 {
220     struct stat         sb;
221     int                 fileLength;
222     int                 fidB;
223 
224     if(stat(entryInfo->pathName, &sb))
225     {
226         if (entryInfo->isDir)
227         {
228             fprintf(stdout, "%s: Directory does not exist\n", entryInfo->pathName);
229         }
230         else
231         {
232             fprintf(stdout, "%s: File does not exist\n", entryInfo->pathName);
233         }
234         return;
235     }
236 
237     if (entryInfo->isDir)
238     {
239         if ( !(sb.st_mode & _S_IFDIR) )
240         {
241             fprintf(stdout, "%s: No longer a directory\n", entryInfo->pathName);
242             return;
243         }
244     }
245     else
246     {
247         fileLength = entryInfo->fileLength;
248 
249         if ( sb.st_mode & _S_IFDIR )
250         {
251             fprintf(stdout, "%s: Not a regular file\n", entryInfo->pathName);
252             return;
253         }
254 
255         // Check size
256         if (sb.st_size != fileLength)
257         {
258             fprintf(stdout, "%s: Size differs\n", entryInfo->pathName);
259             return;
260         }
261 
262         if( (fidB = open(entryInfo->pathName, O_BINARY | O_RDONLY)) == -1 )
263         {
264             fprintf(stderr, "%s: Error opening %s\n", progName, entryInfo->pathName);
265             exit(1);
266         }
267 
268         if (DiffUtility(fid, entryInfo->filePosition, fidB, 0, fileLength))
269         {
270             if (verbose)
271             {
272                 fprintf(stdout, "%s: Same\n", entryInfo->pathName);
273             }
274         }
275         else
276         {
277             fprintf(stdout, "%s: Data differs\n", entryInfo->pathName);
278         }
279 
280         close(fidB);
281         return;
282     }
283 
284 }
285 
286 
Extract(int fid,FSTEntryInfo * entryInfo)287 void Extract(int fid, FSTEntryInfo* entryInfo)
288 {
289     int             outid;
290     int             filePosition;
291     int             fileLength;
292 
293     if (entryInfo->isDir)
294     {
295         CreateDirectory(entryInfo->pathName, NULL);
296     }
297     else
298     {
299         filePosition = entryInfo->filePosition;
300         fileLength = entryInfo->fileLength;
301 
302         if( (outid = open(entryInfo->pathName, O_BINARY | O_TRUNC | O_CREAT | O_WRONLY, 0666)) == -1 )
303         {
304             fprintf(stderr, "Cannot open %s\n", entryInfo->pathName);
305             exit(1);
306         }
307 
308         CopyUtility(fid, filePosition, outid, 0, fileLength);
309 
310         close(outid);
311     }
312 }
313 
314 
ListArc(char * name)315 void ListArc(char* name)
316 {
317     DarchHandle*            handle;
318     FSTEntryInfo            entryInfo;
319 
320     handle = OpenArc(name);
321 
322     if (verbose)
323     {
324         fprintf(stdout, "  Position Length  name\n");
325         fprintf(stdout, "-----------------------\n");
326     }
327 
328     while(GetNextEntry(handle, &entryInfo))
329     {
330         if (verbose)
331         {
332             fprintf(stdout, "%s ", entryInfo.isDir? "d" : "-");
333             fprintf(stdout, "%7d %7d ", entryInfo.filePosition,
334                     entryInfo.fileLength);
335         }
336 
337         fprintf(stdout, "%s", entryInfo.pathName);
338         if (entryInfo.isDir)
339         {
340             fprintf(stdout, "/\n");
341         }
342         else
343         {
344             fprintf(stdout, "\n");
345         }
346     }
347 
348     CloseArc(handle);
349 }
350 
351 
CreateExtractDir(char * extract)352 static void CreateExtractDir(char* extract)
353 {
354     if (CreateDirectory(extract, NULL) == 0)
355     {
356         if (GetLastError() == ERROR_ALREADY_EXISTS)
357         {
358             fprintf(stderr, "%s: Directory %s already exists. Can't extract.\n",
359                     progName, extract);
360             exit(1);
361         }
362         else
363         {
364             fprintf(stderr, "%s: Failed to create directory %s\n", progName,
365                     extract);
366             fprintf(stderr, "last error: %d\n", GetLastError());
367             exit(1);
368         }
369     }
370 }
371 
ExtractArc(char * name,char * root)372 void ExtractArc(char* name, char* root)
373 {
374     DarchHandle*            handle;
375     FSTEntryInfo            entryInfo;
376 
377     handle = OpenArc(name);
378 
379     CreateExtractDir(root);
380 
381     if (SetCurrentDirectory(root) == 0)
382     {
383         fprintf(stderr, "%s: Cannot change directory to %s\n", progName,
384                 root);
385         fprintf(stderr, "%s: Error code is %d\n", progName, GetLastError());        exit(1);
386     }
387 
388     fprintf(stdout, "  Position Length  name\n");
389     fprintf(stdout, "-----------------------\n");
390     while(GetNextEntry(handle, &entryInfo))
391     {
392         fprintf(stdout, "%s ", entryInfo.isDir? "d" : "-");
393         fprintf(stdout, "%7d %7d ", entryInfo.filePosition,
394                 entryInfo.fileLength);
395         fprintf(stdout, "%s", entryInfo.pathName);
396         if (entryInfo.isDir)
397         {
398             fprintf(stdout, "/\n");
399         }
400         else
401         {
402             fprintf(stdout, "\n");
403         }
404 
405         Extract(handle->fid, &entryInfo);
406     }
407 
408     CloseArc(handle);
409 }
410 
411 
DiffArc(char * name,char * root)412 void DiffArc(char* name, char* root)
413 {
414     DarchHandle*            handle;
415     FSTEntryInfo            entryInfo;
416 
417     handle = OpenArc(name);
418 
419     if (SetCurrentDirectory(root) == 0)
420     {
421         fprintf(stderr, "%s: Cannot change directory to %s\n", progName,
422                 root);
423         fprintf(stderr, "%s: Error code is %d\n", progName, GetLastError());
424         exit(1);
425     }
426 
427     while(GetNextEntry(handle, &entryInfo))
428     {
429         fprintf(stdout, "%s", entryInfo.pathName);
430         if (entryInfo.isDir)
431         {
432             fprintf(stdout, "/\n");
433         }
434         else
435         {
436             fprintf(stdout, "\n");
437         }
438 
439         Diff(handle->fid, &entryInfo);
440     }
441 
442     CloseArc(handle);
443 }
444 
445 
446