#include #include "fsctl/fugue.h" #include "fsctl/fugue/bits/fat.h" #include "fsctl/fugue/dirent.h" #include "fsctl/fugue/utils.h" #include "fsctl/utils/fs_table.h" //--- // Internals //--- //--- // Public //--- /* fugue_fs_opendir() : opendir-like function */ int fugue_fs_opendir(fugue_dir_t *dir) { fugue_fs_t fs; if (dir == NULL) return -1; if (fs_table_info(&fs, NULL, NULL) != 0) return -2; memset(dir, 0x00, sizeof(fugue_dir_t)); memcpy(&dir->_private.fs, &fs, sizeof(fugue_fs_t)); dir->current_dir_addr = (uintptr_t)fs._private.root; dir->cluster_addr = (uintptr_t)fs._private.root; dir->cluster_size = fs.props.sector_root_nb * 512; return 0; } /* fugue_fs_readdir() : readdir-like function */ int fugue_fs_readdir(fugue_dir_t *dirent, fugue_file_t *file) { struct fugue_fat_dir *dir; fugue_dir_t dirent_backup; bool error; bool vfat; if (dirent == NULL) return -1; if (file == NULL) return -1; if (dirent->current_dir_addr == 0x00000000) return -2; memset(file, 0x00, sizeof(fugue_file_t)); memcpy(&dirent_backup, dirent, sizeof(fugue_dir_t)); vfat = false; error = false; while (error == false) { /* fetch the current FAT directory and walk */ dir = fugue_dirent_dir_fetch(dirent); if (dir == NULL) { error = true; continue; } //--- // handle special name behaviour //--- switch(dir->DIR_Name[0]) { /* handle free directory */ case 0x00: //fugue_logger_warn("opendir: wierd empty directory block ") error = true; continue; /* dot and dotdot special file */ case '.': if (memcmp(dir->DIR_Name, ". ", 2) == 0) memcpy(file->name, ".", 2); if (memcmp(dir->DIR_Name, ".. ", 3) == 0) memcpy(file->name, "..", 3); if (vfat == true) //fugue_logger_warn("opendir: wierd directory block ") file->type = FUGUE_FILE_TYPE_DIR; file->size = FAT_LONG(dir->DIR_FileSize); return 0; /* removed entry */ case 0x05: case 0xe5: //fugue_logger_notice("opendir : removed entry"); memset(file, 0x00, sizeof(fugue_file_t)); vfat = false; continue; } //--- // handle directory attribute //--- switch(dir->DIR_Attr) { /* handle file name fragment */ case FUGUE_DIR_ATTR_VNAME: fugue_dirent_name_fetch(dirent, file); vfat = true; break; /* file handling */ case FUGUE_DIR_ATTR_RDONLY: case FUGUE_DIR_ATTR_HIDDEN: case FUGUE_DIR_ATTR_SYSTEM: case FUGUE_DIR_ATTR_DIR: case FUGUE_DIR_ATTR_ARCHIVE: case FUGUE_DIR_ATTR_DEVICE: //TODO : file type file->type = FUGUE_FILE_TYPE_FILE; file->size = FAT_LONG(dir->DIR_FileSize); return 0; /* other attribute not handled */ default: //fugue_logger_warn("opendir : unsupported attribute ") error = true; break; } } /* error handling */ memcpy(dirent, &dirent_backup, sizeof(fugue_dir_t)); memset(file, 0x00, sizeof(fugue_file_t)); return -1; } /* fugue_fs_closedir() : closedir-like function */ int fugue_fs_closedir(fugue_dir_t *dir) { if (dir == NULL) return -1; memset(dir, 0x00, sizeof(fugue_dir_t)); dir->current_dir_addr = 0x00000000; dir->cluster_addr = 0x00000000; dir->cluster_size = 0; return 0; }