PS3 Exfat Support

I had similar issues scanning dirs when implementing the file manager. there's a problem in the way the fflib manages mounts and indeed, if a mount is done many times on the same partition it goes haywire.
your approach of calling file_to_sectors after scanning the dir is the right approach. if you take out the mount calls in the function itself, it will not work outside the context. consider this a limitation for now as I haven't found a way to overcome this when I was working on the file manager. this issue is part of the original code and I'm not sure it could be fixed but I'll think of something and let you know if I find anything.

Thank you for your feedback. For now it's ok, but if sometime in the future we get a single library for exFAT/NTFS this could be an issue, because it doesn't work the same way as the file_to_sector for ntfs.

I wonder if it's possible to get the sectors without having to mount the device again or maybe make the library recover the previous status so it can continue reading the next entry in the directories (e.g. I'm using recursive directory scanning).
 
Not sure if what im going to say makes sense, but in the "f_read_sectors" have you tryed to delimit the amounts of readed sectors using strict rules ?
Im thinking in using multiplyers to align the amount of data with the "page size" and "block sizes", a bit related with this discussion https://arstechnica.com/civis/viewtopic.php?f=20&t=224800

Maybe the PS3 is picky with that... and im wondering if every different filesystem could have his specific requirements
 
This is the previous code before my "hack" in version 1.23:
https://github.com/aldostools/webMA...65419/_Projects_/prepISO/include/exfat.h#L114

To make it work, I first had to make a list of the ISOs found in the directory being scanned, then call fflib_file_to_sectors() for each ISO after the directory scan:
https://github.com/aldostools/webMAN-MOD/blob/master/_Projects_/prepISO/include/exfat.h#L168

I see a possible problem in your code - you do recursive call to dir_read and every time you call it, you mount the partition.
this is a 'no, no' as I found out.
if you look at my recursive function for dir scanning, I do the mounting/unmounting outside: https://github.com/lmirel/fm_psx/blob/df5d65c4730fcf4a48ea8195c1bee7b032753feb/source/fsutil.c#L624 in the caller function https://github.com/lmirel/fm_psx/blob/df5d65c4730fcf4a48ea8195c1bee7b032753feb/source/fsutil.c#L176
this avoids many problems.
again, it might or might not work for you but it was the only thing that worked for me.
 
IIRC I had to do the f_mount inside the "dir_read" because when I call fflib_file_to_sectors() the device is always mounted/unmounted:
https://github.com/aldostools/webMAN-MOD/blob/master/_Projects_/fatfs/source/fflib.c#L315
https://github.com/aldostools/webMAN-MOD/blob/master/_Projects_/fatfs/source/fflib.c#L344

I think that the unmount should be removed or do it optionally (maybe use phys for that).

Also I think the following 2 checks in the function f_mount() of ff.c could help to prevent some issues (I haven't had a chance to test it):
Code:
/* Get logical drive number */
vol = get_ldnumber(&rp);
if (vol < 0) return FR_INVALID_DRIVE;
cfs = FatFs[vol]; /* Pointer to fs object */

if( cfs &&  fs) return FR_OK; // cfs is already mounted
if(!cfs && !fs) return FR_OK; // cfs is already unmounted
 
IIRC I had to do the f_mount inside the "dir_read" because when I call fflib_file_to_sectors() the device is always mounted/unmounted:
https://github.com/aldostools/webMAN-MOD/blob/master/_Projects_/fatfs/source/fflib.c#L315
https://github.com/aldostools/webMAN-MOD/blob/master/_Projects_/fatfs/source/fflib.c#L344

I think that the unmount should be removed or do it optionally (maybe use phys for that).
try removing the mount/unmount in fflib_file_to_sectors to see if anything changes. the fs object is not used in fflib_file_to_sectors anyway and you'll just need to make sure it is mounted before the call.

@aldostools let me know if this works better so I can update the lib.
regarding the FS mount itself, it would be best managed in the lib along with the attach of the lib to a device and then use a helper function to get a pointer to the FS object such that it can be used when needed.
 
Last edited:
I successfully integrated exFAT support to ManaGunZ, thanks to your lib @tps, thank you.

But I was suprised to see that my ps4 drive isn't supported. It's a 4To exFAT GPT 512. I saw the FatFs lib include a flag for GPT (FF_LBA64) so I enabled it, but it still didn't work...
After investigating, I found the issue :

- sys_storage_read return EINVAL 0x80010002 Invalid argument or flag.


I know dev_flash use 0x22 as flag, I probably saw it on homebrews... I searched on devwiki I didn't find any information about this flag.
Does anyone have informations about these flags ?


I made a code to search a working flag... but it's very long and I'm not even sure to find something like that.

Code:
void DumpUSB000()
{
    int source;
    u32 read;
    
    char *sector = (char *) malloc(512);
    if(sector==NULL) return ;
    
    int ret = sys_storage_open(USB_MASS_STORAGE(0), &source);
    if( ret != 0 ) {
        print_load("Error : %X", ret);
        FREE(sector);
        return ;
    }
    
    prog_bar1_value = 0;
    prog_bar2_value = 0;
    
    u64 start = 0ULL;
    u64 end = 0xFFFFFFFFFFFFFFFFULL;
    
    long long unsigned int flag = 0;
    for(flag = 0; flag < end; flag+=1) {
        
        u32 v1 = flag >> 32;
         u32 v2 = (flag << 32) >> 32 ;
        double f1 = (double)v1*(double)100 / (double) 0xFFFFFFFF;
          double f2  = (double)v2*(double)100 / (double) 0xFFFFFFFF;
        prog_bar1_value = (s64) f1;
        prog_bar2_value = (s64) f2;
        
        print_head("%.3f%% | %f%% | 0x%ll016X", f2, f1, flag);
        memset(sector, 0, 512);
        
        ret = sys_storage_read(source, 0, 1, sector, &read, flag);
        if( ret == 0 ) break;
        
        if(cancel) {
            print_load("Warning : 0x%llX", flag);
            break;
        }
    }
    sys_storage_close(source);
    
    prog_bar1_value=-1;
    
    FILE *f;
    f = fopen("/dev_hdd0/boot_sector.bin", "wb");
    fwrite(sector, 512, 1, f);
    fclose(f);
    
    FREE(sector);
    
    f = fopen("/dev_hdd0/flag.txt", "wb");
    char res[255];
    sprintf(res, "flag 0x%llX, ret 0x%X\n", (unsigned int) flag, ret);
    fputs(res, f);
    fclose(f);
    
    Delete("/dev_hdd0/tmp/turnoff");
    lv2syscall4(379,0x1100,0,0,0);
}

PS : sys_storage_device_info, sys_storage_open, sys_storage_close works.
 
Last edited:
@Joonie @habib @aldostools @mysis @3141card @sandungas @tps

Sry, to call like that. I read somewhere "calls" aren't working when we edit a message.

it's about my previous post.

That code will take forever. Why not check first just turning on the 64 bits in the flag?

for(int i = 0; i < 64; i++) flag = 1<<i;

Then maybe some combinations of only 2 flags, then 3 and so on...:

for(int i = 0; i < 64; i++)
for(int j = 0; i < 64; i++) flag = 1<<i | 1<<j;

At least with this method you will test all bits in a balanced way.
Your method will test the last bits very late.
 
I successfully integrated exFAT support to ManaGunZ, thanks to your lib @tps, thank you.
Nice :)
Btw, remember to add a new text string with the new filesystem name for the "info tags" that appears in the bottom bar of the game selection screen, im mentioning it because is an small detail easy to miss

And another btw... now that you are going to re-organizing some managunz critical functions related with the filesystem management keep in mind the support for the "multicard reader" of the fatties (for MS, CF, SD devices), i know you was working a bit in it time ago but im not sure how much advanced you was in that matter
Now it could be a good timing to complete that support... or well... incase is too much work organize the code in the best way posible as a preparation to add support for that devices later
 
Last edited:
yep, all done although I can't test fatties devices, I explained what I did on changelog notes you'll see :)

I tried every flag possibilities and it's not working...

I just had idea : I was focused on the 'flag' : "Invalid argument or flag." But with a second thought it might be the capabilitie flag and control flag, as it's a generic error message. According to the official documentation, it's the flag from the function argument.

So, i'm going to test the other unknown argument called "mode" in psdevwiki.
@3141card is it also a single Byte (8 bits) ?
 
Last edited:
@Zar It seems you're omitting the sector count in sys_storage_read() call.

In your code you have:
ret = sys_storage_read(source, 0, 1, sector, &read, flag);

In webMAN MOD, it is declared like this:
int sys_storage_read(sys_device_handle_t device_handle, uint64_t unk, uint64_t start_sector, uint32_t sector_count, void *buf, uint32_t *nread, uint64_t unk2);

unk2 = flag: Normally it is 0, except to read eid0 from flash
#define FLASH_FLAGS 0x22ULL

The following code should work:
ret = sys_storage_read(source, 0, 1, 1, sector, &read, 0);
 
Last edited:
@aldostools
it's because I removed it from the argument, it was always 0 :
Code:
static inline s32 sys_storage_read(int fd, u64 start_sector, u64 nb_sector, const void* buffer, u32 *sectors_read, u64 flags )
{
    lv2syscall7( 602, fd, 0, start_sector, nb_sector, (u64)buffer, (u64)sectors_read, flags );
    return_to_user_prog(s32);
}


in psdevwiki it's defined like this : int sys_storage_read(int fd, int mode?, uint32_t start_sector, uint32_t sectors, uint8_t *bounce_buf, uint32_t *sectors_read, uint64_t flags) mode?=0

unk = mode
unk2 = flag

I tried 0 to 0xFF for these 2 unknown argument and it's still not working :'(
 
NVM I saw what you mean (removed reply).

Could it be a signing issue caused by self-ctrl-flags and self-cap-flags ??
 
Last edited:
I read the official documentation pdf about lv2syscalls, and now i'm pretty sure EINVAL error is about arguments/flag of the syscall as it's mentionnend. I searched just in case sys_storage function, unfortunatly they aren't included in the documentation and the sdk (even if the syscall number exist).

I tested another HDD of 300GB :
- exFAT 512 MBR working
- exFAT 512 GPT working

So, the issue is probably caused by the 4To > 2To ?

I also, noticied when I use sys_storage_get_device_info, it doesn't found the account of sector, it return 0 (the number should be 0x1A78AFBC) although it found the sector size (0x200)

So, my final guess is sys_storage_read return EINV because start_sector = sector_count = 0 !
 
I read the official documentation pdf about lv2syscalls, and now i'm pretty sure EINVAL error is about arguments/flag of the syscall as it's mentionnend. I searched just in case sys_storage function, unfortunatly they aren't included in the documentation and the sdk (even if the syscall number exist).

I tested another HDD of 300GB :
- exFAT 512 MBR working
- exFAT 512 GPT working

So, the issue is probably caused by the 4To > 2To ?

I also, noticied when I use sys_storage_get_device_info, it doesn't found the account of sector, it return 0 (the number should be 0x1A78AFBC) although it found the sector size (0x200)

So, my final guess is sys_storage_read return EINV because start_sector = sector_count = 0 !
FYI
In sys_storage_read, the argument for flag gets processed before being used.
uint64_t the_flag = (arg >> 4 & 0x7fffffffffffffff) << 4 | arg & 7;
At first glance, that's the only processing of the flag value passed as argument to sys_storage_read, then the_flag is copied into a stack based struct which is passed on to another function that does the actual reading making the follow up deeper down the code more difficult, it would take a little more time to reverse the rest of the code.

I saw no other flag parameter processing or validation checks through the first few sub levels of that function, except for one comparison of (the_flag & 0x80000000) with 0 at some point, in other words testing whether the_flag < 0x80000000.

But we have to assume that there must be some comps deeper in the sys_storage_read handling code or in other code that sys_storage_read may execute, when I stopped looking I was already 7 levels down from sys_storage_read and still no comps.

For the sector_start & sector_count parameters, there is no processing or validation checks right away, except for a sector_count 32bit trim, ie the higher 32bit of the 64bit register it is stored in are cleared to ensure that the value is within uint32_t range.
Both params are added (unchecked & unmodified) to that same struct I mentioned above for the_flag & therefore any invalid value detection must be done deeper in the code, most likely in the same location as for the_flag's validation.
But in any case, if ever you ended up passing 0 for sector_count due to a problem with get_device_info output or whatever, getting a EINVAL error would make perfect sense.

Also, as far as I could make out the "mode" parameter gets passed unchecked & unmodified to only one function which appears to ignore it completely, overwriting the register that parameter is stored in without using it or saving it, no matter what value you pass as argument. I think you would be wasting your time testing different values for it.
 
Last edited:
Thank you very much for the work already done.
I don't see the goal of the process on the flag.
I didn't try lot of value on the flag, I'll try the function of aldo on it.

0x22 is a valid flag, it seems to be = 0x20 | 0x02
 
@Zar I'm not able to copy large files to an external usb hdd formatted in exfat. i receive the message "Not enough space", while i can copy from usb to hdd0 large files (i think the cap is 4gb). it doesn't matter if i copy many files contemporairly, if there is a large file among them the operation fails. i'm on fresh evilnat 4.89, managunz 1.42 nightly 66f1d0e, nothing else installed.
 
  • Like
Reactions: Zar

Similar threads

Back
Top