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 
819     if (debugMode)
820     {
821         fprintf(stderr, "Searching %s\n", nameToFind);
822     }
823 
824     dirHandle = FindFirstFile(nameToFind, &findData);
825     if (dirHandle == INVALID_HANDLE_VALUE)
826     {
827         fprintf(stderr, "Failed when opening %s\n", currDir->fileName);
828         fprintf(stderr, "Error code is %d\n", GetLastError());
829         exit(1);
830     }
831 
832     // skip . and .. (Find FirstFile already read ".")
833     result = FindNextFile(dirHandle, &findData);    // read ".."
834     if (!result)
835     {
836         fprintf(stderr, "Failed when reading %s\n", currDir->fileName);
837         fprintf(stderr, "Error code is %d\n", GetLastError());
838         exit(1);
839     }
840 
841     while(1)
842     {
843         result = FindNextFile(dirHandle, &findData);
844 
845         if (!result)
846         {
847             error = GetLastError();
848 
849             if (error == ERROR_NO_MORE_FILES)
850             {
851                 // prepare to return from the function
852                 if (debugMode)
853                 {
854                     fprintf(stderr, "no more files or subdirectories in this directory\n");
855                 }
856                 return;
857             }
858             else
859             {
860                 fprintf(stderr, "Error occurred when reading directory %s\n",
861                         currDir->fileName);
862                 fprintf(stderr, "Error code is %d\n", error);
863                 exit(1);
864             }
865         }
866 
867         if ( NULL == (item = (DirStructure*)malloc(sizeof(DirStructure))) )
868         {
869             fprintf(stderr, "%s: Malloc failed\n", progName);
870             exit(1);
871         }
872 
873         strcpy(item->pathName, currDir->pathName);
874         strcat(item->pathName, "/");
875         item->nameOffset = strlen(item->pathName);
876         strcat(item->pathName, findData.cFileName);
877         item->name = item->pathName + item->nameOffset;
878 
879         strcpy(item->dirName, currDir->dirName);
880         strcpy(item->fileName, currDir->fileName);
881         strcat(item->fileName, "/");
882         strcat(item->fileName, findData.cFileName);
883 
884         item->next = NULL;
885         item->parent = currDir;
886         item->child = NULL;
887         item->file = NULL;
888 
889         item->isDir = (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)? TRUE : FALSE;
890 
891         if (item->isDir)
892         {
893             if (firstDir)
894             {
895                 currDir->child = item;
896                 item->prev = NULL;
897                 firstDir = 0;
898             }
899             else
900             {
901                 lastDir->next = item;
902                 item->prev = lastDir;
903             }
904 
905             lastDir = item;
906 
907             CreateHierarchyFromFilesRecursively(item);
908         }
909         else
910         {
911             if (firstFile)
912             {
913                 currDir->file = item;
914                 item->prev = NULL;
915                 firstFile = 0;
916             }
917             else
918             {
919                 lastFile->next = item;
920                 item->prev = lastFile;
921             }
922 
923             lastFile = item;
924 
925             item->filePosition = 0;
926             item->fileNewPosition = 0;
927 
928             if ( (findData.nFileSizeHigh != 0) ||
929                  (findData.nFileSizeLow >= 0x80000000) )
930             {
931                 fprintf(stderr, "%s: File %s is too large\n", progName,
932                         item->fileName);
933                 exit(1);
934             }
935             item->fileLength = findData.nFileSizeLow;
936 
937             DiskLastPtr->nextInDisc = item;
938             item->prevInDisc = DiskLastPtr;
939             DiskLastPtr = item;
940         }
941 
942     }
943 }
944 
AddItem(DirStructure * parent,DirStructure * item)945 static void AddItem(DirStructure* parent, DirStructure* item)
946 {
947     DirStructure*           curr;
948     DirStructure**          start;
949 
950     item->parent = parent;
951 
952     if (item->isDir)
953         start = &(parent->child);
954     else
955         start = &(parent->file);
956 
957     if (*start == NULL)
958     {
959         *start = item;
960         item->next = NULL;
961         item->prev = NULL;
962     }
963     else
964     {
965         // find last item of the chain
966         for(curr = *start; curr->next; curr = curr->next)
967             ;
968 
969         curr->next = item;
970         item->next = NULL;
971         item->prev = curr;
972     }
973 
974     return;
975 }
976 
MergeDirStructure(DirStructure * root1,DirStructure * root2)977 void MergeDirStructure(DirStructure* root1, DirStructure* root2)
978 {
979     DirStructure*       item;
980     DirStructure*       matched;
981     DirStructure*       next;
982 
983     for(item = root2->child; item; item = item->next)
984     {
985         next = item->next;
986 
987         matched = FindMatchingItemName(root1, item->name, strlen(item->name));
988 
989         if (matched == NULL)
990             AddItem(root1, item);
991         else
992         {
993             if (matched->isDir)
994             {
995                 MergeDirStructure(matched, item);
996             }
997             else
998             {
999                 fprintf(stderr, "%s: %s: File exists\n", progName,
1000                         root1->pathName);
1001                 exit(1);
1002             }
1003 
1004         }
1005     }
1006 
1007     for(item = root2->file; item; item = next)
1008     {
1009         next = item->next;
1010 
1011         matched = FindMatchingItemName(root1, item->name, strlen(item->name));
1012 
1013         if (matched == NULL)
1014             AddItem(root1, item);
1015         else
1016         {
1017             if (matched->isDir)
1018             {
1019                 fprintf(stderr, "%s: %s: Directory exists\n", progName,
1020                         root1->pathName);
1021                 exit(1);
1022             }
1023             else
1024             {
1025                 fprintf(stderr, "%s: %s: File exists\n", progName,
1026                         root1->pathName);
1027                 exit(1);
1028             }
1029 
1030         }
1031     }
1032 
1033 }
1034 
1035 
1036 #define END_OF_PATH(ptr)        \
1037            ( ((ptr)[0] == '\0') || ( ((ptr)[0] == '/') && ((ptr)[1] == '\0') ) )
1038 
1039 
CreateHierarchyFromFiles(char * dirName,char * name)1040 DirStructure* CreateHierarchyFromFiles(char* dirName, char* name)
1041 {
1042     DirStructure*           root;
1043     DirStructure*           last;
1044     DirStructure*           item;
1045     int                     attr;
1046     int                     error;
1047     char*                   nameptr;
1048     int                     next;
1049     struct stat             sb;
1050 
1051     assert(name);
1052 
1053     if ( NULL == (root = (DirStructure*)malloc(sizeof(DirStructure))) )
1054     {
1055         fprintf(stderr, "%s: Malloc failed\n", progName);
1056         exit(1);
1057     }
1058 
1059     InitializeRootDir(root);
1060 
1061     if ( -1 == (attr = GetFileAttributes(name)) )
1062     {
1063         error = GetLastError();
1064         if (error = ERROR_FILE_NOT_FOUND)
1065         {
1066             fprintf(stderr, "%s: Cannot find %s\n", progName, name);
1067         }
1068         else
1069         {
1070             fprintf(stderr, "%s: Error occurred when getting attributes of %s\n",
1071                     progName, name);
1072             fprintf(stderr, "Error code is %d\n", error);
1073         }
1074         exit(1);
1075     }
1076 
1077     nameptr = name;
1078 
1079     last = root;
1080 
1081     while(! END_OF_PATH(nameptr))
1082     {
1083         if ( NULL == (item = (DirStructure*)malloc(sizeof(DirStructure))) )
1084         {
1085             fprintf(stderr, "%s: Malloc failed\n", progName);
1086             exit(1);
1087         }
1088 
1089         // note that since END_OF_PATH(nameptr) = TRUE, next != -1
1090         next = GetFirstDirCount(&nameptr);
1091 
1092         item->isDir = TRUE;
1093         item->next = NULL;
1094         item->prev = NULL;
1095         item->child = NULL;
1096         item->parent = last;
1097         strcpy(item->pathName, name);
1098         item->pathName[(nameptr - name) + next] = '\0';
1099         strcpy(item->dirName, dirName);
1100         strcpy(item->fileName, item->pathName);
1101         item->nameOffset = nameptr - name;
1102         item->name = item->pathName + item->nameOffset;
1103         item->file = NULL;
1104 
1105         nameptr += next;
1106 
1107         last->child = item;
1108         last = item;
1109     }
1110 
1111     if (! (attr & FILE_ATTRIBUTE_DIRECTORY) )
1112     {
1113         last->parent->child = NULL;
1114         last->parent->file = last;
1115 
1116         last->isDir = FALSE;
1117 
1118         if(stat(name, &sb))
1119         {
1120             fprintf(stderr, "%s: %s: Does not exist\n", progName, name);
1121             exit(1);
1122         }
1123 
1124         item->filePosition = 0;
1125         item->fileNewPosition = 0;
1126         item->fileLength = sb.st_size;
1127 
1128         DiskLastPtr->nextInDisc = item;
1129         item->prevInDisc = DiskLastPtr;
1130         DiskLastPtr = item;
1131     }
1132     else
1133         CreateHierarchyFromFilesRecursively(last);
1134 
1135     DiskLastPtr->nextInDisc = (DirStructure*)NULL;
1136 
1137     return root;
1138 }
1139 
1140 
Create(char * currDir,char * name,DirStructure * root)1141 void Create(char* currDir, char* name, DirStructure* root)
1142 {
1143     DirStructure*           root2;
1144 
1145     SetCurrentDirectory(currDir);
1146 
1147     root2 = CreateHierarchyFromFiles(currDir, name);
1148     MergeDirStructure(root, root2);
1149 
1150 }
1151 
CreateArc(char * arcFile,Arg_s * arg,int count)1152 void CreateArc(char* arcFile, Arg_s* arg, int count)
1153 {
1154     int                     i, j;
1155     DirStructure            rootDir;
1156     int                     first = 1;
1157 
1158     // save the current directory before changing
1159     GetCurrentDirectory(FILENAME_MAX, CurrDir);
1160     InitializeRootDir(&rootDir);
1161 
1162     for (i = 0; i < count; i++)
1163     {
1164         for (j = 0; j < arg[i].argNum; j++)
1165         {
1166             Create(arg[i].currDir, (arg[i].argStart)[j], &rootDir);
1167         }
1168     }
1169 
1170     SetCurrentDirectory(CurrDir);
1171 
1172     ConstructFSTFromStructure(arcFile, &rootDir);
1173 }
1174 
1175 
ListArcInDiscOrder(char * name)1176 void ListArcInDiscOrder(char* name)
1177 {
1178     DirStructure*           item;
1179     DirStructure            rootDir;
1180     DarchHandle*            handle;
1181 
1182     handle = OpenArc(name);
1183     ConstructStructureFromFST(handle, &rootDir);
1184 
1185     if (verbose)
1186     {
1187         fprintf(stdout, "File start offset: 0x%08x\n\n", handle->fileStart);
1188         fprintf(stdout, "  Position   Length     name\n");
1189         fprintf(stdout, "--------------------------------------\n");
1190     }
1191 
1192     CloseArc(handle);
1193 
1194     for (item = DiskStart.nextInDisc; item; item = item->nextInDisc)
1195     {
1196         if (verbose)
1197         {
1198             fprintf(stdout, "  0x%08x 0x%08x ", item->fileNewPosition,
1199                     item->fileLength);
1200         }
1201 
1202         fprintf(stdout, "%s\n", item->pathName);
1203     }
1204 
1205 }
1206 
1207