#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; }