fsctl/src/fugue/dir.c

156 lines
4.1 KiB
C

#include <string.h>
#include "fsctl/fugue.h"
#include "fsctl/fugue/bits/fat.h"
#include "fsctl/fugue/dirent.h"
#include "fsctl/fugue/logger.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_dirent_t *dirent)
{
fugue_fs_t fs;
if (dirent == NULL)
return -1;
if (fs_table_info(&fs, NULL, NULL) != 0)
return -2;
return fugue_dirent_init(dirent, &fs);
}
/* fugue_fs_readdir() : readdir-like function */
int fugue_fs_readdir(fugue_dirent_t *dirent, fugue_file_t *file)
{
struct fugue_fat_dir *dir;
fugue_dirent_t dirent_backup;
fugue_logger_t *log;
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_dirent_t));
log = dirent->_private.fs._private.logger;
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_write(log, "[WARN] opendir: empty dir block\n");
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_write(
log,
"[WARN] %p:opendir: wierd dir block layout\n",
dir
);
}
file->type = FUGUE_FILE_TYPE_DIR;
file->size = FAT_LONG(dir->DIR_FileSize);
return 0;
/* removed entry */
case 0x05:
case 0xe5:
fugue_logger_write(
log,
"[NOTICE] %p:opendir : removed entry\n",
dir
);
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_LFN:
fugue_dirent_name_fetch(dirent, file, dir);
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_write(
log,
"[WARN] %p:opendir : KO attr %02x\n",
dir, dir->DIR_Attr
);
error = true;
break;
}
}
/* error handling */
memcpy(dirent, &dirent_backup, sizeof(fugue_dirent_t));
memset(file, 0x00, sizeof(fugue_file_t));
return -1;
}
/* fugue_fs_closedir() : closedir-like function */
int fugue_fs_closedir(fugue_dirent_t *dir)
{
if (dir == NULL)
return -1;
memset(dir, 0x00, sizeof(fugue_dirent_t));
dir->current_dir_addr = 0x00000000;
dir->cluster_addr_start = 0x00000000;
dir->cluster_addr_end = 0;
return 0;
}