From f36a7bfcde756cae3b3e933f0e688137fb684be8 Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Thu, 28 Feb 2002 20:43:50 +0000 Subject: 2002-02-28 Victor V. Vengerov * DOS filesystem including FAT12, FAT16, and FAT32 support submitted. * src/dosfs, src/dosfs/Makefile.am, src/dosfs/stamp-h2.in, src/dosfs/config.h.in, src/dosfs/dosfs.h, src/dosfs/fat.c, src/dosfs/fat.h, src/dosfs/fat_fat_operations.c, src/dosfs/fat_fat_operations.h, src/dosfs/fat_file.c, src/dosfs/fat_file.h, src/dosfs/msdos.h, src/dosfs/msdos_create.c, src/dosfs/msdos_dir.c, src/dosfs/msdos_eval.c, src/dosfs/msdos_file.c, src/dosfs/msdos_free.c, src/dosfs/msdos_fsunmount.c, src/dosfs/msdos_handlers_dir.c, src/dosfs/msdos_handlers_file.c, src/dosfs/msdos_init.c, src/dosfs/msdos_initsupp.c, src/dosfs/msdos_misc.c, src/dosfs/msdos_mknod.c, src/dosfs/msdos_node_type.c, src/dosfs/.cvsignore: New files. * configure.ac, src/Makefile.am, wrapup/Makefile.am: Modified to reflect addition. --- c/src/exec/libfs/src/dosfs/fat_fat_operations.c | 445 ++++++++++++++++++++++++ 1 file changed, 445 insertions(+) create mode 100644 c/src/exec/libfs/src/dosfs/fat_fat_operations.c (limited to 'c/src/exec/libfs/src/dosfs/fat_fat_operations.c') diff --git a/c/src/exec/libfs/src/dosfs/fat_fat_operations.c b/c/src/exec/libfs/src/dosfs/fat_fat_operations.c new file mode 100644 index 0000000000..49b2ab70d3 --- /dev/null +++ b/c/src/exec/libfs/src/dosfs/fat_fat_operations.c @@ -0,0 +1,445 @@ +/* + * fat_fat_operations.c + * + * General operations on File Allocation Table + * + * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia + * Author: Eugeny S. Mints + * + * @(#) $Id$ + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "fat.h" +#include "fat_fat_operations.h" + +/* fat_scan_fat_for_free_clusters -- + * Allocate chain of free clusters from Files Allocation Table + * + * PARAMETERS: + * mt_entry - mount table entry + * chain - the number of the first allocated cluster (first cluster + * in the chain) + * count - count of clusters to allocate (chain length) + * + * RETURNS: + * RC_OK on success, or error code if error occured (errno set + * appropriately) + * + * + */ +int +fat_scan_fat_for_free_clusters( + rtems_filesystem_mount_table_entry_t *mt_entry, + unsigned32 *chain, + unsigned32 count, + unsigned32 *cls_added, + unsigned32 *last_cl + ) +{ + int rc = RC_OK; + fat_fs_info_t *fs_info = mt_entry->fs_info; + unsigned32 cl4find = 2; + unsigned32 next_cln = 0; + unsigned32 save_cln = 0; + unsigned32 data_cls_val = fs_info->vol.data_cls + 2; + unsigned32 i = 2; + + *cls_added = 0; + + if (count == 0) + return rc; + + if ((fs_info->vol.type & FAT_FAT32) && + (fs_info->vol.next_cl != FAT_UNDEFINED_VALUE)) + cl4find = fs_info->vol.next_cl; + + /* + * fs_info->vol.data_cls is exactly the count of data clusters + * starting at cluster 2, so the maximum valid cluster number is + * (fs_info->vol.data_cls + 1) + */ + while (i < data_cls_val) + { + rc = fat_get_fat_cluster(mt_entry, cl4find, &next_cln); + if ( rc != RC_OK ) + { + if (*cls_added != 0) + fat_free_fat_clusters_chain(mt_entry, (*chain)); + return rc; + } + + if ((next_cln & fs_info->vol.mask) == FAT_GENFAT_FREE) + { + /* + * We are enforced to process allocation of the first free cluster + * by separate 'if' statement because otherwise undo function + * wouldn't work properly + */ + if (*cls_added == 0) + { + *chain = cl4find; + rc = fat_set_fat_cluster(mt_entry, cl4find, FAT_GENFAT_EOC); + if ( rc != RC_OK ) + { + /* + * this is the first cluster we tried to allocate so no + * cleanup activity needed + */ + return rc; + } + } + else + { + /* set EOC value to new allocated cluster */ + rc = fat_set_fat_cluster(mt_entry, cl4find, FAT_GENFAT_EOC); + if ( rc != RC_OK ) + { + /* cleanup activity */ + fat_free_fat_clusters_chain(mt_entry, (*chain)); + return rc; + } + + rc = fat_set_fat_cluster(mt_entry, save_cln, cl4find); + if ( rc != RC_OK ) + { + /* cleanup activity */ + fat_free_fat_clusters_chain(mt_entry, (*chain)); + /* trying to save last allocated cluster for future use */ + fat_set_fat_cluster(mt_entry, cl4find, FAT_GENFAT_FREE); + fat_buf_release(fs_info); + return rc; + } + } + + save_cln = cl4find; + (*cls_added)++; + + /* have we satisfied request ? */ + if (*cls_added == count) + { + if (fs_info->vol.type & FAT_FAT32) + { + fs_info->vol.next_cl = save_cln; + if (fs_info->vol.free_cls != 0xFFFFFFFF) + fs_info->vol.free_cls -= (*cls_added); + } + *last_cl = save_cln; + fat_buf_release(fs_info); + return rc; + } + } + i++; + cl4find++; + if (cl4find >= data_cls_val) + cl4find = 2; + } + + if (fs_info->vol.type & FAT_FAT32) + { + fs_info->vol.next_cl = save_cln; + if (fs_info->vol.free_cls != 0xFFFFFFFF) + fs_info->vol.free_cls -= (*cls_added); + } + *last_cl = save_cln; + fat_buf_release(fs_info); + return RC_OK; +} + +/* fat_free_fat_clusters_chain -- + * Free chain of clusters in Files Allocation Table. + * + * PARAMETERS: + * mt_entry - mount table entry + * chain - number of the first cluster in the chain + * + * RETURNS: + * RC_OK on success, or -1 if error occured (errno set appropriately) + */ +int +fat_free_fat_clusters_chain( + rtems_filesystem_mount_table_entry_t *mt_entry, + unsigned32 chain + ) +{ + int rc = RC_OK, rc1 = RC_OK; + fat_fs_info_t *fs_info = mt_entry->fs_info; + unsigned32 cur_cln = chain; + unsigned32 next_cln = 0; + unsigned32 freed_cls_cnt = 0; + + while ((cur_cln & fs_info->vol.mask) != fs_info->vol.eoc_val) + { + rc = fat_get_fat_cluster(mt_entry, cur_cln, &next_cln); + if ( rc != RC_OK ) + { + if ((fs_info->vol.type & FAT_FAT32) && + (fs_info->vol.free_cls != FAT_UNDEFINED_VALUE)) + fs_info->vol.free_cls += freed_cls_cnt; + fat_buf_release(fs_info); + return rc; + } + + rc = fat_set_fat_cluster(mt_entry, cur_cln, FAT_GENFAT_FREE); + if ( rc != RC_OK ) + rc1 = rc; + + freed_cls_cnt++; + cur_cln = next_cln; + } + + if (fs_info->vol.type & FAT_FAT32) + { + fs_info->vol.next_cl = chain; + if (fs_info->vol.free_cls != FAT_UNDEFINED_VALUE) + fs_info->vol.free_cls += freed_cls_cnt; + } + + fat_buf_release(fs_info); + if (rc1 != RC_OK) + return rc1; + + return RC_OK; +} + +/* fat_get_fat_cluster -- + * Fetches the contents of the cluster (link to next cluster in the chain) + * from Files Allocation Table. + * + * PARAMETERS: + * mt_entry - mount table entry + * cln - number of cluster to fetch the contents from + * ret_val - contents of the cluster 'cln' (link to next cluster in + * the chain) + * + * RETURNS: + * RC_OK on success, or -1 if error occured + * and errno set appropriately + */ +int +fat_get_fat_cluster( + rtems_filesystem_mount_table_entry_t *mt_entry, + unsigned32 cln, + unsigned32 *ret_val + ) +{ + int rc = RC_OK; + register fat_fs_info_t *fs_info = mt_entry->fs_info; + bdbuf_buffer *block0 = NULL; + unsigned32 sec = 0; + unsigned32 ofs = 0; + + /* sanity check */ + if ( (cln < 2) || (cln > (fs_info->vol.data_cls + 1)) ) + set_errno_and_return_minus_one(EIO); + + sec = (FAT_FAT_OFFSET(fs_info->vol.type, cln) >> fs_info->vol.sec_log2) + + fs_info->vol.afat_loc; + ofs = FAT_FAT_OFFSET(fs_info->vol.type, cln) & (fs_info->vol.bps - 1); + + rc = fat_buf_access(fs_info, sec, FAT_OP_TYPE_READ, &block0); + if (rc != RC_OK) + return rc; + + switch ( fs_info->vol.type ) + { + case FAT_FAT12: + /* + * we are enforced in complex computations for FAT12 to escape CPU + * align problems for some architectures + */ + *ret_val = (*((unsigned8 *)(block0->buffer + ofs))); + if ( ofs == (fs_info->vol.bps - 1) ) + { + rc = fat_buf_access(fs_info, sec + 1, FAT_OP_TYPE_READ, + &block0); + if (rc != RC_OK) + return rc; + + *ret_val |= (*((unsigned8 *)(block0->buffer)))<<8; + } + else + { + *ret_val |= (*((unsigned8 *)(block0->buffer + ofs + 1)))<<8; + } + + if ( FAT_CLUSTER_IS_ODD(cln) ) + *ret_val = (*ret_val) >> FAT12_SHIFT; + else + *ret_val = (*ret_val) & FAT_FAT12_MASK; + + break; + + case FAT_FAT16: + *ret_val = *((unsigned16 *)(block0->buffer + ofs)); + *ret_val = CF_LE_W(*ret_val); + break; + + case FAT_FAT32: + *ret_val = *((unsigned32 *)(block0->buffer + ofs)); + *ret_val = CF_LE_L(*ret_val); + break; + + default: + set_errno_and_return_minus_one(EIO); + break; + } + + return RC_OK; +} + +/* fat_set_fat_cluster -- + * Set the contents of the cluster (link to next cluster in the chain) + * from Files Allocation Table. + * + * PARAMETERS: + * mt_entry - mount table entry + * cln - number of cluster to set contents to + * in_val - value to set + * + * RETURNS: + * RC_OK on success, or -1 if error occured + * and errno set appropriately + */ +int +fat_set_fat_cluster( + rtems_filesystem_mount_table_entry_t *mt_entry, + unsigned32 cln, + unsigned32 in_val + ) +{ + int rc = RC_OK; + fat_fs_info_t *fs_info = mt_entry->fs_info; + unsigned32 sec = 0; + unsigned32 ofs = 0; + unsigned16 fat16_clv = 0; + unsigned32 fat32_clv = 0; + bdbuf_buffer *block0 = NULL; + + /* sanity check */ + if ( (cln < 2) || (cln > (fs_info->vol.data_cls + 1)) ) + set_errno_and_return_minus_one(EIO); + + sec = (FAT_FAT_OFFSET(fs_info->vol.type, cln) >> fs_info->vol.sec_log2) + + fs_info->vol.afat_loc; + ofs = FAT_FAT_OFFSET(fs_info->vol.type, cln) & (fs_info->vol.bps - 1); + + rc = fat_buf_access(fs_info, sec, FAT_OP_TYPE_READ, &block0); + if (rc != RC_OK) + return rc; + + switch ( fs_info->vol.type ) + { + case FAT_FAT12: + if ( FAT_CLUSTER_IS_ODD(cln) ) + { + fat16_clv = CT_LE_W((((unsigned16)in_val) << FAT_FAT12_SHIFT)); + + *((unsigned8 *)(block0->buffer + ofs)) = + (*((unsigned8 *)(block0->buffer + ofs))) & 0x0F; + + *((unsigned8 *)(block0->buffer + ofs)) = + (*((unsigned8 *)(block0->buffer + ofs))) | + (unsigned8)(fat16_clv & 0x00FF); + + fat_buf_mark_modified(fs_info); + + if ( ofs == (fs_info->vol.bps - 1) ) + { + rc = fat_buf_access(fs_info, sec + 1, FAT_OP_TYPE_READ, + &block0); + if (rc != RC_OK) + return rc; + + *((unsigned8 *)(block0->buffer)) &= 0x00; + + *((unsigned8 *)(block0->buffer)) = + (*((unsigned8 *)(block0->buffer))) | + (unsigned8)((fat16_clv & 0xFF00)>>8); + + fat_buf_mark_modified(fs_info); + } + else + { + *((unsigned8 *)(block0->buffer + ofs + 1)) &= 0x00; + + *((unsigned8 *)(block0->buffer + ofs + 1)) = + (*((unsigned8 *)(block0->buffer + ofs + 1))) | + (unsigned8)((fat16_clv & 0xFF00)>>8); + } + } + else + { + fat16_clv = CT_LE_W((((unsigned16)in_val) & FAT_FAT12_MASK)); + + *((unsigned8 *)(block0->buffer + ofs)) &= 0x00; + + *((unsigned8 *)(block0->buffer + ofs)) = + (*((unsigned8 *)(block0->buffer + ofs))) | + (unsigned8)(fat16_clv & 0x00FF); + + fat_buf_mark_modified(fs_info); + + if ( ofs == (fs_info->vol.bps - 1) ) + { + rc = fat_buf_access(fs_info, sec + 1, FAT_OP_TYPE_READ, + &block0); + if (rc != RC_OK) + return rc; + + *((unsigned8 *)(block0->buffer)) = + (*((unsigned8 *)(block0->buffer))) & 0xF0; + + *((unsigned8 *)(block0->buffer)) = + (*((unsigned8 *)(block0->buffer))) | + (unsigned8)((fat16_clv & 0xFF00)>>8); + + fat_buf_mark_modified(fs_info); + } + else + { + *((unsigned8 *)(block0->buffer + ofs + 1)) = + (*((unsigned8 *)(block0->buffer + ofs + 1))) & 0xF0; + + *((unsigned8 *)(block0->buffer + ofs+1)) = + (*((unsigned8 *)(block0->buffer + ofs+1))) | + (unsigned8)((fat16_clv & 0xFF00)>>8); + } + } + break; + + case FAT_FAT16: + *((unsigned16 *)(block0->buffer + ofs)) = + (unsigned16)(CT_LE_W(in_val)); + fat_buf_mark_modified(fs_info); + break; + + case FAT_FAT32: + fat32_clv = CT_LE_L((in_val & FAT_FAT32_MASK)); + + *((unsigned32 *)(block0->buffer + ofs)) = + (*((unsigned32 *)(block0->buffer + ofs))) & (CT_LE_L(0xF0000000)); + + *((unsigned32 *)(block0->buffer + ofs)) = + fat32_clv | (*((unsigned32 *)(block0->buffer + ofs))); + + fat_buf_mark_modified(fs_info); + break; + + default: + set_errno_and_return_minus_one(EIO); + break; + + } + + return RC_OK; +} -- cgit v1.2.3