From c151cfc347d29c7934db74aa4c7aeceaab0de83f Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Tue, 25 Mar 2003 17:01:45 +0000 Subject: 2003-03-25 Thomas Doerfler PR 367/filesystem * src/dosfs/Makefile.am, src/dosfs/fat.c, src/dosfs/fat.h, src/dosfs/fat_fat_operations.c, src/dosfs/fat_file.c, src/dosfs/msdos.h, src/dosfs/msdos_dir.c: Some bugs were still present in the DOSFS implementation: - FAT12 did not work properly on Big-Endian machines - Some synchronization and error handling problems were present - Some legal codings for EOC were not recognized --- cpukit/libfs/src/dosfs/Makefile.am | 4 ++ cpukit/libfs/src/dosfs/fat.c | 12 ++++- cpukit/libfs/src/dosfs/fat.h | 12 +++-- cpukit/libfs/src/dosfs/fat_fat_operations.c | 26 +++++++-- cpukit/libfs/src/dosfs/fat_file.c | 4 +- cpukit/libfs/src/dosfs/msdos.h | 5 +- cpukit/libfs/src/dosfs/msdos_dir.c | 82 ++++++++++++++++++++++++++--- 7 files changed, 126 insertions(+), 19 deletions(-) (limited to 'cpukit/libfs/src') diff --git a/cpukit/libfs/src/dosfs/Makefile.am b/cpukit/libfs/src/dosfs/Makefile.am index 95bee65c42..4ba0b6d6b0 100644 --- a/cpukit/libfs/src/dosfs/Makefile.am +++ b/cpukit/libfs/src/dosfs/Makefile.am @@ -27,6 +27,10 @@ include_HEADERS = dosfs.h H_FILES = $(PROJECT_INCLUDE) \ $(include_HEADERS:%=$(PROJECT_INCLUDE)/%) +PREINSTALL_FILES = $(PROJECT_INCLUDE) \ + $(include_HEADERS:%=$(PROJECT_INCLUDE)/%) + + $(PROJECT_INCLUDE): @$(mkinstalldirs) $@ diff --git a/cpukit/libfs/src/dosfs/fat.c b/cpukit/libfs/src/dosfs/fat.c index 1b37a22ff5..3c9b10d9f5 100644 --- a/cpukit/libfs/src/dosfs/fat.c +++ b/cpukit/libfs/src/dosfs/fat.c @@ -260,6 +260,16 @@ fat_init_volume_info(rtems_filesystem_mount_table_entry_t *mt_entry) i >>= 1, vol->sec_log2++); vol->spc = FAT_BR_SECTORS_PER_CLUSTER(boot_rec); + /* + * "sectors per cluster" of zero is invalid + * (and would hang the following loop) + */ + if (vol->spc == 0) + { + rtems_disk_release(vol->dd); + set_errno_and_return_minus_one(EINVAL); + } + for (vol->spc_log2 = 0, i = vol->spc; (i & 1) == 0; i >>= 1, vol->spc_log2++); @@ -526,7 +536,7 @@ fat_init_clusters_chain( if ( buf == NULL ) set_errno_and_return_minus_one( EIO ); - while ((cur_cln & fs_info->vol.mask) != fs_info->vol.eoc_val) + while ((cur_cln & fs_info->vol.mask) < fs_info->vol.eoc_val) { ret = fat_cluster_write(mt_entry, cur_cln, buf); if ( ret == -1 ) diff --git a/cpukit/libfs/src/dosfs/fat.h b/cpukit/libfs/src/dosfs/fat.h index ef7fa7b8d4..b8361d55cf 100644 --- a/cpukit/libfs/src/dosfs/fat.h +++ b/cpukit/libfs/src/dosfs/fat.h @@ -83,9 +83,9 @@ extern "C" { #define FAT_UNDEFINED_VALUE (unsigned32)0xFFFFFFFF -#define FAT_FAT12_EOC 0x0FFF -#define FAT_FAT16_EOC 0xFFFF -#define FAT_FAT32_EOC (unsigned32)0x0FFFFFFF +#define FAT_FAT12_EOC 0x0FF8 +#define FAT_FAT16_EOC 0xFFF8 +#define FAT_FAT32_EOC (unsigned32)0x0FFFFFF8 #define FAT_FAT12_FREE 0x0000 #define FAT_FAT16_FREE 0x0000 @@ -306,6 +306,7 @@ fat_buf_access(fat_fs_info_t *fs_info, unsigned32 blk, int op_type, if (sc != RTEMS_SUCCESSFUL) set_errno_and_return_minus_one(EIO); fs_info->c.blk_num = blk; + fs_info->c.modified = 0; fs_info->c.state = FAT_CACHE_ACTUAL; } @@ -321,9 +322,10 @@ fat_buf_access(fat_fs_info_t *fs_info, unsigned32 blk, int op_type, fs_info->vol.bps); sc = rtems_bdbuf_release_modified(fs_info->c.buf); + fs_info->c.state = FAT_CACHE_EMPTY; + fs_info->c.modified = 0; if (sc != RTEMS_SUCCESSFUL) set_errno_and_return_minus_one(EIO); - fs_info->c.modified = 0; if (sec_of_fat && !fs_info->vol.mirror) { @@ -347,6 +349,7 @@ fat_buf_access(fat_fs_info_t *fs_info, unsigned32 blk, int op_type, else { sc = rtems_bdbuf_release(fs_info->c.buf); + fs_info->c.state = FAT_CACHE_EMPTY; if (sc != RTEMS_SUCCESSFUL) set_errno_and_return_minus_one(EIO); @@ -358,6 +361,7 @@ fat_buf_access(fat_fs_info_t *fs_info, unsigned32 blk, int op_type, if (sc != RTEMS_SUCCESSFUL) set_errno_and_return_minus_one(EIO); fs_info->c.blk_num = blk; + fs_info->c.state = FAT_CACHE_ACTUAL; } *buf = fs_info->c.buf; return RC_OK; diff --git a/cpukit/libfs/src/dosfs/fat_fat_operations.c b/cpukit/libfs/src/dosfs/fat_fat_operations.c index 49b2ab70d3..df79729f7c 100644 --- a/cpukit/libfs/src/dosfs/fat_fat_operations.c +++ b/cpukit/libfs/src/dosfs/fat_fat_operations.c @@ -78,7 +78,8 @@ fat_scan_fat_for_free_clusters( return rc; } - if ((next_cln & fs_info->vol.mask) == FAT_GENFAT_FREE) + /*if ((next_cln & fs_info->vol.mask) == FAT_GENFAT_FREE)*/ + if (next_cln == FAT_GENFAT_FREE) { /* * We are enforced to process allocation of the first free cluster @@ -177,7 +178,7 @@ fat_free_fat_clusters_chain( unsigned32 next_cln = 0; unsigned32 freed_cls_cnt = 0; - while ((cur_cln & fs_info->vol.mask) != fs_info->vol.eoc_val) + 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 ) @@ -276,7 +277,6 @@ fat_get_fat_cluster( *ret_val = (*ret_val) >> FAT12_SHIFT; else *ret_val = (*ret_val) & FAT_FAT12_MASK; - break; case FAT_FAT16: @@ -342,8 +342,16 @@ fat_set_fat_cluster( case FAT_FAT12: if ( FAT_CLUSTER_IS_ODD(cln) ) { +#if 0 + /* + * do not perform endian conversion explicitely, + * because following code will enforce little + * endian format implicitly! + */ fat16_clv = CT_LE_W((((unsigned16)in_val) << FAT_FAT12_SHIFT)); - +#else + fat16_clv = ((unsigned16)in_val) << FAT_FAT12_SHIFT; +#endif *((unsigned8 *)(block0->buffer + ofs)) = (*((unsigned8 *)(block0->buffer + ofs))) & 0x0F; @@ -379,8 +387,16 @@ fat_set_fat_cluster( } else { +#if 0 + /* + * do not perform endian conversion explicitely, + * because following code will enforce little + * endian format implicitly! + */ fat16_clv = CT_LE_W((((unsigned16)in_val) & FAT_FAT12_MASK)); - +#else + fat16_clv = ((unsigned16)in_val) & FAT_FAT12_MASK; +#endif *((unsigned8 *)(block0->buffer + ofs)) &= 0x00; *((unsigned8 *)(block0->buffer + ofs)) = diff --git a/cpukit/libfs/src/dosfs/fat_file.c b/cpukit/libfs/src/dosfs/fat_file.c index 8046f47720..0d5dcc87ba 100644 --- a/cpukit/libfs/src/dosfs/fat_file.c +++ b/cpukit/libfs/src/dosfs/fat_file.c @@ -770,7 +770,7 @@ fat_file_datasync( return rc; /* for each cluster of the file ... */ - while ((cur_cln & fs_info->vol.mask) != fs_info->vol.eoc_val) + while ((cur_cln & fs_info->vol.mask) < fs_info->vol.eoc_val) { sec = fat_cluster_num_to_sector_num(mt_entry, cur_cln); /* for each sector in cluster ... */ @@ -830,7 +830,7 @@ fat_file_size( fat_fd->fat_file_size = 0; - while ((cur_cln & fs_info->vol.mask) != fs_info->vol.eoc_val) + while ((cur_cln & fs_info->vol.mask) < fs_info->vol.eoc_val) { save_cln = cur_cln; rc = fat_get_fat_cluster(mt_entry, cur_cln, &cur_cln); diff --git a/cpukit/libfs/src/dosfs/msdos.h b/cpukit/libfs/src/dosfs/msdos.h index 4262d515ef..5a14168012 100644 --- a/cpukit/libfs/src/dosfs/msdos.h +++ b/cpukit/libfs/src/dosfs/msdos.h @@ -138,7 +138,10 @@ typedef rtems_filesystem_node_types_t msdos_node_type_t; #define msdos_is_valid_name_char(_ch) (1) #define msdos_is_separator(_ch) rtems_filesystem_is_separator(_ch) -#define MSDOS_SHORT_NAME_LEN 11 /* 11 characters */ +#define MSDOS_SHORT_BASE_LEN 8 /* 8 characters */ +#define MSDOS_SHORT_EXT_LEN 3 /* 3 characters */ +#define MSDOS_SHORT_NAME_LEN (MSDOS_SHORT_BASE_LEN+\ + MSDOS_SHORT_EXT_LEN) /* 11 chars */ #define MSDOS_NAME_MAX MSDOS_SHORT_NAME_LEN #define MSDOS_NAME_MAX_WITH_DOT (MSDOS_NAME_MAX + 1) diff --git a/cpukit/libfs/src/dosfs/msdos_dir.c b/cpukit/libfs/src/dosfs/msdos_dir.c index 93449cd2fb..5584ec36af 100644 --- a/cpukit/libfs/src/dosfs/msdos_dir.c +++ b/cpukit/libfs/src/dosfs/msdos_dir.c @@ -104,6 +104,75 @@ msdos_dir_close(rtems_libio_t *iop) return RC_OK; } +/* msdos_format_dirent_with_dot -- + * This routine convert a (short) MSDOS filename as present on disk + * (fixed 8+3 characters, filled with blanks, without separator dot) + * to a "normal" format, with between 0 and 8 name chars, + * a separating dot and up to 3 extension characters + * Rules to work: + * - copy any (0-8) "name" part characters that are non-blank + * - if an extension exists, append a dot + * - copy any (0-3) non-blank extension characters + * - append a '\0' (dont count it for the rturn code + * + * PARAMETERS: + * dst: pointer to destination char array (must be big enough) + * src: pointer to source characters + * + * + * RETURNS: + * the number of bytes (without trailing '\0'(written to destination + */ +static ssize_t +msdos_format_dirent_with_dot(char *dst,const char *src) +{ + ssize_t len; + int i; + const char *src_tmp; + + /* + * find last non-blank character of base name + */ + for ((i = MSDOS_SHORT_BASE_LEN , + src_tmp = src + MSDOS_SHORT_BASE_LEN-1); + ((i > 0) && + (*src_tmp == ' ')); + i--,src_tmp--) + {}; + /* + * copy base name to destination + */ + src_tmp = src; + len = i; + while (i-- > 0) { + *dst++ = *src_tmp++; + } + /* + * find last non-blank character of extension + */ + for ((i = MSDOS_SHORT_EXT_LEN , + src_tmp = src + MSDOS_SHORT_BASE_LEN+MSDOS_SHORT_EXT_LEN-1); + ((i > 0) && + (*src_tmp == ' ')); + i--,src_tmp--) + {}; + /* + * extension is not empty + */ + if (i > 0) { + *dst++ = '.'; /* append dot */ + len += i + 1; /* extension + dot */ + src_tmp = src + MSDOS_SHORT_BASE_LEN; + while (i-- > 0) { + *dst++ = *src_tmp++; + len++; + } + } + *dst = '\0'; /* terminate string */ + + return len; +} + /* msdos_dir_read -- * This routine will read the next directory entry based on the directory * offset. The offset should be equal to -n- time the size of an @@ -236,12 +305,13 @@ msdos_dir_read(rtems_libio_t *iop, void *buffer, unsigned32 count) tmp_dirent.d_off = start + cmpltd; tmp_dirent.d_reclen = sizeof(struct dirent); tmp_dirent.d_ino = tmp_fat_fd->ino; - tmp_dirent.d_namlen = MSDOS_SHORT_NAME_LEN; - memcpy(tmp_dirent.d_name, MSDOS_DIR_NAME((fs_info->cl_buf + i)), - MSDOS_SHORT_NAME_LEN); - - /* d_name is null-terminated */ - tmp_dirent.d_name[MSDOS_SHORT_NAME_LEN] = 0; + /* + * convert dir entry from fixed 8+3 format (without dot) + * to 0..8 + 1dot + 0..3 format + */ + tmp_dirent.d_namlen = + msdos_format_dirent_with_dot(tmp_dirent.d_name, + fs_info->cl_buf + i); /* src text */ memcpy(buffer + cmpltd, &tmp_dirent, sizeof(struct dirent)); iop->offset = iop->offset + sizeof(struct dirent); -- cgit v1.2.3