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