152 lines
4.1 KiB
C
152 lines
4.1 KiB
C
#include "fsctl/fugue/dirent.h"
|
|
#include "fsctl/fugue/cluster.h"
|
|
#include "fsctl/fugue/logger.h"
|
|
#include "fsctl/fugue/bits/fat.h"
|
|
|
|
//---
|
|
// Internals
|
|
//---
|
|
|
|
/* _fugue_dirent_checksum() : Fugue checksum handling */
|
|
static uint8_t _fugue_dirent_checksum(uintptr_t directory)
|
|
{
|
|
uint8_t *block;
|
|
uint8_t checksum;
|
|
int a;
|
|
int b;
|
|
|
|
checksum = 0;
|
|
block = (void *)directory;
|
|
for (int i = 0 ; i < 11 ; ++i)
|
|
{
|
|
checksum = checksum & 0xff;
|
|
a = checksum / 2;
|
|
b = checksum * 128;
|
|
checksum = a | b;
|
|
checksum = checksum + block[i];
|
|
}
|
|
checksum = checksum & 0xff;
|
|
return checksum;
|
|
}
|
|
|
|
/* _fugue_dirent_frag_dump() : decode name fragment */
|
|
static int _fugue_dirent_frag_dump(fugue_file_t *file, uint8_t *frag, int n)
|
|
{
|
|
while (--n >= 0)
|
|
{
|
|
file->name[file->name_len] = frag[0];
|
|
if ((frag[0] & 0x80) != 0) {
|
|
file->name[file->name_len] = frag[1];
|
|
file->name_len += 1;
|
|
}
|
|
file->name_len += 1;
|
|
frag = &frag[2];
|
|
}
|
|
file->name[file->name_len] = '\0';
|
|
return 0;
|
|
}
|
|
|
|
//---
|
|
// Public
|
|
//---
|
|
|
|
/* fugue_dirent_init() : init dirent object */
|
|
int fugue_dirent_init(fugue_dirent_t *dirent, fugue_fs_t *fs)
|
|
{
|
|
if (fs == NULL || dirent == NULL)
|
|
return -1;
|
|
memset(dirent, 0x00, sizeof(fugue_dirent_t));
|
|
memcpy(&dirent->_private.fs, fs, sizeof(fugue_fs_t));
|
|
dirent->current_dir_addr = (uintptr_t)fs->_private.root;
|
|
dirent->cluster_addr_start = (uintptr_t)fs->_private.root;
|
|
dirent->cluster_addr_end = (uintptr_t)fs->_private.root;
|
|
dirent->cluster_addr_end += fs->props.sector_root_nb * 512;
|
|
return 0;
|
|
}
|
|
|
|
/* fugue_dirent_dir_fetch() : fetch the current dir blob and walk to next */
|
|
void *fugue_dirent_dir_fetch(fugue_dirent_t *dirent)
|
|
{
|
|
void *dir;
|
|
|
|
dir = (void*)dirent->current_dir_addr;
|
|
if (dir == NULL)
|
|
return NULL;
|
|
|
|
dirent->current_dir_addr += 32;
|
|
if (dirent->current_dir_addr < dirent->cluster_addr_end)
|
|
return dir;
|
|
|
|
dirent->cluster_addr_start = fugue_cluster_find_next(
|
|
&dirent->_private.fs,
|
|
dirent->cluster_idx
|
|
);
|
|
dirent->cluster_addr_end = dirent->cluster_addr_start;
|
|
if (dirent->cluster_addr_start != 0x00000000)
|
|
dirent->cluster_addr_end += dirent->_private.fs.props.cluster_size;
|
|
return dir;
|
|
}
|
|
|
|
/* fugue_dirent_name_fetch() : fetch fragment */
|
|
int fugue_dirent_name_fetch(
|
|
fugue_dirent_t *dirent,
|
|
fugue_file_t *file,
|
|
void *dir
|
|
) {
|
|
fugue_logger_t *log;
|
|
struct fugue_fat_dir_name *lfn;
|
|
|
|
lfn = (void *)dir;
|
|
log = dirent->_private.fs._private.logger;
|
|
|
|
//---
|
|
// check directory block validity
|
|
//---
|
|
|
|
if (lfn->DIR_Attr != FUGUE_DIR_ATTR_LFN) {
|
|
fugue_logger_write(log, "[WARN] %p: LFN type error\n", lfn);
|
|
return -1;
|
|
}
|
|
if (lfn->DIR_Type != 0x00) {
|
|
fugue_logger_write(log, "[WARN] %p: LFN attribute error\n", lfn);
|
|
return -2;
|
|
}
|
|
if (lfn->DIR_FstClus != 0x0000) {
|
|
fugue_logger_write(log, "[WARN] %p: cluster info error\n", lfn);
|
|
return -3;
|
|
}
|
|
if (lfn->DIR_Sequence._low0 != 0 || lfn->DIR_Sequence._low1 != 0) {
|
|
fugue_logger_write(log, "[WARN] %p: dirty sequence\n", lfn);
|
|
return -4;
|
|
}
|
|
if (lfn->checksum != _fugue_dirent_checksum(dirent->current_dir_addr)) {
|
|
fugue_logger_write(log, "[WARN] %p: checksum error\n", lfn);
|
|
return -5;
|
|
}
|
|
|
|
//---
|
|
// check sequence validity
|
|
//---
|
|
|
|
if (lfn->DIR_Sequence.last != 0)
|
|
{
|
|
if (dirent->_private.lfn_prev_idx != 0)
|
|
fugue_logger_write(log, "[WARN] %p: multiple LFN entry\n", lfn);
|
|
dirent->_private.lfn_prev_idx = lfn->DIR_Sequence.id + 1;
|
|
}
|
|
if (dirent->_private.lfn_prev_idx != lfn->DIR_Sequence.id + 1) {
|
|
fugue_logger_write(log, "[WARN] %p: LFN sequence error\n", lfn);
|
|
return -6;
|
|
}
|
|
dirent->_private.lfn_prev_idx = lfn->DIR_Sequence.id;
|
|
|
|
//---
|
|
// Dump name fragment
|
|
//---
|
|
|
|
_fugue_dirent_frag_dump(file, (uint8_t*)&lfn->DIR_Char0, 5);
|
|
_fugue_dirent_frag_dump(file, (uint8_t*)&lfn->DIR_Char5, 5);
|
|
_fugue_dirent_frag_dump(file, (uint8_t*)&lfn->DIR_Char11,2);
|
|
return -1;
|
|
}
|