1 /*---------------------------------------------------------------------------*
2 Project: TwlSDK - FS - libraries
3 File: fs_romfat_default.c
4
5 Copyright 2007-2009 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 $Date:: 2010-03-15#$
14 $Rev: 11308 $
15 $Author: yada $
16
17 *---------------------------------------------------------------------------*/
18
19
20 #include <nitro/fs.h>
21
22 #include <nitro/mi/memory.h>
23 #include <nitro/math/math.h>
24 #include <nitro/std.h>
25
26
27 #include "../include/util.h"
28 #include "../include/command.h"
29 #include "../include/rom.h"
30
31
32 #if defined(FS_IMPLEMENT)
33
34
35 /*---------------------------------------------------------------------------*/
36 /* Declarations */
37
38 // Synchronous system command blocking read structure
39 typedef struct FSiSyncReadParam
40 {
41 FSArchive *arc;
42 u32 pos;
43 }
44 FSiSyncReadParam;
45
46 // Bit and alignment macros
47 #define BIT_MASK(n) ((1 << (n)) - 1)
48
49
50 /*---------------------------------------------------------------------------*/
51 /* Functions */
52
53 /*---------------------------------------------------------------------------*
54 Name: FSi_SeekAndReadSRL
55
56 Description: SRL access callback called from the ROM hash context
57
58 Arguments: userdata Any user-defined data
59 buffer: Transfer destination buffer
60 offset: Transfer source ROM offset
61 length: Transfer size
62
63 Returns: Size of the transmission
64 *---------------------------------------------------------------------------*/
FSi_SeekAndReadSRL(void * userdata,void * buffer,u32 offset,u32 length)65 static int FSi_SeekAndReadSRL(void *userdata, void *buffer, u32 offset, u32 length)
66 {
67 FSFile *file = (FSFile*)userdata;
68 if (file)
69 {
70 (void)FS_SeekFile(file, (int)offset, FS_SEEK_SET);
71 (void)FS_ReadFile(file, buffer, (int)length);
72 }
73 return (int)length;
74 }
75
76 /*---------------------------------------------------------------------------*
77 Name: FSi_TranslateCommand
78
79 Description: Calls a user procedure or the default process and returns the result.
80 If a synchronous command returns an asynchronous response, wait for completion.
81 If an asynchronous command returns an asynchronous response, return it as is.
82
83 Arguments: p_file FSFile structure in which the command argument is stored
84 Command: Command ID
85 block TRUE if blocking
86
87 Returns: Command processing result.
88 *---------------------------------------------------------------------------*/
89 static FSResult FSi_TranslateCommand(FSFile *p_file, FSCommandType command, BOOL block);
90
91 /*---------------------------------------------------------------------------*
92 Name: FSi_ReadTable
93
94 Description: Execute synchronous Read inside synchronous-type command
95
96 Arguments: p Synchronous read structure
97 dst Read data storage destination buffer
98 len Number of bytes to read
99
100 Returns: Result of synchronous read
101 *---------------------------------------------------------------------------*/
FSi_ReadTable(FSiSyncReadParam * p,void * dst,u32 len)102 static FSResult FSi_ReadTable(FSiSyncReadParam * p, void *dst, u32 len)
103 {
104 FSResult result;
105 FSArchive * const arc = p->arc;
106 FSROMFATArchiveContext *context = (FSROMFATArchiveContext*)FS_GetArchiveUserData(arc);
107
108
109 if (context->load_mem)
110 {
111 MI_CpuCopy8((const void *)p->pos, dst, len);
112 result = FS_RESULT_SUCCESS;
113 }
114 else
115 {
116 result = (*context->read_func) (arc, dst, p->pos, len);
117 result = FSi_WaitForArchiveCompletion(arc->list, result);
118 }
119 p->pos += len;
120 return result;
121 }
122
123 /*---------------------------------------------------------------------------*
124 Name: FSi_SeekDirDirect
125
126 Description: Directly moves to beginning of specified directory
127
128 Arguments: file Pointer that stores directory list
129 id Directory ID
130
131 Returns: None.
132 *---------------------------------------------------------------------------*/
FSi_SeekDirDirect(FSFile * file,u32 id)133 static void FSi_SeekDirDirect(FSFile *file, u32 id)
134 {
135 file->arg.seekdir.pos.arc = file->arc;
136 file->arg.seekdir.pos.own_id = (u16)id;
137 file->arg.seekdir.pos.index = 0;
138 file->arg.seekdir.pos.pos = 0;
139 (void)FSi_TranslateCommand(file, FS_COMMAND_SEEKDIR, TRUE);
140 }
141
142 /*---------------------------------------------------------------------------*
143 Name: FSi_SeekDirDefault
144
145 Description: Default implementation of SEEKDIR command
146
147 Arguments: file Handle to process command
148
149 Returns: Command result value
150 *---------------------------------------------------------------------------*/
FSi_SeekDirDefault(FSFile * file)151 static FSResult FSi_SeekDirDefault(FSFile *file)
152 {
153 FSResult result;
154 FSArchive * const arc = file->arc;
155 FSROMFATArchiveContext *context = (FSROMFATArchiveContext*)FS_GetArchiveUserData(arc);
156
157 const FSDirPos * const arg = &file->arg.seekdir.pos;
158 FSArchiveFNT fnt;
159 FSiSyncReadParam param;
160 param.arc = arc;
161 param.pos = context->fnt + arg->own_id * sizeof(fnt);
162 result = FSi_ReadTable(¶m, &fnt, sizeof(fnt));
163 if (result == FS_RESULT_SUCCESS)
164 {
165 file->prop.dir.pos = *arg;
166 if ((arg->index == 0) && (arg->pos == 0))
167 {
168 file->prop.dir.pos.index = fnt.index;
169 file->prop.dir.pos.pos = context->fnt + fnt.start;
170 }
171 file->prop.dir.parent = (u32)(fnt.parent & BIT_MASK(12));
172 }
173 return result;
174 }
175
176 /*---------------------------------------------------------------------------*
177 Name: FSi_ReadDirDefault
178
179 Description: Default implementation of READDIR command
180
181 Arguments: file Handle to process command
182
183 Returns: Command result value
184 *---------------------------------------------------------------------------*/
FSi_ReadDirDefault(FSFile * file)185 static FSResult FSi_ReadDirDefault(FSFile *file)
186 {
187 FSResult result;
188 FSDirEntry *entry = file->arg.readdir.p_entry;
189 u8 len;
190
191 FSiSyncReadParam param;
192 param.arc = file->arc;
193 param.pos = file->prop.dir.pos.pos;
194
195 result = FSi_ReadTable(¶m, &len, sizeof(len));
196
197 if (result == FS_RESULT_SUCCESS)
198 {
199 entry->name_len = (u32)(len & BIT_MASK(7));
200 entry->is_directory = (u32)((len >> 7) & 1);
201 if (entry->name_len == 0)
202 {
203 result = FS_RESULT_FAILURE;
204 }
205 else
206 {
207 if (!file->arg.readdir.skip_string)
208 {
209 result = FSi_ReadTable(¶m, entry->name, entry->name_len);
210 if (result != FS_RESULT_SUCCESS)
211 {
212 return result;
213 }
214 entry->name[entry->name_len] = '\0';
215 }
216 else
217 {
218 param.pos += entry->name_len;
219 }
220 if (!entry->is_directory)
221 {
222 entry->file_id.arc = file->arc;
223 entry->file_id.file_id = file->prop.dir.pos.index;
224 ++file->prop.dir.pos.index;
225 }
226 else
227 {
228 u16 id;
229 result = FSi_ReadTable(¶m, &id, sizeof(id));
230 if (result == FS_RESULT_SUCCESS)
231 {
232 entry->dir_id.arc = file->arc;
233 entry->dir_id.own_id = (u16)(id & BIT_MASK(12));
234 entry->dir_id.index = 0;
235 entry->dir_id.pos = 0;
236 }
237 }
238 if (result == FS_RESULT_SUCCESS)
239 {
240 file->prop.dir.pos.pos = param.pos;
241 }
242 }
243 }
244
245 return result;
246 }
247
248 /*---------------------------------------------------------------------------*
249 Name: FSi_FindPathDefault
250
251 Description: Default implementation of FINDPATH command
252 (Uses SEEKDIR, READDIR commands)
253
254 Arguments: p_dir Handle to process command
255
256 Returns: Command result value
257 *---------------------------------------------------------------------------*/
FSi_FindPathDefault(FSFile * p_dir)258 static FSResult FSi_FindPathDefault(FSFile *p_dir)
259 {
260 const char *path = p_dir->arg.findpath.path;
261 const BOOL is_dir = p_dir->arg.findpath.find_directory;
262
263 // Path name search based on specified directory
264 p_dir->arg.seekdir.pos = p_dir->arg.findpath.pos;
265 (void)FSi_TranslateCommand(p_dir, FS_COMMAND_SEEKDIR, TRUE);
266 for (; *path; path += (*path ? 1 : 0))
267 {
268 // Extract the entry name targeted for the search
269 int name_len = FSi_IncrementSjisPositionToSlash(path, 0);
270 u32 is_directory = ((path[name_len] != '\0') || is_dir);
271 // If an illegal directory such as "//" is detected, failure
272 if (name_len == 0)
273 {
274 return FS_RESULT_INVALID_PARAMETER;
275 }
276 // Special directory specification
277 else if (*path == '.')
278 {
279 // "." is the current directory
280 if (name_len == 1)
281 {
282 path += 1;
283 continue;
284 }
285 // ".." is the parent directory
286 else if ((name_len == 2) & (path[1] == '.'))
287 {
288 if (p_dir->prop.dir.pos.own_id != 0)
289 {
290 FSi_SeekDirDirect(p_dir, p_dir->prop.dir.parent);
291 }
292 path += 2;
293 continue;
294 }
295 }
296 else if (*path == '*')
297 {
298 // "*" specifies a wildcard (Ignore this with the archive procedure)
299 break;
300 }
301 // If an entry name is too long, failure
302 if (name_len > FS_FILE_NAME_MAX)
303 {
304 return FS_RESULT_NO_ENTRY;
305 }
306 // Enumerate entries and sequentially compare
307 else
308 {
309 FSDirEntry etr;
310 p_dir->arg.readdir.p_entry = &etr;
311 p_dir->arg.readdir.skip_string = FALSE;
312 for (;;)
313 {
314 // If corresponding entry was not found, failure
315 if (FSi_TranslateCommand(p_dir, FS_COMMAND_READDIR, TRUE) != FS_RESULT_SUCCESS)
316 {
317 return FS_RESULT_NO_ENTRY;
318 }
319 // If there is no match, ingore
320 if ((is_directory == etr.is_directory) &&
321 (name_len == etr.name_len) && (FSi_StrNICmp(path, etr.name, (u32)name_len) == 0))
322 {
323 // If directory, move to the top again
324 if (is_directory)
325 {
326 path += name_len;
327 p_dir->arg.seekdir.pos = etr.dir_id;
328 (void)FSi_TranslateCommand(p_dir, FS_COMMAND_SEEKDIR, TRUE);
329 break;
330 }
331 // If it is a file and expecting a directory, failure
332 else if (is_dir)
333 {
334 return FS_RESULT_NO_ENTRY;
335 }
336 // File found
337 else
338 {
339 *p_dir->arg.findpath.result.file = etr.file_id;
340 return FS_RESULT_SUCCESS;
341 }
342 }
343 }
344 }
345 }
346 // If file cannot be found, failure
347 if (!is_dir)
348 {
349 return FS_RESULT_NO_ENTRY;
350 }
351 else
352 {
353 *p_dir->arg.findpath.result.dir = p_dir->prop.dir.pos;
354 return FS_RESULT_SUCCESS;
355 }
356 }
357
358 /*---------------------------------------------------------------------------*
359 Name: FSi_GetPathDefault
360
361 Description: Default implementation of GETPATH command
362 (Uses SEEKDIR, READDIR commands)
363
364 Arguments: file Handle to process command
365
366 Returns: Command result value
367 *---------------------------------------------------------------------------*/
FSi_GetPathDefault(FSFile * file)368 static FSResult FSi_GetPathDefault(FSFile *file)
369 {
370 FSResult result;
371 FSArchive * const arc = file->arc;
372 FSGetPathInfo *p_info = &file->arg.getpath;
373 FSDirEntry entry;
374 u32 dir_id;
375 u32 file_id;
376
377 enum
378 { INVALID_ID = 0x10000 };
379
380 FSFile tmp[1];
381 FS_InitFile(tmp);
382 tmp->arc = arc;
383
384 if (FS_IsDir(file))
385 {
386 dir_id = file->prop.dir.pos.own_id;
387 file_id = INVALID_ID;
388 }
389 else
390 {
391 file_id = file->prop.file.own_id;
392 {
393 // Search for all directories from root
394 u32 pos = 0;
395 u32 num_dir = 0;
396 dir_id = INVALID_ID;
397 do
398 {
399 FSi_SeekDirDirect(tmp, pos);
400 // Get total directory count first time
401 if (!pos)
402 {
403 num_dir = tmp->prop.dir.parent;
404 }
405 tmp->arg.readdir.p_entry = &entry;
406 tmp->arg.readdir.skip_string = TRUE;
407 while (FSi_TranslateCommand(tmp, FS_COMMAND_READDIR, TRUE) == FS_RESULT_SUCCESS)
408 {
409 if (!entry.is_directory && (entry.file_id.file_id == file_id))
410 {
411 dir_id = tmp->prop.dir.pos.own_id;
412 break;
413 }
414 }
415 }
416 while ((dir_id == INVALID_ID) && (++pos < num_dir));
417 }
418 }
419
420 // FALSE if the corresponding directory cannot be found
421 if (dir_id == INVALID_ID)
422 {
423 p_info->total_len = 0;
424 result = FS_RESULT_NO_ENTRY;
425 }
426 else
427 {
428 // If path length not calculated, measure once this time
429 {
430 u32 id = dir_id;
431 // First, add "archive name:/"
432 const char *arcname = FS_GetArchiveName(arc);
433 u32 len = (u32)STD_GetStringLength(arcname);
434 len += 2;
435 // Move to standard directory
436 FSi_SeekDirDirect(tmp, id);
437 // If necessary, add file name. (Already obtained)
438 if (file_id != INVALID_ID)
439 {
440 len += entry.name_len;
441 }
442 // Trace back in order and add own name
443 if (id != 0)
444 {
445 do
446 {
447 // Move to parent and search self
448 FSi_SeekDirDirect(tmp, tmp->prop.dir.parent);
449 tmp->arg.readdir.p_entry = &entry;
450 tmp->arg.readdir.skip_string = TRUE;
451 while (FSi_TranslateCommand(tmp, FS_COMMAND_READDIR, TRUE) == FS_RESULT_SUCCESS)
452 {
453 if (entry.is_directory && (entry.dir_id.own_id == id))
454 {
455 len += entry.name_len + 1;
456 break;
457 }
458 }
459 id = tmp->prop.dir.pos.own_id;
460 }
461 while (id != 0);
462 }
463 // Save the currently calculated data
464 p_info->total_len = (u16)(len + 1);
465 p_info->dir_id = (u16)dir_id;
466 }
467
468 // Success if measuring path length is the objective
469 if (!p_info->buf)
470 {
471 result = FS_RESULT_SUCCESS;
472 }
473 // Failure if buffer length is insufficient
474 else if (p_info->buf_len < p_info->total_len)
475 {
476 result = FS_RESULT_NO_MORE_RESOURCE;
477 }
478 // Store the character string from the end
479 else
480 {
481 u8 *dst = p_info->buf;
482 u32 total = p_info->total_len;
483 u32 pos = 0;
484 u32 id = dir_id;
485 // First, add "archive name:/"
486 const char *arcname = FS_GetArchiveName(arc);
487 u32 len = (u32)STD_GetStringLength(arcname);
488 MI_CpuCopy8(arcname, dst + pos, len);
489 pos += len;
490 MI_CpuCopy8(":/", dst + pos, 2);
491 pos += 2;
492 // Move to standard directory
493 FSi_SeekDirDirect(tmp, id);
494 // If necessary, add file name.
495 if (file_id != INVALID_ID)
496 {
497 tmp->arg.readdir.p_entry = &entry;
498 tmp->arg.readdir.skip_string = FALSE;
499 while (FSi_TranslateCommand(tmp, FS_COMMAND_READDIR, TRUE) == FS_RESULT_SUCCESS)
500 {
501 if (!entry.is_directory && (entry.file_id.file_id == file_id))
502 {
503 break;
504 }
505 }
506 len = entry.name_len + 1;
507 MI_CpuCopy8(entry.name, dst + total - len, len);
508 total -= len;
509 }
510 else
511 {
512 // If directory, append only the end
513 dst[total - 1] = '\0';
514 total -= 1;
515 }
516 // Trace back in order and add own name
517 if (id != 0)
518 {
519 do
520 {
521 // Move to parent and search self
522 FSi_SeekDirDirect(tmp, tmp->prop.dir.parent);
523 tmp->arg.readdir.p_entry = &entry;
524 tmp->arg.readdir.skip_string = FALSE;
525 // Add "/"
526 dst[total - 1] = '/';
527 total -= 1;
528 // Search parent's children (previous self)
529 while (FSi_TranslateCommand(tmp, FS_COMMAND_READDIR, TRUE) == FS_RESULT_SUCCESS)
530 {
531 if (entry.is_directory && (entry.dir_id.own_id == id))
532 {
533 u32 len = entry.name_len;
534 MI_CpuCopy8(entry.name, dst + total - len, len);
535 total -= len;
536 break;
537 }
538 }
539 id = tmp->prop.dir.pos.own_id;
540 }
541 while (id != 0);
542 }
543 SDK_ASSERT(pos == total);
544 }
545 result = FS_RESULT_SUCCESS;
546 }
547 return result;
548 }
549
550 /*---------------------------------------------------------------------------*
551 Name: FSi_OpenFileFastDefault
552
553 Description: Default implementation of OPENFILEFAST command
554 (Uses OPENFILEDIRECT command)
555
556 Arguments: p_file Handle to process command
557
558 Returns: Command result value
559 *---------------------------------------------------------------------------*/
FSi_OpenFileFastDefault(FSFile * p_file)560 static FSResult FSi_OpenFileFastDefault(FSFile *p_file)
561 {
562 FSResult result;
563 FSArchive * const p_arc = p_file->arc;
564 FSROMFATArchiveContext *context = (FSROMFATArchiveContext*)FS_GetArchiveUserData(p_arc);
565 const FSFileID *p_id = &p_file->arg.openfilefast.id;
566 const u32 index = p_id->file_id;
567
568 {
569 // Determine validity of FAT accessing region
570 u32 pos = (u32)(index * sizeof(FSArchiveFAT));
571 if (pos >= context->fat_size)
572 {
573 result = FS_RESULT_NO_ENTRY;
574 }
575 else
576 {
577 // Obtain the image area of the specified file from FAT
578 FSArchiveFAT fat;
579 FSiSyncReadParam param;
580 param.arc = p_arc;
581 param.pos = context->fat + pos;
582 result = FSi_ReadTable(¶m, &fat, sizeof(fat));
583 if (result == FS_RESULT_SUCCESS)
584 {
585 // Directly open
586 p_file->arg.openfiledirect.top = fat.top;
587 p_file->arg.openfiledirect.bottom = fat.bottom;
588 p_file->arg.openfiledirect.index = index;
589 result = FSi_TranslateCommand(p_file, FS_COMMAND_OPENFILEDIRECT, TRUE);
590 }
591 }
592 }
593 return result;
594 }
595
596 /*---------------------------------------------------------------------------*
597 Name: FSi_OpenFileDirectDefault
598
599 Description: Default implementation of OPENFILEDIRECT command
600
601 Arguments: p_file Handle to process command
602
603 Returns: Command result value
604 *---------------------------------------------------------------------------*/
FSi_OpenFileDirectDefault(FSFile * p_file)605 static FSResult FSi_OpenFileDirectDefault(FSFile *p_file)
606 {
607 p_file->prop.file.top = p_file->arg.openfiledirect.top;
608 p_file->prop.file.pos = p_file->arg.openfiledirect.top;
609 p_file->prop.file.bottom = p_file->arg.openfiledirect.bottom;
610 p_file->prop.file.own_id = p_file->arg.openfiledirect.index;
611 return FS_RESULT_SUCCESS;
612 }
613
614 /*---------------------------------------------------------------------------*
615 Name: FSi_ReadFileDefault
616
617 Description: Default implementation of READFILE command
618
619 Arguments: file Handle to process command
620
621 Returns: Command result value
622 *---------------------------------------------------------------------------*/
FSi_ReadFileDefault(FSFile * file)623 static FSResult FSi_ReadFileDefault(FSFile *file)
624 {
625 FSArchive * const arc = file->arc;
626 FSROMFATArchiveContext *context = (FSROMFATArchiveContext*)FS_GetArchiveUserData(arc);
627 const u32 pos = file->prop.file.pos;
628 const u32 len = file->arg.readfile.len;
629 void * const dst = file->arg.readfile.dst;
630 file->prop.file.pos += len;
631 return (*context->read_func) (arc, dst, pos, len);
632 }
633
634 /*---------------------------------------------------------------------------*
635 Name: FSi_WriteFileDefault
636
637 Description: Default implementation of WRITEFILE command
638
639 Arguments: file Handle to process command
640
641 Returns: Command result value
642 *---------------------------------------------------------------------------*/
FSi_WriteFileDefault(FSFile * file)643 static FSResult FSi_WriteFileDefault(FSFile *file)
644 {
645 FSArchive * const arc = file->arc;
646 FSROMFATArchiveContext *context = (FSROMFATArchiveContext*)FS_GetArchiveUserData(arc);
647 const u32 pos = file->prop.file.pos;
648 const u32 len = file->arg.writefile.len;
649 const void * const src = file->arg.writefile.src;
650 file->prop.file.pos += len;
651 return (*context->write_func) (arc, src, pos, len);
652 }
653
654 /*---------------------------------------------------------------------------*
655 Name: FSi_IgnoredCommand
656
657 Description: Implements commands that do nothing by default
658
659 Arguments: file Handle to process command
660
661 Returns: Command result value
662 *---------------------------------------------------------------------------*/
FSi_IgnoredCommand(FSFile * file)663 static FSResult FSi_IgnoredCommand(FSFile *file)
664 {
665 (void)file;
666 return FS_RESULT_SUCCESS;
667 }
668
669 /*---------------------------------------------------------------------------*
670 Name: FSi_TranslateCommand
671
672 Description: Calls user procedure or default process
673 If a synchronous command returns an asynchronous response, wait for completion internally.
674 If an asynchronous command returns an asynchronous response, return it as is.
675
676 Arguments: file: FSFile structure that stores the argument
677 Command: Command ID
678 block TRUE if blocking is necessary
679
680 Returns: The processing result for the command.
681 *---------------------------------------------------------------------------*/
FSi_TranslateCommand(FSFile * file,FSCommandType command,BOOL block)682 FSResult FSi_TranslateCommand(FSFile *file, FSCommandType command, BOOL block)
683 {
684 FSResult result = FS_RESULT_PROC_DEFAULT;
685 FSROMFATArchiveContext *context = (FSROMFATArchiveContext*)FS_GetArchiveUserData(file->arc);
686 // Execute if it is a command that supports the procedure
687 if ((context->proc_flag & (1 << command)) != 0)
688 {
689 result = (*context->proc) (file, command);
690 switch (result)
691 {
692 case FS_RESULT_SUCCESS:
693 case FS_RESULT_FAILURE:
694 case FS_RESULT_UNSUPPORTED:
695 break;
696 case FS_RESULT_PROC_ASYNC:
697 // Control asynchronous process handling in detail later.
698 break;
699 case FS_RESULT_PROC_UNKNOWN:
700 // Unknown command, so switch to the default process from this time onward.
701 result = FS_RESULT_PROC_DEFAULT;
702 context->proc_flag &= ~(1 << command);
703 break;
704 }
705 }
706 // If not processed in the procedure, call default process
707 if (result == FS_RESULT_PROC_DEFAULT)
708 {
709 static FSResult (*const (default_table[])) (FSFile *) =
710 {
711 FSi_ReadFileDefault,
712 FSi_WriteFileDefault,
713 FSi_SeekDirDefault,
714 FSi_ReadDirDefault,
715 FSi_FindPathDefault,
716 FSi_GetPathDefault,
717 FSi_OpenFileFastDefault,
718 FSi_OpenFileDirectDefault,
719 FSi_IgnoredCommand,
720 FSi_IgnoredCommand,
721 FSi_IgnoredCommand,
722 FSi_IgnoredCommand,
723 FSi_IgnoredCommand,
724 };
725 if (command < sizeof(default_table) / sizeof(*default_table))
726 {
727 result = (*default_table[command])(file);
728 }
729 else
730 {
731 result = FS_RESULT_UNSUPPORTED;
732 }
733 }
734 // If necessary, block here
735 if (block)
736 {
737 result = FSi_WaitForArchiveCompletion(file, result);
738 }
739 return result;
740 }
741
742 /*---------------------------------------------------------------------------*
743 Name: FSi_ROMFAT_ReadFile
744
745 Description: The FS_COMMAND_READFILE command.
746
747 Arguments: arc: Calling archive
748 file: Target file
749 buffer: Memory to transfer to
750 length: Transfer size
751
752 Returns: The processing result for the command.
753 *---------------------------------------------------------------------------*/
FSi_ROMFAT_ReadFile(FSArchive * arc,FSFile * file,void * buffer,u32 * length)754 static FSResult FSi_ROMFAT_ReadFile(FSArchive *arc, FSFile *file, void *buffer, u32 *length)
755 {
756 FSROMFATProperty *prop = (FSROMFATProperty*)FS_GetFileUserData(file);
757 const u32 pos = prop->file.pos;
758 const u32 rest = (u32)(prop->file.bottom - pos);
759 const u32 org = *length;
760 if (*length > rest)
761 {
762 *length = rest;
763 }
764 file->arg.readfile.dst = buffer;
765 file->arg.readfile.len_org = org;
766 file->arg.readfile.len = *length;
767 (void)arc;
768 return FSi_TranslateCommand(file, FS_COMMAND_READFILE, FALSE);
769 }
770
771 /*---------------------------------------------------------------------------*
772 Name: FSi_ROMFAT_WriteFile
773
774 Description: The FS_COMMAND_WRITEFILE command.
775
776 Arguments: arc: Calling archive
777 file: Target file
778 buffer: Memory to transfer from
779 length: Transfer size
780
781 Returns: The processing result for the command.
782 *---------------------------------------------------------------------------*/
FSi_ROMFAT_WriteFile(FSArchive * arc,FSFile * file,const void * buffer,u32 * length)783 static FSResult FSi_ROMFAT_WriteFile(FSArchive *arc, FSFile *file, const void *buffer, u32 *length)
784 {
785 FSROMFATProperty *prop = (FSROMFATProperty*)FS_GetFileUserData(file);
786 const u32 pos = prop->file.pos;
787 const u32 rest = (u32)(prop->file.bottom - pos);
788 const u32 org = *length;
789 if (*length > rest)
790 {
791 *length = rest;
792 }
793 file->arg.writefile.src = buffer;
794 file->arg.writefile.len_org = org;
795 file->arg.writefile.len = *length;
796 (void)arc;
797 return FSi_TranslateCommand(file, FS_COMMAND_WRITEFILE, FALSE);
798 }
799
800 /*---------------------------------------------------------------------------*
801 Name: FSi_ROMFAT_SeekDirectory
802
803 Description: FS_COMMAND_SEEKDIR command
804
805 Arguments: arc: Calling archive
806 file: Target file
807 id Unique directory ID
808 position Indicate enumeration state
809
810 Returns: The processing result for the command.
811 *---------------------------------------------------------------------------*/
FSi_ROMFAT_SeekDirectory(FSArchive * arc,FSFile * file,u32 id,u32 position)812 static FSResult FSi_ROMFAT_SeekDirectory(FSArchive *arc, FSFile *file, u32 id, u32 position)
813 {
814 FSResult result;
815 FSROMFATCommandInfo *arg = &file->arg;
816 file->arc = arc;
817 arg->seekdir.pos.arc = arc;
818 arg->seekdir.pos.own_id = (u16)(id >> 0);
819 arg->seekdir.pos.index = (u16)(id >> 16);
820 arg->seekdir.pos.pos = position;
821 result = FSi_TranslateCommand(file, FS_COMMAND_SEEKDIR, TRUE);
822 if (result == FS_RESULT_SUCCESS)
823 {
824 FS_SetDirectoryHandle(file, arc, &file->prop);
825 }
826 return result;
827 }
828
829 /*---------------------------------------------------------------------------*
830 Name: FSi_ROMFAT_ReadDirectory
831
832 Description: The FS_COMMAND_READDIR command.
833
834 Arguments: arc: Calling archive
835 file: Target file
836 info: Location to store the information
837
838 Returns: The processing result for the command.
839 *---------------------------------------------------------------------------*/
FSi_ROMFAT_ReadDirectory(FSArchive * arc,FSFile * file,FSDirectoryEntryInfo * info)840 static FSResult FSi_ROMFAT_ReadDirectory(FSArchive *arc, FSFile *file, FSDirectoryEntryInfo *info)
841 {
842 FSResult result;
843 FSDirEntry entry[1];
844 FSROMFATCommandInfo *arg = &file->arg;
845 arg->readdir.p_entry = entry;
846 arg->readdir.skip_string = FALSE;
847 result = FSi_TranslateCommand(file, FS_COMMAND_READDIR, TRUE);
848 if (result == FS_RESULT_SUCCESS)
849 {
850 info->shortname_length = 0;
851 info->longname_length = entry->name_len;
852 MI_CpuCopy8(entry->name, info->longname, info->longname_length);
853 info->longname[info->longname_length] = '\0';
854 if (entry->is_directory)
855 {
856 info->attributes = FS_ATTRIBUTE_IS_DIRECTORY;
857 info->id = (u32)((entry->dir_id.own_id << 0) | (entry->dir_id.index << 16));
858 info->filesize = 0;
859 }
860 else
861 {
862 info->attributes = 0;
863 info->id = entry->file_id.file_id;
864 info->filesize = 0;
865 // If a valid file ID, get file size information from FAT
866 {
867 FSROMFATArchiveContext *context = (FSROMFATArchiveContext*)FS_GetArchiveUserData(arc);
868 u32 pos = (u32)(info->id * sizeof(FSArchiveFAT));
869 if (pos < context->fat_size)
870 {
871 FSArchiveFAT fat;
872 FSiSyncReadParam param;
873 param.arc = arc;
874 param.pos = context->fat + pos;
875 if (FSi_ReadTable(¶m, &fat, sizeof(fat)) == FS_RESULT_SUCCESS)
876 {
877 info->filesize = (u32)(fat.bottom - fat.top);
878 // If running in NTR mode, set flag to disable reading of TWL-specific region
879 if (FSi_IsUnreadableRomOffset(arc, fat.top))
880 {
881 info->attributes |= FS_ATTRIBUTE_IS_OFFLINE;
882 }
883 }
884 }
885 }
886 }
887 info->mtime.year = 0;
888 info->mtime.month = 0;
889 info->mtime.day = 0;
890 info->mtime.hour = 0;
891 info->mtime.minute = 0;
892 info->mtime.second = 0;
893 }
894 (void)arc;
895 return result;
896 }
897
898 /*---------------------------------------------------------------------------*
899 Name: FSi_ROMFAT_FindPath
900
901 Description: FS_COMMAND_FINDPATH command
902
903 Arguments: arc: Calling archive
904 base_dir_id The base directory ID (0 for the root)
905 path Search path
906 target_id ID storage destination
907 target_is_directory Stores whether this is a directory
908
909 Returns: The processing result for the command.
910 *---------------------------------------------------------------------------*/
FSi_ROMFAT_FindPath(FSArchive * arc,u32 base_dir_id,const char * path,u32 * target_id,BOOL target_is_directory)911 static FSResult FSi_ROMFAT_FindPath(FSArchive *arc, u32 base_dir_id, const char *path, u32 *target_id, BOOL target_is_directory)
912 {
913 FSResult result;
914 union
915 {
916 FSFileID file;
917 FSDirPos dir;
918 }
919 id;
920 FSFile tmp[1];
921 FS_InitFile(tmp);
922 tmp->arc = arc;
923 tmp->arg.findpath.pos.arc = arc;
924 tmp->arg.findpath.pos.own_id = (u16)(base_dir_id >> 0);
925 tmp->arg.findpath.pos.index = 0;
926 tmp->arg.findpath.pos.pos = 0;
927 tmp->arg.findpath.path = path;
928 tmp->arg.findpath.find_directory = target_is_directory;
929 if (target_is_directory)
930 {
931 tmp->arg.findpath.result.dir = &id.dir;
932 }
933 else
934 {
935 tmp->arg.findpath.result.file = &id.file;
936 }
937 result = FSi_TranslateCommand(tmp, FS_COMMAND_FINDPATH, TRUE);
938 if (result == FS_RESULT_SUCCESS)
939 {
940 if (target_is_directory)
941 {
942 *target_id = id.dir.own_id;
943 }
944 else
945 {
946 *target_id = id.file.file_id;
947 }
948 }
949 return result;
950 }
951
952 /*---------------------------------------------------------------------------*
953 Name: FSi_ROMFAT_GetPath
954
955 Description: FS_COMMAND_GETPATH command.
956
957 Arguments: arc: Calling archive
958 file: Target file
959 is_directory False, if file is a file, TRUE if it is a directory
960 buffer: Path storage destination
961 length: Buffer size
962
963 Returns: The processing result for the command.
964 *---------------------------------------------------------------------------*/
FSi_ROMFAT_GetPath(FSArchive * arc,FSFile * file,BOOL is_directory,char * buffer,u32 * length)965 static FSResult FSi_ROMFAT_GetPath(FSArchive *arc, FSFile *file, BOOL is_directory, char *buffer, u32 *length)
966 {
967 FSResult result;
968 FSROMFATCommandInfo *arg = &file->arg;
969 arg->getpath.total_len = 0;
970 arg->getpath.dir_id = 0;
971 arg->getpath.buf = (u8 *)buffer;
972 arg->getpath.buf_len = *length;
973 result = FSi_TranslateCommand(file, FS_COMMAND_GETPATH, TRUE);
974 if (result == FS_RESULT_SUCCESS)
975 {
976 *length = arg->getpath.buf_len;
977 }
978 (void)arc;
979 (void)is_directory;
980 return result;
981 }
982
983 /*---------------------------------------------------------------------------*
984 Name: FSi_ROMFAT_OpenFileFast
985
986 Description: The FS_COMMAND_OPENFILEFAST command
987
988 Arguments: arc: Calling archive
989 file: Target file
990 id File ID
991 mode: Access mode
992
993 Returns: The processing result for the command.
994 *---------------------------------------------------------------------------*/
FSi_ROMFAT_OpenFileFast(FSArchive * arc,FSFile * file,u32 id,u32 mode)995 static FSResult FSi_ROMFAT_OpenFileFast(FSArchive *arc, FSFile *file, u32 id, u32 mode)
996 {
997 FSResult result;
998 FSROMFATCommandInfo *arg = &file->arg;
999 arg->openfilefast.id.arc = arc;
1000 arg->openfilefast.id.file_id = id;
1001 result = FSi_TranslateCommand(file, FS_COMMAND_OPENFILEFAST, TRUE);
1002 if (result == FS_RESULT_SUCCESS)
1003 {
1004 FS_SetFileHandle(file, arc, &file->prop);
1005 }
1006 (void)mode;
1007 return result;
1008 }
1009
1010 /*---------------------------------------------------------------------------*
1011 Name: FSi_ROMFAT_OpenFileDirect
1012
1013 Description: The FS_COMMAND_OPENFILEDIRECT command.
1014
1015 Arguments: arc: Calling archive
1016 file: Target file
1017 top File top offset
1018 bottom File bottom offset
1019 id Storage destination for required file ID and results
1020
1021 Returns: The processing result for the command.
1022 *---------------------------------------------------------------------------*/
FSi_ROMFAT_OpenFileDirect(FSArchive * arc,FSFile * file,u32 top,u32 bottom,u32 * id)1023 static FSResult FSi_ROMFAT_OpenFileDirect(FSArchive *arc, FSFile *file, u32 top, u32 bottom, u32 *id)
1024 {
1025 FSResult result;
1026 FSROMFATCommandInfo *arg = &file->arg;
1027 arg->openfiledirect.top = top;
1028 arg->openfiledirect.bottom = bottom;
1029 arg->openfiledirect.index = *id;
1030 result = FSi_TranslateCommand(file, FS_COMMAND_OPENFILEDIRECT, TRUE);
1031 if (result == FS_RESULT_SUCCESS)
1032 {
1033 FS_SetFileHandle(file, arc, &file->prop);
1034 }
1035 return result;
1036 }
1037
1038 /*---------------------------------------------------------------------------*
1039 Name: FSi_ROMFAT_CloseFile
1040
1041 Description: The FS_COMMAND_CLOSEFILE command.
1042
1043 Arguments: arc: Calling archive
1044 file: Target file
1045
1046 Returns: The processing result for the command.
1047 *---------------------------------------------------------------------------*/
FSi_ROMFAT_CloseFile(FSArchive * arc,FSFile * file)1048 static FSResult FSi_ROMFAT_CloseFile(FSArchive *arc, FSFile *file)
1049 {
1050 FSResult result;
1051 result = FSi_TranslateCommand(file, FS_COMMAND_CLOSEFILE, TRUE);
1052 FS_DetachHandle(file);
1053 (void)arc;
1054 return result;
1055 }
1056
1057 /*---------------------------------------------------------------------------*
1058 Name: FSi_ROMFAT_Activate
1059
1060 Description: The FS_COMMAND_ACTIVATE command.
1061
1062 Arguments: arc: Calling archive
1063
1064 Returns: None.
1065 *---------------------------------------------------------------------------*/
FSi_ROMFAT_Activate(FSArchive * arc)1066 static void FSi_ROMFAT_Activate(FSArchive* arc)
1067 {
1068 FSFile tmp[1];
1069 FS_InitFile(tmp);
1070 tmp->arc = arc;
1071 (void)FSi_TranslateCommand(tmp, FS_COMMAND_ACTIVATE, FALSE);
1072 }
1073
1074 /*---------------------------------------------------------------------------*
1075 Name: FSi_ROMFAT_Idle
1076
1077 Description: The FS_COMMAND_ACTIVATE command.
1078
1079 Arguments: arc: Calling archive
1080
1081 Returns: None.
1082 *---------------------------------------------------------------------------*/
FSi_ROMFAT_Idle(FSArchive * arc)1083 static void FSi_ROMFAT_Idle(FSArchive* arc)
1084 {
1085 FSFile tmp[1];
1086 FS_InitFile(tmp);
1087 tmp->arc = arc;
1088 (void)FSi_TranslateCommand(tmp, FS_COMMAND_IDLE, FALSE);
1089 }
1090
1091 /*---------------------------------------------------------------------------*
1092 Name: FSi_ROMFAT_Suspend
1093
1094 Description: The FS_COMMAND_SUSPEND command.
1095
1096 Arguments: arc: Calling archive
1097
1098 Returns: None.
1099 *---------------------------------------------------------------------------*/
FSi_ROMFAT_Suspend(FSArchive * arc)1100 static void FSi_ROMFAT_Suspend(FSArchive* arc)
1101 {
1102 FSFile tmp[1];
1103 FS_InitFile(tmp);
1104 tmp->arc = arc;
1105 (void)FSi_TranslateCommand(tmp, FS_COMMAND_SUSPEND, FALSE);
1106 }
1107
1108 /*---------------------------------------------------------------------------*
1109 Name: FSi_ROMFAT_Resume
1110
1111 Description: The FS_COMMAND_RESUME command.
1112
1113 Arguments: arc: Calling archive
1114
1115 Returns: None.
1116 *---------------------------------------------------------------------------*/
FSi_ROMFAT_Resume(FSArchive * arc)1117 static void FSi_ROMFAT_Resume(FSArchive* arc)
1118 {
1119 FSFile tmp[1];
1120 FS_InitFile(tmp);
1121 tmp->arc = arc;
1122 (void)FSi_TranslateCommand(tmp, FS_COMMAND_RESUME, FALSE);
1123 }
1124
1125 /*---------------------------------------------------------------------------*
1126 Name: FSi_ROMFAT_OpenFile
1127
1128 Description: The FS_COMMAND_OPENFILE command.
1129
1130 Arguments: arc: Calling archive
1131 file: Target file
1132 baseid: Base directory (0 for the root)
1133 path: File path
1134 mode: Access mode
1135
1136 Returns: The processing result for the command.
1137 *---------------------------------------------------------------------------*/
FSi_ROMFAT_OpenFile(FSArchive * arc,FSFile * file,u32 baseid,const char * path,u32 mode)1138 static FSResult FSi_ROMFAT_OpenFile(FSArchive *arc, FSFile *file, u32 baseid, const char *path, u32 mode)
1139 {
1140 FSResult result;
1141 u32 fileid;
1142 result = FSi_ROMFAT_FindPath(arc, baseid, path, &fileid, FALSE);
1143 if (result == FS_RESULT_SUCCESS)
1144 {
1145 result = FSi_ROMFAT_OpenFileFast(arc, file, fileid, mode);
1146 }
1147 return result;
1148 }
1149
1150 /*---------------------------------------------------------------------------*
1151 Name: FSi_ROMFAT_SeekFile
1152
1153 Description: The FS_COMMAND_SEEKFILE command.
1154
1155 Arguments: arc: Calling archive
1156 file: Target file
1157 offset: Displacement and moved-to position
1158 from: Starting point to seek from
1159
1160 Returns: The processing result for the command.
1161 *---------------------------------------------------------------------------*/
FSi_ROMFAT_SeekFile(FSArchive * arc,FSFile * file,int * offset,FSSeekFileMode from)1162 static FSResult FSi_ROMFAT_SeekFile(FSArchive *arc, FSFile *file, int *offset, FSSeekFileMode from)
1163 {
1164 FSROMFATProperty *prop = (FSROMFATProperty*)FS_GetFileUserData(file);
1165 int pos = *offset;
1166 switch (from)
1167 {
1168 case FS_SEEK_SET:
1169 pos += prop->file.top;
1170 break;
1171 case FS_SEEK_CUR:
1172 default:
1173 pos += prop->file.pos;
1174 break;
1175 case FS_SEEK_END:
1176 pos += prop->file.bottom;
1177 break;
1178 }
1179 // Seek processing outside of range failed
1180 if ((pos < (int)prop->file.top) || (pos > (int)prop->file.bottom))
1181 {
1182 return FS_RESULT_INVALID_PARAMETER;
1183 }
1184 else
1185 {
1186 prop->file.pos = (u32)pos;
1187 *offset = pos;
1188 (void)arc;
1189 return FS_RESULT_SUCCESS;
1190 }
1191 }
1192
1193 /*---------------------------------------------------------------------------*
1194 Name: FSi_ROMFAT_GetFileLength
1195
1196 Description: The FS_COMMAND_GETFILELENGTH command.
1197
1198 Arguments: arc: Calling archive
1199 file: Target file
1200 length: Location to save the obtained size
1201
1202 Returns: The processing result for the command.
1203 *---------------------------------------------------------------------------*/
FSi_ROMFAT_GetFileLength(FSArchive * arc,FSFile * file,u32 * length)1204 static FSResult FSi_ROMFAT_GetFileLength(FSArchive *arc, FSFile *file, u32 *length)
1205 {
1206 FSROMFATProperty *prop = (FSROMFATProperty*)FS_GetFileUserData(file);
1207 *length = prop->file.bottom - prop->file.top;
1208 (void)arc;
1209 return FS_RESULT_SUCCESS;
1210 }
1211
1212 /*---------------------------------------------------------------------------*
1213 Name: FSi_ROMFAT_GetFilePosition
1214
1215 Description: The FS_COMMAND_GETFILEPOSITION command.
1216
1217 Arguments: arc: Calling archive
1218 file: Target file
1219 length: Storage destination of gotten position
1220
1221 Returns: The processing result for the command.
1222 *---------------------------------------------------------------------------*/
FSi_ROMFAT_GetFilePosition(FSArchive * arc,FSFile * file,u32 * position)1223 static FSResult FSi_ROMFAT_GetFilePosition(FSArchive *arc, FSFile *file, u32 *position)
1224 {
1225 FSROMFATProperty *prop = (FSROMFATProperty*)FS_GetFileUserData(file);
1226 *position = prop->file.pos - prop->file.top;
1227 (void)arc;
1228 return FS_RESULT_SUCCESS;
1229 }
1230
1231 /*---------------------------------------------------------------------------*
1232 Name: FSi_ROMFAT_Unmount
1233
1234 Description: The FS_COMMAND_UNMOUNT command
1235
1236 Arguments: arc: Calling archive
1237
1238 Returns: None.
1239 *---------------------------------------------------------------------------*/
FSi_ROMFAT_Unmount(FSArchive * arc)1240 static void FSi_ROMFAT_Unmount(FSArchive *arc)
1241 {
1242 FSROMFATArchiveContext *context = (FSROMFATArchiveContext*)FS_GetArchiveUserData(arc);
1243 if (FS_IsArchiveTableLoaded(arc))
1244 {
1245 OS_TWarning("memory may leak. preloaded-table of archive \"%s\" (0x%08X)",
1246 FS_GetArchiveName(arc), context->load_mem);
1247 }
1248 context->base = 0;
1249 context->fat = 0;
1250 context->fat_size = 0;
1251 context->fnt = 0;
1252 context->fnt_size = 0;
1253 context->fat_bak = 0;
1254 context->fnt_bak = 0;
1255 }
1256
1257 /*---------------------------------------------------------------------------*
1258 Name: FSi_ROMFAT_GetArchiveCaps
1259
1260 Description: The FS_COMMAND_GETARCHIVECAPS command.
1261
1262 Arguments: arc: Calling archive
1263 caps: Location to save the device capability flag
1264
1265 Returns: The processing result for the command.
1266 *---------------------------------------------------------------------------*/
FSi_ROMFAT_GetArchiveCaps(FSArchive * arc,u32 * caps)1267 static FSResult FSi_ROMFAT_GetArchiveCaps(FSArchive *arc, u32 *caps)
1268 {
1269 (void)arc;
1270 *caps = 0;
1271 return FS_RESULT_SUCCESS;
1272 }
1273
1274 /*---------------------------------------------------------------------------*
1275 Name: FSi_ROMFAT_OpenDirectory
1276
1277 Description: The FS_COMMAND_OPENDIRECTORY command.
1278
1279 Arguments: arc: Calling archive
1280 file: Target file
1281 baseid: Base directory ID (0 for the root)
1282 path: Path
1283 mode: Access mode
1284
1285 Returns: The processing result for the command.
1286 *---------------------------------------------------------------------------*/
FSi_ROMFAT_OpenDirectory(FSArchive * arc,FSFile * file,u32 baseid,const char * path,u32 mode)1287 static FSResult FSi_ROMFAT_OpenDirectory(FSArchive *arc, FSFile *file, u32 baseid, const char *path, u32 mode)
1288 {
1289 FSResult result = FS_RESULT_ERROR;
1290 u32 id = 0;
1291 result = FSi_ROMFAT_FindPath(arc, baseid, path, &id, TRUE);
1292 if (result == FS_RESULT_SUCCESS)
1293 {
1294 result = FSi_ROMFAT_SeekDirectory(arc, file, id, 0);
1295 }
1296 (void)mode;
1297 return result;
1298 }
1299
1300 /*---------------------------------------------------------------------------*
1301 Name: FSi_ROMFAT_CloseDirectory
1302
1303 Description: The FS_COMMAND_CLOSEDIRECTORY command.
1304
1305 Arguments: arc: Calling archive
1306 file: Target file
1307
1308 Returns: The processing result for the command.
1309 *---------------------------------------------------------------------------*/
FSi_ROMFAT_CloseDirectory(FSArchive * arc,FSFile * file)1310 static FSResult FSi_ROMFAT_CloseDirectory(FSArchive *arc, FSFile *file)
1311 {
1312 FS_DetachHandle(file);
1313 (void)arc;
1314 return FS_RESULT_SUCCESS;
1315 }
1316
1317 /*---------------------------------------------------------------------------*
1318 Name: FSi_ROMFAT_GetPathInfo
1319
1320 Description: The FS_COMMAND_GETPATHINFO command.
1321
1322 Arguments: arc: Calling archive
1323 baseid: Base directory ID (0 for the root)
1324 path: Path
1325 info: Location to save file information
1326
1327 Returns: The processing result for the command.
1328 *---------------------------------------------------------------------------*/
FSi_ROMFAT_GetPathInfo(FSArchive * arc,u32 baseid,const char * path,FSPathInfo * info)1329 static FSResult FSi_ROMFAT_GetPathInfo(FSArchive *arc, u32 baseid, const char *path, FSPathInfo *info)
1330 {
1331 FSResult result = FS_RESULT_ERROR;
1332 u32 id = 0;
1333 MI_CpuFill8(info, 0x00, sizeof(*info));
1334 // Very inefficient; Better to call the function separately
1335 if (FSi_ROMFAT_FindPath(arc, baseid, path, &id, TRUE) == FS_RESULT_SUCCESS)
1336 {
1337 info->attributes = FS_ATTRIBUTE_IS_DIRECTORY;
1338 info->id = id;
1339 result = FS_RESULT_SUCCESS;
1340 }
1341 else if (FSi_ROMFAT_FindPath(arc, baseid, path, &id, FALSE) == FS_RESULT_SUCCESS)
1342 {
1343 info->attributes = 0;
1344 info->id = id;
1345 info->filesize = 0;
1346 // If a valid file ID, get file size information from FAT
1347 {
1348 FSROMFATArchiveContext *context = (FSROMFATArchiveContext*)FS_GetArchiveUserData(arc);
1349 u32 pos = (u32)(id * sizeof(FSArchiveFAT));
1350 if (pos < context->fat_size)
1351 {
1352 FSArchiveFAT fat;
1353 FSiSyncReadParam param;
1354 param.arc = arc;
1355 param.pos = context->fat + pos;
1356 if (FSi_ReadTable(¶m, &fat, sizeof(fat)) == FS_RESULT_SUCCESS)
1357 {
1358 info->filesize = (u32)(fat.bottom - fat.top);
1359 // If running in NTR mode, record with a flag that the TWL dedicated region is not read
1360 if (FSi_IsUnreadableRomOffset(arc, fat.top))
1361 {
1362 info->attributes |= FS_ATTRIBUTE_IS_OFFLINE;
1363 }
1364 }
1365 }
1366 }
1367 result = FS_RESULT_SUCCESS;
1368 }
1369 // The NitroROM format archive prohibits writing by default
1370 info->attributes |= FS_ATTRIBUTE_IS_PROTECTED;
1371 return result;
1372 }
1373
1374 /*---------------------------------------------------------------------------*
1375 Name: FSi_ROMFAT_GetPathInfo
1376
1377 Description: The FATFS_COMMAND_GETARCHIVERESOURCE command.
1378
1379 Arguments: arc: Calling archive
1380 resource: Storage destination of resource information
1381
1382 Returns: The processing result for the command.
1383 *---------------------------------------------------------------------------*/
FSi_ROMFAT_GetArchiveResource(FSArchive * arc,FSArchiveResource * resource)1384 static FSResult FSi_ROMFAT_GetArchiveResource(FSArchive *arc, FSArchiveResource *resource)
1385 {
1386 const CARDRomHeader *header = (const CARDRomHeader *)CARD_GetRomHeader();
1387 resource->bytesPerSector = 0;
1388 resource->sectorsPerCluster = 0;
1389 resource->totalClusters = 0;
1390 resource->availableClusters = 0;
1391 resource->totalSize = header->rom_size;
1392 resource->availableSize = 0;
1393 resource->maxFileHandles = 0x7FFFFFFF;
1394 resource->currentFileHandles = 0;
1395 resource->maxDirectoryHandles = 0x7FFFFFFF;
1396 resource->currentDirectoryHandles = 0;
1397 (void)arc;
1398 return FS_RESULT_SUCCESS;
1399 }
1400
1401 /*---------------------------------------------------------------------------*
1402 Name: FSi_ReadSRLCallback
1403
1404 Description: SRL file read callback
1405
1406 Arguments: p_arc FSArchive structure
1407 dst Transfer destination
1408 src Transfer source
1409 len: Transfer size
1410
1411 Returns: Read process results
1412 *---------------------------------------------------------------------------*/
FSi_ReadSRLCallback(FSArchive * arc,void * buffer,u32 offset,u32 length)1413 static FSResult FSi_ReadSRLCallback(FSArchive *arc, void *buffer, u32 offset, u32 length)
1414 {
1415 CARDRomHashContext *hash = (CARDRomHashContext*)FS_GetArchiveBase(arc);
1416 CARD_ReadRomHashImage(hash, buffer, offset, length);
1417 return FS_RESULT_SUCCESS;
1418 }
1419
1420 /*---------------------------------------------------------------------------*
1421 Name: FSi_SRLArchiveProc
1422
1423 Description: SRL file archive procedure
1424
1425 Arguments: file FSFile structure that stores command information
1426 cmd: Command type.
1427
1428 Returns: Command processing result
1429 *---------------------------------------------------------------------------*/
FSi_SRLArchiveProc(FSFile * file,FSCommandType cmd)1430 static FSResult FSi_SRLArchiveProc(FSFile *file, FSCommandType cmd)
1431 {
1432 (void)file;
1433 switch (cmd)
1434 {
1435 case FS_COMMAND_WRITEFILE:
1436 return FS_RESULT_UNSUPPORTED;
1437 default:
1438 return FS_RESULT_PROC_UNKNOWN;
1439 }
1440 }
1441
1442 /*---------------------------------------------------------------------------*
1443 Name: FSi_MountSRLFile
1444
1445 Description: Mount the ROM file system that is included in the SRL file
1446
1447 Arguments: arc FSArchive structure used in mounting
1448 Names must have been registered
1449 file File targeted for mounting and that is already open
1450 Do not destroy this structure while mounting
1451 hash Hash context structure
1452
1453 Returns: TRUE if the process is successful.
1454 *---------------------------------------------------------------------------*/
FSi_MountSRLFile(FSArchive * arc,FSFile * file,CARDRomHashContext * hash)1455 BOOL FSi_MountSRLFile(FSArchive *arc, FSFile *file, CARDRomHashContext *hash)
1456 {
1457 BOOL retval = FALSE;
1458 static CARDRomHeaderTWL header[1] ATTRIBUTE_ALIGN(32);
1459 if (file &&
1460 (FS_SeekFileToBegin(file) &&
1461 (FS_ReadFile(file, header, sizeof(header)) == sizeof(header))))
1462 {
1463 // For security, NAND applications require a hash table
1464 // When a ROM that runs in NITRO-compatible mode and uses the file system is developed, we will consider adoption
1465 //
1466 if ((((const u8 *)header)[0x1C] & 0x01) != 0)
1467 {
1468 FSResult (*proc)(FSFile*, FSCommandType) = FSi_SRLArchiveProc;
1469 FSResult (*read)(FSArchive*, void*, u32, u32) = FSi_ReadSRLCallback;
1470 FSResult (*write)(FSArchive*, const void*, u32, u32) = NULL;
1471 FS_SetArchiveProc(arc, proc, FS_ARCHIVE_PROC_WRITEFILE);
1472 // Access change is created in the order of arc -> hash -> files
1473 if (FS_LoadArchive(arc, (u32)hash,
1474 header->ntr.fat.offset, header->ntr.fat.length,
1475 header->ntr.fnt.offset, header->ntr.fnt.length,
1476 read, write))
1477 {
1478 // If different from the ROM header of the system work region, the buffer allocated by the CARDi_InitRom function is wasted
1479 //
1480 extern u8 *CARDiHashBufferAddress;
1481 extern u32 CARDiHashBufferLength;
1482 u32 len = CARD_CalcRomHashBufferLength(header);
1483 if (len > CARDiHashBufferLength)
1484 {
1485 u8 *lo = (u8 *)MATH_ROUNDUP((u32)OS_GetMainArenaLo(), 32);
1486 u8 *hi = (u8 *)MATH_ROUNDDOWN((u32)OS_GetMainArenaHi(), 32);
1487 if (&lo[len] > hi)
1488 {
1489 OS_TPanic("cannot allocate memory for ROM-hash from ARENA");
1490 }
1491 else
1492 {
1493 OS_SetMainArenaLo(&lo[len]);
1494 CARDiHashBufferAddress = lo;
1495 CARDiHashBufferLength = len;
1496 }
1497 }
1498 CARD_InitRomHashContext(hash, header,
1499 CARDiHashBufferAddress, CARDiHashBufferLength,
1500 FSi_SeekAndReadSRL, NULL, file);
1501 // Destroy the pointer so that there is no competition for use of the same buffer
1502 CARDiHashBufferAddress = NULL;
1503 CARDiHashBufferLength = 0;
1504 retval = TRUE;
1505 }
1506 }
1507 }
1508 return retval;
1509 }
1510
1511 /*---------------------------------------------------------------------------*
1512 Name: FSi_ReadMemCallback
1513
1514 Description: Default memory read callback
1515
1516 Arguments: p_arc: Archive on which to operate
1517 dst: Storage destination of the memory to read
1518 pos Read position
1519 size Size to read
1520
1521 Returns: Always FS_RESULT_SUCCESS
1522 *---------------------------------------------------------------------------*/
FSi_ReadMemCallback(FSArchive * p_arc,void * dst,u32 pos,u32 size)1523 static FSResult FSi_ReadMemCallback(FSArchive *p_arc, void *dst, u32 pos, u32 size)
1524 {
1525 MI_CpuCopy8((const void *)FS_GetArchiveOffset(p_arc, pos), dst, size);
1526 return FS_RESULT_SUCCESS;
1527 }
1528
1529 /*---------------------------------------------------------------------------*
1530 Name: FSi_WriteMemCallback
1531
1532 Description: Default memory write callback
1533
1534 Arguments: p_arc: Archive on which to operate
1535 dst: Reference destination of the memory to write
1536 pos: Write location
1537 size Size to write
1538
1539 Returns: Always FS_RESULT_SUCCESS
1540 *---------------------------------------------------------------------------*/
FSi_WriteMemCallback(FSArchive * p_arc,const void * src,u32 pos,u32 size)1541 static FSResult FSi_WriteMemCallback(FSArchive *p_arc, const void *src, u32 pos, u32 size)
1542 {
1543 MI_CpuCopy8(src, (void *)FS_GetArchiveOffset(p_arc, pos), size);
1544 return FS_RESULT_SUCCESS;
1545 }
1546
1547 static const FSArchiveInterface FSiArchiveProcInterface =
1548 {
1549 // Commands that are compatible with the old specifications
1550 FSi_ROMFAT_ReadFile,
1551 FSi_ROMFAT_WriteFile,
1552 FSi_ROMFAT_SeekDirectory,
1553 FSi_ROMFAT_ReadDirectory,
1554 FSi_ROMFAT_FindPath,
1555 FSi_ROMFAT_GetPath,
1556 FSi_ROMFAT_OpenFileFast,
1557 FSi_ROMFAT_OpenFileDirect,
1558 FSi_ROMFAT_CloseFile,
1559 FSi_ROMFAT_Activate,
1560 FSi_ROMFAT_Idle,
1561 FSi_ROMFAT_Suspend,
1562 FSi_ROMFAT_Resume,
1563 // New commands that are compatible with the old specifications
1564 FSi_ROMFAT_OpenFile,
1565 FSi_ROMFAT_SeekFile,
1566 FSi_ROMFAT_GetFileLength,
1567 FSi_ROMFAT_GetFilePosition,
1568 // Commands extended by the new specifications (UNSUPPORTED if NULL)
1569 NULL, // Mount
1570 FSi_ROMFAT_Unmount,
1571 FSi_ROMFAT_GetArchiveCaps,
1572 NULL, // CreateFile
1573 NULL, // DeleteFile
1574 NULL, // RenameFile
1575 FSi_ROMFAT_GetPathInfo,
1576 NULL, // SetFileInfo
1577 NULL, // CreateDirectory
1578 NULL, // DeleteDirectory
1579 NULL, // RenameDirectory
1580 FSi_ROMFAT_GetArchiveResource,
1581 NULL, // 29UL
1582 NULL, // FlushFile
1583 NULL, // SetFileLength
1584 FSi_ROMFAT_OpenDirectory,
1585 FSi_ROMFAT_CloseDirectory,
1586 };
1587
1588 /*---------------------------------------------------------------------------*
1589 Name: FS_LoadArchive
1590
1591 Description: Loads the archive into the file system.
1592 Its name must already be registered on the archive list.
1593
1594 Arguments: arc Archive to load
1595 base Any u32 value that can be uniquely used.
1596 fat Starting offset of the FAT table
1597 fat_size Size of FAT table
1598 fat Starting offset of the FNT table
1599 fat_size Size of FNT table
1600 read_func Read access callback.
1601 write_func Write access callback
1602
1603 Returns: TRUE if archive is loaded correctly
1604 *---------------------------------------------------------------------------*/
FS_LoadArchive(FSArchive * arc,u32 base,u32 fat,u32 fat_size,u32 fnt,u32 fnt_size,FS_ARCHIVE_READ_FUNC read_func,FS_ARCHIVE_WRITE_FUNC write_func)1605 BOOL FS_LoadArchive(FSArchive *arc, u32 base,
1606 u32 fat, u32 fat_size,
1607 u32 fnt, u32 fnt_size,
1608 FS_ARCHIVE_READ_FUNC read_func, FS_ARCHIVE_WRITE_FUNC write_func)
1609 {
1610 BOOL retval = FALSE;
1611 SDK_ASSERT(FS_IsAvailable());
1612 SDK_NULL_ASSERT(arc);
1613 SDK_ASSERT(!FS_IsArchiveLoaded(arc));
1614
1615 // Initialize information for archive
1616 {
1617 FSROMFATArchiveContext *context = (FSROMFATArchiveContext*)arc->reserved2;
1618 context->base = base;
1619 context->fat_size = fat_size;
1620 context->fat = fat;
1621 context->fat_bak = fat;
1622 context->fnt_size = fnt_size;
1623 context->fnt = fnt;
1624 context->fnt_bak = fnt;
1625 context->read_func = read_func ? read_func : FSi_ReadMemCallback;
1626 context->write_func = write_func ? write_func : FSi_WriteMemCallback;
1627 context->load_mem = NULL;
1628 return FS_MountArchive(arc, context, &FSiArchiveProcInterface, 0);
1629 }
1630 return retval;
1631 }
1632
1633 /*---------------------------------------------------------------------------*
1634 Name: FS_UnloadArchive
1635
1636 Description: Unload the archive from the file system.
1637 Block until all currently running tasks are completed.
1638
1639 Arguments: arc Archive to unload
1640
1641 Returns: TRUE if archive is unloaded correctly.
1642 *---------------------------------------------------------------------------*/
FS_UnloadArchive(FSArchive * arc)1643 BOOL FS_UnloadArchive(FSArchive *arc)
1644 {
1645 return FS_UnmountArchive(arc);
1646 }
1647
1648 /*---------------------------------------------------------------------------*
1649 Name: FSi_GetFileLengthIfProc
1650
1651 Description: If the specified file is an archive procedure, gets the size.
1652
1653 Arguments: file: File handle
1654 length: Storage destination of the size
1655
1656 Returns: If the specified file is an archive procedure, returns its size.
1657 *---------------------------------------------------------------------------*/
FSi_GetFileLengthIfProc(FSFile * file,u32 * length)1658 BOOL FSi_GetFileLengthIfProc(FSFile *file, u32 *length)
1659 {
1660 return (file->arc->vtbl == &FSiArchiveProcInterface) &&
1661 (FSi_ROMFAT_GetFileLength(file->arc, file, length) == FS_RESULT_SUCCESS);
1662 }
1663
1664 /*---------------------------------------------------------------------------*
1665 Name: FSi_GetFilePositionIfProc
1666
1667 Description: If the specified file is an archive procedure, gets the current position.
1668
1669 Arguments: file: File handle
1670 length: Storage destination of the size
1671
1672 Returns: If the specified file is an archive procedure, returns its current position.
1673 *---------------------------------------------------------------------------*/
FSi_GetFilePositionIfProc(FSFile * file,u32 * length)1674 BOOL FSi_GetFilePositionIfProc(FSFile *file, u32 *length)
1675 {
1676 return (file->arc->vtbl == &FSiArchiveProcInterface) &&
1677 (FSi_ROMFAT_GetFilePosition(file->arc, file, length) == FS_RESULT_SUCCESS);
1678 }
1679
1680 /*---------------------------------------------------------------------------*
1681 Name: FSi_SeekFileIfProc
1682
1683 Description: If the specified file is an archive procedure, move the file pointer.
1684
1685 Arguments: file: File handle
1686 offset: Movement amount
1687 from: Starting point to seek from
1688
1689 Returns: TRUE if successful, FALSE otherwise
1690 *---------------------------------------------------------------------------*/
FSi_SeekFileIfProc(FSFile * file,s32 offset,FSSeekFileMode from)1691 BOOL FSi_SeekFileIfProc(FSFile *file, s32 offset, FSSeekFileMode from)
1692 {
1693 if (file->arc->vtbl == &FSiArchiveProcInterface){
1694 FSResult result;
1695
1696 result = FSi_ROMFAT_SeekFile(file->arc, file, (int*)&offset, from);
1697 file->error = result;
1698 file->arc->result = result;
1699 if (result == FS_RESULT_SUCCESS)
1700 {
1701 return TRUE;
1702 }
1703 }
1704 return FALSE;
1705 }
1706
1707 /*---------------------------------------------------------------------------*
1708 Name: FS_SetArchiveProc
1709
1710 Description: Sets the archive's user procedure.
1711 If proc is NULL or flags is 0, this will simply disable the user procedure.
1712
1713
1714 Arguments: arc Archive for which to set the user procedure.
1715 proc User procedure.
1716 flags Bit collection of commands that hook to procedures.
1717
1718 Returns: Always returns the total table size.
1719 *---------------------------------------------------------------------------*/
FS_SetArchiveProc(FSArchive * arc,FS_ARCHIVE_PROC_FUNC proc,u32 flags)1720 void FS_SetArchiveProc(FSArchive *arc, FS_ARCHIVE_PROC_FUNC proc, u32 flags)
1721 {
1722 FSROMFATArchiveContext *context = (FSROMFATArchiveContext*)arc->reserved2;
1723 if (!flags)
1724 {
1725 proc = NULL;
1726 }
1727 else if (!proc)
1728 {
1729 flags = 0;
1730 }
1731 context->proc = proc;
1732 context->proc_flag = flags;
1733 }
1734
1735 /*---------------------------------------------------------------------------*
1736 Name: FS_LoadArchiveTables
1737
1738 Description: Preloads archive FAT + FNT in memory.
1739 Only if within specified size, execute the load and return the required size.
1740
1741 Arguments: p_arc Archive that will preload table.
1742 p_mem Storage destination buffer for table data
1743 max_size p_mem size
1744
1745 Returns: Always returns the total table size.
1746 *---------------------------------------------------------------------------*/
FS_LoadArchiveTables(FSArchive * p_arc,void * p_mem,u32 max_size)1747 u32 FS_LoadArchiveTables(FSArchive *p_arc, void *p_mem, u32 max_size)
1748 {
1749 SDK_ASSERT(FS_IsAvailable());
1750 SDK_NULL_ASSERT(p_arc);
1751
1752 // If this is a table that has already been loaded, unload it
1753 if ((p_mem != NULL) && FS_IsArchiveTableLoaded(p_arc))
1754 {
1755 (void)FS_UnloadArchiveTables(p_arc);
1756 }
1757
1758 {
1759 FSROMFATArchiveContext *context = (FSROMFATArchiveContext*)FS_GetArchiveUserData(p_arc);
1760 // The preload size is 32-byte aligned.
1761 u32 total_size = (u32)((context->fat_size + context->fnt_size + 32 + 31) & ~31);
1762 if (total_size <= max_size)
1763 {
1764 // If the size is sufficient, load into memory.
1765 u8 *p_cache = (u8 *)(((u32)p_mem + 31) & ~31);
1766 FSFile tmp;
1767 FS_InitFile(&tmp);
1768 // Sometimes the table cannot be read.
1769 // * In that case, nothing is done because the table could not be accessed originally.
1770 if (FS_OpenFileDirect(&tmp, p_arc, context->fat, context->fat + context->fat_size, (u32)~0))
1771 {
1772 if (FS_ReadFile(&tmp, p_cache, (s32)context->fat_size) < 0)
1773 {
1774 MI_CpuFill8(p_cache, 0x00, context->fat_size);
1775 }
1776 (void)FS_CloseFile(&tmp);
1777 }
1778 context->fat = (u32)p_cache;
1779 p_cache += context->fat_size;
1780 if (FS_OpenFileDirect(&tmp, p_arc, context->fnt, context->fnt + context->fnt_size, (u32)~0))
1781 {
1782 if (FS_ReadFile(&tmp, p_cache, (s32)context->fnt_size) < 0)
1783 {
1784 MI_CpuFill8(p_cache, 0x00, context->fnt_size);
1785 }
1786 (void)FS_CloseFile(&tmp);
1787 }
1788 context->fnt = (u32)p_cache;
1789 // Thereafter, preload memory will be used with table read functions.
1790 context->load_mem = p_mem;
1791 p_arc->flag |= FS_ARCHIVE_FLAG_TABLE_LOAD;
1792 }
1793 return total_size;
1794 }
1795 }
1796
1797 /*---------------------------------------------------------------------------*
1798 Name: FS_UnloadArchiveTables
1799
1800 Description: Deallocates the archive's preloaded memory.
1801
1802 Arguments: arc Archive with preloaded memory to release.
1803
1804 Returns: Buffer given by the user as preloaded memory.
1805 *---------------------------------------------------------------------------*/
FS_UnloadArchiveTables(FSArchive * arc)1806 void *FS_UnloadArchiveTables(FSArchive *arc)
1807 {
1808 void *retval = NULL;
1809
1810 SDK_ASSERT(FS_IsAvailable());
1811 SDK_NULL_ASSERT(arc);
1812
1813 if (FS_IsArchiveLoaded(arc))
1814 {
1815 FSROMFATArchiveContext *context = (FSROMFATArchiveContext*)FS_GetArchiveUserData(arc);
1816 BOOL bak_stat = FS_SuspendArchive(arc);
1817 if (FS_IsArchiveTableLoaded(arc))
1818 {
1819 arc->flag &= ~FS_ARCHIVE_FLAG_TABLE_LOAD;
1820 retval = context->load_mem;
1821 context->fat = context->fat_bak;
1822 context->fnt = context->fnt_bak;
1823 context->load_mem = NULL;
1824 }
1825 if (bak_stat)
1826 {
1827 (void)FS_ResumeArchive(arc);
1828 }
1829 }
1830 return retval;
1831 }
1832
1833 /*---------------------------------------------------------------------------*
1834 Name: FS_GetArchiveBase
1835
1836 Description: Gets ROMFAT-type archive base offset
1837
1838 Arguments: arc ROMFAT-type archive
1839
1840 Returns: ROMFAT-type archive base offset
1841 *---------------------------------------------------------------------------*/
FS_GetArchiveBase(const struct FSArchive * arc)1842 u32 FS_GetArchiveBase(const struct FSArchive *arc)
1843 {
1844 FSROMFATArchiveContext *context = (FSROMFATArchiveContext*)FS_GetArchiveUserData(arc);
1845 return context->base;
1846 }
1847
1848 /*---------------------------------------------------------------------------*
1849 Name: FS_GetArchiveFAT
1850
1851 Description: Gets ROMFAT-type archive FAT offset
1852
1853 Arguments: arc ROMFAT-type archive
1854
1855 Returns: ROMFAT-type archive FAT offset
1856 *---------------------------------------------------------------------------*/
FS_GetArchiveFAT(const struct FSArchive * arc)1857 u32 FS_GetArchiveFAT(const struct FSArchive *arc)
1858 {
1859 FSROMFATArchiveContext *context = (FSROMFATArchiveContext*)FS_GetArchiveUserData(arc);
1860 return context->fat;
1861 }
1862
1863 /*---------------------------------------------------------------------------*
1864 Name: FS_GetArchiveFNT
1865
1866 Description: Gets ROMFAT-type archive FNT offset
1867
1868 Arguments: arc ROMFAT-type archive
1869
1870 Returns: ROMFAT-type archive FNT offset
1871 *---------------------------------------------------------------------------*/
FS_GetArchiveFNT(const struct FSArchive * arc)1872 u32 FS_GetArchiveFNT(const struct FSArchive *arc)
1873 {
1874 FSROMFATArchiveContext *context = (FSROMFATArchiveContext*)FS_GetArchiveUserData(arc);
1875 return context->fnt;
1876 }
1877
1878 /* Obtain specified position offset from the archive's base */
1879 /*---------------------------------------------------------------------------*
1880 Name: FS_GetArchiveOffset
1881
1882 Description: Gets specified position offset from the ROMFAT-type archive's base
1883
1884 Arguments: arc ROMFAT-type archive
1885
1886 Returns: Specified position offset with the archive base added
1887 *---------------------------------------------------------------------------*/
FS_GetArchiveOffset(const struct FSArchive * arc,u32 pos)1888 u32 FS_GetArchiveOffset(const struct FSArchive *arc, u32 pos)
1889 {
1890 FSROMFATArchiveContext *context = (FSROMFATArchiveContext*)FS_GetArchiveUserData(arc);
1891 return context->base + pos;
1892 }
1893
1894 /*---------------------------------------------------------------------------*
1895 Name: FS_IsArchiveTableLoaded
1896
1897 Description: Determines whether the ROMFAT-type archive has finished preloading the table.
1898
1899 Arguments: arc ROMFAT-type archive
1900
1901 Returns: TRUE if the table has been preloaded
1902 *---------------------------------------------------------------------------*/
FS_IsArchiveTableLoaded(volatile const struct FSArchive * arc)1903 BOOL FS_IsArchiveTableLoaded(volatile const struct FSArchive *arc)
1904 {
1905 return ((arc->flag & FS_ARCHIVE_FLAG_TABLE_LOAD) != 0);
1906 }
1907
1908 /*---------------------------------------------------------------------------*
1909 Name: FS_GetFileImageTop
1910
1911 Description: Gets the top offset of the file opened from the ROMFAT-type archive
1912
1913
1914 Arguments: file: File handle
1915
1916 Returns: File top offset on the archive
1917 *---------------------------------------------------------------------------*/
FS_GetFileImageTop(const struct FSFile * file)1918 u32 FS_GetFileImageTop(const struct FSFile *file)
1919 {
1920 return file->prop.file.top;
1921 }
1922
1923 /*---------------------------------------------------------------------------*
1924 Name: FS_GetFileImageBottom
1925
1926 Description: Gets the bottom offset of the file opened from the ROMFAT-type archive
1927
1928
1929 Arguments: file: File handle
1930
1931 Returns: File bottom offset on the archive
1932 *---------------------------------------------------------------------------*/
FS_GetFileImageBottom(const struct FSFile * file)1933 u32 FS_GetFileImageBottom(const struct FSFile *file)
1934 {
1935 return file->prop.file.bottom;
1936 }
1937
1938
1939 #endif /* FS_IMPLEMENT */
1940