1 /*---------------------------------------------------------------------------*
2 Project: TwlSDK - FS - libraries
3 File: fs_file.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:: 2009-09-30#$
14 $Rev: 11077 $
15 $Author: yosizaki $
16
17 *---------------------------------------------------------------------------*/
18
19
20 #include <nitro/types.h>
21 #include <nitro/misc.h>
22 #include <nitro/mi.h>
23 #include <nitro/os.h>
24 #include <nitro/pxi.h>
25 #include <nitro/std/string.h>
26 #include <nitro/std/unicode.h>
27 #include <nitro/math/math.h>
28
29 #include <nitro/fs.h>
30
31 #include "../include/rom.h"
32 #include "../include/util.h"
33 #include "../include/command.h"
34
35
36 #define FS_DEBUG_TRACE(...) (void)0
37 //#define FS_DEBUG_TRACE OS_TPrintf
38
39
40 /*---------------------------------------------------------------------------*/
41 /* Functions */
42
43 #if defined(FS_IMPLEMENT)
44
45 /*---------------------------------------------------------------------------*
46 Name: FSi_IsValidTransferRegion
47
48 Description: Simple determination whether buffer used in read/write operations is in a dangerous range.
49
50 Arguments: buffer: Buffer targeted for transfer
51 length: Transfer size
52
53 Returns: pos is either one returned character from the referenced position or -1.
54 *---------------------------------------------------------------------------*/
FSi_IsValidTransferRegion(const void * buffer,s32 length)55 static BOOL FSi_IsValidTransferRegion(const void *buffer, s32 length)
56 {
57 BOOL retval = FALSE;
58 if (buffer == NULL)
59 {
60 OS_TWarning("specified transfer buffer is NULL.\n");
61 }
62 else if (((u32)buffer >= HW_IOREG) && ((u32)buffer < HW_IOREG_END))
63 {
64 OS_TWarning("specified transfer buffer is in I/O register %08X. (seems to be dangerous)\n", buffer);
65 }
66 else if (length < 0)
67 {
68 OS_TWarning("specified transfer size is minus. (%d)\n", length);
69 }
70 else
71 {
72 #if !defined(SDK_TWL)
73 s32 mainmem_size = HW_MAIN_MEM_EX_SIZE;
74 #else
75 s32 mainmem_size = OS_IsRunOnTwl() ? HW_TWL_MAIN_MEM_EX_SIZE : HW_MAIN_MEM_EX_SIZE;
76 #endif
77 if (length > mainmem_size)
78 {
79 OS_TWarning("specified transfer size is over mainmemory-size. (%d)\n", length);
80 }
81 else
82 {
83 retval = TRUE;
84 }
85 }
86 return retval;
87 }
88
89 /*---------------------------------------------------------------------------*
90 Name: FSi_DecrementSjisPosition
91
92 Description: Returns one character from the Shift_JIS string reference position.
93
94 Arguments: str: Pointer indicating the start of the Shift_JIS string
95 pos: Current string reference position (in bytes)
96
97 Returns: pos is either one returned character from the referenced position or -1.
98 *---------------------------------------------------------------------------*/
FSi_DecrementSjisPosition(const char * str,int pos)99 int FSi_DecrementSjisPosition(const char *str, int pos)
100 {
101 // First, go back by just a one-byte amount
102 int prev = --pos;
103 // The separation of characters in Shift_JIS is either by single bytes or successive bytes. Because the leading byte and subsequent byte share a portion of their mapping, the character type cannot be confirmed while that position appears to be the leading byte, so focus goes back farther
104 //
105 //
106 for (; (prev > 0) && STD_IsSjisLeadByte(str[prev - 1]); --prev)
107 {
108 }
109 // When there is a series of double-byte characters with unclear subsequent bytes, such as "===b," this goes back too far by a multiple of 2, so ignore it.
110 // (Take a multiplier of 2)
111 return pos - ((pos - prev) & 1);
112 }
113
114 /*---------------------------------------------------------------------------*
115 Name: FSi_IncrementSjisPositionToSlash
116
117 Description: Advances reference position of Shift_JIS string to either directory delimiter or end.
118
119
120 Arguments: str: Pointer indicating the start of the Shift_JIS string
121 pos: Current string reference position (in bytes)
122
123 Returns: Either first directory delimiter that appears after pos or the end position.
124 *---------------------------------------------------------------------------*/
FSi_IncrementSjisPositionToSlash(const char * str,int pos)125 int FSi_IncrementSjisPositionToSlash(const char *str, int pos)
126 {
127 while (str[pos] && !FSi_IsSlash((u8)str[pos]))
128 {
129 pos = FSi_IncrementSjisPosition(str, pos);
130 }
131 return pos;
132 }
133
134 /*---------------------------------------------------------------------------*
135 Name: FSi_DecrementSjisPositionToSlash
136
137 Description: Return reference position of Shift_JIS string to either directory separator character or beginning.
138
139
140 Arguments: str: Pointer indicating the start of the Shift_JIS string
141 pos: Current string reference position (in bytes)
142
143 Returns: Either first directory delimiter that appears before pos or -1.
144 *---------------------------------------------------------------------------*/
FSi_DecrementSjisPositionToSlash(const char * str,int pos)145 int FSi_DecrementSjisPositionToSlash(const char *str, int pos)
146 {
147 for (;;)
148 {
149 pos = FSi_DecrementSjisPosition(str, pos);
150 if ((pos < 0) || FSi_IsSlash((u8)str[pos]))
151 {
152 break;
153 }
154 }
155 return pos;
156 }
157
158 /*---------------------------------------------------------------------------*
159 Name: FSi_TrimSjisTrailingSlash
160
161 Description: Deletes if end of Shift_JIS string is a directory delimiter.
162
163 Arguments: str: Shift_JIS string
164
165 Returns: Length of string.
166 *---------------------------------------------------------------------------*/
FSi_TrimSjisTrailingSlash(char * str)167 int FSi_TrimSjisTrailingSlash(char *str)
168 {
169 int length = STD_GetStringLength(str);
170 int lastpos = FSi_DecrementSjisPosition(str, length);
171 if ((lastpos >= 0) && FSi_IsSlash((u8)str[lastpos]))
172 {
173 length = lastpos;
174 str[length] = '\0';
175 }
176 return length;
177 }
178
179 /*---------------------------------------------------------------------------*
180 Name: FSi_DecrementUnicodePosition
181
182 Description: Returns one character of the Unicode string reference position.
183
184 Arguments: str: Pointer indicating the start of the Unicode string
185 pos: Current string reference position (in bytes)
186
187 Returns: pos is either one returned character from the referenced position or -1.
188 *---------------------------------------------------------------------------*/
FSi_DecrementUnicodePosition(const u16 * str,int pos)189 int FSi_DecrementUnicodePosition(const u16 *str, int pos)
190 {
191 // First, securely return the amount of 1 character
192 int prev = --pos;
193 // Return one more character if valid surrogate pair
194 if ((pos > 0) &&
195 ((str[pos - 1] >= 0xD800) && (str[pos - 1] <= 0xDC00)) &&
196 ((str[pos - 0] >= 0xDC00) && (str[pos - 0] <= 0xE000)))
197 {
198 --pos;
199 }
200 return pos;
201 }
202
203 /*---------------------------------------------------------------------------*
204 Name: FSi_DecrementUnicodePositionToSlash
205
206 Description: Returns reference position of Unicode string to either directory delimiter or beginning.
207
208
209 Arguments: str: Pointer indicating the start of the Unicode string
210 pos: Current string reference position (in bytes)
211
212 Returns: Either first directory delimiter that appears before pos or -1.
213 *---------------------------------------------------------------------------*/
FSi_DecrementUnicodePositionToSlash(const u16 * str,int pos)214 int FSi_DecrementUnicodePositionToSlash(const u16 *str, int pos)
215 {
216 for (;;)
217 {
218 pos = FSi_DecrementUnicodePosition(str, pos);
219 if ((pos < 0) || FSi_IsUnicodeSlash(str[pos]))
220 {
221 break;
222 }
223 }
224 return pos;
225 }
226
227 /*---------------------------------------------------------------------------*
228 Name: FS_InitFile
229
230 Description: Initializes the FSFile structure.
231
232 Arguments: file: FSFile structure
233
234 Returns: None.
235 *---------------------------------------------------------------------------*/
FS_InitFile(FSFile * file)236 void FS_InitFile(FSFile *file)
237 {
238 SDK_NULL_ASSERT(file);
239 {
240 file->arc = NULL;
241 file->userdata = NULL;
242 file->next = NULL;
243 OS_InitThreadQueue(file->queue);
244 file->stat = 0;
245 file->stat |= (FS_COMMAND_INVALID << FS_FILE_STATUS_CMD_SHIFT);
246 file->argument = NULL;
247 file->error = FS_RESULT_SUCCESS;
248 }
249 }
250
251 /*---------------------------------------------------------------------------*
252 Name: FS_CancelFile
253
254 Description: Requests cancellation of an asynchronous command.
255
256 Arguments: file: File handle
257
258 Returns: None.
259 *---------------------------------------------------------------------------*/
FS_CancelFile(FSFile * file)260 void FS_CancelFile(FSFile *file)
261 {
262 SDK_NULL_ASSERT(file);
263 SDK_ASSERT(FS_IsAvailable());
264 {
265 OSIntrMode bak_psr = OS_DisableInterrupts();
266 if (FS_IsBusy(file))
267 {
268 file->stat |= FS_FILE_STATUS_CANCEL;
269 file->arc->flag |= FS_ARCHIVE_FLAG_CANCELING;
270 }
271 (void)OS_RestoreInterrupts(bak_psr);
272 }
273 }
274
275 /*---------------------------------------------------------------------------*
276 Name: FS_CreateFile
277
278 Description: Generates files.
279
280 Arguments: path: Path name
281 mode: Access mode
282
283 Returns: TRUE if file is generated normally.
284 *---------------------------------------------------------------------------*/
FS_CreateFile(const char * path,u32 permit)285 BOOL FS_CreateFile(const char *path, u32 permit)
286 {
287 BOOL retval = FALSE;
288 FS_DEBUG_TRACE( "%s(%s)\n", __FUNCTION__, path);
289 SDK_NULL_ASSERT(path);
290 SDK_ASSERT(OS_GetProcMode() != OS_PROCMODE_IRQ);
291 {
292 char relpath[FS_ARCHIVE_FULLPATH_MAX + 1];
293 u32 baseid = 0;
294 FSArchive *arc = FS_NormalizePath(path, &baseid, relpath);
295 if (arc)
296 {
297 FSFile file[1];
298 FSArgumentForCreateFile arg[1];
299 FS_InitFile(file);
300 file->arc = arc;
301 file->argument = arg;
302 arg->baseid = baseid;
303 arg->relpath = relpath;
304 arg->permit = permit;
305 retval = FSi_SendCommand(file, FS_COMMAND_CREATEFILE, TRUE);
306 }
307 }
308 return retval;
309 }
310
311 /*---------------------------------------------------------------------------*
312 Name: FS_DeleteFile
313
314 Description: Deletes files.
315
316 Arguments: path: Path name
317
318 Returns: TRUE if file is deleted normally.
319 *---------------------------------------------------------------------------*/
FS_DeleteFile(const char * path)320 BOOL FS_DeleteFile(const char *path)
321 {
322 BOOL retval = FALSE;
323 FS_DEBUG_TRACE( "%s(%s)\n", __FUNCTION__, path);
324 SDK_NULL_ASSERT(path);
325 SDK_ASSERT(OS_GetProcMode() != OS_PROCMODE_IRQ);
326 {
327 char relpath[FS_ARCHIVE_FULLPATH_MAX + 1];
328 u32 baseid = 0;
329 FSArchive *arc = FS_NormalizePath(path, &baseid, relpath);
330 if (arc)
331 {
332 FSFile file[1];
333 FSArgumentForDeleteFile arg[1];
334 FS_InitFile(file);
335 file->arc = arc;
336 file->argument = arg;
337 arg->baseid = baseid;
338 arg->relpath = relpath;
339 retval = FSi_SendCommand(file, FS_COMMAND_DELETEFILE, TRUE);
340 }
341 }
342 return retval;
343 }
344
345 /*---------------------------------------------------------------------------*
346 Name: FS_RenameFile
347
348 Description: Changes the filename.
349
350 Arguments: src: Filename of the conversion source
351 dst: Filename of the conversion target
352
353 Returns: TRUE if filename is changed normally.
354 *---------------------------------------------------------------------------*/
FS_RenameFile(const char * src,const char * dst)355 BOOL FS_RenameFile(const char *src, const char *dst)
356 {
357 BOOL retval = FALSE;
358 FS_DEBUG_TRACE( "%s(%s->%s)\n", __FUNCTION__, src, dst);
359 SDK_NULL_ASSERT(src);
360 SDK_NULL_ASSERT(dst);
361 SDK_ASSERT(OS_GetProcMode() != OS_PROCMODE_IRQ);
362 {
363 char relpath_src[FS_ARCHIVE_FULLPATH_MAX + 1];
364 char relpath_dst[FS_ARCHIVE_FULLPATH_MAX + 1];
365 u32 baseid_src = 0;
366 u32 baseid_dst = 0;
367 FSArchive *arc_src = FS_NormalizePath(src, &baseid_src, relpath_src);
368 FSArchive *arc_dst = FS_NormalizePath(dst, &baseid_dst, relpath_dst);
369 if (arc_src != arc_dst)
370 {
371 OS_TWarning("cannot rename between defferent archives.\n");
372 }
373 else
374 {
375 FSFile file[1];
376 FSArgumentForRenameFile arg[1];
377 FS_InitFile(file);
378 file->arc = arc_src;
379 file->argument = arg;
380 arg->baseid_src = baseid_src;
381 arg->relpath_src = relpath_src;
382 arg->baseid_dst = baseid_dst;
383 arg->relpath_dst = relpath_dst;
384 retval = FSi_SendCommand(file, FS_COMMAND_RENAMEFILE, TRUE);
385 }
386 }
387 return retval;
388 }
389
390 /*---------------------------------------------------------------------------*
391 Name: FS_GetPathInfo
392
393 Description: Gets file or directory information.
394
395 Arguments: path: Path name
396 info: Location to store the information
397
398 Returns: Processing result.
399 *---------------------------------------------------------------------------*/
FS_GetPathInfo(const char * path,FSPathInfo * info)400 BOOL FS_GetPathInfo(const char *path, FSPathInfo *info)
401 {
402 BOOL retval = FALSE;
403 FS_DEBUG_TRACE( "%s\n", __FUNCTION__);
404 SDK_NULL_ASSERT(path);
405 SDK_NULL_ASSERT(info);
406 SDK_ASSERT(OS_GetProcMode() != OS_PROCMODE_IRQ);
407 {
408 char relpath[FS_ARCHIVE_FULLPATH_MAX + 1];
409 u32 baseid = 0;
410 FSArchive *arc = FS_NormalizePath(path, &baseid, relpath);
411 if (arc)
412 {
413 FSFile file[1];
414 FSArgumentForGetPathInfo arg[1];
415 FS_InitFile(file);
416 file->arc = arc;
417 file->argument = arg;
418 arg->baseid = baseid;
419 arg->relpath = relpath;
420 arg->info = info;
421 retval = FSi_SendCommand(file, FS_COMMAND_GETPATHINFO, TRUE);
422 }
423 }
424 return retval;
425 }
426
427 /*---------------------------------------------------------------------------*
428 Name: FS_SetPathInfo
429
430 Description: Sets file information.
431
432 Arguments: path: Path name
433 info: Location to store the information
434
435 Returns: Processing result.
436 *---------------------------------------------------------------------------*/
FS_SetPathInfo(const char * path,const FSPathInfo * info)437 BOOL FS_SetPathInfo(const char *path, const FSPathInfo *info)
438 {
439 BOOL retval = FALSE;
440 FS_DEBUG_TRACE( "%s\n", __FUNCTION__);
441 SDK_NULL_ASSERT(path);
442 SDK_NULL_ASSERT(info);
443 SDK_ASSERT(OS_GetProcMode() != OS_PROCMODE_IRQ);
444 {
445 char relpath[FS_ARCHIVE_FULLPATH_MAX + 1];
446 u32 baseid = 0;
447 FSArchive *arc = FS_NormalizePath(path, &baseid, relpath);
448 if (arc)
449 {
450 FSFile file[1];
451 FSArgumentForSetPathInfo arg[1];
452 FS_InitFile(file);
453 file->arc = arc;
454 file->argument = arg;
455 arg->baseid = baseid;
456 arg->relpath = relpath;
457 arg->info = (FSPathInfo*)info; // To clear FATFS_PROPERTY_CTRL_MASK in info->attributes
458 retval = FSi_SendCommand(file, FS_COMMAND_SETPATHINFO, TRUE);
459 }
460 }
461 return retval;
462 }
463
464 /*---------------------------------------------------------------------------*
465 Name: FS_CreateDirectory
466
467 Description: Generates a directory.
468
469 Arguments: path: Path name
470 mode: Access mode
471
472 Returns: TRUE if directory is generated normally.
473 *---------------------------------------------------------------------------*/
FS_CreateDirectory(const char * path,u32 permit)474 BOOL FS_CreateDirectory(const char *path, u32 permit)
475 {
476 BOOL retval = FALSE;
477 FS_DEBUG_TRACE( "%s(%s)\n", __FUNCTION__, path);
478 SDK_NULL_ASSERT(path);
479 SDK_ASSERT(OS_GetProcMode() != OS_PROCMODE_IRQ);
480 {
481 char relpath[FS_ARCHIVE_FULLPATH_MAX + 1];
482 u32 baseid = 0;
483 FSArchive *arc = FS_NormalizePath(path, &baseid, relpath);
484 if (arc)
485 {
486 FSFile file[1];
487 FSArgumentForCreateDirectory arg[1];
488 FS_InitFile(file);
489 file->arc = arc;
490 file->argument = arg;
491 arg->baseid = baseid;
492 arg->relpath = relpath;
493 arg->permit = permit;
494 retval = FSi_SendCommand(file, FS_COMMAND_CREATEDIRECTORY, TRUE);
495 }
496 }
497 return retval;
498 }
499
500 /*---------------------------------------------------------------------------*
501 Name: FS_DeleteDirectory
502
503 Description: Deletes the directory.
504
505 Arguments: path: Path name
506
507 Returns: TRUE if directory is deleted normally.
508 *---------------------------------------------------------------------------*/
FS_DeleteDirectory(const char * path)509 BOOL FS_DeleteDirectory(const char *path)
510 {
511 BOOL retval = FALSE;
512 FS_DEBUG_TRACE( "%s(%s)\n", __FUNCTION__, path);
513 SDK_NULL_ASSERT(path);
514 SDK_ASSERT(OS_GetProcMode() != OS_PROCMODE_IRQ);
515 {
516 char relpath[FS_ARCHIVE_FULLPATH_MAX + 1];
517 u32 baseid = 0;
518 FSArchive *arc = FS_NormalizePath(path, &baseid, relpath);
519 if (arc)
520 {
521 FSFile file[1];
522 FSArgumentForDeleteDirectory arg[1];
523 FS_InitFile(file);
524 file->arc = arc;
525 file->argument = arg;
526 arg->baseid = baseid;
527 arg->relpath = relpath;
528 retval = FSi_SendCommand(file, FS_COMMAND_DELETEDIRECTORY, TRUE);
529 }
530 }
531 return retval;
532 }
533
534 /*---------------------------------------------------------------------------*
535 Name: FS_RenameDirectory
536
537 Description: Changes the directory name.
538
539 Arguments: src: Directory name of the conversion source
540 dst: Directory name of the conversion destination
541
542 Returns: TRUE if directory name is changed normally.
543 *---------------------------------------------------------------------------*/
FS_RenameDirectory(const char * src,const char * dst)544 BOOL FS_RenameDirectory(const char *src, const char *dst)
545 {
546 BOOL retval = FALSE;
547 FS_DEBUG_TRACE( "%s(%s->%s)\n", __FUNCTION__, src, dst);
548 SDK_NULL_ASSERT(src);
549 SDK_NULL_ASSERT(dst);
550 SDK_ASSERT(OS_GetProcMode() != OS_PROCMODE_IRQ);
551 {
552 char relpath_src[FS_ARCHIVE_FULLPATH_MAX + 1];
553 char relpath_dst[FS_ARCHIVE_FULLPATH_MAX + 1];
554 u32 baseid_src = 0;
555 u32 baseid_dst = 0;
556 FSArchive *arc_src = FS_NormalizePath(src, &baseid_src, relpath_src);
557 FSArchive *arc_dst = FS_NormalizePath(dst, &baseid_dst, relpath_dst);
558 if (arc_src != arc_dst)
559 {
560 OS_TWarning("cannot rename between defferent archives.\n");
561 }
562 else
563 {
564 FSFile file[1];
565 FSArgumentForRenameDirectory arg[1];
566 FS_InitFile(file);
567 file->arc = arc_src;
568 file->argument = arg;
569 arg->baseid_src = baseid_src;
570 arg->relpath_src = relpath_src;
571 arg->baseid_dst = baseid_dst;
572 arg->relpath_dst = relpath_dst;
573 retval = FSi_SendCommand(file, FS_COMMAND_RENAMEDIRECTORY, TRUE);
574 }
575 }
576 return retval;
577 }
578
579 /*---------------------------------------------------------------------------*
580 Name: FSi_GetFullPath
581
582 Description: Converts specified path to full path.
583
584 Arguments: dst: Buffer that stores obtained full path
585 Must be FS_ARCHIVE_FULLPATH_MAX+1 or higher
586 path: Path name of file or directory
587
588 Returns: TRUE if full path was obtained normally.
589 *---------------------------------------------------------------------------*/
FSi_GetFullPath(char * dst,const char * path)590 static BOOL FSi_GetFullPath(char *dst, const char *path)
591 {
592 FSArchive *arc = FS_NormalizePath(path, NULL, dst);
593 if (arc)
594 {
595 const char *arcname = FS_GetArchiveName(arc);
596 int m = STD_GetStringLength(arcname);
597 int n = STD_GetStringLength(dst);
598 (void)STD_MoveMemory(&dst[m + 2], &dst[0], (u32)n + 1);
599 (void)STD_MoveMemory(&dst[0], arcname, (u32)m);
600 dst[m + 0] = ':';
601 dst[m + 1] = '/';
602 }
603 return (arc != NULL);
604 }
605
606 /*---------------------------------------------------------------------------*
607 Name: FSi_ComplementDirectory
608
609 Description: Checks the existence of all parent directories up to the specified path; automatically generates and supplements nonexistent hierarchies.
610
611
612 Arguments: path: Path name of file or directory
613 Supplement a directory one level up from this
614 autogen: Buffer that records the highest directory that was generated automatically
615 Must be FS_ARCHIVE_FULLPATH_MAX+1 or higher
616 Results are returned to autogen regardless of their success or failure; if there is a blank string, it indicates that all results exist.
617
618
619 Returns: TRUE if directory is generated normally.
620 *---------------------------------------------------------------------------*/
FSi_ComplementDirectory(const char * path,char * autogen)621 static BOOL FSi_ComplementDirectory(const char *path, char *autogen)
622 {
623 BOOL retval = FALSE;
624 int root = 0;
625 // Normalize full path name for now. (Reuse autogen to conserve the stack)
626 char *tmppath = autogen;
627 if (FSi_GetFullPath(tmppath, path))
628 {
629 int length = STD_GetStringLength(tmppath);
630 if (length > 0)
631 {
632 int pos = 0;
633 FS_DEBUG_TRACE(" trying to complete \"%s\"\n", tmppath);
634 // Delete the "/" at the end
635 length = FSi_TrimSjisTrailingSlash(tmppath);
636 // Ignore the lowest entry
637 length = FSi_DecrementSjisPositionToSlash(tmppath, length);
638 // Search the deepest hierarchy that exists
639 for (pos = length; pos >= 0;)
640 {
641 FSPathInfo info[1];
642 BOOL exists;
643 tmppath[pos] = '\0';
644 exists = FS_GetPathInfo(tmppath, info);
645 FS_DEBUG_TRACE(" - \"%s\" is%s existent (result:%d)\n", tmppath, exists ? "" : " not",
646 FS_GetArchiveResultCode(tmppath));
647 tmppath[pos] = '/';
648 // If an entry does not exist, go to a higher level in hierarchy
649 if (!exists)
650 {
651 pos = FSi_DecrementSjisPositionToSlash(tmppath, pos);
652 }
653 // If something exists, stop the search for the time being
654 else
655 {
656 // If the same filename exists, certain failure
657 if ((info->attributes & FS_ATTRIBUTE_IS_DIRECTORY) == 0)
658 {
659 pos = -1;
660 }
661 // If the same directory name exists, automatically generate below that level
662 else
663 {
664 ++pos;
665 }
666 break;
667 }
668 }
669 // If a base point is called for, repeatedly generate one after that hierarchy
670 if (pos >= 0)
671 {
672 for (;;)
673 {
674 // If the end is reached, success
675 if (pos >= length)
676 {
677 retval = TRUE;
678 break;
679 }
680 else
681 {
682 pos = FSi_IncrementSjisPositionToSlash(tmppath, pos);
683 tmppath[pos] = '\0';
684 if (!FS_CreateDirectory(tmppath, FS_PERMIT_R | FS_PERMIT_W))
685 {
686 break;
687 }
688 else
689 {
690 // Store the highest hierarchy
691 if (root == 0)
692 {
693 FS_DEBUG_TRACE(" - we have created \"%s\" as root\n", tmppath);
694 root = pos;
695 }
696 tmppath[pos++] = '/';
697 }
698 }
699 }
700 }
701 }
702 }
703 // Record the highest directory automatically generated
704 autogen[root] = '\0';
705 return retval;
706 }
707
708 /*---------------------------------------------------------------------------*
709 Name: FS_CreateFileAuto
710
711 Description: Generates files including the necessary intermediate directories.
712
713 Arguments: path: Path name
714 permit: Access mode
715
716 Returns: TRUE if file is generated normally.
717 *---------------------------------------------------------------------------*/
FS_CreateFileAuto(const char * path,u32 permit)718 BOOL FS_CreateFileAuto(const char *path, u32 permit)
719 {
720 BOOL result = FALSE;
721 char autogen[FS_ARCHIVE_FULLPATH_MAX + 1];
722 FS_DEBUG_TRACE( "%s(%s)\n", __FUNCTION__, path);
723 if (FSi_ComplementDirectory(path, autogen))
724 {
725 result = FS_CreateFile(path, permit);
726 if (!result)
727 {
728 (void)FS_DeleteDirectoryAuto(autogen);
729 }
730 }
731 return result;
732 }
733
734 /*---------------------------------------------------------------------------*
735 Name: FS_DeleteFileAuto
736
737 Description: Deletes files including the necessary intermediate directories.
738
739 Arguments: path: Path name
740
741 Returns: TRUE if file is deleted normally.
742 *---------------------------------------------------------------------------*/
FS_DeleteFileAuto(const char * path)743 BOOL FS_DeleteFileAuto(const char *path)
744 {
745 FS_DEBUG_TRACE( "%s(%s)\n", __FUNCTION__, path);
746 // Exists for consistency in command names, but actually the supplement process is unnecessary
747 return FS_DeleteFile(path);
748 }
749
750 /*---------------------------------------------------------------------------*
751 Name: FS_RenameFileAuto
752
753 Description: Changes filenames including the necessary intermediate directories.
754
755 Arguments: src: Filename of the conversion source
756 dst: Filename of the conversion target
757
758 Returns: TRUE if filename is changed normally.
759 *---------------------------------------------------------------------------*/
FS_RenameFileAuto(const char * src,const char * dst)760 BOOL FS_RenameFileAuto(const char *src, const char *dst)
761 {
762 BOOL result = FALSE;
763 char autogen[FS_ARCHIVE_FULLPATH_MAX + 1];
764 FS_DEBUG_TRACE( "%s(%s->%s)\n", __FUNCTION__);
765 if (FSi_ComplementDirectory(dst, autogen))
766 {
767 result = FS_RenameFile(src, dst);
768 if (!result)
769 {
770 (void)FS_DeleteDirectoryAuto(autogen);
771 }
772 }
773 return result;
774 }
775
776 /*---------------------------------------------------------------------------*
777 Name: FS_CreateDirectoryAuto
778
779 Description: Generates directories including the necessary intermediate directories.
780
781 Arguments: path: Directory name to generate
782 permit: Access mode
783
784 Returns: TRUE if directory is generated normally.
785 *---------------------------------------------------------------------------*/
FS_CreateDirectoryAuto(const char * path,u32 permit)786 BOOL FS_CreateDirectoryAuto(const char *path, u32 permit)
787 {
788 BOOL result = FALSE;
789 char autogen[FS_ARCHIVE_FULLPATH_MAX + 1];
790 FS_DEBUG_TRACE( "%s(%s)\n", __FUNCTION__, path);
791 if (FSi_ComplementDirectory(path, autogen))
792 {
793 result = FS_CreateDirectory(path, permit);
794 if (!result)
795 {
796 (void)FS_DeleteDirectoryAuto(autogen);
797 }
798 }
799 return result;
800 }
801
802 /*---------------------------------------------------------------------------*
803 Name: FS_DeleteDirectoryAuto
804
805 Description: Recursively deletes the directory.
806
807 Arguments: path: Path name
808
809 Returns: TRUE if directory is deleted normally.
810 *---------------------------------------------------------------------------*/
FS_DeleteDirectoryAuto(const char * path)811 BOOL FS_DeleteDirectoryAuto(const char *path)
812 {
813 BOOL retval = FALSE;
814 FS_DEBUG_TRACE( "%s(%s)\n", __FUNCTION__, path);
815 if (path && *path)
816 {
817 char tmppath[FS_ARCHIVE_FULLPATH_MAX + 1];
818 if (FSi_GetFullPath(tmppath, path))
819 {
820 int pos;
821 BOOL mayBeEmpty;
822 int length = FSi_TrimSjisTrailingSlash(tmppath);
823 FS_DEBUG_TRACE(" trying to force-delete \"%s\"\n", tmppath);
824 mayBeEmpty = TRUE;
825 for (pos = 0; pos >= 0;)
826 {
827 BOOL failure = FALSE;
828 // First, try to directly delete the directory and if successful, go to 1 level
829 tmppath[length + pos] = '\0';
830 if (mayBeEmpty && (FS_DeleteDirectory(tmppath) ||
831 (FS_GetArchiveResultCode(tmppath) == FS_RESULT_ALREADY_DONE)))
832 {
833 FS_DEBUG_TRACE(" -> succeeded to delete \"%s\"\n", tmppath);
834 pos = FSi_DecrementSjisPositionToSlash(&tmppath[length], pos);
835 }
836 else
837 {
838 // Enumerate all entries if the directory is to be opened
839 FSFile dir[1];
840 FS_InitFile(dir);
841 if (!FS_OpenDirectory(dir, tmppath, FS_FILEMODE_R))
842 {
843 FS_DEBUG_TRACE(" -> failed to delete & open \"%s\"\n", tmppath);
844 failure = TRUE;
845 }
846 else
847 {
848 FSDirectoryEntryInfo info[1];
849 tmppath[length + pos] = '/';
850 mayBeEmpty = TRUE;
851 while (FS_ReadDirectory(dir, info))
852 {
853 (void)STD_CopyString(&tmppath[length + pos + 1], info->longname);
854 // If the file exists, delete it
855 if ((info->attributes & FS_ATTRIBUTE_IS_DIRECTORY) == 0)
856 {
857 if (!FS_DeleteFile(tmppath))
858 {
859 FS_DEBUG_TRACE(" -> failed to delete file \"%s\"\n", tmppath);
860 failure = TRUE;
861 break;
862 }
863 FS_DEBUG_TRACE(" -> succeeded to delete \"%s\"\n", tmppath);
864 }
865 // If "." or ".." ignore
866 else if ((STD_CompareString(info->longname, ".") == 0) ||
867 (STD_CompareString(info->longname, "..") == 0))
868 {
869 }
870 // If a directory that is empty exists, move to a lower level
871 else if (!FS_DeleteDirectory(tmppath))
872 {
873 pos += 1 + STD_GetStringLength(info->longname);
874 mayBeEmpty = FALSE;
875 break;
876 }
877 }
878 (void)FS_CloseDirectory(dir);
879 }
880 }
881 // Cancel processing when even operations that should succeed fail (such as ALREADY_DONE)
882 if (failure)
883 {
884 break;
885 }
886 }
887 retval = (pos < 0);
888 }
889 }
890 return retval;
891 }
892
893 /*---------------------------------------------------------------------------*
894 Name: FS_RenameDirectoryAuto
895
896 Description: Changes the directory name by automatically generating the necessary intermediate directories.
897
898 Arguments: src: Directory name of the conversion source
899 dst: Directory name of the conversion destination
900
901 Returns: TRUE if directory name is changed normally.
902 *---------------------------------------------------------------------------*/
FS_RenameDirectoryAuto(const char * src,const char * dst)903 BOOL FS_RenameDirectoryAuto(const char *src, const char *dst)
904 {
905 BOOL result = FALSE;
906 char autogen[FS_ARCHIVE_FULLPATH_MAX + 1];
907 FS_DEBUG_TRACE( "%s(%s->%s)\n", __FUNCTION__, src, dst);
908 if (FSi_ComplementDirectory(dst, autogen))
909 {
910 result = FS_RenameDirectory(src, dst);
911 if (!result)
912 {
913 (void)FS_DeleteDirectoryAuto(autogen);
914 }
915 }
916 return result;
917 }
918
919 /*---------------------------------------------------------------------------*
920 Name: FS_GetArchiveResource
921
922 Description: Gets resource information of the specified archive.
923
924 Arguments: path: Path name that specifies the archive
925 resource: Storage destination of obtained resource information
926
927 Returns: TRUE if resource information is obtained normally.
928 *---------------------------------------------------------------------------*/
FS_GetArchiveResource(const char * path,FSArchiveResource * resource)929 BOOL FS_GetArchiveResource(const char *path, FSArchiveResource *resource)
930 {
931 BOOL retval = FALSE;
932 SDK_NULL_ASSERT(path);
933 SDK_ASSERT(OS_GetProcMode() != OS_PROCMODE_IRQ);
934 {
935 FSArchive *arc = FS_NormalizePath(path, NULL, NULL);
936 if (arc)
937 {
938 FSFile file[1];
939 FSArgumentForGetArchiveResource arg[1];
940 FS_InitFile(file);
941 file->arc = arc;
942 file->argument = arg;
943 arg->resource = resource;
944 retval = FSi_SendCommand(file, FS_COMMAND_GETARCHIVERESOURCE, TRUE);
945 }
946 }
947 return retval;
948 }
949
950 /*---------------------------------------------------------------------------*
951 Name: FSi_GetSpaceToCreateDirectoryEntries
952
953 Description: Estimates the volume of the directory entry generated at the same time as the file.
954 (Assumes that the directory that exists in the path is newly generated.)
955
956 Arguments: path: Path name of generated file
957 bytesPerCluster: Number of bytes per cluster on file system
958
959 Returns: Capacity.
960 *---------------------------------------------------------------------------*/
FSi_GetSpaceToCreateDirectoryEntries(const char * path,u32 bytesPerCluster)961 u32 FSi_GetSpaceToCreateDirectoryEntries(const char *path, u32 bytesPerCluster)
962 {
963 static const u32 bytesPerEntry = 32UL;
964 static const u32 longnamePerEntry = 13UL;
965 // Deletes the scheme if it is a full path and individually determines each entry
966 const char *root = STD_SearchString(path, ":");
967 const char *current = (root != NULL) ? (root + 1) : path;
968 u32 totalBytes = 0;
969 u32 restBytesInCluster = 0;
970 current += (*current == '/');
971 while (*current)
972 {
973 BOOL isShortName = FALSE;
974 u32 entries = 0;
975 // Calculate entry name length
976 u32 len = (u32)FSi_IncrementSjisPositionToSlash(current, 0);
977 // Determine whether the entry name can be expressed in 8.3 format
978 #if 0
979 // (FAT drivers employed for TWL are always saved with long filenames, so it was not necessary to strictly determine up to here actually)
980 //
981 {
982 static const char *alnum = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
983 static const char *special = "!#$%&'()*+-<>?@^_`{}~";
984 if ((len <= 8 + 1 + 3) && STD_SearchChar(alnum, current[0]))
985 {
986 u32 namelen = 0;
987 u32 extlen = 0;
988 u32 scanned = 0;
989 for (; namelen < len; ++namelen)
990 {
991 char c = current[scanned + namelen];
992 if (!STD_SearchChar(alnum, c) && !STD_SearchChar(special, c))
993 {
994 break;
995 }
996 }
997 scanned += namelen;
998 if ((scanned < len) && (current[scanned] == '.'))
999 {
1000 ++scanned;
1001 for (; scanned + extlen < len; ++extlen)
1002 {
1003 char c = current[scanned + extlen];
1004 if (!STD_SearchChar(alnum, c) && !STD_SearchChar(special, c))
1005 {
1006 break;
1007 }
1008 }
1009 scanned += extlen;
1010 }
1011 if ((scanned == len) && (namelen <= 8) && (extlen <= 3))
1012 {
1013 isShortName = TRUE;
1014 }
1015 }
1016 }
1017 #endif
1018 // If it is not in 8.3 format, an added entry is needed for long filenames
1019 if (!isShortName)
1020 {
1021 entries += ((len + longnamePerEntry - 1UL) / longnamePerEntry);
1022 }
1023 // Anyway, 1 entry is always considered to be consumed
1024 entries += 1;
1025 current += len;
1026 // If the cluster margins of directories already created by yourself are inadequate, consume excess entries in cluster units
1027 //
1028 {
1029 int over = (int)(entries * bytesPerEntry - restBytesInCluster);
1030 if (over > 0)
1031 {
1032 totalBytes += MATH_ROUNDUP(over, bytesPerCluster);
1033 }
1034 }
1035 // If there is still a lower level, consume 1 cluster as a directory, and the size minus two entries of "." and ".." will be the margin
1036 //
1037 if (*current != '\0')
1038 {
1039 current += 1;
1040 totalBytes += bytesPerCluster;
1041 restBytesInCluster = bytesPerCluster - (2 * bytesPerEntry);
1042 }
1043 }
1044 return totalBytes;
1045 }
1046
1047 /*---------------------------------------------------------------------------*
1048 Name: FS_HasEnoughSpaceToCreateFile
1049
1050 Description: Determines whether it is currently possible to generate files having the specified path name and size
1051
1052 Arguments: resource: Archive information obtained by the FS_GetArchiveResource function in advance
1053 If the function is successful, the sizes consumed by the files are reduced
1054 path: Path name of generated file
1055 size: Size of generated file
1056
1057 Returns: TRUE if it is currently possible to generate files having the specified path name and size.
1058 *---------------------------------------------------------------------------*/
FS_HasEnoughSpaceToCreateFile(FSArchiveResource * resource,const char * path,u32 size)1059 BOOL FS_HasEnoughSpaceToCreateFile(FSArchiveResource *resource, const char *path, u32 size)
1060 {
1061 BOOL retval = FALSE;
1062 u32 bytesPerCluster = resource->bytesPerSector * resource->sectorsPerCluster;
1063 if (bytesPerCluster != 0)
1064 {
1065 u32 needbytes = (FSi_GetSpaceToCreateDirectoryEntries(path, bytesPerCluster) +
1066 MATH_ROUNDUP(size, bytesPerCluster));
1067 u32 needclusters = needbytes / bytesPerCluster;
1068 if (needclusters <= resource->availableClusters)
1069 {
1070 resource->availableClusters -= needclusters;
1071 resource->availableSize -= needbytes;
1072 retval = TRUE;
1073 }
1074 }
1075 return retval;
1076 }
1077
1078 /*---------------------------------------------------------------------------*
1079 Name: FS_IsArchiveReady
1080
1081 Description: Determines whether it is currently possible to use the specified archive.
1082
1083 Arguments: path: Absolute path beginning with "archive name:"
1084
1085 Returns: TRUE if currently possible to use the specified archive name.
1086 FALSE if an SD card archive that is not inserted in the slot or a save data archive not yet imported.
1087
1088 *---------------------------------------------------------------------------*/
FS_IsArchiveReady(const char * path)1089 BOOL FS_IsArchiveReady(const char *path)
1090 {
1091 FSArchiveResource resource[1];
1092 return FS_GetArchiveResource(path, resource);
1093 }
1094
1095 /*---------------------------------------------------------------------------*
1096 Name: FS_FlushFile
1097
1098 Description: Applies the file changes to the device.
1099
1100 Arguments: file: File handle
1101
1102 Returns: Processing result.
1103 *---------------------------------------------------------------------------*/
FS_FlushFile(FSFile * file)1104 FSResult FS_FlushFile(FSFile *file)
1105 {
1106 FSResult retval = FS_RESULT_ERROR;
1107 SDK_NULL_ASSERT(file);
1108 SDK_ASSERT(FS_IsFile(file));
1109 SDK_ASSERT(OS_GetProcMode() != OS_PROCMODE_IRQ);
1110 {
1111 (void)FSi_SendCommand(file, FS_COMMAND_FLUSHFILE, TRUE);
1112 retval = FS_GetResultCode(file);
1113 }
1114 return retval;
1115 }
1116
1117 /*---------------------------------------------------------------------------*
1118 Name: FS_SetFileLength
1119
1120 Description: Changes the file size.
1121
1122 Arguments: file: File handle
1123 length: Size after changes
1124
1125 Returns: Processing result.
1126 *---------------------------------------------------------------------------*/
FS_SetFileLength(FSFile * file,u32 length)1127 FSResult FS_SetFileLength(FSFile *file, u32 length)
1128 {
1129 FSResult retval = FS_RESULT_ERROR;
1130 SDK_NULL_ASSERT(file);
1131 SDK_ASSERT(FS_IsFile(file));
1132 SDK_ASSERT(OS_GetProcMode() != OS_PROCMODE_IRQ);
1133 {
1134 FSArgumentForSetFileLength arg[1];
1135 file->argument = arg;
1136 arg->length = length;
1137 (void)FSi_SendCommand(file, FS_COMMAND_SETFILELENGTH, TRUE);
1138 retval = FS_GetResultCode(file);
1139 }
1140 return retval;
1141 }
1142
1143 /*---------------------------------------------------------------------------*
1144 Name: FS_GetPathName
1145
1146 Description: Gets path name of the specified handle.
1147
1148 Arguments: file: File or directory
1149 buffer: Path storage destination
1150 length: Buffer size
1151
1152 Returns: TRUE if successful.
1153 *---------------------------------------------------------------------------*/
FS_GetPathName(FSFile * file,char * buffer,u32 length)1154 BOOL FS_GetPathName(FSFile *file, char *buffer, u32 length)
1155 {
1156 BOOL retval = FALSE;
1157 SDK_ASSERT(FS_IsAvailable());
1158 SDK_ASSERT(FS_IsFile(file) || FS_IsDir(file));
1159 SDK_ASSERT(OS_GetProcMode() != OS_PROCMODE_IRQ);
1160 {
1161 FSArgumentForGetPath arg[1];
1162 file->argument = arg;
1163 arg->is_directory = FS_IsDir(file);
1164 arg->buffer = buffer;
1165 arg->length = length;
1166 retval = FSi_SendCommand(file, FS_COMMAND_GETPATH, TRUE);
1167 }
1168 return retval;
1169 }
1170
1171 /*---------------------------------------------------------------------------*
1172 Name: FS_GetPathLength
1173
1174 Description: Gets length of full path name of the specified file or directory.
1175
1176 Arguments: file: File or directory handle
1177
1178 Returns: Length of the path name that included '\0' at the end if successful, and -1 if failed.
1179 *---------------------------------------------------------------------------*/
FS_GetPathLength(FSFile * file)1180 s32 FS_GetPathLength(FSFile *file)
1181 {
1182 s32 retval = -1;
1183 if (FS_GetPathName(file, NULL, 0))
1184 {
1185 retval = file->arg.getpath.total_len;
1186 }
1187 return retval;
1188 }
1189
1190 /*---------------------------------------------------------------------------*
1191 Name: FS_ConvertPathToFileID
1192
1193 Description: Gets file ID from the path name.
1194
1195 Arguments: p_fileid: FSFileID storage destination
1196 path: Path name
1197
1198 Returns: TRUE if successful.
1199 *---------------------------------------------------------------------------*/
FS_ConvertPathToFileID(FSFileID * p_fileid,const char * path)1200 BOOL FS_ConvertPathToFileID(FSFileID *p_fileid, const char *path)
1201 {
1202 BOOL retval = FALSE;
1203 SDK_NULL_ASSERT(p_fileid);
1204 SDK_NULL_ASSERT(path);
1205 SDK_ASSERT(FS_IsAvailable());
1206 SDK_ASSERT(OS_GetProcMode() != OS_PROCMODE_IRQ);
1207 {
1208 char relpath[FS_ARCHIVE_FULLPATH_MAX + 1];
1209 u32 baseid = 0;
1210 FSArchive *arc = FS_NormalizePath(path, &baseid, relpath);
1211 if (arc)
1212 {
1213 FSFile file[1];
1214 FSArgumentForFindPath arg[1];
1215 FS_InitFile(file);
1216 file->arc = arc;
1217 file->argument = arg;
1218 arg->baseid = baseid;
1219 arg->relpath = relpath;
1220 arg->target_is_directory = FALSE;
1221 if (FSi_SendCommand(file, FS_COMMAND_FINDPATH, TRUE))
1222 {
1223 p_fileid->arc = arc;
1224 p_fileid->file_id = arg->target_id;
1225 retval = TRUE;
1226 }
1227 }
1228 }
1229 return retval;
1230 }
1231
1232 /*---------------------------------------------------------------------------*
1233 Name: FS_OpenFileDirect
1234
1235 Description: Opens the file by directly specifying the region of the archive.
1236
1237 Arguments: file: FSFile that retains handle information
1238 arc: Archive that is the map source
1239 image_top: Offset for the file image start
1240 image_bottom: Offset of the file image terminator
1241 id: Arbitrarily specified file ID
1242
1243 Returns: TRUE if successful.
1244 *---------------------------------------------------------------------------*/
FS_OpenFileDirect(FSFile * file,FSArchive * arc,u32 image_top,u32 image_bottom,u32 id)1245 BOOL FS_OpenFileDirect(FSFile *file, FSArchive *arc,
1246 u32 image_top, u32 image_bottom, u32 id)
1247 {
1248 BOOL retval = FALSE;
1249 SDK_NULL_ASSERT(file);
1250 SDK_NULL_ASSERT(arc);
1251 SDK_ASSERT(FS_IsAvailable());
1252 SDK_ASSERT(!FS_IsFile(file));
1253 SDK_ASSERT(OS_GetProcMode() != OS_PROCMODE_IRQ);
1254 {
1255 FSArgumentForOpenFileDirect arg[1];
1256 file->arc = arc;
1257 file->argument = arg;
1258 arg->id = id;
1259 arg->top = image_top;
1260 arg->bottom = image_bottom;
1261 arg->mode = 0;
1262 retval = FSi_SendCommand(file, FS_COMMAND_OPENFILEDIRECT, TRUE);
1263 }
1264 return retval;
1265 }
1266
1267 /*---------------------------------------------------------------------------*
1268 Name: FS_OpenFileFast
1269
1270 Description: Opens the file by specifying the ID.
1271
1272 Arguments: file: FSFile that retains handle information
1273 id: FSFileID that indicates the file to be opened
1274
1275 Returns: TRUE if successful.
1276 *---------------------------------------------------------------------------*/
FS_OpenFileFast(FSFile * file,FSFileID id)1277 BOOL FS_OpenFileFast(FSFile *file, FSFileID id)
1278 {
1279 BOOL retval = FALSE;
1280 SDK_NULL_ASSERT(file);
1281 SDK_ASSERT(FS_IsAvailable());
1282 SDK_ASSERT(!FS_IsFile(file));
1283 SDK_ASSERT(OS_GetProcMode() != OS_PROCMODE_IRQ);
1284 if (id.arc)
1285 {
1286 FSArgumentForOpenFileFast arg[1];
1287 file->arc = id.arc;
1288 file->argument = arg;
1289 arg->id = id.file_id;
1290 arg->mode = 0;
1291 retval = FSi_SendCommand(file, FS_COMMAND_OPENFILEFAST, TRUE);
1292 }
1293 return retval;
1294 }
1295
1296 /*---------------------------------------------------------------------------*
1297 Name: FS_OpenFileEx
1298
1299 Description: Opens the file by specifying the path name.
1300
1301 Arguments: file: FSFile structure
1302 path: Path name
1303
1304 Returns: TRUE if successful.
1305 *---------------------------------------------------------------------------*/
FS_OpenFileEx(FSFile * file,const char * path,u32 mode)1306 BOOL FS_OpenFileEx(FSFile *file, const char *path, u32 mode)
1307 {
1308 BOOL retval = FALSE;
1309 FS_DEBUG_TRACE( "%s\n", __FUNCTION__);
1310 SDK_NULL_ASSERT(file);
1311 SDK_NULL_ASSERT(path);
1312 SDK_ASSERT(OS_GetProcMode() != OS_PROCMODE_IRQ);
1313
1314 // Logic check relating to FS_FILEMODE_L
1315 // (It is meaningless if there is a size restriction when opening in creation mode)
1316 if (((mode & FS_FILEMODE_L) != 0) &&
1317 ((mode & FS_FILEMODE_RW) == FS_FILEMODE_W))
1318 {
1319 OS_TWarning("\"FS_FILEMODE_WL\" seems useless.\n"
1320 "(this means creating empty file and prohibiting any modifications)");
1321 }
1322 {
1323 char relpath[FS_ARCHIVE_FULLPATH_MAX + 1];
1324 u32 baseid = 0;
1325 FSArchive *arc = FS_NormalizePath(path, &baseid, relpath);
1326 if (arc)
1327 {
1328 FSArgumentForOpenFile arg[1];
1329 FS_InitFile(file);
1330 file->arc = arc;
1331 file->argument = arg;
1332 arg->baseid = baseid;
1333 arg->relpath = relpath;
1334 arg->mode = mode;
1335 if (FSi_SendCommand(file, FS_COMMAND_OPENFILE, TRUE))
1336 {
1337 retval = TRUE;
1338 }
1339 else
1340 {
1341 file->arc = NULL;
1342 }
1343 }
1344 }
1345 return retval;
1346 }
1347
1348 /*---------------------------------------------------------------------------*
1349 Name: FS_CloseFile
1350
1351 Description: Closes the file.
1352
1353 Arguments: file: File handle
1354
1355 Returns: TRUE if successful.
1356 *---------------------------------------------------------------------------*/
FS_CloseFile(FSFile * file)1357 BOOL FS_CloseFile(FSFile *file)
1358 {
1359 BOOL retval = FALSE;
1360 FS_DEBUG_TRACE( "%s\n", __FUNCTION__);
1361 SDK_NULL_ASSERT(file);
1362 SDK_ASSERT(FS_IsAvailable());
1363 SDK_ASSERT(FS_IsFile(file));
1364 SDK_ASSERT(OS_GetProcMode() != OS_PROCMODE_IRQ);
1365 {
1366 retval = FSi_SendCommand(file, FS_COMMAND_CLOSEFILE, TRUE);
1367 }
1368 return retval;
1369 }
1370
1371 /*---------------------------------------------------------------------------*
1372 Name: FS_GetSeekCacheSize
1373
1374 Description: Finds the necessary buffer size for the full cache for high-speed reverse seek.
1375
1376 Arguments: path
1377
1378 Returns: Size if successful; 0 if failed.
1379 *---------------------------------------------------------------------------*/
FS_GetSeekCacheSize(const char * path)1380 u32 FS_GetSeekCacheSize(const char *path)
1381 {
1382 u32 retval = 0;
1383 // Gets the size if the file exists
1384 FSPathInfo info;
1385 if (FS_GetPathInfo(path, &info) &&
1386 ((info.attributes & FS_ATTRIBUTE_IS_DIRECTORY) == 0))
1387 {
1388 // Get FAT information of the corresponding archive
1389 FSArchiveResource resource;
1390 if (FS_GetArchiveResource(path, &resource))
1391 {
1392 // Calculate the cache size if the actual archive of the FAT base
1393 u32 bytesPerCluster = resource.sectorsPerCluster * resource.bytesPerSector;
1394 if (bytesPerCluster != 0)
1395 {
1396 static const u32 fatBits = 32;
1397 retval = (u32)((info.filesize + bytesPerCluster - 1) / bytesPerCluster) * ((fatBits + 4) / 8);
1398 // Add margin to align the portions before and after the buffer to the cache lines
1399 retval += (u32)(HW_CACHE_LINE_SIZE * 2);
1400 }
1401 }
1402 }
1403 return retval;
1404 }
1405
1406 /*---------------------------------------------------------------------------*
1407 Name: FS_SetSeekCache
1408
1409 Description: Assigns cache buffer for high-speed reverse seek.
1410
1411 Arguments: file: File handle
1412 buf: Cache buffer
1413 buf_size: Cache buffer size
1414
1415 Returns: TRUE if successful.
1416 *---------------------------------------------------------------------------*/
FS_SetSeekCache(FSFile * file,void * buf,u32 buf_size)1417 BOOL FS_SetSeekCache(FSFile *file, void* buf, u32 buf_size)
1418 {
1419 FSArgumentForSetSeekCache arg[1];
1420 BOOL retval = FALSE;
1421 SDK_ASSERT(FS_IsAvailable());
1422 SDK_ASSERT(FS_IsFile(file));
1423
1424 file->argument = arg;
1425 arg->buf = buf;
1426 arg->buf_size = buf_size;
1427 retval = FSi_SendCommand(file, FS_COMMAND_SETSEEKCACHE, TRUE);
1428
1429 return retval;
1430 }
1431
1432 /*---------------------------------------------------------------------------*
1433 Name: FS_GetFileLength
1434
1435 Description: Gets file size.
1436
1437 Arguments: file: File handle
1438
1439 Returns: File size.
1440 *---------------------------------------------------------------------------*/
FS_GetFileLength(FSFile * file)1441 u32 FS_GetFileLength(FSFile *file)
1442 {
1443 u32 retval = 0;
1444 SDK_ASSERT(FS_IsAvailable());
1445 SDK_ASSERT(FS_IsFile(file));
1446 // Can reference directly in this case if it is an archive procedure
1447 if (!FSi_GetFileLengthIfProc(file, &retval))
1448 {
1449 FSArgumentForGetFileLength arg[1];
1450 file->argument = arg;
1451 arg->length = 0;
1452 if (FSi_SendCommand(file, FS_COMMAND_GETFILELENGTH, TRUE))
1453 {
1454 retval = arg->length;
1455 }
1456 }
1457 return retval;
1458 }
1459
1460 /*---------------------------------------------------------------------------*
1461 Name: FS_GetFilePosition
1462
1463 Description: Gets the current position of the file pointer.
1464
1465 Arguments: file: File handle
1466
1467 Returns: Current position of the file pointer.
1468 *---------------------------------------------------------------------------*/
FS_GetFilePosition(FSFile * file)1469 u32 FS_GetFilePosition(FSFile *file)
1470 {
1471 u32 retval = 0;
1472 SDK_ASSERT(FS_IsAvailable());
1473 SDK_ASSERT(FS_IsFile(file));
1474 // Can reference directly in this case if it is an archive procedure
1475 if (!FSi_GetFilePositionIfProc(file, &retval))
1476 {
1477 FSArgumentForGetFilePosition arg[1];
1478 file->argument = arg;
1479 arg->position = 0;
1480 if (FSi_SendCommand(file, FS_COMMAND_GETFILEPOSITION, TRUE))
1481 {
1482 retval = arg->position;
1483 }
1484 }
1485 return retval;
1486 }
1487
1488 /*---------------------------------------------------------------------------*
1489 Name: FS_SeekFile
1490
1491 Description: Moves the file pointer.
1492
1493 Arguments: file: File handle
1494 offset: Movement amount
1495 origin: Movement starting point
1496
1497 Returns: TRUE if successful.
1498 *---------------------------------------------------------------------------*/
FS_SeekFile(FSFile * file,s32 offset,FSSeekFileMode origin)1499 BOOL FS_SeekFile(FSFile *file, s32 offset, FSSeekFileMode origin)
1500 {
1501 BOOL retval = FALSE;
1502 FS_DEBUG_TRACE( "%s\n", __FUNCTION__);
1503 SDK_NULL_ASSERT(file);
1504 SDK_ASSERT(FS_IsAvailable());
1505 SDK_ASSERT(FS_IsFile(file));
1506 {
1507 FSArgumentForSeekFile arg[1];
1508 file->argument = arg;
1509 arg->offset = (int)offset;
1510 arg->from = origin;
1511 retval = FSi_SendCommand(file, FS_COMMAND_SEEKFILE, TRUE);
1512 }
1513 return retval;
1514 }
1515
1516 /*---------------------------------------------------------------------------*
1517 Name: FS_ReadFile
1518
1519 Description: Read data from the file.
1520
1521 Arguments: file: File handle
1522 buffer: Transfer destination buffer
1523 length: Read size.
1524
1525 Returns: Actual read size if successful, -1 if failed.
1526 *---------------------------------------------------------------------------*/
FS_ReadFile(FSFile * file,void * buffer,s32 length)1527 s32 FS_ReadFile(FSFile *file, void *buffer, s32 length)
1528 {
1529 FS_DEBUG_TRACE( "%s\n", __FUNCTION__);
1530 SDK_NULL_ASSERT(file);
1531 SDK_ASSERT(FSi_IsValidTransferRegion(buffer, length));
1532 SDK_ASSERT(FS_IsAvailable());
1533 SDK_ASSERT(FS_IsFile(file) && !FS_IsBusy(file));
1534 SDK_ASSERT(OS_GetProcMode() != OS_PROCMODE_IRQ);
1535 {
1536 FSArgumentForReadFile arg[1];
1537 file->argument = arg;
1538 arg->buffer = buffer;
1539 arg->length = (u32)length;
1540 if (FSi_SendCommand(file, FS_COMMAND_READFILE, TRUE))
1541 {
1542 length = (s32)arg->length;
1543 }
1544 else
1545 {
1546 if( file->error == FS_RESULT_INVALID_PARAMETER) {
1547 length = -1; //If not read at all
1548 }else{
1549 length = (s32)arg->length; //If reading was tried, a value higher than -1 is entered
1550 }
1551 }
1552 }
1553 return length;
1554 }
1555
1556 /*---------------------------------------------------------------------------*
1557 Name: FS_ReadFileAsync
1558
1559 Description: Asynchronously reads data from the file.
1560
1561 Arguments: file: File handle
1562 buffer: Transfer destination buffer
1563 length: Read size
1564
1565 Returns: Simply the same value as the length if successful, and -1 if failed.
1566 *---------------------------------------------------------------------------*/
FS_ReadFileAsync(FSFile * file,void * buffer,s32 length)1567 s32 FS_ReadFileAsync(FSFile *file, void *buffer, s32 length)
1568 {
1569 FS_DEBUG_TRACE( "%s\n", __FUNCTION__);
1570 SDK_NULL_ASSERT(file);
1571 SDK_ASSERT(FSi_IsValidTransferRegion(buffer, length));
1572 SDK_ASSERT(FS_IsAvailable());
1573 SDK_ASSERT(FS_IsFile(file) && !FS_IsBusy(file));
1574 // Correct size in this case if it is an archive procedure
1575 {
1576 u32 end, pos;
1577 if (FSi_GetFilePositionIfProc(file, &pos) &&
1578 FSi_GetFileLengthIfProc(file, &end) &&
1579 (pos + length > end))
1580 {
1581 length = (s32)(end - pos);
1582 }
1583 }
1584 {
1585 FSArgumentForReadFile *arg = (FSArgumentForReadFile*)file->reserved2;
1586 file->argument = arg;
1587 arg->buffer = buffer;
1588 arg->length = (u32)length;
1589 (void)FSi_SendCommand(file, FS_COMMAND_READFILE, FALSE);
1590 }
1591 return length;
1592 }
1593
1594 /*---------------------------------------------------------------------------*
1595 Name: FS_WriteFile
1596
1597 Description: Writes data to the file.
1598
1599 Arguments: file: File handle
1600 buffer: Transfer source buffer
1601 length: Write size
1602
1603 Returns: Actual write size if successful, -1 if failed.
1604 *---------------------------------------------------------------------------*/
FS_WriteFile(FSFile * file,const void * buffer,s32 length)1605 s32 FS_WriteFile(FSFile *file, const void *buffer, s32 length)
1606 {
1607 FS_DEBUG_TRACE( "%s\n", __FUNCTION__);
1608 SDK_NULL_ASSERT(file);
1609 SDK_ASSERT(FSi_IsValidTransferRegion(buffer, length));
1610 SDK_ASSERT(FS_IsAvailable());
1611 SDK_ASSERT(FS_IsFile(file) && !FS_IsBusy(file));
1612 SDK_ASSERT(OS_GetProcMode() != OS_PROCMODE_IRQ);
1613 {
1614 FSArgumentForWriteFile arg[1];
1615 file->argument = arg;
1616 arg->buffer = buffer;
1617 arg->length = (u32)length;
1618 if (FSi_SendCommand(file, FS_COMMAND_WRITEFILE, TRUE))
1619 {
1620 length = (s32)arg->length;
1621 }
1622 else
1623 {
1624 if( file->error == FS_RESULT_INVALID_PARAMETER) {
1625 length = -1; //If not written at all
1626 }else{
1627 length = (s32)arg->length; //If writing was tried, a value higher than -1 is entered
1628 }
1629 }
1630 }
1631 return length;
1632 }
1633
1634 /*---------------------------------------------------------------------------*
1635 Name: FS_WriteFileAsync
1636
1637 Description: Asynchronously writes data to file.
1638
1639 Arguments: file: File handle
1640 buffer: Transfer source buffer
1641 length: Write size
1642
1643 Returns: Simply the same value as the length if successful, and -1 if failed.
1644 *---------------------------------------------------------------------------*/
FS_WriteFileAsync(FSFile * file,const void * buffer,s32 length)1645 s32 FS_WriteFileAsync(FSFile *file, const void *buffer, s32 length)
1646 {
1647 SDK_NULL_ASSERT(file);
1648 SDK_ASSERT(FSi_IsValidTransferRegion(buffer, length));
1649 SDK_ASSERT(FS_IsAvailable());
1650 SDK_ASSERT(FS_IsFile(file) && !FS_IsBusy(file));
1651 // Correct size in this case if it is an archive procedure
1652 {
1653 u32 end, pos;
1654 if (FSi_GetFilePositionIfProc(file, &pos) &&
1655 FSi_GetFileLengthIfProc(file, &end) &&
1656 (pos + length > end))
1657 {
1658 length = (s32)(end - pos);
1659 }
1660 }
1661 {
1662 FSArgumentForWriteFile *arg = (FSArgumentForWriteFile*)file->reserved2;
1663 file->argument = arg;
1664 arg->buffer = buffer;
1665 arg->length = (u32)length;
1666 (void)FSi_SendCommand(file, FS_COMMAND_WRITEFILE, FALSE);
1667 }
1668 return length;
1669 }
1670
1671 /*---------------------------------------------------------------------------*
1672 Name: FS_OpenDirectory
1673
1674 Description: Opens the directory handle.
1675
1676 Arguments: file: FSFile structure
1677 path: Path name
1678 mode: Access mode
1679
1680 Returns: TRUE if successful.
1681 *---------------------------------------------------------------------------*/
FS_OpenDirectory(FSFile * file,const char * path,u32 mode)1682 BOOL FS_OpenDirectory(FSFile *file, const char *path, u32 mode)
1683 {
1684 BOOL retval = FALSE;
1685 FS_DEBUG_TRACE( "%s\n", __FUNCTION__);
1686 SDK_NULL_ASSERT(path);
1687 SDK_ASSERT(OS_GetProcMode() != OS_PROCMODE_IRQ);
1688 {
1689 char relpath[FS_ARCHIVE_FULLPATH_MAX + 1];
1690 u32 baseid = 0;
1691 FSArchive *arc = FS_NormalizePath(path, &baseid, relpath);
1692 if (arc)
1693 {
1694 FSArgumentForOpenDirectory arg[1];
1695 FS_InitFile(file);
1696 file->arc = arc;
1697 file->argument = arg;
1698 arg->baseid = baseid;
1699 arg->relpath = relpath;
1700 arg->mode = mode;
1701 if (FSi_SendCommand(file, FS_COMMAND_OPENDIRECTORY, TRUE))
1702 {
1703 retval = TRUE;
1704 }
1705 else
1706 {
1707 file->arc = NULL;
1708 }
1709 }
1710 }
1711 return retval;
1712 }
1713
1714 /*---------------------------------------------------------------------------*
1715 Name: FS_CloseDirectory
1716
1717 Description: Closes the directory handle.
1718
1719 Arguments: file: FSFile structure
1720
1721 Returns: TRUE if successful.
1722 *---------------------------------------------------------------------------*/
FS_CloseDirectory(FSFile * file)1723 BOOL FS_CloseDirectory(FSFile *file)
1724 {
1725 BOOL retval = FALSE;
1726 FS_DEBUG_TRACE( "%s\n", __FUNCTION__);
1727 SDK_NULL_ASSERT(file);
1728 SDK_ASSERT(FS_IsAvailable());
1729 SDK_ASSERT(FS_IsDir(file));
1730 SDK_ASSERT(OS_GetProcMode() != OS_PROCMODE_IRQ);
1731 {
1732 if (FSi_SendCommand(file, FS_COMMAND_CLOSEDIRECTORY, TRUE))
1733 {
1734 retval = TRUE;
1735 }
1736 }
1737 return retval;
1738 }
1739
1740 /*---------------------------------------------------------------------------*
1741 Name: FS_ReadDirectory
1742
1743 Description: Reads only one entry of the directory and advances.
1744
1745 Arguments: file: FSFile structure
1746 info: FSDirectoryEntryInfo structure
1747
1748 Returns: TRUE if successful.
1749 *---------------------------------------------------------------------------*/
FS_ReadDirectory(FSFile * file,FSDirectoryEntryInfo * info)1750 BOOL FS_ReadDirectory(FSFile *file, FSDirectoryEntryInfo *info)
1751 {
1752 BOOL retval = FALSE;
1753 SDK_NULL_ASSERT(file);
1754 SDK_NULL_ASSERT(info);
1755 SDK_ASSERT(FS_IsAvailable());
1756 SDK_ASSERT(FS_IsDir(file));
1757 SDK_ASSERT(OS_GetProcMode() != OS_PROCMODE_IRQ);
1758 {
1759 FSArgumentForReadDirectory arg[1];
1760 file->argument = arg;
1761 arg->info = info;
1762 MI_CpuFill8(info, 0x00, sizeof(info));
1763 info->id = FS_INVALID_FILE_ID;
1764 if (FSi_SendCommand(file, FS_COMMAND_READDIR, TRUE))
1765 {
1766 retval = TRUE;
1767 }
1768 }
1769 return retval;
1770 }
1771
1772 /*---------------------------------------------------------------------------*
1773 Name: FS_SeekDir
1774
1775 Description: Opens by specifying the directory position.
1776
1777 Arguments: file: FSFile structure
1778 pos: Directory position obtained by FS_ReadDir and FS_TellDir
1779
1780 Returns: TRUE if successful.
1781 *---------------------------------------------------------------------------*/
FS_SeekDir(FSFile * file,const FSDirPos * pos)1782 BOOL FS_SeekDir(FSFile *file, const FSDirPos *pos)
1783 {
1784 BOOL retval = FALSE;
1785 SDK_NULL_ASSERT(file);
1786 SDK_NULL_ASSERT(pos);
1787 SDK_NULL_ASSERT(pos->arc);
1788 SDK_ASSERT(FS_IsAvailable());
1789 SDK_ASSERT(OS_GetProcMode() != OS_PROCMODE_IRQ);
1790 {
1791 FSArgumentForSeekDirectory arg[1];
1792 arg->id = (u32)((pos->own_id << 0) | (pos->index << 16));
1793 arg->position = pos->pos;
1794 file->arc = pos->arc;
1795 file->argument = arg;
1796 if (FSi_SendCommand(file, FS_COMMAND_SEEKDIR, TRUE))
1797 {
1798 file->stat |= FS_FILE_STATUS_IS_DIR;
1799 retval = TRUE;
1800 }
1801 }
1802 return retval;
1803 }
1804
1805 /*---------------------------------------------------------------------------*
1806 Name: FS_TellDir
1807
1808 Description: Gets current directory position from directory handle.
1809
1810 Arguments: dir: Directory handle
1811 pos: Storage destination of the directory position
1812
1813 Returns: TRUE if successful.
1814 *---------------------------------------------------------------------------*/
FS_TellDir(const FSFile * dir,FSDirPos * pos)1815 BOOL FS_TellDir(const FSFile *dir, FSDirPos *pos)
1816 {
1817 BOOL retval = FALSE;
1818 SDK_NULL_ASSERT(dir);
1819 SDK_NULL_ASSERT(pos);
1820 SDK_ASSERT(FS_IsAvailable());
1821 SDK_ASSERT(FS_IsDir(dir));
1822 {
1823 *pos = dir->prop.dir.pos;
1824 retval = TRUE;
1825 }
1826 return retval;
1827 }
1828
1829 /*---------------------------------------------------------------------------*
1830 Name: FS_RewindDir
1831
1832 Description: Returns enumeration position of the directory handle to the top.
1833
1834 Arguments: dir: Directory handle
1835
1836 Returns: TRUE if successful.
1837 *---------------------------------------------------------------------------*/
FS_RewindDir(FSFile * dir)1838 BOOL FS_RewindDir(FSFile *dir)
1839 {
1840 BOOL retval = FALSE;
1841 SDK_NULL_ASSERT(dir);
1842 SDK_ASSERT(FS_IsAvailable());
1843 SDK_ASSERT(FS_IsDir(dir));
1844 SDK_ASSERT(OS_GetProcMode() != OS_PROCMODE_IRQ);
1845
1846 {
1847 FSDirPos pos;
1848 pos.arc = dir->arc;
1849 pos.own_id = dir->prop.dir.pos.own_id;
1850 pos.pos = 0;
1851 pos.index = 0;
1852 retval = FS_SeekDir(dir, &pos);
1853 }
1854 return retval;
1855 }
1856
1857
1858 /*---------------------------------------------------------------------------*
1859 * Unicode support
1860 *---------------------------------------------------------------------------*/
1861
1862 enum
1863 {
1864 FS_UNICODE_CONVSRC_ASCII,
1865 FS_UNICODE_CONVSRC_SHIFT_JIS,
1866 FS_UNICODE_CONVSRC_UNICODE
1867 };
1868
1869 /*---------------------------------------------------------------------------*
1870 Name: FSi_CopySafeUnicodeString
1871
1872 Description: Checks buffer size and copies string as Unicode.
1873
1874 Arguments: dst: Transfer destination buffer
1875 dstlen: Transfer destination size
1876 src: Transfer source buffer
1877 srclen: Transfer character size
1878 srctype: Character set of transfer source
1879 stickyFailure: FALSE, if truncated at transfer origin
1880
1881 Returns: Actually stored character count.
1882 *---------------------------------------------------------------------------*/
FSi_CopySafeUnicodeString(u16 * dst,int dstlen,const void * srcptr,int srclen,int srctype,BOOL * stickyFailure)1883 static int FSi_CopySafeUnicodeString(u16 *dst, int dstlen,
1884 const void *srcptr, int srclen,
1885 int srctype, BOOL *stickyFailure)
1886 {
1887 int srcpos = 0;
1888 int dstpos = 0;
1889 if (srctype == FS_UNICODE_CONVSRC_ASCII)
1890 {
1891 const char *src = (const char *)srcptr;
1892 int n = (dstlen - 1 < srclen) ? (dstlen - 1) : srclen;
1893 while ((dstpos < n) && src[srcpos])
1894 {
1895 dst[dstpos++] = (u8)src[srcpos++];
1896 }
1897 if ((srcpos < srclen) && src[srcpos])
1898 {
1899 *stickyFailure = TRUE;
1900 }
1901 }
1902 else if (srctype == FS_UNICODE_CONVSRC_UNICODE)
1903 {
1904 const u16 *src = (const u16 *)srcptr;
1905 int n = (dstlen - 1 < srclen) ? (dstlen - 1) : srclen;
1906 while ((dstpos < n) && src[srcpos])
1907 {
1908 dst[dstpos++] = src[srcpos++];
1909 }
1910 if ((srcpos < srclen) && src[srcpos])
1911 {
1912 *stickyFailure = TRUE;
1913 }
1914 }
1915 else if (srctype == FS_UNICODE_CONVSRC_SHIFT_JIS)
1916 {
1917 const char *src = (const char *)srcptr;
1918 srcpos = srclen;
1919 dstpos = dstlen - 1;
1920 (void)FSi_ConvertStringSjisToUnicode(dst, &dstpos, src, &srcpos, NULL);
1921 if ((srcpos < srclen) && src[srcpos])
1922 {
1923 *stickyFailure = TRUE;
1924 }
1925 }
1926 dst[dstpos] = L'\0';
1927 return dstpos;
1928 }
1929
1930 /*---------------------------------------------------------------------------*
1931 Name: FSi_NormalizePathWtoW
1932
1933 Description: Converts Unicode path to Unicode full path that includes up to the archive name.
1934
1935 Arguments: path: Non-normalized path string
1936 baseid: Standard directory ID storage destination or NULL
1937 relpath: Path name storage destination after conversion or NULL
1938
1939 Returns: Archive pointer or NULL.
1940 *---------------------------------------------------------------------------*/
1941 FSArchive* FSi_NormalizePathWtoW(const u16 *path, u32*baseid, u16 *relpath);
FSi_NormalizePathWtoW(const u16 * path,u32 * baseid,u16 * relpath)1942 FSArchive* FSi_NormalizePathWtoW(const u16 *path, u32*baseid, u16 *relpath)
1943 {
1944 FSArchive *arc = NULL;
1945 int pathlen = 0;
1946 int pathmax = FS_ARCHIVE_FULLPATH_MAX + 1;
1947 BOOL stickyFailure = FALSE;
1948 // First, specify archive to be the command target
1949 // If specified Unicode path is absolute path, get archive
1950 BOOL absolute = FALSE;
1951 int arcnameLen;
1952 for (arcnameLen = 0; arcnameLen < FS_ARCHIVE_NAME_LONG_MAX + 1; ++arcnameLen)
1953 {
1954 if (path[arcnameLen] == L'\0')
1955 {
1956 break;
1957 }
1958 else if (FSi_IsUnicodeSlash(path[arcnameLen]))
1959 {
1960 break;
1961 }
1962 else if (path[arcnameLen] == L':')
1963 {
1964 char arcname[FS_ARCHIVE_NAME_LONG_MAX + 1];
1965 int j;
1966 for (j = 0; j < arcnameLen; ++j)
1967 {
1968 arcname[j] = (char)path[j];
1969 }
1970 arcname[arcnameLen] = '\0';
1971 arc = FS_FindArchive(arcname, arcnameLen);
1972 break;
1973 }
1974 }
1975 if (arc)
1976 {
1977 absolute = TRUE;
1978 *baseid = 0;
1979 }
1980 else
1981 {
1982 arc = FS_NormalizePath("", baseid, NULL);
1983 }
1984 if (arc)
1985 {
1986 // If archive cannot support Unicode, fails here
1987 u32 caps = 0;
1988 (void)arc->vtbl->GetArchiveCaps(arc, &caps);
1989 if ((caps & FS_ARCHIVE_CAPS_UNICODE) == 0)
1990 {
1991 arc = NULL;
1992 }
1993 else
1994 {
1995 // Stores archive name at top
1996 pathlen += FSi_CopySafeUnicodeString(&relpath[pathlen], pathmax - pathlen,
1997 FS_GetArchiveName(arc), FS_ARCHIVE_NAME_LONG_MAX,
1998 FS_UNICODE_CONVSRC_ASCII, &stickyFailure);
1999 pathlen += FSi_CopySafeUnicodeString(&relpath[pathlen], pathmax - pathlen,
2000 L":", 1,
2001 FS_UNICODE_CONVSRC_UNICODE, &stickyFailure);
2002 // If absolute path, link the root and below as it is
2003 if (absolute)
2004 {
2005 path += arcnameLen + 1 + FSi_IsUnicodeSlash(path[arcnameLen + 1]);
2006 }
2007 // If current root, directly link to the root and below
2008 else if (FSi_IsUnicodeSlash(*path))
2009 {
2010 path += 1;
2011 }
2012 // If the current directory, convert Shift_JIS to Unicode and link
2013 else
2014 {
2015 pathlen += FSi_CopySafeUnicodeString(&relpath[pathlen], pathmax - pathlen,
2016 L"/", 1,
2017 FS_UNICODE_CONVSRC_UNICODE, &stickyFailure);
2018 pathlen += FSi_CopySafeUnicodeString(&relpath[pathlen], pathmax - pathlen,
2019 FS_GetCurrentDirectory(), FS_ENTRY_LONGNAME_MAX,
2020 FS_UNICODE_CONVSRC_SHIFT_JIS, &stickyFailure);
2021 }
2022 // Link the remaining portion
2023 pathlen += FSi_CopySafeUnicodeString(&relpath[pathlen], pathmax - pathlen,
2024 L"/", 1,
2025 FS_UNICODE_CONVSRC_UNICODE, &stickyFailure);
2026 {
2027 // Be careful of special entry names and normalize relative path
2028 int curlen = 0;
2029 while (!stickyFailure)
2030 {
2031 u16 c = path[curlen];
2032 if ((c != L'\0') && !FSi_IsUnicodeSlash(c))
2033 {
2034 curlen += 1;
2035 }
2036 else
2037 {
2038 // Ignore empty directory
2039 if (curlen == 0)
2040 {
2041 }
2042 // Ignore "." (current directory)
2043 else if ((curlen == 1) && (path[0] == L'.'))
2044 {
2045 }
2046 // ".." (parent directory) raises the root one level as the upper limit
2047 else if ((curlen == 2) && (path[0] == '.') && (path[1] == '.'))
2048 {
2049 if ((pathlen > 2) && (relpath[pathlen - 2] != L':'))
2050 {
2051 --pathlen;
2052 pathlen = FSi_DecrementUnicodePositionToSlash(relpath, pathlen) + 1;
2053 }
2054 }
2055 // Add entry for anything else
2056 else
2057 {
2058 pathlen += FSi_CopySafeUnicodeString(&relpath[pathlen], pathmax - pathlen,
2059 path, curlen,
2060 FS_UNICODE_CONVSRC_UNICODE, &stickyFailure);
2061 if (c != L'\0')
2062 {
2063 pathlen += FSi_CopySafeUnicodeString(&relpath[pathlen], pathmax - pathlen,
2064 L"/", 1,
2065 FS_UNICODE_CONVSRC_UNICODE, &stickyFailure);
2066 }
2067 }
2068 if (c == L'\0')
2069 {
2070 break;
2071 }
2072 path += curlen + 1;
2073 curlen = 0;
2074 }
2075 }
2076 }
2077 relpath[pathlen] = L'\0';
2078 }
2079 }
2080 return stickyFailure ? NULL : arc;
2081 }
2082
2083 /*---------------------------------------------------------------------------*
2084 Name: FS_OpenFileExW
2085
2086 Description: Opens the file by specifying the path name.
2087
2088 Arguments: file: FSFile structure
2089 path: Path name
2090
2091 Returns: TRUE if successful.
2092 *---------------------------------------------------------------------------*/
FS_OpenFileExW(FSFile * file,const u16 * path,u32 mode)2093 BOOL FS_OpenFileExW(FSFile *file, const u16 *path, u32 mode)
2094 {
2095 BOOL retval = FALSE;
2096 FS_DEBUG_TRACE( "%s\n", __FUNCTION__);
2097 SDK_NULL_ASSERT(file);
2098 SDK_NULL_ASSERT(path);
2099 SDK_ASSERT(OS_GetProcMode() != OS_PROCMODE_IRQ);
2100
2101 // Logic check relating to FS_FILEMODE_L
2102 // (It is meaningless if there is a size restriction when opening in creation mode)
2103 if (((mode & FS_FILEMODE_L) != 0) &&
2104 ((mode & FS_FILEMODE_RW) == FS_FILEMODE_W))
2105 {
2106 OS_TWarning("\"FS_FILEMODE_WL\" seems useless.\n"
2107 "(this means creating empty file and prohibiting any modifications)");
2108 }
2109 {
2110 u16 relpath[FS_ARCHIVE_FULLPATH_MAX + 1];
2111 u32 baseid = 0;
2112 FSArchive *arc = FSi_NormalizePathWtoW(path, &baseid, relpath);
2113 // Currently, to limit to the minimum changes where the Unicode can be used, return unsupported with archives that do not support Unicode such as ROM and the like
2114 //
2115 if (!arc)
2116 {
2117 file->error = FS_RESULT_UNSUPPORTED;
2118 }
2119 else
2120 {
2121 FSArgumentForOpenFile arg[1];
2122 FS_InitFile(file);
2123 file->arc = arc;
2124 file->argument = arg;
2125 arg->baseid = baseid;
2126 arg->relpath = (char*)relpath;
2127 arg->mode = mode;
2128 file->stat |= FS_FILE_STATUS_UNICODE_MODE;
2129 if (FSi_SendCommand(file, FS_COMMAND_OPENFILE, TRUE))
2130 {
2131 retval = TRUE;
2132 }
2133 else
2134 {
2135 file->arc = NULL;
2136 }
2137 }
2138 }
2139 return retval;
2140 }
2141
2142 /*---------------------------------------------------------------------------*
2143 Name: FS_OpenDirectoryW
2144
2145 Description: Opens the directory handle.
2146
2147 Arguments: file: FSFile structure
2148 path: Path name
2149 mode: Access mode
2150
2151 Returns: TRUE if successful.
2152 *---------------------------------------------------------------------------*/
FS_OpenDirectoryW(FSFile * file,const u16 * path,u32 mode)2153 BOOL FS_OpenDirectoryW(FSFile *file, const u16 *path, u32 mode)
2154 {
2155 BOOL retval = FALSE;
2156 FS_DEBUG_TRACE( "%s\n", __FUNCTION__);
2157 SDK_NULL_ASSERT(path);
2158 SDK_ASSERT(OS_GetProcMode() != OS_PROCMODE_IRQ);
2159 {
2160 u16 relpath[FS_ARCHIVE_FULLPATH_MAX + 1];
2161 u32 baseid = 0;
2162 FSArchive *arc = FSi_NormalizePathWtoW(path, &baseid, relpath);
2163 // Currently, to limit to the minimum changes where the Unicode can be used, return unsupported with archives that do not support Unicode such as ROM and the like
2164 //
2165 if (!arc)
2166 {
2167 file->error = FS_RESULT_UNSUPPORTED;
2168 }
2169 else
2170 {
2171 FSArgumentForOpenDirectory arg[1];
2172 FS_InitFile(file);
2173 file->arc = arc;
2174 file->argument = arg;
2175 arg->baseid = baseid;
2176 arg->relpath = (char*)relpath;
2177 arg->mode = mode;
2178 file->stat |= FS_FILE_STATUS_UNICODE_MODE;
2179 if (FSi_SendCommand(file, FS_COMMAND_OPENDIRECTORY, TRUE))
2180 {
2181 retval = TRUE;
2182 }
2183 else
2184 {
2185 file->arc = NULL;
2186 }
2187 }
2188 }
2189 return retval;
2190 }
2191
2192 /*---------------------------------------------------------------------------*
2193 Name: FS_ReadDirectoryW
2194
2195 Description: Reads only one entry of the directory and advances.
2196
2197 Arguments: file: FSFile structure
2198 info: FSDirectoryEntryInfo structure
2199
2200 Returns: TRUE if successful.
2201 *---------------------------------------------------------------------------*/
FS_ReadDirectoryW(FSFile * file,FSDirectoryEntryInfoW * info)2202 BOOL FS_ReadDirectoryW(FSFile *file, FSDirectoryEntryInfoW *info)
2203 {
2204 BOOL retval = FALSE;
2205 SDK_NULL_ASSERT(file);
2206 SDK_NULL_ASSERT(info);
2207 SDK_ASSERT(FS_IsAvailable());
2208 SDK_ASSERT(FS_IsDir(file));
2209 SDK_ASSERT(OS_GetProcMode() != OS_PROCMODE_IRQ);
2210 {
2211 FSArchive *arc = file->arc;
2212 // Currently, to limit to the minimum changes where the Unicode can be used, return unsupported with archives that do not support Unicode such as ROM and the like
2213 //
2214 u32 caps = 0;
2215 (void)arc->vtbl->GetArchiveCaps(arc, &caps);
2216 if ((caps & FS_ARCHIVE_CAPS_UNICODE) == 0)
2217 {
2218 file->error = FS_RESULT_UNSUPPORTED;
2219 }
2220 else
2221 {
2222 FSArgumentForReadDirectory arg[1];
2223 file->argument = arg;
2224 arg->info = (FSDirectoryEntryInfo*)info;
2225 MI_CpuFill8(info, 0x00, sizeof(info));
2226 info->id = FS_INVALID_FILE_ID;
2227 file->stat |= FS_FILE_STATUS_UNICODE_MODE;
2228 if (FSi_SendCommand(file, FS_COMMAND_READDIR, TRUE))
2229 {
2230 retval = TRUE;
2231 }
2232 }
2233 }
2234 return retval;
2235 }
2236
2237
2238 /*---------------------------------------------------------------------------*
2239 * Deprecated Functions
2240 *---------------------------------------------------------------------------*/
2241
2242 /*---------------------------------------------------------------------------*
2243 Name: FSi_ConvertToDirEntry
2244
2245 Description: Converts from FSDirectoryEntryInfo structure to FSDirEntry structure.
2246
2247 Arguments: entry: FSDirEntry structure of the conversion destination
2248 arc: Archive that obtained the conversion source information
2249 info: FSDirectoryEntryInfo structure of the conversion source
2250
2251 Returns: TRUE if successful.
2252 *---------------------------------------------------------------------------*/
FSi_ConvertToDirEntry(FSDirEntry * entry,FSArchive * arc,const FSDirectoryEntryInfo * info)2253 static void FSi_ConvertToDirEntry(FSDirEntry *entry, FSArchive *arc, const FSDirectoryEntryInfo *info)
2254 {
2255 entry->name_len = info->longname_length;
2256 if (entry->name_len > sizeof(entry->name) - 1)
2257 {
2258 entry->name_len = sizeof(entry->name) - 1;
2259 }
2260 MI_CpuCopy8(info->longname, entry->name, entry->name_len);
2261 entry->name[entry->name_len] = '\0';
2262 if (info->id == FS_INVALID_FILE_ID)
2263 {
2264 entry->is_directory = FALSE;
2265 entry->file_id.file_id = FS_INVALID_FILE_ID;
2266 entry->file_id.arc = NULL;
2267 }
2268 else if ((info->attributes & FS_ATTRIBUTE_IS_DIRECTORY) != 0)
2269 {
2270 entry->is_directory = TRUE;
2271 entry->dir_id.arc = arc;
2272 entry->dir_id.own_id = (u16)(info->id >> 0);
2273 entry->dir_id.index = (u16)(info->id >> 16);
2274 entry->dir_id.pos = 0;
2275 }
2276 else
2277 {
2278 entry->is_directory = FALSE;
2279 entry->file_id.file_id = info->id;
2280 entry->file_id.arc = arc;
2281 }
2282 }
2283
2284 /*---------------------------------------------------------------------------*
2285 Name: FS_OpenFile
2286
2287 Description: Opens the file by specifying the path name.
2288
2289 Arguments: file: FSFile structure
2290 path: Path name
2291
2292 Returns: TRUE if successful.
2293 *---------------------------------------------------------------------------*/
FS_OpenFile(FSFile * file,const char * path)2294 BOOL FS_OpenFile(FSFile *file, const char *path)
2295 {
2296 return FS_OpenFileEx(file, path, FS_FILEMODE_R);
2297 }
2298
2299 /*---------------------------------------------------------------------------*
2300 Name: FS_GetLength
2301
2302 Description: Gets file size.
2303
2304 Arguments: file: File handle
2305
2306 Returns: File size.
2307 *---------------------------------------------------------------------------*/
FS_GetLength(FSFile * file)2308 u32 FS_GetLength(FSFile *file)
2309 {
2310 return FS_GetFileLength(file);
2311 }
2312
2313 /*---------------------------------------------------------------------------*
2314 Name: FS_GetPosition
2315
2316 Description: Gets the current position of the file pointer.
2317
2318 Arguments: file: File handle
2319
2320 Returns: Current position of the file pointer.
2321 *---------------------------------------------------------------------------*/
FS_GetPosition(FSFile * file)2322 u32 FS_GetPosition(FSFile *file)
2323 {
2324 return FS_GetFilePosition(file);
2325 }
2326
2327 /*---------------------------------------------------------------------------*
2328 Name: FS_FindDir
2329
2330 Description: Opens the directory handle.
2331
2332 Arguments: dir: FSFile structure
2333 path: Path name
2334
2335 Returns: TRUE if successful.
2336 *---------------------------------------------------------------------------*/
FS_FindDir(FSFile * dir,const char * path)2337 BOOL FS_FindDir(FSFile *dir, const char *path)
2338 {
2339 return FS_OpenDirectory(dir, path, FS_FILEMODE_R);
2340 }
2341
2342 /*---------------------------------------------------------------------------*
2343 Name: FS_ReadDir
2344
2345 Description: Reads only one entry of the directory and advances.
2346
2347 Arguments: file: FSFile structure
2348 entry: FSDirEntry structure
2349
2350 Returns: TRUE if successful.
2351 *---------------------------------------------------------------------------*/
FS_ReadDir(FSFile * file,FSDirEntry * entry)2352 BOOL FS_ReadDir(FSFile *file, FSDirEntry *entry)
2353 {
2354 BOOL retval = FALSE;
2355 FSDirectoryEntryInfo info[1];
2356 if (FS_ReadDirectory(file, info))
2357 {
2358 FSi_ConvertToDirEntry(entry, FS_GetAttachedArchive(file), info);
2359 retval = TRUE;
2360 }
2361 return retval;
2362 }
2363
2364 /*---------------------------------------------------------------------------*
2365 Name: FS_ChangeDir
2366
2367 Description: Changes the current directory.
2368
2369 Arguments: path: Path name
2370
2371 Returns: TRUE if successful.
2372 *---------------------------------------------------------------------------*/
FS_ChangeDir(const char * path)2373 BOOL FS_ChangeDir(const char *path)
2374 {
2375 return FS_SetCurrentDirectory(path);
2376 }
2377
2378 /*---------------------------------------------------------------------------*
2379 Name: FS_GetFileInfo
2380
2381 Description: Gets the file information.
2382
2383 Arguments: path: Path name
2384 info: Location to store the information
2385
2386 Returns: Processing result.
2387 *---------------------------------------------------------------------------*/
FS_GetFileInfo(const char * path,FSFileInfo * info)2388 FSResult FS_GetFileInfo(const char *path, FSFileInfo *info)
2389 {
2390 return FS_GetPathInfo(path, info) ? FS_RESULT_SUCCESS : FS_GetArchiveResultCode(path);
2391 }
2392
2393
2394 #endif /* FS_IMPLEMENT */
2395
2396 // The following is also used outside the FS library, so it is not targeted by FS_IMPLEMENT
2397 // Support for Unicode on ARM7 is necessary only for TWL operations, so locate on extended memory
2398 #if defined(SDK_TWL) && defined(SDK_ARM7)
2399 #include <twl/ltdmain_begin.h>
2400 #endif
2401
2402 static const int FSiUnicodeBufferQueueMax = 4;
2403 static OSMessageQueue FSiUnicodeBufferQueue[1];
2404 static OSMessage FSiUnicodeBufferQueueArray[FSiUnicodeBufferQueueMax];
2405 static BOOL FSiUnicodeBufferQueueInitialized = FALSE;
2406 static u16 FSiUnicodeBufferTable[FSiUnicodeBufferQueueMax][FS_ARCHIVE_FULLPATH_MAX + 1];
2407
2408 /*---------------------------------------------------------------------------*
2409 Name: FSi_GetUnicodeBuffer
2410
2411 Description: Gets temporary buffer for Unicode conversion.
2412 The FS library is used for conversion of Shift_JIS.
2413
2414 Arguments: src: Shift_JIS string needed in Unicode conversion or NULL
2415
2416 Returns: String buffer converted to UTF16-LE if necessary.
2417 *---------------------------------------------------------------------------*/
FSi_GetUnicodeBuffer(const char * src)2418 u16* FSi_GetUnicodeBuffer(const char *src)
2419 {
2420 u16 *retval = NULL;
2421 // Added buffer to message queue when making the initial call
2422 OSIntrMode bak = OS_DisableInterrupts();
2423 if (!FSiUnicodeBufferQueueInitialized)
2424 {
2425 int i;
2426 FSiUnicodeBufferQueueInitialized = TRUE;
2427 OS_InitMessageQueue(FSiUnicodeBufferQueue, FSiUnicodeBufferQueueArray, 4);
2428 for (i = 0; i < FSiUnicodeBufferQueueMax; ++i)
2429 {
2430 (void)OS_SendMessage(FSiUnicodeBufferQueue, FSiUnicodeBufferTable[i], OS_MESSAGE_BLOCK);
2431 }
2432 }
2433 (void)OS_RestoreInterrupts(bak);
2434 // Allocate the buffer from the message queue (if not necessary, block here)
2435 (void)OS_ReceiveMessage(FSiUnicodeBufferQueue, (OSMessage*)&retval, OS_MESSAGE_BLOCK);
2436 if (src)
2437 {
2438 int dstlen = FS_ARCHIVE_FULLPATH_MAX;
2439 (void)FSi_ConvertStringSjisToUnicode(retval, &dstlen, src, NULL, NULL);
2440 retval[dstlen] = L'\0';
2441 }
2442 return retval;
2443 }
2444
2445 /*---------------------------------------------------------------------------*
2446 Name: FSi_ReleaseUnicodeBuffer
2447
2448 Description: Deallocates the temporary buffer for Unicode conversion.
2449
2450 Arguments: buf: Buffer allocated by the FSi_GetUnicodeBuffer function
2451
2452 Returns: None.
2453 *---------------------------------------------------------------------------*/
FSi_ReleaseUnicodeBuffer(const void * buf)2454 void FSi_ReleaseUnicodeBuffer(const void *buf)
2455 {
2456 if (buf)
2457 {
2458 // Return used buffer to the message queue
2459 (void)OS_SendMessage(FSiUnicodeBufferQueue, (OSMessage)buf, OS_MESSAGE_BLOCK);
2460 }
2461 }
2462
2463 /*---------------------------------------------------------------------------*
2464 Name: FSi_ConvertStringSjisToUnicode
2465
2466 Description: Converts a Shift_JIS string into a Unicode string.
2467 When the path name being handled is clearly only in ASCII code, and the mutual conversion of Unicode and ShiftJIS can be simplified, it is possible to prevent the standard processes of the STD library from linking by overwriting this function.
2468
2469
2470
2471
2472 Arguments: dst: Conversion destination buffer
2473 The storage process is ignored if NULL is specified.
2474 dst_len: Pointer which stores and passes the maximum number of characters for the conversion destination buffer, then receives the number of characters that were actually stored.
2475 Ignored when NULL is given.
2476
2477 src: Conversion source buffer
2478 src_len: Pointer which stores and passes the maximum number of characters to be converted, then receives the number actually converted.
2479 The end-of-string position takes priority over this specification.
2480 When either a negative value is stored and passed, or NULL is given, the character count is revised to be the number of characters to the end of the string.
2481
2482
2483 callback: Callback to be called if there are any characters that can't be converted.
2484 When NULL is specified, the conversion process ends at the position of the character that cannot be converted.
2485
2486
2487 Returns: Result of the conversion process.
2488 *---------------------------------------------------------------------------*/
2489 SDK_WEAK_SYMBOL
FSi_ConvertStringSjisToUnicode(u16 * dst,int * dst_len,const char * src,int * src_len,STDConvertUnicodeCallback callback)2490 STDResult FSi_ConvertStringSjisToUnicode(u16 *dst, int *dst_len,
2491 const char *src, int *src_len,
2492 STDConvertUnicodeCallback callback)
2493 __attribute__((never_inline))
2494 {
2495 return STD_ConvertStringSjisToUnicode(dst, dst_len, src, src_len, callback);
2496 }
2497
2498 /*---------------------------------------------------------------------------*
2499 Name: FSi_ConvertStringUnicodeToSjis
2500
2501 Description: Converts a Unicode string into a Shift_JIS string.
2502 When the path name being handled is clearly only in ASCII code, and the mutual conversion of Unicode and ShiftJIS can be simplified, it is possible to prevent the standard processes of the STD library from linking by overwriting this function.
2503
2504
2505
2506
2507 Arguments: dst: Conversion destination buffer
2508 The storage process is ignored if NULL is specified.
2509 dst_len: Pointer which stores and passes the maximum number of characters for the conversion destination buffer, then receives the number of characters that were actually stored.
2510 Ignored when NULL is given.
2511
2512 src: Conversion source buffer
2513 src_len: Pointer which stores and passes the maximum number of characters to be converted, then receives the number actually converted.
2514 The end-of-string position takes priority over this specification.
2515 When either a negative value is stored and passed, or NULL is given, the character count is revised to be the number of characters to the end of the string.
2516
2517
2518 callback: Callback to be called if there are any characters that can't be converted.
2519 When NULL is specified, the conversion process ends at the position of the character that cannot be converted.
2520
2521
2522 Returns: Result of the conversion process.
2523 *---------------------------------------------------------------------------*/
2524 SDK_WEAK_SYMBOL
FSi_ConvertStringUnicodeToSjis(char * dst,int * dst_len,const u16 * src,int * src_len,STDConvertSjisCallback callback)2525 STDResult FSi_ConvertStringUnicodeToSjis(char *dst, int *dst_len,
2526 const u16 *src, int *src_len,
2527 STDConvertSjisCallback callback)
2528 __attribute__((never_inline))
2529 {
2530 return STD_ConvertStringUnicodeToSjis(dst, dst_len, src, src_len, callback);
2531 }
2532
2533 #if defined(SDK_TWL) && defined(SDK_ARM7)
2534 #include <twl/ltdmain_end.h>
2535 #endif
2536