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