2309 lines
68 KiB
C
2309 lines
68 KiB
C
#include "vfs.h"
|
|
#include "fat.h"
|
|
#include "memory.h"
|
|
#include "console.h"
|
|
#include "hd.h"
|
|
#include "rtc.h"
|
|
#include "string.h"
|
|
#include "ramdisk.h"
|
|
|
|
unsigned int cluster_to_sec(struct vfs_device_t *device, unsigned int cluster);
|
|
void fat_set_cluster_entry(struct vfs_device_t *device, unsigned int cluster, unsigned int value);
|
|
|
|
unsigned int fat_alloc_cluster(struct vfs_device_t *device, unsigned int prevcluster) {
|
|
struct fat_data *data = (struct fat_data *)device->fs_data;
|
|
char *buffer;
|
|
|
|
unsigned int start_search = 2;
|
|
unsigned int i;
|
|
|
|
if (data->fat == 2) {
|
|
|
|
buffer = (char *)dbmalloc(data->superblock.BPB_BytesPerSec, "fat_alloc_cluster");
|
|
|
|
if (device->device == 1) {
|
|
ramdisk_read_block(data->superblock.FatType.Fat32.BPB_FSInfo, buffer, data->superblock.BPB_BytesPerSec);
|
|
} else if ((device->device & 0xff00) == 0x100) {
|
|
hd_read_block((device->device & 0xff), data->superblock.FatType.Fat32.BPB_FSInfo, buffer, data->superblock.BPB_BytesPerSec);
|
|
}
|
|
|
|
struct fat_fsinfo *fsinfo = (struct fat_fsinfo *)buffer;
|
|
|
|
if (fsinfo->FSI_LeadSig == 0x41615252 && fsinfo->FSI_StructSig == 0x61417272 && fsinfo->FSI_TailSig == 0xAA550000) {
|
|
start_search = fsinfo->FSI_Nxt_Free;
|
|
}
|
|
|
|
free(buffer);
|
|
}
|
|
|
|
unsigned int sector;
|
|
unsigned int offset;
|
|
unsigned int last_sector = -1;
|
|
buffer = (char *)dbmalloc(data->superblock.BPB_BytesPerSec, "fat_alloc_cluster");
|
|
|
|
search_again:
|
|
|
|
for (i=start_search;i<data->count_of_clusters;i++) {
|
|
unsigned int fatOffset;
|
|
if (data->fat != 0) {
|
|
if (data->fat == 1) {
|
|
fatOffset = i * 2;
|
|
} else if (data->fat == 2) {
|
|
fatOffset = i * 4;
|
|
}
|
|
|
|
sector = data->superblock.BPB_RsvdSecCnt + (fatOffset / data->superblock.BPB_BytesPerSec);
|
|
offset = fatOffset % data->superblock.BPB_BytesPerSec;
|
|
|
|
if (last_sector != sector) {
|
|
if (device->device == 1) {
|
|
ramdisk_read_block(sector, buffer, data->superblock.BPB_BytesPerSec);
|
|
} else if ((device->device & 0xff00) == 0x100) {
|
|
hd_read_block((device->device & 0xff), sector, buffer, data->superblock.BPB_BytesPerSec);
|
|
}
|
|
}
|
|
|
|
if (data->fat == 1) {
|
|
unsigned short fat16clusterEntryVal = *((unsigned short *)&buffer[offset]);
|
|
if (fat16clusterEntryVal == 0) {
|
|
break;
|
|
}
|
|
} else if (data->fat == 2) {
|
|
unsigned int fat32clusterEntryVal = *((unsigned int *)&buffer[offset]);
|
|
if (fat32clusterEntryVal == 0) {
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
fatOffset = i + (i / 2);
|
|
sector = data->superblock.BPB_RsvdSecCnt + (fatOffset / data->superblock.BPB_BytesPerSec);
|
|
int offset = fatOffset % data->superblock.BPB_BytesPerSec;
|
|
|
|
if (last_sector != sector) {
|
|
if (device->device == 1) {
|
|
ramdisk_read_blocks(sector, 2, buffer, data->superblock.BPB_BytesPerSec);
|
|
} else if ((device->device & 0xff00) == 0x100) {
|
|
hd_read_blocks((device->device & 0xff), sector, 2, buffer, data->superblock.BPB_BytesPerSec);
|
|
}
|
|
}
|
|
|
|
unsigned short fat12clusterEntryVal = *((unsigned short *)&buffer[offset]);
|
|
if (i & 0x0001) {
|
|
fat12clusterEntryVal = fat12clusterEntryVal >> 4;
|
|
} else {
|
|
fat12clusterEntryVal = fat12clusterEntryVal & 0x0fff;
|
|
}
|
|
if (fat12clusterEntryVal == 0) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (i == data->count_of_clusters) {
|
|
if (start_search > 2) {
|
|
start_search = 2;
|
|
goto search_again;
|
|
}
|
|
free(buffer);
|
|
return 0;
|
|
} else {
|
|
if (prevcluster) {
|
|
fat_set_cluster_entry(device, prevcluster, i);
|
|
}
|
|
unsigned int value;
|
|
if (data->fat == 0) {
|
|
value = 0xfff;
|
|
} else if (data->fat == 1) {
|
|
value = 0xffff;
|
|
} else {
|
|
value = 0x0fffffff;
|
|
}
|
|
fat_set_cluster_entry(device, i, value);
|
|
|
|
// zero out cluster
|
|
buffer = (char *)dbmalloc(data->superblock.BPB_SecPerClus * data->superblock.BPB_BytesPerSec, "fat_alloc_cluster");
|
|
memset(buffer, 0, data->superblock.BPB_SecPerClus * data->superblock.BPB_BytesPerSec);
|
|
|
|
if (device->device == 1) {
|
|
ramdisk_write_blocks(cluster_to_sec(device, i), data->superblock.BPB_SecPerClus, buffer, data->superblock.BPB_BytesPerSec);
|
|
} else if ((device->device & 0xff00) == 0x100) {
|
|
hd_write_blocks((device->device & 0xff), cluster_to_sec(device, i), data->superblock.BPB_SecPerClus, buffer, data->superblock.BPB_BytesPerSec);
|
|
}
|
|
free(buffer);
|
|
return i;
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
if (device->device == 1) {
|
|
ramdisk_read_block(0, buffer, 512);
|
|
} else if ((device->device & 0xff00) == 0x100) {
|
|
hd_read_block((device->device & 0xff), 0, buffer, 512);
|
|
}
|
|
memcpy((char *)&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);
|
|
free(fatData);
|
|
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;
|
|
}
|
|
|
|
void fat_set_cluster_entry(struct vfs_device_t *device, unsigned int cluster, unsigned int value) {
|
|
struct fat_data *data = (struct fat_data *)device->fs_data;
|
|
unsigned int fatOffset;
|
|
unsigned int fatsz;
|
|
int i;
|
|
for (i=0;i<data->superblock.BPB_NumFATs;i++) {
|
|
if (data->fat != 0) {
|
|
if (data->fat == 1) {
|
|
fatOffset = cluster * 2;
|
|
fatsz = data->superblock.BPB_FATSz16;
|
|
} else if (data->fat == 2) {
|
|
fatOffset = cluster * 4;
|
|
fatsz = data->superblock.FatType.Fat32.BPB_FATSz32;
|
|
}
|
|
unsigned int sector = data->superblock.BPB_RsvdSecCnt + (i * fatsz) + (fatOffset / data->superblock.BPB_BytesPerSec);
|
|
unsigned int offset = fatOffset % data->superblock.BPB_BytesPerSec;
|
|
char *buffer = (char *)dbmalloc(data->superblock.BPB_BytesPerSec, "fat_set_cluster_entry");
|
|
if (!buffer) {
|
|
// fail.
|
|
}
|
|
if (device->device == 1) {
|
|
ramdisk_read_block(sector, buffer, data->superblock.BPB_BytesPerSec);
|
|
} else if ((device->device & 0xff00) == 0x100) {
|
|
hd_read_block((device->device & 0xff), sector, buffer, data->superblock.BPB_BytesPerSec);
|
|
}
|
|
|
|
if (data->fat == 1) {
|
|
*((unsigned short *)&buffer[offset]) = (unsigned short)value;
|
|
} else if (data->fat == 2) {
|
|
value = value & 0x0fffffff;
|
|
*((unsigned int *)&buffer[offset]) = *((unsigned int *)&buffer[offset]) & 0xf0000000;
|
|
*((unsigned int *)&buffer[offset]) = *((unsigned int *)&buffer[offset]) | value;
|
|
}
|
|
if (device->device == 1) {
|
|
ramdisk_write_block(sector, buffer, data->superblock.BPB_BytesPerSec);
|
|
} else if ((device->device & 0xff00) == 0x100) {
|
|
hd_write_block((device->device & 0xff), sector, buffer, data->superblock.BPB_BytesPerSec);
|
|
}
|
|
free(buffer);
|
|
} else {
|
|
fatsz = data->superblock.BPB_FATSz16;
|
|
fatOffset = cluster + (cluster / 2);
|
|
unsigned int sector = data->superblock.BPB_RsvdSecCnt + (i * fatsz) + (fatOffset / data->superblock.BPB_BytesPerSec);
|
|
unsigned int offset = fatOffset % data->superblock.BPB_BytesPerSec;
|
|
|
|
char *buffer = (char *)dbmalloc(data->superblock.BPB_BytesPerSec * 2, "fat_set_cluster_entry");
|
|
if (!buffer) {
|
|
// fail
|
|
}
|
|
if (device->device == 1) {
|
|
ramdisk_read_blocks(sector, 2, buffer, data->superblock.BPB_BytesPerSec);
|
|
} else if ((device->device & 0xff00) == 0x100) {
|
|
hd_read_blocks((device->device & 0xff), sector, 2, buffer, data->superblock.BPB_BytesPerSec);
|
|
}
|
|
|
|
unsigned short fat12clusterEntryVal;
|
|
if (cluster & 0x0001) {
|
|
value = value << 4;
|
|
*(unsigned short *)&buffer[offset] = (*((unsigned short *)&buffer[offset])) & 0x000f;
|
|
} else {
|
|
value = value & 0x0fff;
|
|
*(unsigned short *)&buffer[offset] = (*((unsigned short *)&buffer[offset])) & 0xf000;
|
|
}
|
|
*(unsigned short *)&buffer[offset] = (*((unsigned short *)&buffer[offset])) | (unsigned short)value;
|
|
|
|
if (device->device == 1) {
|
|
ramdisk_write_blocks(sector, 2, buffer, data->superblock.BPB_BytesPerSec);
|
|
} else if ((device->device & 0xff00) == 0x100) {
|
|
hd_write_blocks((device->device & 0xff), sector, 2, buffer, data->superblock.BPB_BytesPerSec);
|
|
}
|
|
free(buffer);
|
|
}
|
|
}
|
|
}
|
|
|
|
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 *)dbmalloc(data->superblock.BPB_BytesPerSec, "fat_get_cluster_entry");
|
|
if (!buffer) {
|
|
// fail.
|
|
kprintf("Failed to allocate memory\n");
|
|
}
|
|
if (device->device == 1) {
|
|
ramdisk_read_block(sector, buffer, data->superblock.BPB_BytesPerSec);
|
|
} else if ((device->device & 0xff00) == 0x100) {
|
|
hd_read_block((device->device & 0xff), sector, buffer, data->superblock.BPB_BytesPerSec);
|
|
}
|
|
|
|
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 *)dbmalloc(data->superblock.BPB_BytesPerSec * 2, "fat_get_cluster_entry");
|
|
if (!buffer) {
|
|
// fail
|
|
kprintf("Failed to allocate memory\n");
|
|
}
|
|
if (device->device == 1) {
|
|
ramdisk_read_blocks(sector, 2, buffer, data->superblock.BPB_BytesPerSec);
|
|
} else if ((device->device & 0xff00) == 0x100) {
|
|
hd_read_blocks((device->device & 0xff), sector, 2, buffer, data->superblock.BPB_BytesPerSec);
|
|
}
|
|
|
|
unsigned short fat12clusterEntryVal = *((unsigned short *)&buffer[offset]);
|
|
if (cluster & 0x0001) {
|
|
fat12clusterEntryVal = fat12clusterEntryVal >> 4;
|
|
} else {
|
|
fat12clusterEntryVal = fat12clusterEntryVal & 0x0fff;
|
|
}
|
|
return (unsigned int)fat12clusterEntryVal;
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
void fat_write_entire_file(struct vfs_device_t *device, unsigned int start_cluster, char *buffer, unsigned int len) {
|
|
struct fat_data *data = (struct fat_data *)device->fs_data;
|
|
|
|
|
|
unsigned int *clusterchain = (unsigned int *)dbmalloc(sizeof(unsigned int) * 2, "fat_write_entire_file");
|
|
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 j;
|
|
|
|
|
|
for (j=0;j<i;j++) {
|
|
if (device->device == 1) {
|
|
ramdisk_write_blocks(cluster_to_sec(device, clusterchain[j]), data->superblock.BPB_SecPerClus, &buffer[j * data->superblock.BPB_SecPerClus * data->superblock.BPB_BytesPerSec], data->superblock.BPB_BytesPerSec);
|
|
}else if ((device->device & 0xff00) == 0x100) {
|
|
hd_write_blocks((device->device & 0xff),cluster_to_sec(device, clusterchain[j]), data->superblock.BPB_SecPerClus, &buffer[j * data->superblock.BPB_SecPerClus * data->superblock.BPB_BytesPerSec], data->superblock.BPB_BytesPerSec);
|
|
}
|
|
}
|
|
free(clusterchain);
|
|
return;
|
|
}
|
|
|
|
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 *)dbmalloc(sizeof(unsigned int) * 2, "fat_read_entire_file 1");
|
|
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 *)dbmalloc(len, "fat_read_entire_file 2");
|
|
|
|
int j;
|
|
|
|
char *buffer_loc = *buffer;
|
|
|
|
for (j=0;j<i;j++) {
|
|
if (device->device == 1) {
|
|
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);
|
|
}else if ((device->device & 0xff00) == 0x100) {
|
|
hd_read_blocks((device->device & 0xff),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);
|
|
}
|
|
}
|
|
|
|
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 bad;
|
|
|
|
int badcharacters[] = {0x22, 0x2A, 0x2B, 0x2C, 0x2E, 0x2F, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x5B, 0x5C, 0x5D, 0x7C};
|
|
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 == 0xE5) {
|
|
continue;
|
|
}
|
|
if (ldir->LDIR_Ord == 0x00) {
|
|
break;
|
|
}
|
|
if (ldir->LDIR_Ord & 0x40) {
|
|
memset(long_filename, 0, 256);
|
|
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 & 0x3F) - 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 & 0x3F) - 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 & 0x3F) - 1) + k + 5 + 6;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
int offset = 13 * ((ldir->LDIR_Ord & 0x3F) - 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;
|
|
}
|
|
|
|
bad = 0;
|
|
for (j=0;j<11;j++) {
|
|
if (dir->DIR_Name[j] < 0x20 && dir->DIR_Name[j] != 0x05) {
|
|
bad = 1;
|
|
break;
|
|
}
|
|
|
|
if (!(j == 0 && dir->DIR_Name[j] == ' ')) {
|
|
for (k=0;k<16;k++) {
|
|
if (dir->DIR_Name[j] == badcharacters[k]) {
|
|
bad = 1;
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
bad = 1;
|
|
}
|
|
|
|
if (bad == 1) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (bad == 1) {
|
|
continue;
|
|
}
|
|
|
|
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 (k=8;k<11;k++) {
|
|
if (dir->DIR_Name[k] == ' ') {
|
|
break;
|
|
} else {
|
|
temp[j + 1 + (k - 8)] = 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 *)dbmalloc(sizeof(struct fat_file_info), "fat_find_sub_entry");
|
|
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;
|
|
info->clusterchain = (void *)0;
|
|
return info;
|
|
} else if (type == 1 && !(dir->DIR_Attribute & ATTR_DIRECTORY)) {
|
|
free(buffer);
|
|
struct fat_file_info *info = (struct fat_file_info *)dbmalloc(sizeof(struct fat_file_info), "fat_find_sub_entry");
|
|
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;
|
|
info->clusterchain = (void *)0;
|
|
return info;
|
|
} else if (type == -1){
|
|
free(buffer);
|
|
struct fat_file_info *info = (struct fat_file_info *)dbmalloc(sizeof(struct fat_file_info), "fat_find_sub_entry");
|
|
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;
|
|
info->clusterchain = (void *)0;
|
|
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;
|
|
}
|
|
|
|
|
|
int fat_find_dentry_offset(char *basename, char *buffer, int len, int *last_flag) {
|
|
int i;
|
|
int nent = (strlen(basename) / 13) + 1;
|
|
if (strlen(basename) % 13 != 0) {
|
|
nent ++;
|
|
}
|
|
int n = 0;
|
|
int offset = -1;
|
|
|
|
if (basename[0] == '.') {
|
|
nent = 1;
|
|
}
|
|
|
|
for (i=0;i<len / 32;i++) {
|
|
struct fat_dir *dir = (struct fat_dir *)&buffer[i * 32];
|
|
if (dir->DIR_Name[0] == 0xE5) {
|
|
if (offset == -1) {
|
|
offset = i;
|
|
}
|
|
n++;
|
|
if (n == nent) {
|
|
*last_flag = 0;
|
|
break;
|
|
}
|
|
} else if (dir->DIR_Name[0] == 0x00) {
|
|
if (offset == -1) {
|
|
offset = i;
|
|
*last_flag = 1;
|
|
}
|
|
if (offset + nent + 1 > len / 32) {
|
|
offset = -1;
|
|
}
|
|
break;
|
|
} else {
|
|
n = 0;
|
|
offset = -1;
|
|
}
|
|
}
|
|
return offset;
|
|
}
|
|
|
|
int fat_create_dentry(struct vfs_device_t *device, char *path, int start_cluster, int type) {
|
|
char *path_copy;
|
|
char *directory;
|
|
char *basename;
|
|
char *buffer;
|
|
int i;
|
|
unsigned int len;
|
|
char shortname[11];
|
|
struct fat_data *data = (struct fat_data *)device->fs_data;
|
|
unsigned int first_root_dir_sec;
|
|
unsigned int clusterchain;
|
|
|
|
memset(shortname, ' ', 11);
|
|
|
|
path_copy = (char *)dbmalloc(strlen(path) + 1, "fat_create_dentry");
|
|
strcpy(path_copy, path);
|
|
|
|
directory = path_copy;
|
|
|
|
for (i=strlen(path_copy) -1;i>=0;i--) {
|
|
if (path_copy[i] == '/') {
|
|
path_copy[i] = '\0';
|
|
basename = &path_copy[i+1];
|
|
break;
|
|
}
|
|
}
|
|
|
|
struct fat_file_info *info = NULL;
|
|
|
|
if (directory[0] == '\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 *)dbmalloc(len, "fat_create_dentry");
|
|
if (device->device == 1) {
|
|
ramdisk_read_blocks(first_root_dir_sec, data->root_dir_sectors, buffer, data->superblock.BPB_BytesPerSec);
|
|
} else if ((device->device & 0xf00) == 0x100) {
|
|
hd_read_blocks((device->device & 0xff), first_root_dir_sec, data->root_dir_sectors, buffer, data->superblock.BPB_BytesPerSec);
|
|
}
|
|
} else {
|
|
len = fat_read_entire_file(device, data->superblock.FatType.Fat32.BPB_RootClus, &buffer);
|
|
}
|
|
} else {
|
|
info = fat_check_if_exists(device, directory, 0);
|
|
unsigned int cluster = info->start_cluster;
|
|
len = fat_read_entire_file(device, cluster, &buffer);
|
|
}
|
|
|
|
int tail = 0;
|
|
int highest_tail = 0;
|
|
int j;
|
|
int k;
|
|
int last_flag;
|
|
int flag_cont = 0;
|
|
while (1) {
|
|
if (basename[0] != '.') {
|
|
for (i=0;i<len / 32;i++) {
|
|
struct fat_dir *dir = (struct fat_dir *)&buffer[i * 32];
|
|
|
|
if (!(dir->DIR_Attribute & ATTR_LONG_NAME)) {
|
|
flag_cont = 0;
|
|
for (j=0;j<8;j++) {
|
|
if (j > strlen(basename) && dir->DIR_Name[j] != ' ') {
|
|
flag_cont = 1;
|
|
break;
|
|
}
|
|
if (dir->DIR_Name[j] != toupper(basename[j])) {
|
|
flag_cont = 1;
|
|
break;
|
|
}
|
|
}
|
|
if (flag_cont) {
|
|
continue;
|
|
}
|
|
|
|
for (j=0;j<8;j++) {
|
|
if (dir->DIR_Name[j] == '~') {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (j==8) {
|
|
tail = 1;
|
|
highest_tail = 1;
|
|
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 extpos = strlen(basename);
|
|
|
|
if (type != 0) {
|
|
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) + 8] = toupper(basename[j]);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (i=0;i<extpos && i < 8;i++) {
|
|
shortname[i] = toupper(basename[i]);
|
|
}
|
|
|
|
if (tail > 0) {
|
|
for (i=7;i>1;i--) {
|
|
shortname[i] = (tail % 10) + '0';
|
|
tail = tail / 10;
|
|
if (tail == 0) {
|
|
shortname[i-1] = '~';
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
shortname[0] = basename[0];
|
|
shortname[1] = (basename[1] == '.' ? '.' : ' ');
|
|
shortname[2] = ' ';
|
|
shortname[3] = ' ';
|
|
shortname[4] = ' ';
|
|
shortname[5] = ' ';
|
|
shortname[6] = ' ';
|
|
shortname[7] = ' ';
|
|
shortname[8] = ' ';
|
|
shortname[9] = ' ';
|
|
shortname[10] = ' ';
|
|
}
|
|
|
|
unsigned int offset = fat_find_dentry_offset(basename, buffer, len, &last_flag);
|
|
|
|
if (offset != -1) {
|
|
// found empty dentrys
|
|
int count = 0;
|
|
if (basename[0] != '.') {
|
|
count = strlen(basename) / 13;
|
|
if (strlen(basename) % 13) {
|
|
count ++;
|
|
}
|
|
for (i=count - 1;i>=0;i--) {
|
|
struct fat_long_dir *ldir = (struct fat_long_dir *)&buffer[(offset + i) * 32];
|
|
ldir->LDIR_Ord = i + 1;
|
|
if (i==count -1) {
|
|
ldir->LDIR_Ord |= 0x40;
|
|
}
|
|
if ((i * 13) +1 > strlen(basename) + 1) {
|
|
ldir->LDIR_Name1[0] = 0xffff;
|
|
} else {
|
|
ldir->LDIR_Name1[0] = basename[(i * 13)];
|
|
}
|
|
if ((i * 13) +1 > strlen(basename) + 1) {
|
|
ldir->LDIR_Name1[1] = 0xffff;
|
|
} else {
|
|
ldir->LDIR_Name1[1] = basename[(i * 13)+1];
|
|
}
|
|
if ((i * 13)+2 > strlen(basename) + 1) {
|
|
ldir->LDIR_Name1[2] = 0xffff;
|
|
} else {
|
|
ldir->LDIR_Name1[2] = basename[(i * 13)+2];
|
|
}
|
|
if ((i * 13)+3 > strlen(basename) + 1) {
|
|
ldir->LDIR_Name1[3] = 0xffff;
|
|
} else {
|
|
ldir->LDIR_Name1[3] = basename[(i * 13)+3];
|
|
}
|
|
|
|
if ((i * 13)+4 > strlen(basename) + 1) {
|
|
ldir->LDIR_Name1[4] = 0xffff;
|
|
} else {
|
|
ldir->LDIR_Name1[4] = basename[(i * 13)+4];
|
|
}
|
|
ldir->LDIR_Attrib = ATTR_LONG_NAME;
|
|
ldir->LDIR_Type = 0;
|
|
ldir->LDIR_Chksum = fat_long_dir_chksum(shortname);
|
|
if ((i * 13)+5 > strlen(basename) + 1) {
|
|
ldir->LDIR_Name2[0] = 0xffff;
|
|
} else {
|
|
ldir->LDIR_Name2[0] = basename[(i * 13)+5];
|
|
}
|
|
if ((i * 13)+6 > strlen(basename) + 1) {
|
|
ldir->LDIR_Name2[1] = 0xffff;
|
|
} else {
|
|
ldir->LDIR_Name2[1] = basename[(i * 13)+6];
|
|
}
|
|
if ((i * 13)+7 > strlen(basename) + 1) {
|
|
ldir->LDIR_Name2[2] = 0xffff;
|
|
} else {
|
|
ldir->LDIR_Name2[2] = basename[(i * 13)+7];
|
|
}
|
|
if ((i * 13)+8 > strlen(basename) + 1) {
|
|
ldir->LDIR_Name2[3] = 0xffff;
|
|
} else {
|
|
ldir->LDIR_Name2[3] = basename[(i * 13)+8];
|
|
}
|
|
if ((i * 13)+9 > strlen(basename) + 1) {
|
|
ldir->LDIR_Name2[4] = 0xffff;
|
|
} else {
|
|
ldir->LDIR_Name2[4] = basename[(i * 13)+9];
|
|
}
|
|
if ((i * 13)+10 > strlen(basename) + 1) {
|
|
ldir->LDIR_Name2[5] = 0xffff;
|
|
} else {
|
|
ldir->LDIR_Name2[5] = basename[(i * 13)+10];
|
|
}
|
|
|
|
if ((i * 13)+11 > strlen(basename) + 1) {
|
|
ldir->LDIR_Name3[0] = 0xffff;
|
|
} else {
|
|
ldir->LDIR_Name3[0] = basename[(i * 13)+11];
|
|
}
|
|
|
|
if ((i * 13)+12 > strlen(basename) + 1) {
|
|
ldir->LDIR_Name3[1] = 0xffff;
|
|
} else {
|
|
ldir->LDIR_Name3[1] = basename[(i * 13)+12];
|
|
}
|
|
memcpy(&buffer[(offset + i) * 32], (char *)ldir, sizeof(struct fat_long_dir));
|
|
}
|
|
}
|
|
struct fat_dir *dir = (struct fat_dir *)&buffer[(offset + count) * 32];
|
|
memcpy(dir->DIR_Name, shortname, 11);
|
|
if (type == 0) {
|
|
dir->DIR_Attribute = ATTR_DIRECTORY;
|
|
} else {
|
|
dir->DIR_Attribute = 0;
|
|
}
|
|
dir->DIR_NTRes = 0;
|
|
dir->DIR_CrtTimeTenth = 0;
|
|
|
|
if (data->fat != 2) {
|
|
dir->DIR_FirstClustHi = 0;
|
|
} else {
|
|
dir->DIR_FirstClustHi = (start_cluster & 0x0fff0000) >> 16;
|
|
}
|
|
dir->DIR_WrtTime = rtc_get_fat_time();
|
|
dir->DIR_WrtDate = rtc_get_fat_date();
|
|
if (data->fat == 0) {
|
|
dir->DIR_FirstClustLo = start_cluster & 0x0fff;
|
|
} else {
|
|
dir->DIR_FirstClustLo = start_cluster & 0xffff;
|
|
}
|
|
dir->DIR_FileSize = 0;
|
|
|
|
if (last_flag == 1) {
|
|
char *zeroend = (char *)&buffer[(offset + count + 2) * 32];
|
|
memset(zeroend, 0, len -((offset + count + 2) * 32));
|
|
}
|
|
// write out file
|
|
if (directory[0] == '\0') {
|
|
if (data->fat != 2) {
|
|
if (device->device == 1) {
|
|
ramdisk_write_blocks(first_root_dir_sec, data->root_dir_sectors, buffer, data->superblock.BPB_BytesPerSec);
|
|
} else if ((device->device & 0xff00) == 0x100) {
|
|
hd_write_blocks((device->device & 0xff), first_root_dir_sec, data->root_dir_sectors, buffer, data->superblock.BPB_BytesPerSec);
|
|
}
|
|
free(buffer);
|
|
return 0;
|
|
}
|
|
clusterchain = data->superblock.FatType.Fat32.BPB_RootClus;
|
|
} else {
|
|
clusterchain = info->start_cluster;
|
|
}
|
|
|
|
unsigned int lastcluster;
|
|
int i = 0;
|
|
do {
|
|
if (device->device == 1) {
|
|
ramdisk_write_blocks(cluster_to_sec(device, clusterchain), data->superblock.BPB_SecPerClus, &buffer[i * data->superblock.BPB_SecPerClus * data->superblock.BPB_BytesPerSec] , data->superblock.BPB_BytesPerSec);
|
|
} else if ((device->device & 0xff00) == 0x100) {
|
|
hd_write_blocks((device->device & 0xff), cluster_to_sec(device, clusterchain), data->superblock.BPB_SecPerClus, &buffer[i * data->superblock.BPB_SecPerClus * data->superblock.BPB_BytesPerSec], data->superblock.BPB_BytesPerSec);
|
|
}
|
|
lastcluster = clusterchain;
|
|
i++;
|
|
clusterchain = fat_get_cluster_entry(device, lastcluster);
|
|
} while (!is_EOC(device, lastcluster));
|
|
if (info != NULL) free(info);
|
|
return 0;
|
|
} else {
|
|
// need to append dentry
|
|
|
|
if (directory[0] == '\0') {
|
|
if (data->fat != 2) {
|
|
// out of space in the root directory...
|
|
free(buffer);
|
|
return -1;
|
|
}
|
|
clusterchain = data->superblock.FatType.Fat32.BPB_RootClus;
|
|
} else {
|
|
clusterchain = info->start_cluster;
|
|
}
|
|
|
|
unsigned int lastcluster;
|
|
while (!is_EOC(device, clusterchain)) {
|
|
lastcluster = clusterchain;
|
|
clusterchain = fat_get_cluster_entry(device, lastcluster);
|
|
}
|
|
|
|
unsigned int new_cluster = fat_alloc_cluster(device, lastcluster);
|
|
if (!new_cluster) {
|
|
free(buffer);
|
|
free(info);
|
|
return -1;
|
|
}
|
|
len = len + data->superblock.BPB_SecPerClus * data->superblock.BPB_BytesPerSec;
|
|
buffer = (char *)realloc(buffer, len);
|
|
}
|
|
}
|
|
}
|
|
|
|
int fat_create_file(struct vfs_device_t *device, char *path) {
|
|
fat_create_dentry(device, path, 0, 1);
|
|
}
|
|
|
|
int fat_create_directory(struct vfs_device_t *device, char *path) {
|
|
char *dotentry = (char *)dbmalloc(strlen(path) + 3, "fat_create_directory");
|
|
char *dotdotentry = (char *)dbmalloc(strlen(path) + 4, "fat_create_directory");
|
|
struct fat_data *data = (struct fat_data *)device->fs_data;
|
|
char *path_copy = (char *)dbmalloc(strlen(path) + 1, "fat_create_directory");
|
|
int i;
|
|
int root = 0;
|
|
struct fat_file_info *info = NULL;
|
|
int ret;
|
|
|
|
strcpy(path_copy, path);
|
|
|
|
for (i=strlen(path_copy)-1;i >= 0; i--) {
|
|
if (path_copy[i] == '/') {
|
|
path_copy[i] = '\0';
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (strlen(path_copy) == 0) {
|
|
root = 1;
|
|
free(path_copy);
|
|
} else {
|
|
|
|
info = fat_check_if_exists(device, path_copy, 0);
|
|
|
|
if (!info) {
|
|
free(dotentry);
|
|
free(dotdotentry);
|
|
free(path_copy);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
strcpy(dotentry, path);
|
|
dotentry[strlen(path)] = '/';
|
|
dotentry[strlen(path) + 1] = '.';
|
|
dotentry[strlen(path) + 2] = '\0';
|
|
|
|
strcpy(dotdotentry, dotentry);
|
|
dotdotentry[strlen(path) + 2] = '.';
|
|
dotdotentry[strlen(path) + 3] = '\0';
|
|
|
|
unsigned int new_cluster = fat_alloc_cluster(device, 0);
|
|
|
|
// clear out cluster
|
|
char *buffer = (char *)dbmalloc(data->superblock.BPB_BytesPerSec * data->superblock.BPB_SecPerClus, "fat_create_directory");
|
|
memset(buffer, 0, data->superblock.BPB_BytesPerSec * data->superblock.BPB_SecPerClus);
|
|
|
|
if (device->device == 1) {
|
|
ramdisk_write_blocks(cluster_to_sec(device, new_cluster), data->superblock.BPB_SecPerClus, buffer, data->superblock.BPB_BytesPerSec);
|
|
} else if ((device->device & 0xff00) == 0x100) {
|
|
hd_write_blocks((device->device & 0xff), cluster_to_sec(device, new_cluster), data->superblock.BPB_SecPerClus, buffer, data->superblock.BPB_BytesPerSec);
|
|
}
|
|
|
|
free(buffer);
|
|
|
|
ret = fat_create_dentry(device, path, new_cluster, 0);
|
|
|
|
if (root == 1) {
|
|
fat_create_dentry(device, dotentry, 0, 0);
|
|
fat_create_dentry(device, dotdotentry, 0, 0);
|
|
|
|
} else {
|
|
fat_create_dentry(device, dotentry, new_cluster, 0);
|
|
fat_create_dentry(device, dotdotentry, info->start_cluster, 0);
|
|
|
|
}
|
|
|
|
if (info != NULL) {
|
|
free(info);
|
|
}
|
|
free(dotentry);
|
|
free(dotdotentry);
|
|
|
|
|
|
return 0;
|
|
}
|
|
|
|
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;
|
|
int bad;
|
|
|
|
int badcharacters[] = {0x22, 0x2A, 0x2B, 0x2C, 0x2E, 0x2F, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x5B, 0x5C, 0x5D, 0x7C};
|
|
|
|
|
|
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 *)dbmalloc(sizeof(struct fat_file_info), "fat_check_if_exists");
|
|
if (!info) {
|
|
return NULL;
|
|
}
|
|
info->start_cluster = 0;
|
|
info->file_size = 0;
|
|
info->type = 0;
|
|
info->clusterchain = (void *)0;
|
|
return info;
|
|
}
|
|
|
|
buffer = (char *)dbmalloc(len, "fat_check_if_exists");
|
|
if (device->device == 1) {
|
|
ramdisk_read_blocks(first_root_dir_sec, data->root_dir_sectors, buffer, data->superblock.BPB_BytesPerSec);
|
|
} else if ((device->device & 0xff00) == 0x100) {
|
|
hd_read_blocks(device->device & 0xff, first_root_dir_sec, data->root_dir_sectors, buffer, data->superblock.BPB_BytesPerSec);
|
|
}
|
|
} 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 *)dbmalloc(sizeof(struct fat_file_info), "fat_check_if_exists");
|
|
if (!info) {
|
|
return NULL;
|
|
}
|
|
info->start_cluster = data->superblock.FatType.Fat32.BPB_RootClus;
|
|
info->file_size = len;
|
|
info->type = 0;
|
|
info->clusterchain = (void *)0;
|
|
free(buffer);
|
|
return info;
|
|
}
|
|
|
|
}
|
|
|
|
// buffer contains the root directory contents...
|
|
int i;
|
|
int parts = 0;
|
|
char *path_copy = (char *)dbmalloc(strlen(path) + 1, "fat_check_if_exists");
|
|
|
|
strcpy(path_copy, path);
|
|
|
|
if (path_copy[strlen(path_copy) - 1] == '/') {
|
|
path_copy[strlen(path_copy) - 1] = '\0';
|
|
}
|
|
parts = 1;
|
|
|
|
for (i=1;i<strlen(path_copy);i++) {
|
|
if (path_copy[i] == '/') {
|
|
parts++;
|
|
}
|
|
}
|
|
|
|
char **ptr = (char **)dbmalloc(sizeof(char *) * parts , "fat_check_if_exists");
|
|
|
|
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 == 0xE5) {
|
|
continue;
|
|
}
|
|
if (ldir->LDIR_Ord == 0x00) {
|
|
break;
|
|
}
|
|
if (ldir->LDIR_Ord & 0x40) {
|
|
memset(long_filename, 0, 256);
|
|
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 & 0x3F) - 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 & 0x3F) - 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 & 0x3F) - 1) + k + 5 + 6;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
int offset = 13 * ((ldir->LDIR_Ord & 0x3F) - 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;
|
|
}
|
|
|
|
bad = 0;
|
|
for (j=0;j<11;j++) {
|
|
if (dir->DIR_Name[j] < 0x20 && dir->DIR_Name[j] != 0x05) {
|
|
bad = 1;
|
|
break;
|
|
}
|
|
if (!(j == 0 && dir->DIR_Name[j] == ' ')) {
|
|
for (k=0;k<16;k++) {
|
|
if (dir->DIR_Name[j] == badcharacters[k]) {
|
|
bad = 1;
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
bad = 1;
|
|
}
|
|
|
|
if (bad == 1) {
|
|
break;
|
|
}
|
|
}
|
|
if (bad == 1) {
|
|
continue;
|
|
}
|
|
|
|
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 (k=8;k<11;k++) {
|
|
if (dir->DIR_Name[k] == ' ') {
|
|
break;
|
|
} else {
|
|
temp[j + 1 + (k - 8)] = 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 *)dbmalloc(sizeof(struct fat_file_info), "fat_check_if_exists");
|
|
if (!info) {
|
|
return NULL;
|
|
}
|
|
|
|
info->start_cluster = ((unsigned int)dir->DIR_FirstClustHi << (unsigned int)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;
|
|
info->clusterchain = (void *)0;
|
|
return info;
|
|
} else if (type == 1 && !(dir->DIR_Attribute & ATTR_DIRECTORY)) {
|
|
free(buffer);
|
|
struct fat_file_info *info = (struct fat_file_info *)dbmalloc(sizeof(struct fat_file_info), "fat_check_if_exists");
|
|
if (!info) {
|
|
return NULL;
|
|
}
|
|
|
|
info->start_cluster = ((unsigned int)dir->DIR_FirstClustHi << (unsigned int)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;
|
|
info->clusterchain = (void *)0;
|
|
return info;
|
|
} else if (type == -1) {
|
|
free(buffer);
|
|
struct fat_file_info *info = (struct fat_file_info *)dbmalloc(sizeof(struct fat_file_info), "fat_check_if_exists");
|
|
if (!info) {
|
|
return NULL;
|
|
}
|
|
|
|
info->start_cluster = ((unsigned int)dir->DIR_FirstClustHi << (unsigned int)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;
|
|
info->clusterchain = (void *)0;
|
|
|
|
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_clear_cluster_chain(struct vfs_device_t *device, unsigned int start_cluster) {
|
|
int i;
|
|
unsigned int *clusterchain = (unsigned int *)dbmalloc(sizeof(unsigned int) * 2, "fat_clear_cluster_chain");
|
|
|
|
clusterchain[0] = start_cluster;
|
|
clusterchain[1] = fat_get_cluster_entry(device, start_cluster);
|
|
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 j;
|
|
for (j=0;j<i;j++) {
|
|
fat_set_cluster_entry(device, clusterchain[j], 0);
|
|
}
|
|
|
|
free(clusterchain);
|
|
}
|
|
|
|
int fat_trunc_file(struct vfs_device_t *device, struct fat_file_info *info, char *filename) {
|
|
fat_clear_cluster_chain(device, info->start_cluster);
|
|
struct fat_data *data = (struct fat_data *)device->fs_data;
|
|
int j, i;
|
|
char *temp_buff = (char *)dbmalloc(strlen(filename) + 1, "fat_trunc_file");
|
|
char *fname;
|
|
strcpy(temp_buff, filename);
|
|
|
|
for (j=strlen(temp_buff)-1;j>=0;j++) {
|
|
if (temp_buff[j] == '/') {
|
|
temp_buff[j] = '\0';
|
|
fname = &temp_buff[j+1];
|
|
break;
|
|
}
|
|
}
|
|
int dirlen;
|
|
struct fat_file_info *dirinfo;
|
|
unsigned int first_root_dir_sec;
|
|
char *buffer2;
|
|
|
|
if (strlen(temp_buff) == 0) {
|
|
// root directory
|
|
if (data->fat != 2) {
|
|
first_root_dir_sec = data->superblock.BPB_RsvdSecCnt + (data->superblock.BPB_NumFATs * data->superblock.BPB_FATSz16);
|
|
dirlen = data->root_dir_sectors * data->superblock.BPB_BytesPerSec;
|
|
buffer2 = (char *)dbmalloc(dirlen, "fat_trunc_file");
|
|
if (device->device == 1) {
|
|
ramdisk_read_blocks(first_root_dir_sec, data->root_dir_sectors, buffer2, data->superblock.BPB_BytesPerSec);
|
|
} else if ((device->device & 0xff00) == 0x100) {
|
|
hd_read_blocks(device->device & 0xff, first_root_dir_sec, data->root_dir_sectors, buffer2, data->superblock.BPB_BytesPerSec);
|
|
}
|
|
} else {
|
|
dirlen = fat_read_entire_file(device, data->superblock.FatType.Fat32.BPB_RootClus, &buffer2);
|
|
}
|
|
} else {
|
|
// other directory
|
|
dirinfo = fat_check_if_exists(device, temp_buff, 0);
|
|
dirlen = fat_read_entire_file(device, dirinfo->start_cluster, &buffer2);
|
|
}
|
|
|
|
char long_filename[256];
|
|
char temp[13];
|
|
unsigned char chksum = 0;
|
|
|
|
int badcharacters[] = {0x22, 0x2A, 0x2B, 0x2C, 0x2E, 0x2F, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x5B, 0x5C, 0x5D, 0x7C};
|
|
int k = 0;
|
|
int long_name_len = 0;
|
|
int bad;
|
|
|
|
for (i=0;i<dirlen / 32;i++) {
|
|
memset(temp, 0, 13);
|
|
struct fat_dir *dir = (struct fat_dir *)&buffer2[i * 32];
|
|
if (dir->DIR_Attribute & ATTR_LONG_NAME) {
|
|
struct fat_long_dir *ldir = (struct fat_long_dir *)dir;
|
|
if (ldir->LDIR_Ord == 0xE5) {
|
|
continue;
|
|
}
|
|
if (ldir->LDIR_Ord == 0x00) {
|
|
break;
|
|
}
|
|
if (ldir->LDIR_Ord & 0x40) {
|
|
memset(long_filename, 0, 256);
|
|
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 & 0x3F) - 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 & 0x3F) - 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 & 0x3F) - 1) + k + 5 + 6;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
int offset = 13 * ((ldir->LDIR_Ord & 0x3F) - 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;
|
|
}
|
|
|
|
bad = 0;
|
|
for (j=0;j<11;j++) {
|
|
if (dir->DIR_Name[j] < 0x20 && dir->DIR_Name[j] != 0x05) {
|
|
bad = 1;
|
|
break;
|
|
}
|
|
if (!(j == 0 && dir->DIR_Name[j] == ' ')) {
|
|
for (k=0;k<16;k++) {
|
|
if (dir->DIR_Name[j] == badcharacters[k]) {
|
|
bad = 1;
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
bad = 1;
|
|
}
|
|
|
|
if (bad == 1) {
|
|
break;
|
|
}
|
|
}
|
|
if (bad == 1) {
|
|
continue;
|
|
}
|
|
|
|
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 (k=8;k<11;k++) {
|
|
if (dir->DIR_Name[k] == ' ') {
|
|
break;
|
|
} else {
|
|
temp[j + 1 + (k - 8)] = dir->DIR_Name[j];
|
|
}
|
|
}
|
|
}
|
|
|
|
if (((strlen(long_filename) > 0) && (strcmp(long_filename, fname) == 0)) || (strcmp(temp, fname) == 0)) {
|
|
if (data->fat == 2) {
|
|
dir->DIR_FirstClustHi = 0x0;
|
|
dir->DIR_FirstClustLo = 0x0;
|
|
} else if (data->fat == 1) {
|
|
dir->DIR_FirstClustHi = 0;
|
|
dir->DIR_FirstClustLo = 0x0;
|
|
} else {
|
|
dir->DIR_FirstClustHi = 0;
|
|
dir->DIR_FirstClustLo = 0x0;
|
|
}
|
|
|
|
if (strlen(temp_buff) == 0) {
|
|
// root directory
|
|
if (data->fat != 2) {
|
|
first_root_dir_sec = data->superblock.BPB_RsvdSecCnt + (data->superblock.BPB_NumFATs * data->superblock.BPB_FATSz16);
|
|
dirlen = data->root_dir_sectors * data->superblock.BPB_BytesPerSec;
|
|
|
|
if (device->device == 1) {
|
|
ramdisk_write_blocks(first_root_dir_sec, data->root_dir_sectors, buffer2, data->superblock.BPB_BytesPerSec);
|
|
} else if ((device->device & 0xff00) == 0x100) {
|
|
hd_write_blocks(device->device & 0xff, first_root_dir_sec, data->root_dir_sectors, buffer2, data->superblock.BPB_BytesPerSec);
|
|
}
|
|
} else {
|
|
fat_write_entire_file(device, data->superblock.FatType.Fat32.BPB_RootClus, buffer2, dirlen);
|
|
}
|
|
} else {
|
|
// other directory
|
|
fat_write_entire_file(device, dirinfo->start_cluster, buffer2, dirlen);
|
|
}
|
|
free(buffer2);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
int fat_write_data(struct vfs_device_t *device, struct fat_file_info *info, char *filename, char *buffer, int len, unsigned long long offset) {
|
|
struct fat_data *data = (struct fat_data *)device->fs_data;
|
|
char *buffer2;
|
|
int i = 1;
|
|
int j;
|
|
int new_start_cluster = 0;
|
|
|
|
if (info->type == 0) {
|
|
// it's a directory...
|
|
return 0;
|
|
}
|
|
|
|
if (len > 0) {
|
|
if (info->clusterchain != (void *)0) {
|
|
free(info->clusterchain);
|
|
info->clusterchain = (void *)0;
|
|
}
|
|
unsigned int *clusterchain;
|
|
|
|
if (info->start_cluster != 0x0) {
|
|
clusterchain = (unsigned int *)dbmalloc(sizeof(unsigned int) * 2, "fat_write_file");
|
|
clusterchain[0] = info->start_cluster;
|
|
|
|
clusterchain[1] = fat_get_cluster_entry(device, info->start_cluster);
|
|
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]);
|
|
}
|
|
|
|
if (len + offset > info->file_size + (info->file_size % (data->superblock.BPB_BytesPerSec * data->superblock.BPB_SecPerClus))) {
|
|
int needed_clusters = ((len + offset) - (info->file_size + (info->file_size % (data->superblock.BPB_BytesPerSec * data->superblock.BPB_SecPerClus)))) / (data->superblock.BPB_BytesPerSec * data->superblock.BPB_SecPerClus);
|
|
|
|
if (((len + offset) - (info->file_size + (info->file_size % (data->superblock.BPB_BytesPerSec * data->superblock.BPB_SecPerClus)))) % (data->superblock.BPB_BytesPerSec * data->superblock.BPB_SecPerClus)) {
|
|
needed_clusters++;
|
|
}
|
|
|
|
|
|
clusterchain = (unsigned int *)realloc(clusterchain, sizeof(unsigned int) * (i + needed_clusters));
|
|
for (j=i;j<needed_clusters + i - 1;j++) {
|
|
clusterchain[j + 1] = fat_alloc_cluster(device, clusterchain[j]);
|
|
}
|
|
i = j;
|
|
}
|
|
} else {
|
|
int needed_clusters = (len + offset) / (data->superblock.BPB_BytesPerSec * data->superblock.BPB_SecPerClus);
|
|
if ((len + offset) % (data->superblock.BPB_BytesPerSec * data->superblock.BPB_SecPerClus)) {
|
|
needed_clusters++;
|
|
}
|
|
|
|
clusterchain = (unsigned int *)dbmalloc(sizeof(unsigned int) * needed_clusters, "fat_write_file");
|
|
clusterchain[0] = fat_alloc_cluster(device, 0);
|
|
|
|
new_start_cluster = clusterchain[0];
|
|
|
|
info->start_cluster = new_start_cluster;
|
|
|
|
for (j=0;j<needed_clusters-1;j++) {
|
|
clusterchain[j + 1] = fat_alloc_cluster(device, clusterchain[j]);
|
|
}
|
|
i = j;
|
|
}
|
|
|
|
if (len + offset > info->file_size) {
|
|
info->file_size = len + offset;
|
|
}
|
|
|
|
int start_cluster;
|
|
int end_cluster;
|
|
|
|
start_cluster = offset / (data->superblock.BPB_SecPerClus * data->superblock.BPB_BytesPerSec);
|
|
end_cluster = offset + len / (data->superblock.BPB_SecPerClus * data->superblock.BPB_BytesPerSec);
|
|
if (offset + len % (data->superblock.BPB_SecPerClus * data->superblock.BPB_BytesPerSec)) {
|
|
end_cluster++;
|
|
}
|
|
|
|
buffer2 = (char *)dbmalloc((end_cluster - start_cluster) * (data->superblock.BPB_SecPerClus * data->superblock.BPB_BytesPerSec), "fat_write_file");
|
|
|
|
// read in clusters
|
|
for (j=start_cluster;j<end_cluster;j++) {
|
|
if (device->device == 1) {
|
|
ramdisk_read_blocks(cluster_to_sec(device, clusterchain[j]), data->superblock.BPB_SecPerClus, &buffer2[(j - start_cluster) * data->superblock.BPB_SecPerClus * data->superblock.BPB_BytesPerSec], data->superblock.BPB_BytesPerSec);
|
|
} else if ((device->device & 0xff00) == 0x100) {
|
|
hd_read_blocks(device->device & 0xff, cluster_to_sec(device, clusterchain[j]), data->superblock.BPB_SecPerClus, &buffer2[(j - start_cluster) * data->superblock.BPB_SecPerClus * data->superblock.BPB_BytesPerSec], data->superblock.BPB_BytesPerSec);
|
|
}
|
|
}
|
|
// modify data
|
|
memcpy(&buffer2[offset - (start_cluster * (data->superblock.BPB_SecPerClus * data->superblock.BPB_BytesPerSec))], buffer, len);
|
|
|
|
// write out clusters
|
|
for (j=start_cluster;j<end_cluster;j++) {
|
|
if (device->device == 1) {
|
|
ramdisk_write_blocks(cluster_to_sec(device, clusterchain[j]), data->superblock.BPB_SecPerClus, &buffer2[(j - start_cluster) * data->superblock.BPB_SecPerClus * data->superblock.BPB_BytesPerSec], data->superblock.BPB_BytesPerSec);
|
|
} else if ((device->device & 0xff00) == 0x100) {
|
|
hd_write_blocks(device->device & 0xff, cluster_to_sec(device, clusterchain[j]), data->superblock.BPB_SecPerClus, &buffer2[(j - start_cluster) * data->superblock.BPB_SecPerClus * data->superblock.BPB_BytesPerSec], data->superblock.BPB_BytesPerSec);
|
|
}
|
|
}
|
|
|
|
free(buffer2);
|
|
|
|
// update dentry
|
|
|
|
char *temp_buff = (char *)dbmalloc(strlen(filename) + 1, "fat_write_file");
|
|
char *fname;
|
|
strcpy(temp_buff, filename);
|
|
|
|
for (j=strlen(temp_buff)-1;j>=0;j--) {
|
|
if (temp_buff[j] == '/') {
|
|
temp_buff[j] = '\0';
|
|
fname = &temp_buff[j+1];
|
|
break;
|
|
}
|
|
}
|
|
int dirlen;
|
|
struct fat_file_info *dirinfo;
|
|
unsigned int first_root_dir_sec;
|
|
|
|
if (strlen(temp_buff) == 0) {
|
|
// root directory
|
|
if (data->fat != 2) {
|
|
first_root_dir_sec = data->superblock.BPB_RsvdSecCnt + (data->superblock.BPB_NumFATs * data->superblock.BPB_FATSz16);
|
|
dirlen = data->root_dir_sectors * data->superblock.BPB_BytesPerSec;
|
|
buffer2 = (char *)dbmalloc(dirlen, "fat_write_file");
|
|
if (device->device == 1) {
|
|
ramdisk_read_blocks(first_root_dir_sec, data->root_dir_sectors, buffer2, data->superblock.BPB_BytesPerSec);
|
|
} else if ((device->device & 0xff00) == 0x100) {
|
|
hd_read_blocks(device->device & 0xff, first_root_dir_sec, data->root_dir_sectors, buffer2, data->superblock.BPB_BytesPerSec);
|
|
}
|
|
} else {
|
|
dirlen = fat_read_entire_file(device, data->superblock.FatType.Fat32.BPB_RootClus, &buffer2);
|
|
}
|
|
} else {
|
|
// other directory
|
|
dirinfo = fat_check_if_exists(device, temp_buff, 0);
|
|
dirlen = fat_read_entire_file(device, dirinfo->start_cluster, &buffer2);
|
|
}
|
|
|
|
char long_filename[256];
|
|
char temp[13];
|
|
unsigned char chksum = 0;
|
|
|
|
int badcharacters[] = {0x22, 0x2A, 0x2B, 0x2C, 0x2E, 0x2F, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x5B, 0x5C, 0x5D, 0x7C};
|
|
int k = 0;
|
|
int long_name_len = 0;
|
|
int bad;
|
|
|
|
for (i=0;i<dirlen / 32;i++) {
|
|
memset(temp, 0, 13);
|
|
struct fat_dir *dir = (struct fat_dir *)&buffer2[i * 32];
|
|
|
|
if (dir->DIR_Attribute & ATTR_LONG_NAME) {
|
|
struct fat_long_dir *ldir = (struct fat_long_dir *)dir;
|
|
if (ldir->LDIR_Ord == 0xE5) {
|
|
continue;
|
|
}
|
|
if (ldir->LDIR_Ord == 0x00) {
|
|
free(buffer2);
|
|
break;
|
|
}
|
|
if (ldir->LDIR_Ord & 0x40) {
|
|
memset(long_filename, 0, 256);
|
|
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 & 0x3F) - 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 & 0x3F) - 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 & 0x3F) - 1) + k + 5 + 6;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
int offset = 13 * ((ldir->LDIR_Ord & 0x3F) - 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) {
|
|
free(buffer2);
|
|
break;
|
|
}
|
|
|
|
bad = 0;
|
|
for (j=0;j<11;j++) {
|
|
if (dir->DIR_Name[j] < 0x20 && dir->DIR_Name[j] != 0x05) {
|
|
bad = 1;
|
|
break;
|
|
}
|
|
if (!(j == 0 && dir->DIR_Name[j] == ' ')) {
|
|
for (k=0;k<16;k++) {
|
|
if (dir->DIR_Name[j] == badcharacters[k]) {
|
|
bad = 1;
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
bad = 1;
|
|
}
|
|
|
|
if (bad == 1) {
|
|
break;
|
|
}
|
|
}
|
|
if (bad == 1) {
|
|
continue;
|
|
}
|
|
|
|
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[j] = '.';
|
|
for (k=8;k<11;k++) {
|
|
if (dir->DIR_Name[k] == ' ') {
|
|
break;
|
|
} else {
|
|
temp[j + 1 + (k - 8)] = dir->DIR_Name[j];
|
|
}
|
|
}
|
|
}
|
|
if (((strlen(long_filename) > 0) && (strcmp(long_filename, fname) == 0)) || (strcmp(temp, fname) == 0)) {
|
|
dir->DIR_FileSize = info->file_size;
|
|
dir->DIR_WrtTime = rtc_get_fat_time();
|
|
dir->DIR_WrtDate = rtc_get_fat_date();
|
|
if (new_start_cluster != 0) {
|
|
kprintf("Updating start cluster...\n");
|
|
if (data->fat == 2) {
|
|
dir->DIR_FirstClustHi = (0x0fff0000 & new_start_cluster) >> 16;
|
|
dir->DIR_FirstClustLo = 0xffff & new_start_cluster;
|
|
} else if (data->fat == 1) {
|
|
dir->DIR_FirstClustHi = 0;
|
|
dir->DIR_FirstClustLo = 0xffff & new_start_cluster;
|
|
} else {
|
|
dir->DIR_FirstClustHi = 0;
|
|
dir->DIR_FirstClustLo = 0x0fff & new_start_cluster;
|
|
}
|
|
}
|
|
if (strlen(temp_buff) == 0) {
|
|
// root directory
|
|
if (data->fat != 2) {
|
|
first_root_dir_sec = data->superblock.BPB_RsvdSecCnt + (data->superblock.BPB_NumFATs * data->superblock.BPB_FATSz16);
|
|
dirlen = data->root_dir_sectors * data->superblock.BPB_BytesPerSec;
|
|
|
|
if (device->device == 1) {
|
|
ramdisk_write_blocks(first_root_dir_sec, data->root_dir_sectors, buffer2, data->superblock.BPB_BytesPerSec);
|
|
} else if ((device->device & 0xff00) == 0x100) {
|
|
hd_write_blocks(device->device & 0xff, first_root_dir_sec, data->root_dir_sectors, buffer2, data->superblock.BPB_BytesPerSec);
|
|
}
|
|
} else {
|
|
fat_write_entire_file(device, data->superblock.FatType.Fat32.BPB_RootClus, buffer2, dirlen);
|
|
}
|
|
} else {
|
|
// other directory
|
|
fat_write_entire_file(device, dirinfo->start_cluster, buffer2, dirlen);
|
|
}
|
|
free(buffer2);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return len;
|
|
}
|
|
|
|
int fat_read_data(struct vfs_device_t *device, struct fat_file_info *info, char *buffer, int len, unsigned long long 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) {
|
|
int i = 1;
|
|
int j;
|
|
int blocks_read;
|
|
|
|
if (info->clusterchain == (void *)0) {
|
|
info->clusterchain = (unsigned int *)dbmalloc(sizeof(unsigned int) * 2, "fat_read_data 1");
|
|
info->clusterchain[0] = info->start_cluster;
|
|
info->clusterchain[1] = fat_get_cluster_entry(device, info->start_cluster);
|
|
|
|
while (!is_EOC(device, info->clusterchain[i])) {
|
|
i++;
|
|
info->clusterchain = (unsigned int *)realloc(info->clusterchain, sizeof(unsigned int) * (i + 1));
|
|
info->clusterchain[i] = fat_get_cluster_entry(device, info->clusterchain[i-1]);
|
|
}
|
|
}
|
|
|
|
unsigned int *clusterchain = info->clusterchain;
|
|
|
|
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 = 0;
|
|
|
|
char *tempbuffer = (char *)dbmalloc(data->superblock.BPB_SecPerClus * data->superblock.BPB_BytesPerSec, "fat_read_data 2");
|
|
|
|
if (len + cluster_offset % (data->superblock.BPB_SecPerClus * data->superblock.BPB_BytesPerSec) > 0) {
|
|
cluster_count += 1;
|
|
}
|
|
|
|
if (device->device == 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);
|
|
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);
|
|
return len;
|
|
}
|
|
}
|
|
}
|
|
} else if ((device->device & 0xff00) == 0x100) {
|
|
for (j=0;j<cluster_count;j++) {
|
|
|
|
blocks_read = hd_read_blocks((device->device & 0xff), 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);
|
|
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);
|
|
return len;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return len;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
int fat_get_dents(struct vfs_device_t *device, struct fat_file_info *info, char *buffer, int len, unsigned long long 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 *)dbmalloc(dirlen, "fat_get_dents");
|
|
|
|
if (device->device == 1) {
|
|
ramdisk_read_blocks(first_root_dir_sec, data->root_dir_sectors, buffer2, data->superblock.BPB_BytesPerSec);
|
|
} else if ((device->device & 0xff00) == 0x100) {
|
|
hd_read_blocks((device->device & 0xff), first_root_dir_sec, data->root_dir_sectors, buffer2, data->superblock.BPB_BytesPerSec);
|
|
}
|
|
|
|
dir_buffer = (char *)dbmalloc(data->root_dir_sectors * data->superblock.BPB_BytesPerSec - offset + 1, "fat_get_dents");
|
|
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;
|
|
}
|
|
|
|
if (offset >= newsz) {
|
|
free(buffer2);
|
|
return 0;
|
|
}
|
|
|
|
dir_buffer = (char *)dbmalloc(newsz - offset + 1, "fat_get_dents");
|
|
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;
|
|
int bad;
|
|
|
|
int badcharacters[] = {0x22, 0x2A, 0x2B, 0x2C, 0x2E, 0x2F, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x5B, 0x5C, 0x5D, 0x7C};
|
|
|
|
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 == 0xE5) {
|
|
continue;
|
|
}
|
|
if (ldir->LDIR_Ord == 0x00) {
|
|
info->file_size = offset + (i * 32);
|
|
break;
|
|
}
|
|
if (ldir->LDIR_Ord & 0x40) {
|
|
memset(long_filename, 0, 256);
|
|
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 & 0x3F) - 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 & 0x3F) - 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 & 0x3F) - 1) + k + 5 + 6;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!long_name_len) {
|
|
13 * ((ldir->LDIR_Ord & 0x3F) - 1) + k + 5 + 6 + 2;
|
|
}
|
|
|
|
int offset = 13 * ((ldir->LDIR_Ord & 0x3F) - 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;
|
|
}
|
|
|
|
bad = 0;
|
|
for (j=0;j<11;j++) {
|
|
if (dir->DIR_Name[j] < 0x20 && dir->DIR_Name[j] != 0x05) {
|
|
bad = 1;
|
|
break;
|
|
}
|
|
if (!(j == 0 && dir->DIR_Name[j] == ' ')) {
|
|
for (k=0;k<16;k++) {
|
|
if (dir->DIR_Name[j] == badcharacters[k]) {
|
|
bad = 1;
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
bad = 1;
|
|
}
|
|
|
|
if (bad == 1) {
|
|
break;
|
|
}
|
|
}
|
|
if (bad == 1) {
|
|
continue;
|
|
}
|
|
|
|
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 (k=8;k<11;k++) {
|
|
if (dir->DIR_Name[k] == ' ') {
|
|
break;
|
|
} else {
|
|
temp[j + 1 + (k - 8)] = 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;
|
|
}
|