📄 fat16.c
字号:
if(!fs->partition->device_read(offset, &first_char, sizeof(first_char)))
return 0;
/* check if we found a free directory entry */
if(first_char == FAT16_DIRENTRY_DELETED || !first_char)
{
/* check if we have the needed number of available entries */
++free_dir_entries_found;
if(free_dir_entries_found >= free_dir_entries_needed)
break;
offset += 32;
}
else
{
offset += 32;
Dir_Entry_Offset = offset;
free_dir_entries_found = 0;
}
}
return Dir_Entry_Offset;
#else
return 0;
#endif
}
/**********************************************************************
* 函数 Fat16_Write_Dir_Entry --- 添加一条目录项
* note:
* The file name is not checked for invalid characters.
*
* note:
* The generation of the short 8.3 file name is quite
* simple. The first eight characters are used for the filename.
* The extension, if any, is made up of the first three characters
* following the last dot within the long filename. If the
* filename (without the extension) is longer than eight characters,
* the lower byte of the cluster number replaces the last two
* characters to avoid name clashes. In any other case, it is your
* responsibility to avoid name clashes.
*
* 输入参数 fs:The filesystem on which to operate
* dir_entry:The directory entry to write.
* 返回值 0 --- 失败
* 1 --- 成功
**********************************************************************/
u8
Fat16_Write_Dir_Entry(const struct Fat16_FS_Struct* fs, struct Fat16_Dir_Entry_Struct* dir_entry)
{
#if FAT16_WRITE_SUPPORT
if(!fs || !dir_entry)
return 0;
#if FAT16_DATETIME_SUPPORT
{
u16 year;
u8 month;
u8 day;
u8 hour;
u8 min;
u8 sec;
fat16_get_datetime(&year, &month, &day, &hour, &min, &sec);
fat16_set_file_modification_date(dir_entry, year, month, day);
fat16_set_file_modification_time(dir_entry, hour, min, sec);
}
#endif
device_write_t device_write = fs->partition->device_write;
u32 offset = dir_entry->Entry_Offset;
const char* name = dir_entry->Long_Name;
u8 name_len = strlen(name);
u8 lfn_entry_count = (name_len + 12) / 13;
u8 buffer[32];
/* write 8.3 entry */
/* generate 8.3 file name */
memset(&buffer[0], ' ', 11);
char* name_ext = strrchr(name, '.');
if(name_ext && *++name_ext)
{
u8 name_ext_len = strlen(name_ext);
name_len -= name_ext_len + 1;
if(name_ext_len > 3)
name_ext_len = 3;
memcpy(&buffer[8], name_ext, name_ext_len);
}
if(name_len <= 8)
{
memcpy(buffer, name, name_len);
/* For now, we create lfn entries for all files,
* except the "." and ".." directory references.
* This is to avoid difficulties with capitalization,
* as 8.3 filenames allow uppercase letters only.
*
* Theoretically it would be possible to leave
* the 8.3 entry alone if the basename and the
* extension have no mixed capitalization.
*/
if(name[0] == '.' &&
((name[1] == '.' && name[2] == '\0') ||
name[1] == '\0')
)
lfn_entry_count = 0;
}
else
{
memcpy(buffer, name, 8);
/* Minimize 8.3 name clashes by appending
* the lower byte of the cluster number.
*/
u8 num = dir_entry->Cluster & 0xff;
buffer[6] = (num < 0xa0) ? ('0' + (num >> 4)) : ('a' + (num >> 4));
num &= 0x0f;
buffer[7] = (num < 0x0a) ? ('0' + num) : ('a' + num);
}
if(buffer[0] == FAT16_DIRENTRY_DELETED)
buffer[0] = 0x05;
/* fill directory entry buffer */
memset(&buffer[11], 0, sizeof(buffer) - 11);
buffer[0x0b] = dir_entry->Attributes;
#if FAT16_DATETIME_SUPPORT
buffer[0x16] = (dir_entry->modification_time >> 0) & 0xff;
buffer[0x17] = (dir_entry->modification_time >> 8) & 0xff;
buffer[0x18] = (dir_entry->modification_date >> 0) & 0xff;
buffer[0x19] = (dir_entry->modification_date >> 8) & 0xff;
#endif
buffer[0x1a] = (dir_entry->Cluster >> 0) & 0xff;
buffer[0x1b] = (dir_entry->Cluster >> 8) & 0xff;
buffer[0x1c] = (dir_entry->File_Size >> 0) & 0xff;
buffer[0x1d] = (dir_entry->File_Size >> 8) & 0xff;
buffer[0x1e] = (dir_entry->File_Size >> 16) & 0xff;
buffer[0x1f] = (dir_entry->File_Size >> 24) & 0xff;
/* write to disk */
if(!device_write(offset + (u32) lfn_entry_count * 32, buffer, sizeof(buffer)))
return 0;
/* calculate checksum of 8.3 name */
u8 checksum = buffer[0];
for(u8 i = 1; i < 11; ++i)
checksum = ((checksum >> 1) | (checksum << 7)) + buffer[i];
/* write lfn entries */
for(u8 lfn_entry = lfn_entry_count; lfn_entry > 0; --lfn_entry)
{
memset(buffer, 0xff, sizeof(buffer));
/* set file name */
const char* Long_Name_curr = name + (lfn_entry - 1) * 13;
u8 i = 1;
while(i < 0x1f)
{
buffer[i++] = *Long_Name_curr;
buffer[i++] = 0;
switch(i)
{
case 0x0b:
i = 0x0e;
break;
case 0x1a:
i = 0x1c;
break;
}
if(!*Long_Name_curr++)
break;
}
/* set index of lfn entry */
buffer[0x00] = lfn_entry;
if(lfn_entry == lfn_entry_count)
buffer[0x00] |= FAT16_DIRENTRY_LFNLAST;
/* mark as lfn entry */
buffer[0x0b] = 0x0f;
/* set 8.3 checksum */
buffer[0x0d] = checksum;
/* clear reserved bytes */
buffer[0x0c] = 0;
buffer[0x1a] = 0;
buffer[0x1b] = 0;
/* write entry */
device_write(offset, buffer, sizeof(buffer));
offset += sizeof(buffer);
}
return 1;
#else
return 0;
#endif
}
/**********************************************************************
* 函数 Fat16_Create_File --- 创建文件
* note:
* 创建文件并返回文件路径信息,如果文件已经存在,则创建失败,并返回
* 已存在文件的信息存放于 dir_entry
*
* 输入参数 parent:The handle of the directory in which to create the file.
* file:The name of the file to create.
* 输出参数 dir_entry:The directory entry to fill for the new file.
* 返回值 0 --- 失败
* 1 --- 成功
**********************************************************************/
u8
Fat16_Create_File(struct Fat16_Dir_Struct* parent,
const char* file,
struct Fat16_Dir_Entry_Struct* dir_entry)
{
#if FAT16_WRITE_SUPPORT
if(!parent || !file || !file[0] || !dir_entry)
return 0;
/* check if the file already exists */
while(1)
{
if(!Fat16_Read_Dir(parent, dir_entry))
break;
if(strcmp(file, dir_entry->Long_Name) == 0)
{
Fat16_Reset_Dir(parent);
return 0;
}
}
struct Fat16_FS_Struct* fs = parent->fs;
/* prepare directory entry with values already known */
memset(dir_entry, 0, sizeof(*dir_entry));
strncpy(dir_entry->Long_Name, file, sizeof(dir_entry->Long_Name) - 1);
/* find place where to store directory entry */
if(!(dir_entry->Entry_Offset = Fat16_Find_Offset_For_Dir_Entry(fs, parent, dir_entry)))
return 0;
/* write directory entry to disk */
if(!Fat16_Write_Dir_Entry(fs, dir_entry))
return 0;
return 1;
#else
return 0;
#endif
}
/**********************************************************************
* 函数 Fat16_Delete_File --- 删除文件或者目录
* note:
* 如果删除目录前,没有删除其子目录和子文件,其占用的空间将被浪费,
* 子目录和子文件将不会被释放出来
*
* 输入参数 fs:The filesystem on which to operate.
* dir_entry:The directory entry of the file to delete.
* 返回值 0 --- 失败
* 1 --- 成功
**********************************************************************/
u8
Fat16_Delete_File(struct Fat16_FS_Struct* fs, struct Fat16_Dir_Entry_Struct* dir_entry)
{
#if FAT16_WRITE_SUPPORT
if(!fs || !dir_entry)
return 0;
/* get offset of the file's directory entry */
u32 Dir_Entry_Offset = dir_entry->Entry_Offset;
if(!Dir_Entry_Offset)
return 0;
u8 buffer[12];
while(1)
{
/* read directory entry */
if(!fs->partition->device_read(Dir_Entry_Offset, buffer, sizeof(buffer)))
return 0;
/* mark the directory entry as deleted */
buffer[0] = FAT16_DIRENTRY_DELETED;
/* write back entry */
if(!fs->partition->device_write(Dir_Entry_Offset, buffer, sizeof(buffer)))
return 0;
/* check if we deleted the whole entry */
if(buffer[11] != 0x0f)
break;
Dir_Entry_Offset += 32;
}
/* We deleted the directory entry. The next thing to do is
* marking all occupied clusters as free.
*/
return (dir_entry->Cluster == 0 || Fat16_Free_Clusters(fs, dir_entry->Cluster));
#else
return 0;
#endif
}
/**********************************************************************
* 函数 Fat16_Create_Dir --- 创建一个目录
* note:
* 创建目录并返回目录路径信息,如果目录已经存在,则创建失败,并返回
* 已存在目录的信息存放于 dir_entry
*
* 输入参数 parent:The handle of the parent directory of the new directory.
* dir:The name of the directory to create.
* dir_entry:The directory entry to fill for the new directory.
* 返回值 0 --- 失败
* 1 --- 成功
**********************************************************************/
u8
Fat16_Create_Dir(struct Fat16_Dir_Struct* parent,
const char* dir,
struct Fat16_Dir_Entry_Struct* dir_entry)
{
#if FAT16_WRITE_SUPPORT
if(!parent || !dir || !dir[0] || !dir_entry)
return 0;
/* check if the file or directory already exists */
while(1)
{
if(!Fat16_Read_Dir(parent, dir_entry))
break;
if(strcmp(dir, dir_entry->Long_Name) == 0)
{
Fat16_Reset_Dir(parent);
return 0;
}
}
struct Fat16_FS_Struct* fs = parent->fs;
/* allocate cluster which will hold directory entries */
u16 dir_cluster = Fat16_Append_Clusters(fs, 0, 1);
if(!dir_cluster)
return 0;
/* clear cluster to prevent bogus directory entries */
Fat16_Clear_Cluster(fs, dir_cluster);
memset(dir_entry, 0, sizeof(*dir_entry));
dir_entry->Attributes = FAT16_ATTRIB_DIR;
/* create "." directory self reference */
dir_entry->Entry_Offset = fs->header.Cluster_Zero_Offset +
(u32) (dir_cluster - 2) * fs->header.Cluster_Size;
dir_entry->Long_Name[0] = '.';
dir_entry->Cluster = dir_cluster;
if(!Fat16_Write_Dir_Entry(fs, dir_entry))
{
Fat16_Free_Clusters(fs, dir_cluster);
return 0;
}
/* create ".." parent directory reference */
dir_entry->Entry_Offset += 32;
dir_entry->Long_Name[1] = '.';
dir_entry->Cluster = parent->dir_entry.Cluster;
if(!Fat16_Write_Dir_Entry(fs, dir_entry))
{
Fat16_Free_Clusters(fs, dir_cluster);
return 0;
}
/* fill directory entry */
strncpy(dir_entry->Long_Name, dir, sizeof(dir_entry->Long_Name) - 1);
dir_entry->Cluster = dir_cluster;
/* find place where to store directory entry */
if(!(dir_entry->Entry_Offset = Fat16_Find_Offset_For_Dir_Entry(fs, parent, dir_entry)))
{
Fat16_Free_Clusters(fs, dir_cluster);
return 0;
}
/* write directory to disk */
if(!Fat16_Write_Dir_Entry(fs, dir_entry))
{
Fat16_Free_Clusters(
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -