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