1 /*---------------------------------------------------------------------------*
2   Project:  FST generator for dvd archiver
3   File:     fst.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: fst.c,v $
14   Revision 1.1  2006/04/20 01:41:22  hiratsu
15   Initial check-in.
16 
17 
18     1     7/02/01 11:34p Hashida
19     Initial revision.
20 
21   $NoKeywords: $
22  *---------------------------------------------------------------------------*/
23 
24 #include "darch.h"
25 #include <Windows.h>
26 
27 
28 static char tmpFilePrefix[FILENAME_MAX];
29 
30 int dirSearch(char* dirName, int myEntry);
31 
32 int             stringCount;
33 FSTEntryInfo*   lastInfo;
34 FSTEntryInfo    rootEntryInfo;
35 int             entryNum;
36 
makeTmpFileNames(void)37 void makeTmpFileNames(void)
38 {
39     char*     tmp;
40 
41     // get TMP or TEMP variable
42     if (NULL == (tmp = getenv("TMP")) )
43     {
44         if (NULL == (tmp = getenv("TEMP")) )
45         {
46             tmp = "c:\\windows\\temp";
47         }
48     }
49 
50     if (debugMode)
51     {
52         fprintf(stdout, "Use %s for temporary directory\n", tmp);
53     }
54 
55     strcpy((void*)tmpFilePrefix, (void*)tmp);
56     strcat((void*)tmpFilePrefix, "\\__makedisktmp__");
57 
58     strcpy((void*)fstFile, (void*)tmpFilePrefix);
59     strcat((void*)fstFile, (void*)"fst");
60 
61     strcpy((void*)userFile, (void*)tmpFilePrefix);
62     strcat((void*)userFile, (void*)"user");
63 }
64 
65 /*---------------------------------------------------------------------------*
66   Name:         dirSearch
67 
68   Description:  search under the current directory to fill FSTEntryInfo
69                 structure.
70 
71   Arguments:    myEntry:    entry number of the directory
72 
73   Returns:      last entry
74  *---------------------------------------------------------------------------*/
dirSearch(char * dirName,int myEntry)75 int dirSearch(char* dirName, int myEntry)
76 {
77     WIN32_FIND_DATA     findData;
78     HANDLE              dirHandle;
79     BOOL                result;
80     FSTEntryInfo*       currInfo;
81     int                 entryCount = myEntry;
82     int                 error;
83     char                nameToFind[256];
84 
85     if (debugMode)
86     {
87         fprintf(stderr, "directory %s\n", dirName);
88     }
89 
90 
91     strcpy(nameToFind, dirName);
92     strcat(nameToFind, "/*");       /* dummy comment for emacs */
93 
94     if (debugMode)
95     {
96         fprintf(stderr, "Searching %s\n", nameToFind);
97     }
98 
99     dirHandle = FindFirstFile(nameToFind, &findData);
100     if (dirHandle == INVALID_HANDLE_VALUE)
101     {
102         fprintf(stderr, "Failed when opening %s\n", dirName);
103         fprintf(stderr, "Error code is %d\n", GetLastError());
104         exit(1);
105     }
106 
107     // skip . and .. (Find FirstFile already read ".")
108     result = FindNextFile(dirHandle, &findData);    // read ".."
109     if (!result)
110     {
111         fprintf(stderr, "Failed when reading %s\n", dirName);
112         fprintf(stderr, "Error code is %d\n", GetLastError());
113         exit(1);
114     }
115 
116     while(1)
117     {
118         result = FindNextFile(dirHandle, &findData);
119 
120         if (!result)
121         {
122             error = GetLastError();
123 
124             if (error == ERROR_NO_MORE_FILES)
125             {
126                 // prepare to return from the function
127                 if (debugMode)
128                 {
129                     fprintf(stderr, "no more files or subdirectories in this directory\n");
130                 }
131                 break;
132             }
133             else
134             {
135                 fprintf(stderr, "Error occurred when reading directory %s\n",
136                         dirName);
137                 fprintf(stderr, "Error code is %d\n", error);
138                 exit(1);
139             }
140         }
141         entryCount++;
142 
143         if ( NULL == (currInfo = (FSTEntryInfo*)malloc(sizeof(FSTEntryInfo))) )
144         {
145             fprintf(stderr, "malloc failed\n");
146             exit(1);
147         }
148         lastInfo->next = currInfo;
149         lastInfo = currInfo;
150 
151         strcpy(currInfo->pathName, dirName);
152         strcat(currInfo->pathName, "/");
153 
154         // member 'name' holds the name of file or directory w/o path
155         currInfo->name = (char*)currInfo->pathName
156                          + strlen(currInfo->pathName);
157         strcat(currInfo->pathName, findData.cFileName);
158 
159         if (debugMode)
160         {
161             fprintf(stderr, "name is %s\n", currInfo->name);
162         }
163 
164         currInfo->nameOffset = stringCount;
165 
166         stringCount += ( strlen(currInfo->name) + 1 );
167 
168         if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
169         {
170             if (debugMode)
171             {
172                 fprintf(stderr, "this is a dir\n");
173             }
174 
175             currInfo->isDir = TRUE;
176             currInfo->parentEntry = myEntry;
177 
178             // dirSearch returns the last entry
179             entryCount = dirSearch(currInfo->pathName, entryCount);
180 
181             currInfo->nextEntry = entryCount + 1;
182         }
183         else
184         {
185             if (debugMode)
186             {
187                 fprintf(stderr, "this is a file\n");
188             }
189 
190             currInfo->isDir = FALSE;
191 
192             if ( (findData.nFileSizeHigh != 0) ||
193                  (findData.nFileSizeLow >= 0x80000000) )
194             {
195                 fprintf(stderr, "%s: File %s is too large\n", progName,
196                         currInfo->pathName);
197                 exit(1);
198             }
199             currInfo->fileLength = findData.nFileSizeLow;
200 
201             if (debugMode)
202             {
203                 fprintf(stderr, "file length is %d\n", currInfo->fileLength);
204             }
205 
206         }
207 
208     }
209 
210     if (!FindClose(dirHandle))
211     {
212         fprintf(stderr, "Error occurred when closing directory %s\n",
213                 dirName);
214         fprintf(stderr, "Error code is %d\n", GetLastError());
215         exit(1);
216     }
217 
218     return entryCount;
219 }
220 
221 
222 /*---------------------------------------------------------------------------*
223   Name:         geography
224 
225   Description:  rearrange file position according as geography script
226                 (not supporting geography script now)
227 
228   Arguments:    none
229 
230   Returns:      none
231  *---------------------------------------------------------------------------*/
geography(void)232 void geography(void)
233 {
234     FSTEntryInfo  *curr;
235     int           position;
236 
237     position = map.userFilePosition;
238 
239     for(curr = &rootEntryInfo; curr; curr = curr->next)
240     {
241         if (curr->isDir)
242         {
243             continue;
244         }
245 
246         position = roundUp4B(position);
247         curr->filePosition = position;
248 
249         position += curr->fileLength;
250     }
251 
252     map.userFileLength = position - map.userFilePosition;
253 }
254 
255 
createFST(void)256 void createFST(void)
257 {
258     void*         FST;
259     FSTEntry*     currFSTEntry;
260     FSTEntryInfo  *curr;
261     char*         FSTStringStart;
262     int           i;
263     int           fid;
264 
265 
266     if ( NULL == (FST = calloc(map.fstLength, 1)) )
267     {
268         fprintf(stderr, "malloc failed\n");
269         exit(1);
270     }
271     currFSTEntry = (FSTEntry*)FST;
272     FSTStringStart = (char*)(currFSTEntry + entryNum);
273 
274     if (debugMode)
275     {
276         fprintf(stderr, "entrynum is %d\n", entryNum);
277     }
278 
279     curr = &rootEntryInfo;
280     for(i = 0; i < entryNum; i++)
281     {
282         setIsDir(currFSTEntry, (char)curr->isDir);
283 
284         setStringOff(currFSTEntry, curr->nameOffset);
285 
286         if (debugMode)
287         {
288             fprintf(stderr, "pathname: %s\n", curr->pathName);
289             fprintf(stderr, "name: %s\n", curr->name);
290             fprintf(stderr, "nameoffset: %d\n", curr->nameOffset);
291         }
292 
293         strcpy( (void*)(FSTStringStart + curr->nameOffset),
294                 (void*)curr->name );
295 
296         if (curr->isDir)
297         {
298             setParent(currFSTEntry, curr->parentEntry);
299             setNextEntry(currFSTEntry, curr->nextEntry);
300         }
301         else
302         {
303             setPosition(currFSTEntry, curr->filePosition);
304             setLength(currFSTEntry, curr->fileLength);
305 
306         }
307 
308         curr = curr->next;
309         currFSTEntry++;
310     }
311 
312     if (debugMode)
313     {
314         fprintf(stderr, "fst file name is %s\n", fstFile);
315     }
316 
317     if( (fid = open(fstFile, O_BINARY | O_TRUNC | O_CREAT | O_WRONLY, 0666)) == -1 )
318     {
319         fprintf(stderr, "error opening an fst file\n");
320         exit(1);
321     }
322 
323     if (map.fstLength != write(fid, FST, map.fstLength))
324     {
325         fprintf(stderr, "error writing file\n");
326         exit(1);
327     }
328 
329     if (close(fid) == -1)
330     {
331         fprintf(stderr, "error closing file\n");
332         exit(1);
333     }
334 
335     // Free FST
336     free(FST);
337 
338 }
339 
createUserFile(void)340 void createUserFile(void)
341 {
342     FSTEntryInfo  *curr;
343     int           fids;
344     int           fidd;
345 
346 
347     if (debugMode)
348     {
349         fprintf(stderr, "userfileLength is 0x%08x\n", map.userFileLength);
350     }
351 
352     if( (fidd = open(userFile, O_TRUNC | O_CREAT | O_BINARY | O_WRONLY, 0666)) == -1 )
353     {
354         fprintf(stderr, "error opening user file\n");
355         exit(1);
356     }
357 
358     for(curr = &rootEntryInfo; curr; curr = curr->next)
359     {
360         if (curr->isDir)
361         {
362             if (verbose)
363             {
364                 fprintf(stdout, "%s", curr->pathName);
365                 fprintf(stdout, "/\n");
366             }
367             continue;
368         }
369 
370         if (verbose)
371         {
372             fprintf(stdout, "%s", curr->pathName);
373             fprintf(stdout, "\n");
374         }
375 
376         // read the file into the position where already decided
377         if( (fids = open(curr->pathName, O_BINARY | O_RDONLY)) == -1 )
378         {
379             fprintf(stderr, "error opening %s\n", curr->pathName);
380             exit(1);
381         }
382 
383         CopyUtility(fids, 0,
384                     fidd, curr->filePosition - map.userFilePosition,
385                     curr->fileLength);
386 
387         if (close(fids) == -1)
388         {
389             fprintf(stderr, "error closing %s\n", curr->pathName);
390             exit(1);
391         }
392     }
393 
394     if (close(fidd) == -1)
395     {
396         fprintf(stderr, "error closing user file\n");
397         exit(1);
398     }
399 
400 }
401 
402 
makeFST(void)403 int makeFST(void)
404 {
405     FSTEntryInfo  *curr;
406     FSTEntryInfo  *next;
407 
408 
409     strcpy(rootEntryInfo.pathName, "");
410     rootEntryInfo.name = rootEntryInfo.pathName;
411     rootEntryInfo.nameOffset = 0;
412     rootEntryInfo.isDir = TRUE;
413     rootEntryInfo.parentEntry = 0;
414 
415     lastInfo = &rootEntryInfo;
416 
417     entryNum = dirSearch(arcRoot, 0) + 1;
418     rootEntryInfo.nextEntry = entryNum;
419 
420     lastInfo->next = NULL;             // end mark
421 
422     if (debugMode)
423     {
424         fprintf(stderr, "finished making FST\n");
425         fprintf(stderr, "size of fstentry is %d\n", sizeof(FSTEntry));
426     }
427 
428     map.fstLength = sizeof(FSTEntry) * entryNum + stringCount;
429     map.fstPosition = sizeof(ARCHeader);
430     map.userFilePosition = roundUp4B(map.fstPosition + map.fstLength);
431 
432     // special solution; we put fst size here
433 //    rootEntryInfo.parentEntry = map.fstLength;
434 
435     geography();
436 
437     createFST();
438 
439     createUserFile();
440 
441     // Free each FSTEntryInfo structures
442     for (next = rootEntryInfo.next; next != NULL; )
443     {
444         curr = next;
445         next = curr->next;
446         free((void*)curr);
447     }
448 
449     return 0;
450 }
451