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