1 /*---------------------------------------------------------------------------*
2   Project:  functions to delete files from archive
3   File:     delete.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: create.c,v $
14   Revision 1.2  05/15/2006 05:15:06  kawaset
15   header.reserve[] is explicitly cleared in ConstructFSTFromStructure().
16 
17   Revision 1.1  04/20/2006 01:41:22  hiratsu
18   Initial check-in.
19 
20 
21     3     03/05/01 15:01 Hashida
22     Fixed two bugs.
23     - A bug that darchD.exe crashes if same files are specified to the
24     argument.
25     - A bug that darchD.exe malfunctions if a directory/file name is a part
26     of other directory/file name that is listed before the name.
27 
28     1     7/02/01 11:34p Hashida
29     Initial revision.
30 
31   $NoKeywords: $
32  *---------------------------------------------------------------------------*/
33 
34 #include "darch.h"
35 
36 extern DarchHandle* OpenArc(char* fileName);
37 extern BOOL GetNextEntry(DarchHandle* handle, FSTEntryInfo* entryInfo);
38 extern BOOL CloseArc(DarchHandle* handle);
39 
40 static char CurrDir[FILENAME_MAX];
41 
42 typedef struct DirStructure DirStructure;
43 
44 struct DirStructure
45 {
46     DirStructure*       next;
47     DirStructure*       prev;
48     DirStructure*       child;
49     DirStructure*       parent;
50     char                pathName[FILENAME_MAX];     // file name in archive
51     char*               name;
52     int                 nameOffset;
53     DirStructure*       file;
54     BOOL                isDir;
55 
56     int                 entrynum;
57     int                 numItems;
58     DirStructure*       nextInFst;
59     DirStructure*       nextInDisc;                 // only valid for files
60     DirStructure*       prevInDisc;                 // only valid for files
61 
62     char                dirName[FILENAME_MAX];
63     char                fileName[FILENAME_MAX];     // file name in the real world
64     int                 fileLength;
65     int                 filePosition;
66     int                 fileNewPosition;
67 };
68 
69 DirStructure            DiskStart;
70 DirStructure*           DiskLastPtr = &DiskStart;
71 
72 
InsertInDiscList(DirStructure * item)73 void InsertInDiscList(DirStructure* item)
74 {
75     DirStructure*           s;
76     DirStructure*           p;
77 
78 
79     p = &DiskStart;
80     for (s = DiskStart.nextInDisc; s; s = s->nextInDisc)
81     {
82         p = s;
83 
84         if (item->fileNewPosition < s->fileNewPosition)
85         {
86             s->prevInDisc->nextInDisc = item;
87             item->prevInDisc = s->prevInDisc;
88 
89             s->prevInDisc = item;
90             item->nextInDisc = s;
91             return;
92         }
93     }
94 
95     item->nextInDisc = NULL;
96 
97     p->nextInDisc = item;
98     item->prevInDisc = p;
99     return;
100 }
101 
102 
103 /*---------------------------------------------------------------------------*
104   Name:         CreateHierarchy
105 
106   Description:  Create hierarchy using DirStructure.
107 
108   Arguments:    handle:      handle for archive
109                 currDir:     current directory (= parent directory for
110                             directories we are checking)
111                 nextEntry:   start of next directory (i.e.nextEntry-1 is the
112                             end of currDir)
113 
114   Returns:      None
115  *---------------------------------------------------------------------------*/
CreateHierarchy(DarchHandle * handle,DirStructure * currDir,int nextEntry)116 void CreateHierarchy(DarchHandle* handle, DirStructure* currDir, int nextEntry)
117 {
118     DirStructure*           lastDir;
119     DirStructure*           item;
120     DirStructure*           lastFile;
121     int                     firstDir = 1;
122     int                     firstFile = 1;
123     FSTEntryInfo            entryInfo;
124 
125     // If handle->currEntry == nextEntry - 1, then the next GetNextEntry will
126     // return item that is not under this directory, so we shouldn't proceed
127     while(handle->currEntry < nextEntry - 1)
128     {
129         // this GetNextEntry should never return NULL
130         GetNextEntry(handle, &entryInfo);
131 
132         if ( NULL == (item = (DirStructure*)malloc(sizeof(DirStructure))) )
133         {
134             fprintf(stderr, "%s: Malloc failed\n", progName);
135             exit(1);
136         }
137 
138         strcpy(item->pathName, entryInfo.pathName);
139         item->nameOffset = entryInfo.nameOffset;
140         item->name = item->pathName + item->nameOffset;
141 
142         item->next = NULL;
143         item->parent = currDir;
144         item->child = NULL;
145         item->file = NULL;
146 
147         if (item->isDir = entryInfo.isDir)
148         {
149             if (firstDir)
150             {
151                 currDir->child = item;
152                 item->prev = NULL;
153                 firstDir = 0;
154             }
155             else
156             {
157                 lastDir->next = item;
158                 item->prev = lastDir;
159             }
160 
161             lastDir = item;
162 
163             CreateHierarchy(handle, item, entryInfo.nextEntry);
164         }
165         else
166         {
167             if (firstFile)
168             {
169                 currDir->file = item;
170                 item->prev = NULL;
171                 firstFile = 0;
172             }
173             else
174             {
175                 lastFile->next = item;
176                 item->prev = lastFile;
177             }
178 
179             lastFile = item;
180 
181             strcpy(item->dirName, ".");
182             strcpy(item->fileName, handle->name);
183             item->filePosition = entryInfo.filePosition;
184             item->fileNewPosition = entryInfo.filePosition;
185             item->fileLength = entryInfo.fileLength;
186 
187             InsertInDiscList(item);
188         }
189 
190     }
191 }
192 
193 
194 /*---------------------------------------------------------------------------*
195   Name:         freeDir
196 
197   Description:  free memory allocated for directory structure recursively
198 
199   Arguments:    item:        dir structure to free
200 
201   Returns:      None
202  *---------------------------------------------------------------------------*/
freeDir(DirStructure * item)203 void freeDir(DirStructure* item)
204 {
205     DirStructure*           child;
206     DirStructure*           file;
207     DirStructure*           tmp;
208 
209     for(child = item->child; child != NULL;)
210     {
211         tmp = child->next;
212         freeDir(child);
213         child = tmp;
214     }
215 
216     for(file = item->file; file != NULL;)
217     {
218         file->prevInDisc->nextInDisc = file->nextInDisc;
219         if (file->nextInDisc)
220         {
221             file->nextInDisc->prevInDisc = file->prevInDisc;
222         }
223 
224         tmp = file->next;
225         free(file);
226         file = tmp;
227     }
228 
229     free(item);
230 }
231 
232 
233 /*---------------------------------------------------------------------------*
234   Name:         DeleteItemFromStructure
235 
236   Description:  Delete specified item from file structure
237 
238   Arguments:    item:        dir structure to delete
239 
240   Returns:      None
241  *---------------------------------------------------------------------------*/
DeleteItemFromStructure(DirStructure * item)242 void DeleteItemFromStructure(DirStructure* item)
243 {
244     DirStructure*           prevItem;
245     DirStructure*           nextItem;
246     DirStructure*           parent;
247 
248     prevItem = item->prev;
249     if (prevItem == NULL)
250     {
251         parent = item->parent;
252         if (item->isDir)
253             parent->child = item->next;
254         else
255             parent->file = item->next;
256 
257     }
258     else
259     {
260         prevItem->next = item->next;
261     }
262 
263     nextItem = item->next;
264     if (nextItem)
265         nextItem->prev = prevItem;
266 
267     if (!item->isDir)
268     {
269         item->prevInDisc->nextInDisc = item->nextInDisc;
270         if (item->nextInDisc)
271         {
272             item->nextInDisc->prevInDisc = item->prevInDisc;
273         }
274     }
275 
276     if (item->isDir)
277         freeDir(item);
278     else
279         free(item);
280 }
281 
282 /*---------------------------------------------------------------------------*
283   Name:         MyStrnCmp
284 
285   Description:  Compare two strings up to maxlen
286 
287   Arguments:    str1:        string 1
288                 str2:        string 2
289                 maxlen:      maximum length to compare
290 
291   Returns:      0 if same, 1 otherwise
292  *---------------------------------------------------------------------------*/
MyStrnCmp(char * str1,char * str2,u32 maxlen)293 static int MyStrnCmp(char* str1, char* str2, u32 maxlen)
294 {
295     u32         i = maxlen;
296 
297     if (maxlen == 0)
298         return 1;
299 
300     for (i = 0; i < maxlen; i++)
301     {
302         if (tolower(*str1) != tolower(*str2))
303             return 1;
304         if (*str1 == '\0')
305             return 0;
306         str1++;
307         str2++;
308     }
309 
310     return 0;
311 }
312 
313 /*---------------------------------------------------------------------------*
314   Name:         FindMatchingItemName
315 
316   Description:  Get directory structure that has /name/ under dir
317 
318   Arguments:    dir:         directory structure. Search dir/file under this dir
319                 name:        name of the directory/file (updated if the first
320                             char of the string is "/")
321                 count:       only count chars are compared from /name/
322 
323   Returns:      dir structure is returned if any is matched. NULL is returned
324                 otherwise
325  *---------------------------------------------------------------------------*/
FindMatchingItemName(DirStructure * dir,char * name,int count)326 DirStructure* FindMatchingItemName(DirStructure* dir, char* name, int count)
327 {
328     DirStructure*           item;
329 
330 
331     // Note that name member of item is null-terminated.
332     for(item = dir->child; item != NULL; item = item->next)
333     {
334         if ( (MyStrnCmp(item->name, name, count) == 0) &&
335              (strlen(item->name) == count) )
336             return item;
337     }
338 
339     for(item = dir->file; item != NULL; item = item->next)
340     {
341         if ( (MyStrnCmp(item->name, name, count) == 0) &&
342              (strlen(item->name) == count) )
343             return item;
344     }
345 
346     return NULL;
347 }
348 
349 /*---------------------------------------------------------------------------*
350   Name:         GetFirstDirCount
351 
352   Description:  Get length of the first directory/file name
353 
354   Arguments:    name:        name of the directory/file (updated if the first
355                             char of the string is "/")
356 
357   Returns:      -1 if name is NULL or just "/". Length of the first directory/
358                 file name otherwise
359  *---------------------------------------------------------------------------*/
GetFirstDirCount(char ** name)360 int GetFirstDirCount(char** name)
361 {
362     char*               ptr;
363 
364     // Ignore leading '/' if any
365     if (**name == '/')
366         (*name)++;
367 
368     // if the first letter is end mark, return -1
369     if (**name == '\0')
370         return -1;
371 
372     ptr = *name;
373     while( (*ptr != '/') && (*ptr != '\0') )
374         ptr++;
375 
376     return (ptr - *name);
377 }
378 
379 /*---------------------------------------------------------------------------*
380   Name:         Delete
381 
382   Description:  Detete specified name from file structure
383 
384   Arguments:    name:        name of the directory/file to delete
385                 root:        root dir for the structure
386 
387   Returns:      None
388  *---------------------------------------------------------------------------*/
Delete(char * name,DirStructure * root)389 void Delete(char* name, DirStructure* root)
390 {
391     DirStructure*           curr;
392     DirStructure*           item;
393     int                     n;
394     char*                   nameptr;
395 
396     nameptr = name;
397     curr = root;
398 
399     // if the name is "" or "/", do nothing
400     n = GetFirstDirCount(&nameptr);
401     if (n == -1)
402         return;
403 
404     while(1)
405     {
406         // if /curr/ is a file, it means it matched to a file but there's
407         // some strings still left to compare, which is bad
408         if ( (!curr->isDir) ||
409              ( (item = FindMatchingItemName(curr, nameptr, n)) == NULL ) )
410         {
411             fprintf(stderr, "%s: %s: Not found in archive\n", progName, name);
412             exit(1);
413         }
414 
415         nameptr += n;
416         n = GetFirstDirCount(&nameptr);
417         if (n == -1)
418             break;
419 
420         curr = item;
421     }
422 
423     DeleteItemFromStructure(item);
424 }
425 
426 
InitializeRootDir(DirStructure * root)427 void InitializeRootDir(DirStructure* root)
428 {
429     root->next = NULL;
430     root->prev = NULL;
431     root->child = NULL;
432     root->parent = root;
433     root->pathName[0] = '\0';
434     root->name = root->pathName;
435     root->nameOffset = 0;
436     root->file = NULL;
437     root->isDir = TRUE;
438     root->entrynum = 0;
439 }
440 
441 /*---------------------------------------------------------------------------*
442   Name:         ConstructStructureFromFST
443 
444   Description:  Create hierarchy using DirStructure.
445 
446   Arguments:    handle:      DarchHandle structure for the archive file
447                 root:        root dir for the structure
448 
449   Returns:      None
450  *---------------------------------------------------------------------------*/
ConstructStructureFromFST(DarchHandle * handle,DirStructure * root)451 void ConstructStructureFromFST(DarchHandle* handle, DirStructure* root)
452 {
453     root->next = NULL;
454     root->prev = NULL;
455     root->child = NULL;
456     root->parent = root;
457     root->pathName[0] = '\0';
458     root->name = root->pathName;
459     root->nameOffset = 0;
460     root->file = NULL;
461     root->isDir = TRUE;
462     root->entrynum = 0;
463 
464     DiskStart.nextInDisc = NULL;
465     DiskStart.prevInDisc = NULL;
466 
467     CreateHierarchy(handle, root, handle->entryNum);
468 }
469 
470 /*---------------------------------------------------------------------------*
471   Name:         DecideOrderInFst
472 
473   Description:  Make chain of items in the order in FST
474 
475   Arguments:    start:       the starting directory to enum
476                 numItems:    [out]number of items including /start/
477                 charLength:  [out]sum of names of all items under start
478                             including /start/
479 
480   Returns:      last item of items under the directory
481  *---------------------------------------------------------------------------*/
DecideOrderInFst(DirStructure * start,int * numItems,int * charLength)482 DirStructure* DecideOrderInFst(DirStructure* start, int* numItems, int* charLength)
483 {
484     int                 chars;
485     DirStructure*       curr;
486     DirStructure*       last;
487     int                 subTotal, subCharLength;
488     int                 count;
489 
490     // we start from 1 because the count includes /start/
491     count = 1;
492     chars = strlen(start->name) + 1;
493 
494     last = start;
495     if (start->file)
496         curr = start->file;
497     else
498         curr = start->child;
499 
500     while(curr)
501     {
502         last->nextInFst = curr;
503 
504         if (curr->isDir)
505         {
506             last = DecideOrderInFst(curr, &subTotal, &subCharLength);
507 
508             curr->numItems = subTotal;
509             count += subTotal;
510             chars += subCharLength;
511 
512             curr = curr->next;
513         }
514         else
515         {
516             last = curr;
517 
518             count++;
519             chars += strlen(curr->name) + 1;
520 
521             if (curr->next)
522                 curr = curr->next;
523             else
524                 curr = curr->parent->child;
525         }
526     }
527 
528     *numItems = count;
529     *charLength = chars;
530 
531     return last;
532 }
533 
GetArcNewName(char * newname,char * oldname)534 void GetArcNewName(char* newname, char* oldname)
535 {
536     char*               ptr;
537 
538     ptr = strrchr(oldname, '/');
539     if (ptr == NULL)
540     {
541         ptr = strrchr(oldname, '\\');
542     }
543 
544     if (ptr != NULL)
545     {
546         ptr++;
547     }
548     else
549     {
550         ptr = oldname;
551     }
552 
553     strncpy(newname, oldname, ptr-oldname);
554     newname[ptr-oldname] = '\0';
555 
556     strcat(newname, "___");
557     strcat(newname, ptr);
558     strcat(newname, ".new");
559 }
560 
561 
DeterminPositionInDisc(int userPos)562 void DeterminPositionInDisc(int userPos)
563 {
564     DirStructure*           item;
565 
566     for (item = &DiskStart; item->nextInDisc; )
567     {
568         item = item->nextInDisc;
569 
570         item->fileNewPosition = userPos;
571         userPos += RoundUp32B(item->fileLength);
572     }
573 }
574 
575 /*---------------------------------------------------------------------------*
576   Name:         ConstructFSTFromStructure
577 
578   Description:  Construct FST from structure and make new archive
579 
580   Arguments:    arcName:     archive name
581                 root:        root dir for the structure
582 
583   Returns:      None
584  *---------------------------------------------------------------------------*/
ConstructFSTFromStructure(char * arcName,DirStructure * root)585 void ConstructFSTFromStructure(char* arcName, DirStructure* root)
586 {
587     int                 total;
588     int                 charLength, numItems;
589     DirStructure*       item;
590     char*               FSTStringStart;
591     char*               charPtr;
592     FSTEntry*           currFSTEntry;
593     int                 fidOld, fidNew;
594     char                arcNewName[FILENAME_MAX];
595     void*               fst;
596     int                 i;
597     int                 userPos;
598     int                 fstPos;
599     int                 fstLength;
600     char                currDirectory[FILENAME_MAX];
601     ARCHeader           header;
602 
603 
604     if (GetCurrentDirectory(FILENAME_MAX, currDirectory) >= FILENAME_MAX)
605     {
606         fprintf(stderr, "%s: Assertion error\n", progName);
607         exit(1);
608     }
609 
610     GetArcNewName(arcNewName, arcName);
611 
612     if( (fidNew = open(arcNewName, O_BINARY | O_TRUNC | O_CREAT | O_WRONLY, 0666)) == -1 )
613     {
614         fprintf(stderr, "%s: Error opening %s\n", progName, arcNewName);
615         exit(1);
616     }
617 
618     DecideOrderInFst(root, &numItems, &charLength);
619     root->numItems = total = numItems;
620 
621     fstLength = total * sizeof(FSTEntry) + charLength;
622 
623     if ( NULL == (fst = malloc(fstLength)) )
624     {
625         fprintf(stderr, "%s: Malloc failed\n", progName);
626         exit(1);
627     }
628 
629     currFSTEntry = (FSTEntry*)fst;
630     charPtr = FSTStringStart = (char*)(currFSTEntry + total);
631 
632     item = root;
633     fstPos = sizeof(ARCHeader);
634     userPos = RoundUp32B(fstPos + fstLength);
635 
636     DeterminPositionInDisc(userPos);
637 
638     header.magic = REV32(DARCH_MAGIC);
639     header.fstStart = REV32(fstPos);
640     header.fstSize = REV32(fstLength);
641     header.fileStart = REV32(userPos);
642     header.reserve[0] = 0;
643     header.reserve[1] = 0;
644     header.reserve[2] = 0;
645     header.reserve[3] = 0;
646 
647     for(i = 0; i < total; i++)
648     {
649         item->entrynum = i;
650 
651         setIsDir(currFSTEntry, item->isDir);
652         setStringOff(currFSTEntry, charPtr - FSTStringStart);
653 
654         if (debugMode)
655         {
656             fprintf(stderr, "pathname: %s\n", item->pathName);
657             fprintf(stderr, "name: %s\n", item->name);
658         }
659 
660         strcpy(charPtr, item->name);
661         charPtr += strlen(item->name) + 1;
662 
663         if (item->isDir)
664         {
665             setParent(currFSTEntry, item->parent->entrynum);
666             setNextEntry(currFSTEntry, (i + item->numItems));
667         }
668         else
669         {
670 //            setPosition(currFSTEntry, userPos);
671             setPosition(currFSTEntry, item->fileNewPosition);
672             setLength(currFSTEntry, item->fileLength);
673 
674             if(SetCurrentDirectory(item->dirName) == 0)
675             {
676                 fprintf(stderr, "%s: Error when changing curr directory to %s\n",
677                         progName, item->dirName);
678                 fprintf(stderr, "Error code is %d\n", GetLastError());
679                 exit(1);
680             }
681 
682             if( (fidOld = open(item->fileName, O_BINARY | O_RDONLY)) == -1 )
683             {
684                 fprintf(stderr, "%s: Error opening %s\n", progName, item->fileName);
685                 exit(1);
686             }
687 
688             CopyUtility(fidOld, item->filePosition, fidNew, item->fileNewPosition,
689                         item->fileLength);
690             close(fidOld);
691 
692             // XXX need to be aligned in 4bytes for disk access?
693 //            userPos += item->fileLength;
694         }
695 
696         item = item->nextInFst;
697         currFSTEntry++;
698     }
699 
700     // write fst
701     if ( -1 == lseek(fidNew, fstPos, SEEK_SET) )
702     {
703         fprintf(stderr, "%s: lseek failed on archive\n", progName);
704         exit(1);
705     }
706 
707     if (fstLength != write(fidNew, fst, fstLength))
708     {
709         fprintf(stderr, "%s: Cannot write archive\n", progName);
710         exit (1);
711     }
712 
713     // write header
714     if ( -1 == lseek(fidNew, 0, SEEK_SET) )
715     {
716         fprintf(stderr, "%s: lseek failed on archive\n", progName);
717         exit(1);
718     }
719 
720     if (sizeof(ARCHeader) != write(fidNew, &header, sizeof(ARCHeader)))
721     {
722         fprintf(stderr, "%s: Cannot write archive\n", progName);
723         exit (1);
724     }
725 
726     close(fidNew);
727 
728     if(SetCurrentDirectory(currDirectory) == 0)
729     {
730         fprintf(stderr, "%s: Error when changing curr directory to %s\n",
731                 progName, currDirectory);
732         fprintf(stderr, "Error code is %d\n", GetLastError());
733         exit(1);
734     }
735 
736     // we ignore error message
737     if (unlink(arcName) == -1)
738     {
739         if (errno != ENOENT)
740         {
741             fprintf(stderr, "%s: Error unlinking %s\n", progName,
742                     arcName);
743             perror("unlink");
744             exit(1);
745         }
746     }
747 
748     if (MoveFile(arcNewName, arcName) == 0)
749     {
750         fprintf(stderr, "%s: Error renaming %s to %s\n", progName, arcNewName,
751                 arcName);
752         fprintf(stderr, "Error code is %d\n", GetLastError());
753         exit(1);
754     }
755 
756 }
757 
758 
759 /*---------------------------------------------------------------------------*
760   Name:         DeleteArc
761 
762   Description:  Delete files from archive
763 
764   Arguments:    arcFile:     archive name
765                 arg:         file list to delete
766                 count:       num of list
767 
768   Returns:      None
769  *---------------------------------------------------------------------------*/
DeleteArc(char * arcFile,Arg_s * arg,int count)770 void DeleteArc(char* arcFile, Arg_s* arg, int count)
771 {
772     int                     i, j;
773     DirStructure            rootDir;
774     DarchHandle*            handle;
775 
776     handle = OpenArc(arcFile);
777     ConstructStructureFromFST(handle, &rootDir);
778     CloseArc(handle);
779 
780     for (i = 0; i < count; i++)
781     {
782         for (j = 0; j < arg[i].argNum; j++)
783         {
784             Delete((arg[i].argStart)[j], &rootDir);
785         }
786     }
787 
788     ConstructFSTFromStructure(arcFile, &rootDir);
789 
790 }
791 
792 
793 /*---------------------------------------------------------------------------*
794   Name:         CreateHierarchyFromFilesRecursively
795 
796   Description:  search under /currDir/ to create hierarchy
797 
798   Arguments:    currDir:     directory to search.
799 
800   Returns:      None
801  *---------------------------------------------------------------------------*/
CreateHierarchyFromFilesRecursively(DirStructure * currDir)802 void CreateHierarchyFromFilesRecursively(DirStructure* currDir)
803 {
804     WIN32_FIND_DATA         findData;
805     HANDLE                  dirHandle;
806     DirStructure*           lastDir;
807     DirStructure*           item;
808     DirStructure*           lastFile;
809     int                     firstDir = 1;
810     int                     firstFile = 1;
811     char                    nameToFind[FILENAME_MAX];
812     BOOL                    result;
813     int                     error;
814 
815     strcpy(nameToFind, currDir->fileName);
816     strcat(nameToFind, "/*");       /* dummy comment for emacs */
817 
818     if (debugMode)
819     {
820         fprintf(stderr, "Searching %s\n", nameToFind);
821     }
822 
823     dirHandle = FindFirstFile(nameToFind, &findData);
824     if (dirHandle == INVALID_HANDLE_VALUE)
825     {
826         fprintf(stderr, "Failed when opening %s\n", currDir->fileName);
827         fprintf(stderr, "Error code is %d\n", GetLastError());
828         exit(1);
829     }
830 
831     // skip . and .. (Find FirstFile already read ".")
832     result = FindNextFile(dirHandle, &findData);    // read ".."
833     if (!result)
834     {
835         fprintf(stderr, "Failed when reading %s\n", currDir->fileName);
836         fprintf(stderr, "Error code is %d\n", GetLastError());
837         exit(1);
838     }
839 
840     while(1)
841     {
842         result = FindNextFile(dirHandle, &findData);
843 
844         if (!result)
845         {
846             error = GetLastError();
847 
848             if (error == ERROR_NO_MORE_FILES)
849             {
850                 // prepare to return from the function
851                 if (debugMode)
852                 {
853                     fprintf(stderr, "no more files or subdirectories in this directory\n");
854                 }
855                 return;
856             }
857             else
858             {
859                 fprintf(stderr, "Error occurred when reading directory %s\n",
860                         currDir->fileName);
861                 fprintf(stderr, "Error code is %d\n", error);
862                 exit(1);
863             }
864         }
865 
866         if ( NULL == (item = (DirStructure*)malloc(sizeof(DirStructure))) )
867         {
868             fprintf(stderr, "%s: Malloc failed\n", progName);
869             exit(1);
870         }
871 
872         strcpy(item->pathName, currDir->pathName);
873         strcat(item->pathName, "/");
874         item->nameOffset = strlen(item->pathName);
875         strcat(item->pathName, findData.cFileName);
876         item->name = item->pathName + item->nameOffset;
877 
878         strcpy(item->dirName, currDir->dirName);
879         strcpy(item->fileName, currDir->fileName);
880         strcat(item->fileName, "/");
881         strcat(item->fileName, findData.cFileName);
882 
883         item->next = NULL;
884         item->parent = currDir;
885         item->child = NULL;
886         item->file = NULL;
887 
888         item->isDir = (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)? TRUE : FALSE;
889 
890         if (item->isDir)
891         {
892             if (firstDir)
893             {
894                 currDir->child = item;
895                 item->prev = NULL;
896                 firstDir = 0;
897             }
898             else
899             {
900                 lastDir->next = item;
901                 item->prev = lastDir;
902             }
903 
904             lastDir = item;
905 
906             CreateHierarchyFromFilesRecursively(item);
907         }
908         else
909         {
910             if (firstFile)
911             {
912                 currDir->file = item;
913                 item->prev = NULL;
914                 firstFile = 0;
915             }
916             else
917             {
918                 lastFile->next = item;
919                 item->prev = lastFile;
920             }
921 
922             lastFile = item;
923 
924             item->filePosition = 0;
925             item->fileNewPosition = 0;
926 
927             if ( (findData.nFileSizeHigh != 0) ||
928                  (findData.nFileSizeLow >= 0x80000000) )
929             {
930                 fprintf(stderr, "%s: File %s is too large\n", progName,
931                         item->fileName);
932                 exit(1);
933             }
934             item->fileLength = findData.nFileSizeLow;
935 
936             DiskLastPtr->nextInDisc = item;
937             item->prevInDisc = DiskLastPtr;
938             DiskLastPtr = item;
939         }
940 
941     }
942 }
943 
AddItem(DirStructure * parent,DirStructure * item)944 static void AddItem(DirStructure* parent, DirStructure* item)
945 {
946     DirStructure*           curr;
947     DirStructure**          start;
948 
949     item->parent = parent;
950 
951     if (item->isDir)
952         start = &(parent->child);
953     else
954         start = &(parent->file);
955 
956     if (*start == NULL)
957     {
958         *start = item;
959         item->next = NULL;
960         item->prev = NULL;
961     }
962     else
963     {
964         // find last item of the chain
965         for(curr = *start; curr->next; curr = curr->next)
966             ;
967 
968         curr->next = item;
969         item->next = NULL;
970         item->prev = curr;
971     }
972 
973     return;
974 }
975 
MergeDirStructure(DirStructure * root1,DirStructure * root2)976 void MergeDirStructure(DirStructure* root1, DirStructure* root2)
977 {
978     DirStructure*       item;
979     DirStructure*       matched;
980     DirStructure*       next;
981 
982     for(item = root2->child; item; item = item->next)
983     {
984         next = item->next;
985 
986         matched = FindMatchingItemName(root1, item->name, strlen(item->name));
987 
988         if (matched == NULL)
989             AddItem(root1, item);
990         else
991         {
992             if (matched->isDir)
993             {
994                 MergeDirStructure(matched, item);
995             }
996             else
997             {
998                 fprintf(stderr, "%s: %s: File exists\n", progName,
999                         root1->pathName);
1000                 exit(1);
1001             }
1002 
1003         }
1004     }
1005 
1006     for(item = root2->file; item; item = next)
1007     {
1008         next = item->next;
1009 
1010         matched = FindMatchingItemName(root1, item->name, strlen(item->name));
1011 
1012         if (matched == NULL)
1013             AddItem(root1, item);
1014         else
1015         {
1016             if (matched->isDir)
1017             {
1018                 fprintf(stderr, "%s: %s: Directory exists\n", progName,
1019                         root1->pathName);
1020                 exit(1);
1021             }
1022             else
1023             {
1024                 fprintf(stderr, "%s: %s: File exists\n", progName,
1025                         root1->pathName);
1026                 exit(1);
1027             }
1028 
1029         }
1030     }
1031 
1032 }
1033 
1034 
1035 #define END_OF_PATH(ptr)        \
1036            ( ((ptr)[0] == '\0') || ( ((ptr)[0] == '/') && ((ptr)[1] == '\0') ) )
1037 
1038 
CreateHierarchyFromFiles(char * dirName,char * name)1039 DirStructure* CreateHierarchyFromFiles(char* dirName, char* name)
1040 {
1041     DirStructure*           root;
1042     DirStructure*           last;
1043     DirStructure*           item;
1044     int                     attr;
1045     int                     error;
1046     char*                   nameptr;
1047     int                     next;
1048     struct stat             sb;
1049 
1050     assert(name);
1051 
1052     if ( NULL == (root = (DirStructure*)malloc(sizeof(DirStructure))) )
1053     {
1054         fprintf(stderr, "%s: Malloc failed\n", progName);
1055         exit(1);
1056     }
1057 
1058     InitializeRootDir(root);
1059 
1060     if ( -1 == (attr = GetFileAttributes(name)) )
1061     {
1062         error = GetLastError();
1063         if (error = ERROR_FILE_NOT_FOUND)
1064         {
1065             fprintf(stderr, "%s: Cannot find %s\n", progName, name);
1066         }
1067         else
1068         {
1069             fprintf(stderr, "%s: Error occurred when getting attributes of %s\n",
1070                     progName, name);
1071             fprintf(stderr, "Error code is %d\n", error);
1072         }
1073         exit(1);
1074     }
1075 
1076     nameptr = name;
1077 
1078     last = root;
1079 
1080     while(! END_OF_PATH(nameptr))
1081     {
1082         if ( NULL == (item = (DirStructure*)malloc(sizeof(DirStructure))) )
1083         {
1084             fprintf(stderr, "%s: Malloc failed\n", progName);
1085             exit(1);
1086         }
1087 
1088         // note that since END_OF_PATH(nameptr) = TRUE, next != -1
1089         next = GetFirstDirCount(&nameptr);
1090 
1091         item->isDir = TRUE;
1092         item->next = NULL;
1093         item->prev = NULL;
1094         item->child = NULL;
1095         item->parent = last;
1096         strcpy(item->pathName, name);
1097         item->pathName[(nameptr - name) + next] = '\0';
1098         strcpy(item->dirName, dirName);
1099         strcpy(item->fileName, item->pathName);
1100         item->nameOffset = nameptr - name;
1101         item->name = item->pathName + item->nameOffset;
1102         item->file = NULL;
1103 
1104         nameptr += next;
1105 
1106         last->child = item;
1107         last = item;
1108     }
1109 
1110     if (! (attr & FILE_ATTRIBUTE_DIRECTORY) )
1111     {
1112         last->parent->child = NULL;
1113         last->parent->file = last;
1114 
1115         last->isDir = FALSE;
1116 
1117         if(stat(name, &sb))
1118         {
1119             fprintf(stderr, "%s: %s: Does not exist\n", progName, name);
1120             exit(1);
1121         }
1122 
1123         item->filePosition = 0;
1124         item->fileNewPosition = 0;
1125         item->fileLength = sb.st_size;
1126 
1127         DiskLastPtr->nextInDisc = item;
1128         item->prevInDisc = DiskLastPtr;
1129         DiskLastPtr = item;
1130     }
1131     else
1132         CreateHierarchyFromFilesRecursively(last);
1133 
1134     DiskLastPtr->nextInDisc = (DirStructure*)NULL;
1135 
1136     return root;
1137 }
1138 
1139 
Create(char * currDir,char * name,DirStructure * root)1140 void Create(char* currDir, char* name, DirStructure* root)
1141 {
1142     DirStructure*           root2;
1143 
1144     SetCurrentDirectory(currDir);
1145 
1146     root2 = CreateHierarchyFromFiles(currDir, name);
1147     MergeDirStructure(root, root2);
1148 
1149 }
1150 
CreateArc(char * arcFile,Arg_s * arg,int count)1151 void CreateArc(char* arcFile, Arg_s* arg, int count)
1152 {
1153     int                     i, j;
1154     DirStructure            rootDir;
1155     int                     first = 1;
1156 
1157     // save the current directory before changing
1158     GetCurrentDirectory(FILENAME_MAX, CurrDir);
1159     InitializeRootDir(&rootDir);
1160 
1161     for (i = 0; i < count; i++)
1162     {
1163         for (j = 0; j < arg[i].argNum; j++)
1164         {
1165             Create(arg[i].currDir, (arg[i].argStart)[j], &rootDir);
1166         }
1167     }
1168 
1169     SetCurrentDirectory(CurrDir);
1170 
1171     ConstructFSTFromStructure(arcFile, &rootDir);
1172 }
1173 
1174 
ListArcInDiscOrder(char * name)1175 void ListArcInDiscOrder(char* name)
1176 {
1177     DirStructure*           item;
1178     DirStructure            rootDir;
1179     DarchHandle*            handle;
1180 
1181     handle = OpenArc(name);
1182     ConstructStructureFromFST(handle, &rootDir);
1183 
1184     if (verbose)
1185     {
1186         fprintf(stdout, "File start offset: 0x%08x\n\n", handle->fileStart);
1187         fprintf(stdout, "  Position   Length     name\n");
1188         fprintf(stdout, "--------------------------------------\n");
1189     }
1190 
1191     CloseArc(handle);
1192 
1193     for (item = DiskStart.nextInDisc; item; item = item->nextInDisc)
1194     {
1195         if (verbose)
1196         {
1197             fprintf(stdout, "  0x%08x 0x%08x ", item->fileNewPosition,
1198                     item->fileLength);
1199         }
1200 
1201         fprintf(stdout, "%s\n", item->pathName);
1202     }
1203 
1204 }
1205 
1206