about summary refs log blame commit diff stats
path: root/kernel.soso/fatfilesystem.c
blob: 9e3c2116c22f98d5ae905786f0c36b61e7acbd58 (plain) (tree)































                                                                                                 
                                







                                       
                                          



                                       
                                                                                             


                                                         
                                                   
                                                                   

                                                       


                                                              

                                                          




                                   
                                 



















                                                                           
                                              


                                                     
                                                                      
 
                                  




                                                          
                      












                                                        
                                                                                                  
                                                         
                                                   
                                                                   

                                                       







                            
                                                                      


                                                                          
                                                       





                               
                                    



                                     
                            















                                                                
                        





                                                           
                                                    


                                                 
                      
                         
                                          


                                                          
                                              







                                                       
                                                    

                                                      
              










                                                 
                                                                  


                                                                          
                                                                     

                                             

                                             


















                                                                      
                                    


                                 
                            















                                                                
                        





                                                           
                                                    



                                                   
                      














                                                                  
                                                    

                                             
              


                                        
                                       

                                       
              
                                                     
                                                




                                           
                                                     

                       
          
                                                  




                

                                                           







                                              
                                                                                               
                      





                  

                                                            







                                               
                      





                  

                                                            






                                     
                     













                                            
                      







                               
                                                           
                                             





                               
                                    


                                     
                            















                                                                
                        





                                                           
                                                



                                                   

                                                    

                                          
              










                                      
                                            
                                                 


                                      
                                         







                               
                                    


                                     
                            















                                                                
                        





                                                           
                                       


                            
                    















                                                      
                      









                               

                                    













                                                       
   


             
                                







                                                                                   
   
                                                                              














                                                                                                   
   












                                                                                                            
   







                                                             
                   




                                                   
                








                                                            
                











                                                          
#include "fatfilesystem.h"
#include "common.h"
#include "fs.h"
#include "alloc.h"
#include "fatfs_ff.h"
#include "fatfs_diskio.h"
#include "screen.h"

#define SEEK_SET	0	/* Seek from beginning of file.  */
#define SEEK_CUR	1	/* Seek from current position.  */
#define SEEK_END	2

#define O_RDONLY	     00
#define O_WRONLY	     01
#define O_RDWR		     02

static BOOL mount(const char* sourcePath, const char* targetPath, uint32 flags, void *data);
static BOOL checkMount(const char* sourcePath, const char* targetPath, uint32 flags, void *data);
static FileSystemDirent* readdir(FileSystemNode *node, uint32 index);
static FileSystemNode* finddir(FileSystemNode *node, char *name);
static int32 read(File *file, uint32 size, uint8 *buffer);
static int32 write(File *file, uint32 size, uint8 *buffer);
static int32 lseek(File *file, int32 offset, int32 whence);
static int32 stat(FileSystemNode *node, struct stat* buf);
static BOOL open(File *file, uint32 flags);
static void close(File *file);

static FileSystemDirent gFileSystemDirent;

static FileSystemNode* gMountedBlockDevices[FF_VOLUMES];


void initializeFatFileSystem() {
    FileSystem fs;
    memset((uint8*)&fs, 0, sizeof(fs));
    strcpy(fs.name, "fat");
    fs.mount = mount;
    fs.checkMount = checkMount;

    registerFileSystem(&fs);

    for (int i = 0; i < FF_VOLUMES; ++i) {
        gMountedBlockDevices[i] = NULL;
    }
}

static BOOL mount(const char* sourcePath, const char* targetPath, uint32 flags, void *data) {
    printkf("fat mount source: %s\n", sourcePath);

    FileSystemNode* node = getFileSystemNode(sourcePath);
    if (node && node->nodeType == FT_BlockDevice) {
        FileSystemNode* targetNode = getFileSystemNode(targetPath);
        if (targetNode) {
            if (targetNode->nodeType == FT_Directory) {
                printkf("fat mount target: %s\n", targetPath);

                int32 volume = -1;
                for (int32 v = 0; v < FF_VOLUMES; ++v) {
                    if (NULL == gMountedBlockDevices[v]) {
                        volume = v;
                        break;
                    }
                }

                if (volume < 0) {
                    return FALSE;
                }

                FileSystemNode* newNode = kmalloc(sizeof(FileSystemNode));

                memset((uint8*)newNode, 0, sizeof(FileSystemNode));
                strcpy(newNode->name, targetNode->name);
                newNode->nodeType = FT_Directory;
                newNode->open = open;
                newNode->readdir = readdir;
                newNode->finddir = finddir;
                newNode->parent = targetNode->parent;
                newNode->mountSource = node;
                newNode->privateNodeData = (void*)volume;

                gMountedBlockDevices[volume] = node;

                FATFS* fatFs = (FATFS*)kmalloc(sizeof(FATFS));
                //uint8 work[512];
                //FRESULT fr = f_mkfs("", FM_FAT | FM_SFD, 512, work, 512);
                //printkf("f_mkfs: %d\n", fr);
                char path[8];
                sprintf(path, "%d:", volume);
                FRESULT fr = f_mount(fatFs, path, 1);
                //printkf("f_mount: fr:%d drv:%d\n", fr, fatFs->pdrv);

                if (FR_OK == fr) {
                    targetNode->nodeType |= FT_MountPoint;
                    targetNode->mountPoint = newNode;

                    return TRUE;
                }
                else {
                    kfree(newNode);

                    kfree(fatFs);

                    gMountedBlockDevices[volume] = NULL;
                }
            }
        }
    }

    return FALSE;
}

static BOOL checkMount(const char* sourcePath, const char* targetPath, uint32 flags, void *data) {
    FileSystemNode* node = getFileSystemNode(sourcePath);
    if (node && node->nodeType == FT_BlockDevice) {
        FileSystemNode* targetNode = getFileSystemNode(targetPath);
        if (targetNode) {
            if (targetNode->nodeType == FT_Directory) {
                return TRUE;
            }
        }
    }

    return FALSE;
}

static FileSystemDirent* readdir(FileSystemNode *node, uint32 index) {
    //when node is the root of mounted filesystem,
    //node->mountSource is the source node (eg. disk partition /dev/hd1p1)

    //printkf("readdir1: node->name:%s\n", node->name);

    uint8 targetPath[128];

    FileSystemNode *n = node;
    int charIndex = 126;
    memset(targetPath, 0, 128);
    while (NULL == n->mountSource) {
        int length = strlen(n->name);

        charIndex -= length;

        if (charIndex < 2) {
            return NULL;
        }

        strcpyNonNull((char*)(targetPath + charIndex), n->name);
        charIndex -= 1;
        targetPath[charIndex] = '/';

        n = n->parent;
    }

    char number[8];
    sprintf(number, "%d", n->privateNodeData);//volume nuber

    targetPath[charIndex] = ':';
    int length = strlen(number);
    charIndex -= length;
    if (charIndex < 0) {
        return NULL;
    }

    strcpyNonNull((char*)(targetPath + charIndex), number);
    uint8* target = targetPath + charIndex;

    //printkf("readdir: targetpath:[%s]\n", target);

    DIR dir;
    FRESULT fr = f_opendir(&dir, (TCHAR*)target);
    if (FR_OK == fr) {
        FILINFO fileInfo;
        for (int i = 0; i <= index; ++i) {
            memset((uint8*)&fileInfo, 0, sizeof(FILINFO));
            fr = f_readdir(&dir, &fileInfo);

            if (strlen(fileInfo.fname) <= 0) {
                f_closedir(&dir);

                return NULL;
            }
        }

        gFileSystemDirent.inode = 0;
        strcpy(gFileSystemDirent.name, fileInfo.fname);
        if ((fileInfo.fattrib & AM_DIR) == AM_DIR) {
            gFileSystemDirent.fileType = FT_Directory;
        }
        else {
            gFileSystemDirent.fileType = FT_File;
        }

        f_closedir(&dir);

        return &gFileSystemDirent;
    }

    return NULL;
}

static FileSystemNode* finddir(FileSystemNode *node, char *name) {
    //when node is the root of mounted filesystem,
    //node->mountSource is the source node (eg. disk partition /dev/hd1p1)

    //printkf("finddir1: node->name:%s name:%s\n", node->name, name);

    FileSystemNode* child = node->firstChild;
    while (NULL != child) {
        if (strcmp(name, child->name) == 0) {
            return child;
        }

        child = child->nextSibling;
    }

    //If we are here, this file is accesed first time in this session.
    //So we create its node...

    uint8 targetPath[128];

    FileSystemNode *n = node;
    int charIndex = 126;
    memset(targetPath, 0, 128);
    int length = strlen(name);
    charIndex -= length;
    strcpyNonNull((char*)(targetPath + charIndex), name);
    charIndex -= 1;
    targetPath[charIndex] = '/';
    while (NULL == n->mountSource) {
        length = strlen(n->name);
        charIndex -= length;

        if (charIndex < 2) {
            return NULL;
        }

        strcpyNonNull((char*)(targetPath + charIndex), n->name);
        charIndex -= 1;
        targetPath[charIndex] = '/';

        n = n->parent;
    }

    char number[8];
    sprintf(number, "%d", n->privateNodeData);//volume nuber

    targetPath[charIndex] = ':';
    length = strlen(number);
    charIndex -= length;
    if (charIndex < 0) {
        return NULL;
    }

    strcpyNonNull((char*)(targetPath + charIndex), number);
    uint8* target = targetPath + charIndex;

    //printkf("finddir: targetpath:[%s]\n", target);

    FILINFO fileInfo;
    memset((uint8*)&fileInfo, 0, sizeof(FILINFO));
    FRESULT fr = f_stat((TCHAR*)target, &fileInfo);
    if (FR_OK == fr) {
        FileSystemNode* newNode = kmalloc(sizeof(FileSystemNode));

        memset((uint8*)newNode, 0, sizeof(FileSystemNode));
        strcpy(newNode->name, name);
        newNode->parent = node;
        newNode->readdir = readdir;
        newNode->finddir = finddir;
        newNode->open = open;
        newNode->close = close;
        newNode->read = read;
        newNode->write = write;
        newNode->lseek = lseek;
        newNode->stat = stat;
        newNode->length = fileInfo.fsize;

        if ((fileInfo.fattrib & AM_DIR) == AM_DIR) {
            newNode->nodeType = FT_Directory;
        }
        else {
            newNode->nodeType = FT_File;
        }

        if (NULL == node->firstChild) {
            node->firstChild = newNode;
        }
        else {
            FileSystemNode* child = node->firstChild;
            while (NULL != child->nextSibling) {
                child = child->nextSibling;
            }
            child->nextSibling = newNode;
        }

        //printkf("finddir: returning [%s]\n", name);
        return newNode;
    }
    else {
        //printkf("finddir error: fr: %d]\n", fr);
    }

    return NULL;
}

static int32 read(File *file, uint32 size, uint8 *buffer) {
    if (file->privateData == NULL) {
        return -1;
    }

    FIL* f = (FIL*)file->privateData;

    UINT br = 0;
    FRESULT fr = f_read(f, buffer, size, &br);
    file->offset = f->fptr;
    //printkf("fat read: name:%s size:%d hasRead:%d, fr:%d\n", file->node->name, size, br, fr);
    if (FR_OK == fr) {
        return br;
    }

    return -1;
}

static int32 write(File *file, uint32 size, uint8 *buffer) {
    if (file->privateData == NULL) {
        return -1;
    }

    FIL* f = (FIL*)file->privateData;

    UINT bw = 0;
    FRESULT fr = f_write(f, buffer, size, &bw);
    file->offset = f->fptr;
    if (FR_OK == fr) {
        return bw;
    }

    return -1;
}

static int32 lseek(File *file, int32 offset, int32 whence) {
    if (file->privateData == NULL) {
        return -1;
    }

    FIL* f = (FIL*)file->privateData;

    FRESULT fr = FR_INVALID_OBJECT;

    switch (whence) {
    case SEEK_SET:
        fr = f_lseek(f, offset);
        break;
    case SEEK_CUR:
        fr = f_lseek(f, f_tell(f) + offset);
        break;
    case SEEK_END:
        fr = f_lseek(f, f_size(f) + offset);
        break;
    default:
        break;
    }


    if (FR_OK == fr) {
        file->offset = f->fptr;

        return file->offset;
    }

    return -1;
}

static int32 stat(FileSystemNode *node, struct stat* buf) {
    //printkf("fat stat [%s]\n", node->name);

    uint8 targetPath[128];

    FileSystemNode *n = node;
    int charIndex = 126;
    memset(targetPath, 0, 128);
    while (NULL == n->mountSource) {
        int length = strlen(n->name);
        charIndex -= length;

        if (charIndex < 2) {
            return NULL;
        }

        strcpyNonNull((char*)(targetPath + charIndex), n->name);
        charIndex -= 1;
        targetPath[charIndex] = '/';

        n = n->parent;
    }

    char number[8];
    sprintf(number, "%d", n->privateNodeData);//volume nuber

    targetPath[charIndex] = ':';
    int length = strlen(number);
    charIndex -= length;
    if (charIndex < 0) {
        return NULL;
    }

    strcpyNonNull((char*)(targetPath + charIndex), number);
    uint8* target = targetPath + charIndex;

    //printkf("fat stat target:[%s]\n", target);

    FILINFO fileInfo;
    memset((uint8*)&fileInfo, 0, sizeof(FILINFO));
    FRESULT fr = f_stat((TCHAR*)target, &fileInfo);
    if (FR_OK == fr) {
        if ((fileInfo.fattrib & AM_DIR) == AM_DIR) {
            node->nodeType = FT_Directory;
        }
        else {
            node->nodeType = FT_File;
        }

        node->length = fileInfo.fsize;

        return 1;
    }

    return -1; //Error
}

static BOOL open(File *file, uint32 flags) {
    //printkf("fat open %s\n", file->node->name);

    FileSystemNode *node = file->node;

    if (node->nodeType == FT_Directory) {
        return TRUE;
    }

    uint8 targetPath[128];

    FileSystemNode *n = node;
    int charIndex = 126;
    memset(targetPath, 0, 128);
    while (NULL == n->mountSource) {
        int length = strlen(n->name);
        charIndex -= length;

        if (charIndex < 2) {
            return NULL;
        }

        strcpyNonNull((char*)(targetPath + charIndex), n->name);
        charIndex -= 1;
        targetPath[charIndex] = '/';

        n = n->parent;
    }

    char number[8];
    sprintf(number, "%d", n->privateNodeData);//volume nuber

    targetPath[charIndex] = ':';
    int length = strlen(number);
    charIndex -= length;
    if (charIndex < 0) {
        return NULL;
    }

    strcpyNonNull((char*)(targetPath + charIndex), number);
    uint8* target = targetPath + charIndex;

    //printkf("fat open %s\n", target);

    int fatfsMode = FA_READ;

    switch (flags) {
    case O_RDONLY:
        fatfsMode = FA_READ;
        break;
    case O_WRONLY:
        fatfsMode = FA_WRITE;
        break;
    case O_RDWR:
        fatfsMode = (FA_READ | FA_WRITE);
        break;
        //TODO: append, create
    default:
        break;
    }

    FIL* f = (FIL*)kmalloc(sizeof(FIL));
    FRESULT fr = f_open(f, (TCHAR*)target, fatfsMode);
    if (FR_OK == fr) {
        file->offset = f->fptr;

        file->privateData = f;

        return TRUE;
    }

    return FALSE;
}

static void close(File *file) {
    if (file->privateData == NULL) {
        return;
    }

    FIL* f = (FIL*)file->privateData;

    f_close(f);

    kfree(f);

    file->privateData = NULL;
}

DSTATUS disk_initialize(
        BYTE pdrv		//Physical drive nmuber
) {
    return 0;
}

DSTATUS disk_status(BYTE pdrv) {
    return 0;
}

DRESULT disk_read (
    BYTE pdrv,			/* Physical drive nmuber (0) */
    BYTE *buff,			/* Pointer to the data buffer to store read data */
    DWORD sector,		/* Start sector number (LBA) */
    UINT count			/* Number of sectors to read */
) {
    //printkf("disk_read() drv:%d sector:%d count:%d\n", pdrv, sector, count);

    if (gMountedBlockDevices[pdrv] == NULL) return RES_NOTRDY;

    //if (sector >= RamDiskSize) return RES_PARERR;

    gMountedBlockDevices[pdrv]->readBlock(gMountedBlockDevices[pdrv], (uint32)sector, count, buff);

    return RES_OK;
}

DRESULT disk_write (
    BYTE pdrv,			/* Physical drive nmuber (0) */
    const BYTE *buff,	/* Pointer to the data to be written */
    DWORD sector,		/* Start sector number (LBA) */
    UINT count			/* Number of sectors to write */
) {
    if (gMountedBlockDevices[pdrv] == NULL) return RES_NOTRDY;

    //if (sector >= RamDiskSize) return RES_PARERR;

    gMountedBlockDevices[pdrv]->writeBlock(gMountedBlockDevices[pdrv], (uint32)sector, count, (uint8*)buff);

    return RES_OK;
}

DRESULT disk_ioctl (
    BYTE pdrv,		/* Physical drive nmuber (0) */
    BYTE ctrl,		/* Control code */
    void* buff		/* Buffer to send/receive data block */
) {
    if (gMountedBlockDevices[pdrv] == NULL) return RES_ERROR;

    DRESULT dr = RES_ERROR;

    File* f = NULL;

    uint32 value = 0;

    switch (ctrl) {
    case CTRL_SYNC:
        dr = RES_OK;
        break;
    case GET_SECTOR_COUNT:
        f = open_fs(gMountedBlockDevices[pdrv], 0);
        if (f) {
            ioctl_fs(f, IC_GetSectorCount, &value);
            *(DWORD*)buff = value;
            dr = RES_OK;
            close_fs(f);
        }
        printkf("disk_ioctl GET_SECTOR_COUNT: %d\n", value);
        break;
    case GET_BLOCK_SIZE:
        f = open_fs(gMountedBlockDevices[pdrv], 0);
        if (f) {
            ioctl_fs(f, IC_GetSectorSizeInBytes, &value);
            *(DWORD*)buff = value;
            dr = RES_OK;
            close_fs(f);
        }
        printkf("disk_ioctl GET_BLOCK_SIZE: %d\n", value);
        *(DWORD*)buff = value;
        dr = RES_OK;
        break;
    }
    return dr;
}