1285 lines
34 KiB
C
1285 lines
34 KiB
C
#include "vfs.h"
|
|
#include "fat.h"
|
|
#include "memory.h"
|
|
#include "console.h"
|
|
|
|
int fat_load_superblock(struct vfs_device_t *device) {
|
|
unsigned char *buffer;
|
|
struct fat_data *fatData;
|
|
|
|
buffer = (char *)malloc(512);
|
|
if (!buffer) {
|
|
return 0;
|
|
}
|
|
fatData = (struct fat_data *)malloc(sizeof(struct fat_data));
|
|
if (!fatData) {
|
|
free(buffer);
|
|
return 0;
|
|
}
|
|
switch (device->device) {
|
|
case 1:
|
|
ramdisk_read_block(0, buffer, 512);
|
|
break;
|
|
}
|
|
memcpy(&fatData->superblock, buffer, sizeof(struct BPB));
|
|
|
|
if (buffer[510] == 0x55 && buffer[511] == 0xAA) {
|
|
free(buffer);
|
|
|
|
if (fatData->superblock.BPB_FATSz16 != 0) {
|
|
fatData->fat_size = fatData->superblock.BPB_FATSz16;
|
|
} else {
|
|
fatData->fat_size = fatData->superblock.FatType.Fat32.BPB_FATSz32;
|
|
}
|
|
|
|
|
|
fatData->root_dir_sectors = ((fatData->superblock.BPB_RootEntCnt * 32) + (fatData->superblock.BPB_BytesPerSec - 1)) / fatData->superblock.BPB_BytesPerSec;
|
|
fatData->first_data_sec = fatData->superblock.BPB_RsvdSecCnt + (fatData->superblock.BPB_NumFATs * fatData->fat_size) + fatData->root_dir_sectors;
|
|
|
|
if (fatData->superblock.BPB_TotSec16 != 0) {
|
|
fatData->totsec = fatData->superblock.BPB_TotSec16;
|
|
} else {
|
|
fatData->totsec = fatData->superblock.BPB_TotSec32;
|
|
}
|
|
|
|
fatData->data_sec = fatData->totsec - (fatData->superblock.BPB_RsvdSecCnt + (fatData->superblock.BPB_NumFATs * fatData->fat_size) + fatData->root_dir_sectors);
|
|
|
|
|
|
fatData->count_of_clusters = fatData->data_sec / fatData->superblock.BPB_SecPerClus;
|
|
|
|
if (fatData->count_of_clusters < 4085) {
|
|
fatData->fat = 0;
|
|
kprintf("FAT FS: Fat12\n");
|
|
} else if (fatData->count_of_clusters < 65525) {
|
|
fatData->fat = 1;
|
|
kprintf("FAT FS: Fat16\n");
|
|
} else {
|
|
fatData->fat = 2;
|
|
kprintf("FAT FS: Fat32\n");
|
|
}
|
|
|
|
device->fs_data = fatData;
|
|
return 1;
|
|
}
|
|
kprintf("FAT FS: Unrecognised Filesystem.\n");
|
|
free(buffer);
|
|
return 0;
|
|
}
|
|
|
|
unsigned int cluster_to_sec(struct vfs_device_t *device, unsigned int cluster) {
|
|
struct fat_data *data = (struct fat_data *)device->fs_data;
|
|
return (cluster - 2) * data->superblock.BPB_SecPerClus + data->first_data_sec;
|
|
}
|
|
|
|
unsigned int fat_get_cluster_entry(struct vfs_device_t *device, unsigned int cluster) {
|
|
struct fat_data *data = (struct fat_data *)device->fs_data;
|
|
unsigned int fatOffset;
|
|
if (data->fat != 0) {
|
|
if (data->fat == 1) {
|
|
fatOffset = cluster * 2;
|
|
} else if (data->fat == 2) {
|
|
fatOffset = cluster * 4;
|
|
}
|
|
unsigned int sector = data->superblock.BPB_RsvdSecCnt + (fatOffset / data->superblock.BPB_BytesPerSec);
|
|
unsigned int offset = fatOffset % data->superblock.BPB_BytesPerSec;
|
|
char *buffer = (char *)malloc(data->superblock.BPB_BytesPerSec);
|
|
if (!buffer) {
|
|
// fail.
|
|
}
|
|
switch (device->device) {
|
|
case 1:
|
|
ramdisk_read_block(sector, buffer, data->superblock.BPB_BytesPerSec);
|
|
break;
|
|
}
|
|
|
|
if (data->fat == 1) {
|
|
unsigned short fat16clusterEntryVal = *((unsigned short *)&buffer[offset]);
|
|
return (unsigned int)fat16clusterEntryVal;
|
|
} else if (data->fat == 2) {
|
|
unsigned int fat32clusterEntryVal = *((unsigned int *)&buffer[offset]);
|
|
return fat32clusterEntryVal;
|
|
}
|
|
} else {
|
|
fatOffset = cluster + (cluster / 2);
|
|
unsigned int sector = data->superblock.BPB_RsvdSecCnt + (fatOffset / data->superblock.BPB_BytesPerSec);
|
|
unsigned int offset = fatOffset % data->superblock.BPB_BytesPerSec;
|
|
|
|
char *buffer = (char *)malloc(data->superblock.BPB_BytesPerSec * 2);
|
|
if (!buffer) {
|
|
// fail
|
|
}
|
|
switch (device->device) {
|
|
case 1:
|
|
ramdisk_read_blocks(sector, 2, buffer, data->superblock.BPB_BytesPerSec);
|
|
break;
|
|
}
|
|
|
|
unsigned short fat12clusterEntryVal = *((unsigned short *)&buffer[offset]);
|
|
if (cluster & 0x0001) {
|
|
fat12clusterEntryVal = fat12clusterEntryVal >> 4;
|
|
} else {
|
|
fat12clusterEntryVal = fat12clusterEntryVal & 0x0fff;
|
|
}
|
|
return (unsigned int)fat12clusterEntryVal;
|
|
}
|
|
}
|
|
|
|
unsigned int fat_get_offset_for_cluster(struct vfs_device_t *device, unsigned int cluster) {
|
|
struct fat_data *data = (struct fat_data *)device->fs_data;
|
|
}
|
|
|
|
unsigned char is_EOC(struct vfs_device_t *device, unsigned int content) {
|
|
struct fat_data *data = (struct fat_data *)device->fs_data;
|
|
|
|
if (data->fat == 0) {
|
|
if (content >= 0x0ff8) {
|
|
return 1;
|
|
}
|
|
} else if (data->fat == 1) {
|
|
if (content >= 0xfff8) {
|
|
return 1;
|
|
}
|
|
} else if (data->fat == 2) {
|
|
if (content >= 0x0ffffff8) {
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
unsigned int fat_read_entire_file(struct vfs_device_t *device, unsigned int start_cluster, char **buffer) {
|
|
struct fat_data *data = (struct fat_data *)device->fs_data;
|
|
|
|
|
|
unsigned int *clusterchain = (unsigned int *)malloc(sizeof(unsigned int) * 2);
|
|
clusterchain[0] = start_cluster;
|
|
clusterchain[1] = fat_get_cluster_entry(device, start_cluster);
|
|
int i = 1;
|
|
while (!is_EOC(device, clusterchain[i])) {
|
|
i++;
|
|
clusterchain = (unsigned int *)realloc(clusterchain, sizeof(unsigned int) * (i + 1));
|
|
clusterchain[i] = fat_get_cluster_entry(device, clusterchain[i-1]);
|
|
}
|
|
int len = (i + 1) * data->superblock.BPB_SecPerClus * data->superblock.BPB_BytesPerSec;
|
|
*buffer = (char *)malloc(len);
|
|
unsigned int first_sec = cluster_to_sec(device, start_cluster);
|
|
|
|
int j;
|
|
|
|
char *buffer_loc;
|
|
|
|
for (j=0;j<i;j++) {
|
|
switch(device->device) {
|
|
case 1:
|
|
buffer_loc = *buffer;
|
|
ramdisk_read_blocks(cluster_to_sec(device, clusterchain[j]), data->superblock.BPB_SecPerClus, &buffer_loc[j * data->superblock.BPB_SecPerClus * data->superblock.BPB_BytesPerSec], data->superblock.BPB_BytesPerSec);
|
|
break;
|
|
}
|
|
}
|
|
free(clusterchain);
|
|
return len;
|
|
}
|
|
|
|
unsigned char fat_long_dir_chksum(unsigned char *shortfname) {
|
|
short FcbNameLen;
|
|
unsigned char Sum;
|
|
|
|
Sum = 0;
|
|
for (FcbNameLen=11;FcbNameLen != 0; FcbNameLen--) {
|
|
Sum = ((Sum & 1) ? 0x80 : 0) + (Sum >> 1) + *shortfname++;
|
|
}
|
|
return Sum;
|
|
}
|
|
|
|
struct fat_file_info *fat_find_sub_entry(struct vfs_device_t *device, unsigned int start_cluster, char **ptr, int part, int parts, int type) {
|
|
struct fat_data *data = (struct fat_data *)device->fs_data;
|
|
char *buffer;
|
|
int len;
|
|
int i;
|
|
int j;
|
|
char temp[13];
|
|
char long_filename[256];
|
|
unsigned char chksum = 0;
|
|
|
|
int k = 0;
|
|
int long_name_len = 0;
|
|
memset(long_filename, 0, 256);
|
|
|
|
len = fat_read_entire_file(device, start_cluster, &buffer);
|
|
|
|
for (i=0;i<len / 32;i++) {
|
|
struct fat_dir *dir = (struct fat_dir *)&buffer[i * 32];
|
|
if (dir->DIR_Attribute & ATTR_LONG_NAME) {
|
|
struct fat_long_dir *ldir = (struct fat_long_dir *)dir;
|
|
if (ldir->LDIR_Ord & 0x40) {
|
|
memset(long_filename, 0, 256, 0);
|
|
long_name_len = 0;
|
|
chksum = ldir->LDIR_Chksum;
|
|
// last entry
|
|
// check length
|
|
for (k=0;k<5;k++) {
|
|
if (ldir->LDIR_Name1[k] == 0x0000) {
|
|
long_name_len = 13 * (ldir->LDIR_Ord & ~(0x40) - 1) + k;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!long_name_len) {
|
|
for (k=0;k<6;k++) {
|
|
if (ldir->LDIR_Name2[k] == 0x0000) {
|
|
long_name_len = 13 * (ldir->LDIR_Ord & ~(0x40) - 1) + k + 5;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (!long_name_len) {
|
|
for (k=0;k<2;k++) {
|
|
if (ldir->LDIR_Name3[k] == 0x0000) {
|
|
long_name_len = 13 * (ldir->LDIR_Ord & ~(0x40) - 1) + k + 5 + 6;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
int offset = 13 * (ldir->LDIR_Ord & ~(0x40) - 1);
|
|
|
|
for (k=0;k<5;k++) {
|
|
long_filename[offset + k] = (char)(ldir->LDIR_Name1[k] & 0xFF);
|
|
}
|
|
|
|
for (k=0;k<6;k++) {
|
|
long_filename[offset + 5 + k] = (char)(ldir->LDIR_Name2[k] & 0xFF);
|
|
}
|
|
for (k=0;k<2;k++) {
|
|
long_filename[offset + 11 + k] = (char)(ldir->LDIR_Name3[k] & 0xFF);
|
|
}
|
|
} else {
|
|
int offset = 13 * (ldir->LDIR_Ord - 1);
|
|
for (k=0;k<5;k++) {
|
|
long_filename[offset + k] = (char)(ldir->LDIR_Name1[k] & 0xFF);
|
|
}
|
|
|
|
for (k=0;k<6;k++) {
|
|
long_filename[offset + 5 + k] = (char)(ldir->LDIR_Name2[k] & 0xFF);
|
|
}
|
|
for (k=0;k<2;k++) {
|
|
long_filename[offset + 11 + k] = (char)(ldir->LDIR_Name3[k] & 0xFF);
|
|
}
|
|
}
|
|
} else {
|
|
memset(temp, 0, 13);
|
|
|
|
if (dir->DIR_Name[0] == 0xE5) {
|
|
continue;
|
|
}
|
|
if (dir->DIR_Name[0] == 0x00) {
|
|
break;
|
|
}
|
|
if (dir->DIR_Name[0] == 0x05) {
|
|
temp[0] = 0xE5;
|
|
} else {
|
|
temp[0] = dir->DIR_Name[0];
|
|
}
|
|
for (j=1;j<8;j++) {
|
|
if ( dir->DIR_Name[j] == ' ') {
|
|
break;
|
|
} else {
|
|
temp[j] = dir->DIR_Name[j];
|
|
}
|
|
}
|
|
|
|
if (dir->DIR_Name[8] != ' ') {
|
|
temp[8] = '.';
|
|
for (j=8;j<11;j++) {
|
|
if (dir->DIR_Name[j] == ' ') {
|
|
break;
|
|
} else {
|
|
temp[j + 1] == dir->DIR_Name[j];
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if (parts == part + 1) {
|
|
if (chksum != fat_long_dir_chksum(dir->DIR_Name)) {
|
|
memset(long_filename, 0, 256);
|
|
}
|
|
|
|
if (strcmp(ptr[part], long_filename) == 0 || strcmp(ptr[part], temp) == 0) {
|
|
if (type == 0 && (dir->DIR_Attribute & ATTR_DIRECTORY)) {
|
|
free(buffer);
|
|
struct fat_file_info *info = (struct fat_file_info *)malloc(sizeof(struct fat_file_info));
|
|
if (!info) {
|
|
return NULL;
|
|
}
|
|
|
|
info->start_cluster = (dir->DIR_FirstClustHi << 0xffff) | dir->DIR_FirstClustLo;
|
|
info->file_size = dir->DIR_FileSize;
|
|
info->type = 0;
|
|
unsigned int thetime = get_time_since_epoch((dir->DIR_WrtDate & 0x7F) + 80, (dir->DIR_WrtDate >> 7) & 0xF, (dir->DIR_WrtDate >> 11) & 0x1F, dir->DIR_WrtTime & 0xF, (dir->DIR_WrtTime >> 4) & 0x3F, ((dir->DIR_WrtTime >> 11) & 0x1F) * 2);
|
|
|
|
info->atime = thetime;
|
|
info->ctime = thetime;
|
|
info->mtime = thetime;
|
|
return info;
|
|
} else if (type == 1 && !(dir->DIR_Attribute & ATTR_DIRECTORY)) {
|
|
free(buffer);
|
|
struct fat_file_info *info = (struct fat_file_info *)malloc(sizeof(struct fat_file_info));
|
|
if (!info) {
|
|
return NULL;
|
|
}
|
|
|
|
info->start_cluster = (dir->DIR_FirstClustHi << 0xffff) | dir->DIR_FirstClustLo;
|
|
info->file_size = dir->DIR_FileSize;
|
|
info->type = 1;
|
|
unsigned int thetime = get_time_since_epoch((dir->DIR_WrtDate & 0x7F) + 80, (dir->DIR_WrtDate >> 7) & 0xF, (dir->DIR_WrtDate >> 11) & 0x1F, dir->DIR_WrtTime & 0xF, (dir->DIR_WrtTime >> 4) & 0x3F, ((dir->DIR_WrtTime >> 11) & 0x1F) * 2);
|
|
|
|
info->atime = thetime;
|
|
info->ctime = thetime;
|
|
info->mtime = thetime;
|
|
return info;
|
|
} else if (type == -1){
|
|
free(buffer);
|
|
struct fat_file_info *info = (struct fat_file_info *)malloc(sizeof(struct fat_file_info));
|
|
if (!info) {
|
|
return NULL;
|
|
}
|
|
if (!(dir->DIR_Attribute & ATTR_DIRECTORY)) {
|
|
info->type = 1;
|
|
} else {
|
|
info->type = 0;
|
|
}
|
|
info->start_cluster = (dir->DIR_FirstClustHi << 0xffff) | dir->DIR_FirstClustLo;
|
|
info->file_size = dir->DIR_FileSize;
|
|
unsigned int thetime = get_time_since_epoch((dir->DIR_WrtDate & 0x7F) + 80, (dir->DIR_WrtDate >> 7) & 0xF, (dir->DIR_WrtDate >> 11) & 0x1F, dir->DIR_WrtTime & 0xF, (dir->DIR_WrtTime >> 4) & 0x3F, ((dir->DIR_WrtTime >> 11) & 0x1F) * 2);
|
|
|
|
info->atime = thetime;
|
|
info->ctime = thetime;
|
|
info->mtime = thetime;
|
|
return info;
|
|
} else {
|
|
return NULL;
|
|
}
|
|
}
|
|
} else {
|
|
if (chksum != fat_long_dir_chksum(dir->DIR_Name)) {
|
|
memset(long_filename, 0, 256);
|
|
}
|
|
|
|
if (strcmp(ptr[part], long_filename) == 0 || strcmp(ptr[part], temp) == 0) {
|
|
unsigned int start_cluster = (dir->DIR_FirstClustHi << 0xffff) | dir->DIR_FirstClustLo;
|
|
|
|
if (dir->DIR_Attribute & ATTR_DIRECTORY) {
|
|
free(buffer);
|
|
return fat_find_sub_entry(device, start_cluster, ptr, part + 1, parts, type);
|
|
} else {
|
|
free(buffer);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
#if 0
|
|
|
|
int fat_create_dentry(struct vfs_device_t *device, char *path) {
|
|
char *path_copy;
|
|
char *directory;
|
|
char *basename;
|
|
char *buffer;
|
|
int i;
|
|
char shortname[11];
|
|
memset(shortname, ' ', 11);
|
|
|
|
path_copy = (char *)malloc(strlen(path) + 1);
|
|
strcpy(path_copy, path);
|
|
|
|
directory = path_copy;
|
|
|
|
for (i=strlen(path_copy) -1;i>=0;i--) {
|
|
if (path_copy[i] == '/') {
|
|
paht_copy[i] = '\0';
|
|
basename = &path_copy[i+1];
|
|
break;
|
|
}
|
|
}
|
|
|
|
struct fat_file_info *info = fat_check_if_exists(device, directory, 0);
|
|
if (info == NULL) {
|
|
return 0;
|
|
}
|
|
if (directory[0] == '/' && directory[1] == '\0') {
|
|
if (data->fat != 2) {
|
|
first_root_dir_sec = data->superblock.BPB_RsvdSecCnt + (data->superblock.BPB_NumFATs * data->superblock.BPB_FATSz16);
|
|
len = data->root_dir_sectors * data->superblock.BPB_BytesPerSec;
|
|
buffer = (char *)malloc(len);
|
|
switch(device->device) {
|
|
case 1:
|
|
ramdisk_read_blocks(first_root_dir_sec, data->root_dir_sectors, buffer, data->superblock.BPB_BytesPerSec);
|
|
break;
|
|
}
|
|
} else {
|
|
len = fat_read_entire_file(device, data->superblock.FatType.Fat32.BPB_RootClus, &buffer);
|
|
}
|
|
} else {
|
|
unsigned int cluster = info->start_cluster;
|
|
len = fat_read_entire_file(device, cluster, &buffer);
|
|
}
|
|
|
|
int tail = 1;
|
|
int highest_tail = 1;
|
|
int j;
|
|
int k;
|
|
|
|
for (i=0;i<len / 32;i++) {
|
|
struct fat_dir *dir = (struct fat_dir *)&buffer[i * 32];
|
|
|
|
if (!(dir->DIR_Attribute & ATTR_LONG_NAME)) {
|
|
for (j=0;j<8;j++) {
|
|
if (dir->DIR_Name[j] == '~') {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (j==8) {
|
|
continue;
|
|
}
|
|
|
|
for (k=0;k<j;k++) {
|
|
if (dir->DIR_Name[k] != toupper(basename[k])) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (k!=j) {
|
|
continue;
|
|
}
|
|
|
|
int thetail = 0;
|
|
|
|
for (k=j+1;k<8;j++) {
|
|
thetail = thetail * 10 + (dir->DIR_Name[k] - '0');
|
|
}
|
|
|
|
if (thetail == tail) {
|
|
tail = highest_tail + 1;
|
|
}
|
|
if (thetail > highest_tail) {
|
|
highest_tail = thetail;
|
|
}
|
|
}
|
|
}
|
|
|
|
int nent = (basename / 13) + 1;
|
|
if (basename % 13 != 0) {
|
|
nent ++;
|
|
}
|
|
int n = 0;
|
|
int offset = -1;
|
|
for (i=0;i<len / 32;i++) {
|
|
struct fat_dir *dir = (struct fat_dir *)&buffer[i * 32];
|
|
if (dir->DIR_Name[0] == 0xE5 || dir->DIR_Name[0] == 0x00) {
|
|
if (offset == -1) {
|
|
offset = i;
|
|
}
|
|
n++;
|
|
if (n == nent) {
|
|
break;
|
|
}
|
|
} else {
|
|
n = 0;
|
|
offset = -1;
|
|
}
|
|
}
|
|
|
|
int extpos = strlen(basename);
|
|
|
|
for (i=strlen(basename) - 1;i > 0; i--) {
|
|
if (basename[i] == '.') {
|
|
extpos = i;
|
|
for (j=i+1;j<strlen(basename) && j < i + 4;j++) {
|
|
shortname[j-(i+1) + 9] = toupper(basename[j]);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (i=0;i<extpos && i < 8;i++) {
|
|
shortname[i] = toupper(basename[i]);
|
|
}
|
|
|
|
for (i=8;i>1;i--) {
|
|
shortname[i] = tail % 10
|
|
tail = tail / 10;
|
|
if (tail == 0) {
|
|
shortname[i-1] = '~';
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (offset != -1) {
|
|
// found empty dentrys
|
|
int count = basename / 13;
|
|
if (basename % 13) {
|
|
count ++;
|
|
}
|
|
for (i=0;i<count;i++) {
|
|
struct fat_dir *dir = (struct fat_long_dir *)&buffer[(offset + i) * 32];
|
|
dir->LDIR_Ord = i;
|
|
dir->LDIR_Name1[0] = basename[i];
|
|
if ((i * 13) +1 > strlen(basename)) {
|
|
dir->LDIR_Name1[1] = '\0';
|
|
} else {
|
|
dir->LDIR_Name1[1] = basename[(i * 13)+1];
|
|
}
|
|
if ((i * 13)+2 > strlen(basename)) {
|
|
dir->LDIR_Name1[2] = '\0';
|
|
} else {
|
|
dir->LDIR_Name1[2] = basename[(i * 13)+2];
|
|
}
|
|
if ((i * 13)+3 > strlen(basename)) {
|
|
dir->LDIR_Name1[3] = '\0';
|
|
} else {
|
|
dir->LDIR_Name1[3] = basename[(i * 13)+3];
|
|
}
|
|
|
|
if ((i * 13)+4 > strlen(basename)) {
|
|
dir->LDIR_Name1[4] = '\0';
|
|
} else {
|
|
dir->LDIR_Name1[4] = basename[(i * 13)+4];
|
|
}
|
|
dir->LDIR_Attr = ATTR_LONG_NAME;
|
|
dir->LDIR_Type = 0;
|
|
dir->LDIR_Chksum = fat_long_dir_chksum(shortname);
|
|
if ((i * 13)+5 > strlen(basename)) {
|
|
dir->LDIR_Name2[0] = '\0';
|
|
} else {
|
|
dir->LDIR_Name2[0] = basename[(i * 13)+5];
|
|
}
|
|
if ((i * 13)+6 > strlen(basename)) {
|
|
dir->LDIR_Name2[1] = '\0';
|
|
} else {
|
|
dir->LDIR_Name2[1] = basename[(i * 13)+6];
|
|
}
|
|
if ((i * 13)+7 > strlen(basename)) {
|
|
dir->LDIR_Name2[2] = '\0';
|
|
} else {
|
|
dir->LDIR_Name2[2] = basename[(i * 13)+7];
|
|
}
|
|
if ((i * 13)+8 > strlen(basename)) {
|
|
dir->LDIR_Name2[3] = '\0';
|
|
} else {
|
|
dir->LDIR_Name2[3] = basename[(i * 13)+8];
|
|
}
|
|
if ((i * 13)+9 > strlen(basename)) {
|
|
dir->LDIR_Name2[4] = '\0';
|
|
} else {
|
|
dir->LDIR_Name2[4] = basename[(i * 13)+9];
|
|
}
|
|
if ((i * 13)+10 > strlen(basename)) {
|
|
dir->LDIR_Name2[5] = '\0';
|
|
} else {
|
|
dir->LDIR_Name2[5] = basename[(i * 13)+10];
|
|
}
|
|
dir->LDIR_FirstClustLo = 0;
|
|
if ((i * 13)+11 > strlen(basename)) {
|
|
dir->LDIR_Name3[0] = '\0';
|
|
} else {
|
|
dir->LDIR_Name3[0] = basename[(i * 13)+11];
|
|
if ((i * 13)+12 > strlen(basename)) {
|
|
dir->LDIR_Name3[1] = '\0';
|
|
} else {
|
|
dir->LDIR_Name3[1] = basename[(i * 13)+12];
|
|
}
|
|
}
|
|
struct fat_dir *dir = (struct fat_dir *)&buffer[(offset + count) * 32];
|
|
memcpy(dir->DIR_Name, shortname, 11);
|
|
dir->DIR_Attribute = 0;
|
|
dir->DIR_NTRes = 0;
|
|
dir->DIR_CrtTimeTenth = 0;
|
|
dir->DIR_FirstClustHi
|
|
} else {
|
|
// need to append dentry
|
|
}
|
|
}
|
|
#endif
|
|
|
|
struct fat_file_info *fat_check_if_exists(struct vfs_device_t *device, char *path, int type) {
|
|
unsigned int first_root_dir_sec;
|
|
struct fat_data *data = (struct fat_data *)device->fs_data;
|
|
char *buffer;
|
|
int len;
|
|
if (data->fat != 2) {
|
|
first_root_dir_sec = data->superblock.BPB_RsvdSecCnt + (data->superblock.BPB_NumFATs * data->superblock.BPB_FATSz16);
|
|
len = data->root_dir_sectors * data->superblock.BPB_BytesPerSec;
|
|
|
|
if (strcmp(path, "/") == 0) {
|
|
struct fat_file_info *info = (struct fat_file_info *)malloc(sizeof(struct fat_file_info));
|
|
if (!info) {
|
|
return NULL;
|
|
}
|
|
info->start_cluster = 0;
|
|
info->file_size = 0;
|
|
info->type = 0;
|
|
|
|
return info;
|
|
}
|
|
|
|
buffer = (char *)malloc(len);
|
|
switch(device->device) {
|
|
case 1:
|
|
ramdisk_read_blocks(first_root_dir_sec, data->root_dir_sectors, buffer, data->superblock.BPB_BytesPerSec);
|
|
break;
|
|
}
|
|
} else {
|
|
len = fat_read_entire_file(device, data->superblock.FatType.Fat32.BPB_RootClus, &buffer);
|
|
if (strcmp(path, "/") == 0) {
|
|
struct fat_file_info *info = (struct fat_file_info *)malloc(sizeof(struct fat_file_info));
|
|
if (!info) {
|
|
return NULL;
|
|
}
|
|
info->start_cluster = data->superblock.FatType.Fat32.BPB_RootClus;
|
|
info->file_size = len;
|
|
info->type = 0;
|
|
free(buffer);
|
|
return info;
|
|
}
|
|
|
|
}
|
|
|
|
// buffer contains the root directory contents...
|
|
int i;
|
|
int parts = 0;
|
|
char *path_copy = (char *)malloc(strlen(path) + 1);
|
|
|
|
strcpy(path_copy, path);
|
|
|
|
if (path_copy[strlen(path_copy) - 1] == '/') {
|
|
path[strlen(path_copy) - 1] = '\0';
|
|
}
|
|
parts = 1;
|
|
|
|
for (i=1;i<strlen(path_copy);i++) {
|
|
if (path_copy[i] == '/') {
|
|
parts++;
|
|
}
|
|
}
|
|
|
|
char **ptr = (char **)malloc(sizeof(char *) * parts );
|
|
|
|
ptr[0] = &path_copy[1];
|
|
int j = 0;
|
|
int k = strlen(path_copy);
|
|
for (i=1;i<k;i++) {
|
|
if (path_copy[i] == '/') {
|
|
ptr[++j] = &path_copy[i+1];
|
|
path_copy[i] = '\0';
|
|
}
|
|
}
|
|
|
|
char temp[13];
|
|
char long_filename[256];
|
|
unsigned char chksum = 0;
|
|
|
|
k = 0;
|
|
int long_name_len = 0;
|
|
memset(long_filename, 0, 256);
|
|
|
|
for (i=0;i<len / 32;i++) {
|
|
memset(temp, 0, 13);
|
|
struct fat_dir *dir = (struct fat_dir *)&buffer[i * 32];
|
|
|
|
if (dir->DIR_Attribute & ATTR_LONG_NAME) {
|
|
struct fat_long_dir *ldir = (struct fat_long_dir *)dir;
|
|
if (ldir->LDIR_Ord & 0x40) {
|
|
memset(long_filename, 0, 256, 0);
|
|
long_name_len = 0;
|
|
chksum = ldir->LDIR_Chksum;
|
|
// last entry
|
|
// check length
|
|
for (k=0;k<5;k++) {
|
|
if (ldir->LDIR_Name1[k] == 0x0000) {
|
|
long_name_len = 13 * (ldir->LDIR_Ord & ~(0x40) - 1) + k;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!long_name_len) {
|
|
for (k=0;k<6;k++) {
|
|
if (ldir->LDIR_Name2[k] == 0x0000) {
|
|
long_name_len = 13 * (ldir->LDIR_Ord & ~(0x40) - 1) + k + 5;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (!long_name_len) {
|
|
for (k=0;k<2;k++) {
|
|
if (ldir->LDIR_Name3[k] == 0x0000) {
|
|
long_name_len = 13 * (ldir->LDIR_Ord & ~(0x40) - 1) + k + 5 + 6;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
int offset = 13 * (ldir->LDIR_Ord & ~(0x40) - 1);
|
|
|
|
for (k=0;k<5;k++) {
|
|
long_filename[offset + k] = (char)(ldir->LDIR_Name1[k] & 0xFF);
|
|
}
|
|
|
|
for (k=0;k<6;k++) {
|
|
long_filename[offset + 5 + k] = (char)(ldir->LDIR_Name2[k] & 0xFF);
|
|
}
|
|
for (k=0;k<2;k++) {
|
|
long_filename[offset + 11 + k] = (char)(ldir->LDIR_Name3[k] & 0xFF);
|
|
}
|
|
} else {
|
|
int offset = 13 * (ldir->LDIR_Ord - 1);
|
|
for (k=0;k<5;k++) {
|
|
long_filename[offset + k] = (char)(ldir->LDIR_Name1[k] & 0xFF);
|
|
}
|
|
|
|
for (k=0;k<6;k++) {
|
|
long_filename[offset + 5 + k] = (char)(ldir->LDIR_Name2[k] & 0xFF);
|
|
}
|
|
for (k=0;k<2;k++) {
|
|
long_filename[offset + 11 + k] = (char)(ldir->LDIR_Name3[k] & 0xFF);
|
|
}
|
|
}
|
|
} else {
|
|
if (dir->DIR_Name[0] == 0xE5) {
|
|
continue;
|
|
}
|
|
if (dir->DIR_Name[0] == 0x00) {
|
|
break;
|
|
}
|
|
if (dir->DIR_Name[0] == 0x05) {
|
|
temp[0] = 0xE5;
|
|
} else {
|
|
temp[0] = dir->DIR_Name[0];
|
|
}
|
|
for (j=1;j<8;j++) {
|
|
if ( dir->DIR_Name[j] == ' ') {
|
|
break;
|
|
} else {
|
|
temp[j] = dir->DIR_Name[j];
|
|
}
|
|
}
|
|
|
|
if (dir->DIR_Name[8] != ' ') {
|
|
temp[8] = '.';
|
|
for (j=8;j<11;j++) {
|
|
if (dir->DIR_Name[j] == ' ') {
|
|
break;
|
|
} else {
|
|
temp[j + 1] = dir->DIR_Name[j];
|
|
}
|
|
}
|
|
}
|
|
|
|
if (parts == 1) {
|
|
if (chksum != fat_long_dir_chksum(dir->DIR_Name)) {
|
|
memset(long_filename, 0, 256);
|
|
}
|
|
|
|
if (strcmp(ptr[0], long_filename) == 0 || strcmp(ptr[0], temp) == 0) {
|
|
if (type == 0 && (dir->DIR_Attribute & ATTR_DIRECTORY)) {
|
|
free(buffer);
|
|
struct fat_file_info *info = (struct fat_file_info *)malloc(sizeof(struct fat_file_info));
|
|
if (!info) {
|
|
return NULL;
|
|
}
|
|
|
|
info->start_cluster = (dir->DIR_FirstClustHi << 0xffff) | dir->DIR_FirstClustLo;
|
|
info->file_size = dir->DIR_FileSize;
|
|
info->type = 0;
|
|
|
|
unsigned int thetime = get_time_since_epoch((dir->DIR_WrtDate & 0x7F) + 80, (dir->DIR_WrtDate >> 7) & 0xF, (dir->DIR_WrtDate >> 11) & 0x1F, dir->DIR_WrtTime & 0xF, (dir->DIR_WrtTime >> 4) & 0x3F, ((dir->DIR_WrtTime >> 11) & 0x1F) * 2);
|
|
|
|
info->atime = thetime;
|
|
info->ctime = thetime;
|
|
info->mtime = thetime;
|
|
return info;
|
|
} else if (type == 1 && !(dir->DIR_Attribute & ATTR_DIRECTORY)) {
|
|
free(buffer);
|
|
struct fat_file_info *info = (struct fat_file_info *)malloc(sizeof(struct fat_file_info));
|
|
if (!info) {
|
|
return NULL;
|
|
}
|
|
|
|
info->start_cluster = (dir->DIR_FirstClustHi << 0xffff) | dir->DIR_FirstClustLo;
|
|
info->file_size = dir->DIR_FileSize;
|
|
info->type = 1;
|
|
unsigned int thetime = get_time_since_epoch((dir->DIR_WrtDate & 0x7F) + 80, (dir->DIR_WrtDate >> 7) & 0xF, (dir->DIR_WrtDate >> 11) & 0x1F, dir->DIR_WrtTime & 0xF, (dir->DIR_WrtTime >> 4) & 0x3F, ((dir->DIR_WrtTime >> 11) & 0x1F) * 2);
|
|
|
|
info->atime = thetime;
|
|
info->ctime = thetime;
|
|
info->mtime = thetime;
|
|
return info;
|
|
} else if (type == -1) {
|
|
free(buffer);
|
|
struct fat_file_info *info = (struct fat_file_info *)malloc(sizeof(struct fat_file_info));
|
|
if (!info) {
|
|
return NULL;
|
|
}
|
|
|
|
info->start_cluster = (dir->DIR_FirstClustHi << 0xffff) | dir->DIR_FirstClustLo;
|
|
info->file_size = dir->DIR_FileSize;
|
|
if (!(dir->DIR_Attribute & ATTR_DIRECTORY)) {
|
|
info->type = 1;
|
|
} else {
|
|
info->type = 0;
|
|
}
|
|
unsigned int thetime = get_time_since_epoch((dir->DIR_WrtDate & 0x7F) + 80, (dir->DIR_WrtDate >> 7) & 0xF, (dir->DIR_WrtDate >> 11) & 0x1F, dir->DIR_WrtTime & 0xF, (dir->DIR_WrtTime >> 4) & 0x3F, ((dir->DIR_WrtTime >> 11) & 0x1F) * 2);
|
|
|
|
info->atime = thetime;
|
|
info->ctime = thetime;
|
|
info->mtime = thetime;
|
|
|
|
return info;
|
|
}
|
|
|
|
free(buffer);
|
|
return NULL;
|
|
}
|
|
} else {
|
|
if (chksum != fat_long_dir_chksum(dir->DIR_Name)) {
|
|
memset(long_filename, 0, 256);
|
|
}
|
|
if (strcmp(ptr[0], long_filename) == 0 || strcmp(ptr[0], temp) == 0) {
|
|
unsigned int start_cluster = (dir->DIR_FirstClustHi << 0xffff) | dir->DIR_FirstClustLo;
|
|
|
|
if (dir->DIR_Attribute & ATTR_DIRECTORY) {
|
|
free(buffer);
|
|
return fat_find_sub_entry(device, start_cluster, ptr, 1, parts, type);
|
|
} else {
|
|
free(buffer);
|
|
return NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int fat_change_directory(struct vfs_device_t *device, char *path) {
|
|
if (path[0] == '/' && path[1] == '\0') {
|
|
return 1;
|
|
} else {
|
|
if (fat_check_if_exists(device, path, 0)) {
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
void fat_list_contents(struct vfs_device_t *device, char *cwd) {
|
|
struct fat_data *data = (struct fat_data *)device->fs_data;
|
|
char *buffer;
|
|
unsigned int len;
|
|
char temp[13];
|
|
char long_filename[256];
|
|
unsigned char chksum = 0;
|
|
int i;
|
|
int j;
|
|
int k = 0;
|
|
int long_name_len = 0;
|
|
unsigned int first_root_dir_sec;
|
|
|
|
if (cwd[0] == '/' && cwd[1] == '\0') {
|
|
if (data->fat != 2) {
|
|
first_root_dir_sec = data->superblock.BPB_RsvdSecCnt + (data->superblock.BPB_NumFATs * data->superblock.BPB_FATSz16);
|
|
len = data->root_dir_sectors * data->superblock.BPB_BytesPerSec;
|
|
buffer = (char *)malloc(len);
|
|
switch(device->device) {
|
|
case 1:
|
|
ramdisk_read_blocks(first_root_dir_sec, data->root_dir_sectors, buffer, data->superblock.BPB_BytesPerSec);
|
|
break;
|
|
}
|
|
} else {
|
|
len = fat_read_entire_file(device, data->superblock.FatType.Fat32.BPB_RootClus, &buffer);
|
|
}
|
|
} else {
|
|
unsigned int cluster = fat_check_if_exists(device, cwd, 0)->start_cluster;
|
|
len = fat_read_entire_file(device, cluster, &buffer);
|
|
}
|
|
|
|
|
|
|
|
|
|
for (i=0;i<len / 32; i++) {
|
|
memset(temp, 0, 13);
|
|
struct fat_dir *dir = (struct fat_dir *)&buffer[i * 32];
|
|
|
|
if (dir->DIR_Attribute & ATTR_LONG_NAME) {
|
|
struct fat_long_dir *ldir = (struct fat_long_dir *)dir;
|
|
if (ldir->LDIR_Ord & 0x40) {
|
|
memset(long_filename, 0, 256, 0);
|
|
long_name_len = 0;
|
|
chksum = ldir->LDIR_Chksum;
|
|
// last entry
|
|
// check length
|
|
for (k=0;k<5;k++) {
|
|
if (ldir->LDIR_Name1[k] == 0x0000) {
|
|
long_name_len = 13 * (ldir->LDIR_Ord & ~(0x40) - 1) + k;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!long_name_len) {
|
|
for (k=0;k<6;k++) {
|
|
if (ldir->LDIR_Name2[k] == 0x0000) {
|
|
long_name_len = 13 * (ldir->LDIR_Ord & ~(0x40) - 1) + k + 5;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (!long_name_len) {
|
|
for (k=0;k<2;k++) {
|
|
if (ldir->LDIR_Name3[k] == 0x0000) {
|
|
long_name_len = 13 * (ldir->LDIR_Ord & ~(0x40) - 1) + k + 5 + 6;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
int offset = 13 * (ldir->LDIR_Ord & ~(0x40) - 1);
|
|
|
|
for (k=0;k<5;k++) {
|
|
long_filename[offset + k] = (char)(ldir->LDIR_Name1[k] & 0xFF);
|
|
}
|
|
|
|
for (k=0;k<6;k++) {
|
|
long_filename[offset + 5 + k] = (char)(ldir->LDIR_Name2[k] & 0xFF);
|
|
}
|
|
for (k=0;k<2;k++) {
|
|
long_filename[offset + 11 + k] = (char)(ldir->LDIR_Name3[k] & 0xFF);
|
|
}
|
|
} else {
|
|
int offset = 13 * (ldir->LDIR_Ord - 1);
|
|
for (k=0;k<5;k++) {
|
|
long_filename[offset + k] = (char)(ldir->LDIR_Name1[k] & 0xFF);
|
|
}
|
|
|
|
for (k=0;k<6;k++) {
|
|
long_filename[offset + 5 + k] = (char)(ldir->LDIR_Name2[k] & 0xFF);
|
|
}
|
|
for (k=0;k<2;k++) {
|
|
long_filename[offset + 11 + k] = (char)(ldir->LDIR_Name3[k] & 0xFF);
|
|
}
|
|
}
|
|
} else {
|
|
if (dir->DIR_Name[0] == 0xE5) {
|
|
continue;
|
|
}
|
|
if (dir->DIR_Name[0] == 0x00) {
|
|
break;
|
|
}
|
|
if (dir->DIR_Name[0] == 0x05) {
|
|
temp[0] = 0xE5;
|
|
} else {
|
|
temp[0] = dir->DIR_Name[0];
|
|
}
|
|
for (j=1;j<8;j++) {
|
|
if ( dir->DIR_Name[j] == ' ') {
|
|
break;
|
|
} else {
|
|
temp[j] = dir->DIR_Name[j];
|
|
}
|
|
}
|
|
|
|
if (dir->DIR_Name[8] != ' ') {
|
|
temp[8] = '.';
|
|
for (j=8;j<11;j++) {
|
|
if (dir->DIR_Name[j] == ' ') {
|
|
break;
|
|
} else {
|
|
temp[j + 1] = dir->DIR_Name[j];
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if (chksum != fat_long_dir_chksum(dir->DIR_Name)) {
|
|
memset(long_filename, 0, 256);
|
|
}
|
|
|
|
if (strlen(long_filename) > 0) {
|
|
kprintf("%s\n", long_filename);
|
|
} else {
|
|
kprintf("%s\n", temp);
|
|
}
|
|
}
|
|
}
|
|
|
|
free(buffer);
|
|
}
|
|
|
|
int fat_read_data(struct vfs_device_t *device, struct fat_file_info *info, char *buffer, int len, int offset) {
|
|
struct fat_data *data = (struct fat_data *)device->fs_data;
|
|
|
|
if (info->type == 0) {
|
|
// it's a directory...
|
|
return 0;
|
|
}
|
|
|
|
if (len + offset > info->file_size) {
|
|
len = info->file_size - offset;
|
|
}
|
|
|
|
if (len > 0) {
|
|
|
|
unsigned int *clusterchain = (unsigned int *)malloc(sizeof(unsigned int) * 2);
|
|
clusterchain[0] = info->start_cluster;
|
|
clusterchain[1] = fat_get_cluster_entry(device, info->start_cluster);
|
|
int i = 1;
|
|
int j;
|
|
int blocks_read;
|
|
|
|
while (!is_EOC(device, clusterchain[i])) {
|
|
i++;
|
|
clusterchain = (unsigned int *)realloc(clusterchain, sizeof(unsigned int) * (i + 1));
|
|
clusterchain[i] = fat_get_cluster_entry(device, clusterchain[i-1]);
|
|
}
|
|
|
|
unsigned int cluster_start = offset / (data->superblock.BPB_SecPerClus * data->superblock.BPB_BytesPerSec);
|
|
unsigned int cluster_offset = offset % (data->superblock.BPB_SecPerClus * data->superblock.BPB_BytesPerSec);
|
|
unsigned int cluster_count = len + cluster_offset / (data->superblock.BPB_SecPerClus * data->superblock.BPB_BytesPerSec);
|
|
unsigned int buffer_at;
|
|
|
|
char *tempbuffer = (char *)malloc(data->superblock.BPB_SecPerClus * data->superblock.BPB_BytesPerSec);
|
|
|
|
if (len + cluster_offset % (data->superblock.BPB_SecPerClus * data->superblock.BPB_BytesPerSec) > 0) {
|
|
cluster_count += 1;
|
|
}
|
|
|
|
switch (device->device) {
|
|
case 1:
|
|
|
|
for (j=0;j<cluster_count;j++) {
|
|
blocks_read = ramdisk_read_blocks(cluster_to_sec(device, clusterchain[cluster_start + j]), data->superblock.BPB_SecPerClus, tempbuffer, data->superblock.BPB_BytesPerSec);
|
|
if (j==0) {
|
|
if (len + cluster_offset > data->superblock.BPB_SecPerClus * data->superblock.BPB_BytesPerSec) {
|
|
memcpy(buffer, &tempbuffer[cluster_offset], data->superblock.BPB_SecPerClus * data->superblock.BPB_BytesPerSec - cluster_offset);
|
|
buffer_at = data->superblock.BPB_SecPerClus * data->superblock.BPB_BytesPerSec - cluster_offset;
|
|
} else {
|
|
memcpy(buffer, &tempbuffer[cluster_offset], len);
|
|
free(tempbuffer);
|
|
free(clusterchain);
|
|
return len;
|
|
}
|
|
} else {
|
|
if (len - buffer_at >= data->superblock.BPB_SecPerClus * data->superblock.BPB_BytesPerSec) {
|
|
memcpy(&buffer[buffer_at], tempbuffer, data->superblock.BPB_SecPerClus * data->superblock.BPB_BytesPerSec);
|
|
buffer_at += data->superblock.BPB_SecPerClus * data->superblock.BPB_BytesPerSec;
|
|
} else {
|
|
memcpy(&buffer[buffer_at], tempbuffer, len - buffer_at);
|
|
free(tempbuffer);
|
|
free(clusterchain);
|
|
return len;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
free(clusterchain);
|
|
return len;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
int fat_get_dents(struct vfs_device_t *device, struct fat_file_info *info, char *buffer, int len, int offset) {
|
|
struct fat_data *data = (struct fat_data *)device->fs_data;
|
|
char *dir_buffer;
|
|
unsigned int bytesread;
|
|
char *buffer2;
|
|
|
|
if (info->start_cluster == 0) {
|
|
unsigned int first_root_dir_sec = data->superblock.BPB_RsvdSecCnt + (data->superblock.BPB_NumFATs * data->superblock.BPB_FATSz16);
|
|
unsigned int dirlen;
|
|
|
|
if (info->file_size == 0) {
|
|
dirlen = data->root_dir_sectors * data->superblock.BPB_BytesPerSec;
|
|
} else {
|
|
dirlen = info->file_size;
|
|
}
|
|
if (offset >= dirlen) {
|
|
return 0;
|
|
}
|
|
|
|
buffer2 = (char *)malloc(dirlen);
|
|
|
|
switch(device->device) {
|
|
case 1:
|
|
ramdisk_read_blocks(first_root_dir_sec, data->root_dir_sectors, buffer2, data->superblock.BPB_BytesPerSec);
|
|
break;
|
|
}
|
|
|
|
dir_buffer = (char *)malloc(data->root_dir_sectors * data->superblock.BPB_BytesPerSec - offset + 1);
|
|
memcpy(dir_buffer, &buffer2[offset], data->root_dir_sectors * data->superblock.BPB_BytesPerSec - offset);
|
|
free(buffer2);
|
|
bytesread = data->root_dir_sectors * data->superblock.BPB_BytesPerSec - offset;
|
|
} else {
|
|
unsigned int newsz;
|
|
|
|
int dirlen = fat_read_entire_file(device, info->start_cluster, &buffer2);
|
|
if (info->file_size == 0) {
|
|
newsz = dirlen;
|
|
} else {
|
|
newsz = info->file_size;
|
|
}
|
|
|
|
dir_buffer = (char *)malloc(newsz - offset + 1);
|
|
memcpy(dir_buffer, &buffer2[offset], newsz - offset);
|
|
free(buffer2);
|
|
bytesread = newsz - offset;
|
|
}
|
|
|
|
char temp[13];
|
|
char long_filename[256];
|
|
int long_name_len = 0;
|
|
int buff_offset = 0;
|
|
unsigned char chksum = 0;
|
|
int i;
|
|
int j;
|
|
int k = 0;
|
|
|
|
for (i=0;i<bytesread / 32;i++) {
|
|
memset(temp, 0, 13);
|
|
struct fat_dir *dir = (struct fat_dir *)&dir_buffer[i * 32];
|
|
|
|
if (dir->DIR_Attribute & ATTR_LONG_NAME) {
|
|
struct fat_long_dir *ldir = (struct fat_long_dir *)dir;
|
|
if (ldir->LDIR_Ord & 0x40) {
|
|
memset(long_filename, 0, 256, 0);
|
|
long_name_len = 0;
|
|
chksum = ldir->LDIR_Chksum;
|
|
// last entry
|
|
// check length
|
|
for (k=0;k<5;k++) {
|
|
if (ldir->LDIR_Name1[k] == 0x0000) {
|
|
long_name_len = 13 * (ldir->LDIR_Ord & ~(0x40) - 1) + k;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!long_name_len) {
|
|
for (k=0;k<6;k++) {
|
|
if (ldir->LDIR_Name2[k] == 0x0000) {
|
|
long_name_len = 13 * (ldir->LDIR_Ord & ~(0x40) - 1) + k + 5;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (!long_name_len) {
|
|
for (k=0;k<2;k++) {
|
|
if (ldir->LDIR_Name3[k] == 0x0000) {
|
|
long_name_len = 13 * (ldir->LDIR_Ord & ~(0x40) - 1) + k + 5 + 6;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
int offset = 13 * (ldir->LDIR_Ord & ~(0x40) - 1);
|
|
|
|
for (k=0;k<5;k++) {
|
|
long_filename[offset + k] = (char)(ldir->LDIR_Name1[k] & 0xFF);
|
|
}
|
|
|
|
for (k=0;k<6;k++) {
|
|
long_filename[offset + 5 + k] = (char)(ldir->LDIR_Name2[k] & 0xFF);
|
|
}
|
|
for (k=0;k<2;k++) {
|
|
long_filename[offset + 11 + k] = (char)(ldir->LDIR_Name3[k] & 0xFF);
|
|
}
|
|
} else {
|
|
int offset = 13 * (ldir->LDIR_Ord - 1);
|
|
for (k=0;k<5;k++) {
|
|
long_filename[offset + k] = (char)(ldir->LDIR_Name1[k] & 0xFF);
|
|
}
|
|
|
|
for (k=0;k<6;k++) {
|
|
long_filename[offset + 5 + k] = (char)(ldir->LDIR_Name2[k] & 0xFF);
|
|
}
|
|
for (k=0;k<2;k++) {
|
|
long_filename[offset + 11 + k] = (char)(ldir->LDIR_Name3[k] & 0xFF);
|
|
}
|
|
}
|
|
} else {
|
|
if (dir->DIR_Name[0] == 0xE5) {
|
|
continue;
|
|
}
|
|
if (dir->DIR_Name[0] == 0x00) {
|
|
info->file_size = offset + buff_offset;
|
|
break;
|
|
}
|
|
if (dir->DIR_Name[0] == 0x05) {
|
|
temp[0] = 0xE5;
|
|
} else {
|
|
temp[0] = dir->DIR_Name[0];
|
|
}
|
|
for (j=1;j<8;j++) {
|
|
if ( dir->DIR_Name[j] == ' ') {
|
|
break;
|
|
} else {
|
|
temp[j] = dir->DIR_Name[j];
|
|
}
|
|
}
|
|
|
|
if (dir->DIR_Name[8] != ' ') {
|
|
temp[8] = '.';
|
|
for (j=8;j<11;j++) {
|
|
if (dir->DIR_Name[j] == ' ') {
|
|
break;
|
|
} else {
|
|
temp[j + 1] = dir->DIR_Name[j];
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if (chksum != fat_long_dir_chksum(dir->DIR_Name)) {
|
|
memset(long_filename, 0, 256);
|
|
}
|
|
|
|
struct quinn_dirent_t *dent = (struct quinn_dirent_t *)(&buffer[buff_offset]);
|
|
|
|
if (strlen(long_filename) > 0) {
|
|
if (buff_offset + sizeof(struct quinn_dirent_t) + (strlen(long_filename)) > len) {
|
|
free(dir_buffer);
|
|
return buff_offset;
|
|
}
|
|
|
|
dent->name_len = strlen(long_filename);
|
|
dent->rec_len = sizeof(struct quinn_dirent_t) + strlen(long_filename);
|
|
dent->next_offset = buff_offset + dent->rec_len;
|
|
strcpy(dent->name, long_filename);
|
|
buff_offset = dent->next_offset;
|
|
} else {
|
|
if (buff_offset + sizeof(struct quinn_dirent_t) + (strlen(temp)) > len) {
|
|
free(dir_buffer);
|
|
return buff_offset;
|
|
}
|
|
dent->name_len = strlen(temp);
|
|
dent->rec_len = sizeof(struct quinn_dirent_t) + strlen(temp);
|
|
dent->next_offset = buff_offset + dent->rec_len;
|
|
strcpy(dent->name, temp);
|
|
buff_offset = dent->next_offset;
|
|
}
|
|
}
|
|
}
|
|
free(dir_buffer);
|
|
return buff_offset;
|
|
}
|