diff options
author | Chris Johns <chrisj@rtems.org> | 2009-04-29 08:31:27 +0000 |
---|---|---|
committer | Chris Johns <chrisj@rtems.org> | 2009-04-29 08:31:27 +0000 |
commit | 07d6fd513f1c4d3c6905c880948671de1181fac2 (patch) | |
tree | 4dabf3fdd0b056bba7b0e9beb40f01277e5c2776 /cpukit/libfs | |
parent | 2009-04-28 Chris Johns <chrisj@rtems.org> (diff) | |
download | rtems-07d6fd513f1c4d3c6905c880948671de1181fac2.tar.bz2 |
2009-04-29 Chris Johns <chrisj@rtems.org>
* libcsupport/include/rtems/libio.h: Add rtems_off64_t for
internal use. Update the internal off_t to the 64bit offset.
* libnetworking/lib/ftpfs.c, libnetworking/lib/tftpDriver.c,
libfs/src/nfsclient/src/nfs.c, libfs/src/imfs/imfs_fifo.c,
libfs/src/imfs/memfile.c, libfs/src/imfs/imfs_directory.c,
libfs/src/imfs/imfs.h, libfs/src/imfs/deviceio.c: Change off_t to
rtems_off64_t.
* libmisc/shell/main_msdosfmt.c: Add an info level so the format
code can tell the user what is happening. Add more options to
control the format configuration.
* libfs/src/dosfs/msdos_format.c: Add a print function to display
the format progress and print statements. Select a better default
cluster size depending on the size of the disk. This lowers the
size of the FAT on large disks. Read and maintain the MRB
partition information.
* libfs/src/dosfs/dosfs.h, libfs/src/dosfs/fat.h,
libfs/src/dosfs/fat_file.c, libfs/src/dosfs/fat_file.h,
libfs/src/dosfs/msdos.h, libfs/src/dosfs/msdos_conv.c,
libfs/src/dosfs/msdos_create.c, libfs/src/dosfs/msdos_file.c,
libfs/src/dosfs/msdos_handlers_dir.c,
libfs/src/dosfs/msdos_handlers_file.c,
libfs/src/dosfs/msdos_init.c, libfs/src/dosfs/msdos_initsupp.c,
libfs/src/dosfs/msdos_misc.c, libfs/src/dosfs/msdos_mknod.c: Add
long file name support. Change off_t to rtems_off64_t.
Diffstat (limited to 'cpukit/libfs')
23 files changed, 1715 insertions, 584 deletions
diff --git a/cpukit/libfs/src/dosfs/dosfs.h b/cpukit/libfs/src/dosfs/dosfs.h index 3292b02dc4..cde67e38e3 100644 --- a/cpukit/libfs/src/dosfs/dosfs.h +++ b/cpukit/libfs/src/dosfs/dosfs.h @@ -32,6 +32,11 @@ extern rtems_filesystem_operations_table msdos_ops; #define MSDOS_FMT_FAT16 2 #define MSDOS_FMT_FAT32 3 +#define MSDOS_FMT_INFO_LEVEL_NONE (0) +#define MSDOS_FMT_INFO_LEVEL_INFO (1) +#define MSDOS_FMT_INFO_LEVEL_DETAIL (2) +#define MSDOS_FMT_INFO_LEVEL_DEBUG (3) + /* * data to be filled out for formatter: parameters for format call * any parameter set to 0 or NULL will be automatically detected/computed @@ -51,6 +56,7 @@ typedef struct { /* value. This can optimize clusters */ /* to be located at start of track */ /* or start of flash block */ + int info_level; /* The amount of info to output */ } msdos_format_request_param_t; /*=========================================================================*\ diff --git a/cpukit/libfs/src/dosfs/fat.h b/cpukit/libfs/src/dosfs/fat.h index 83505922cc..74d0512fe5 100644 --- a/cpukit/libfs/src/dosfs/fat.h +++ b/cpukit/libfs/src/dosfs/fat.h @@ -250,7 +250,7 @@ extern "C" { #define FAT_GET_FSINFO_TRAIL_SIGNATURE(x) FAT_GET_VAL32(x,508) #define FAT_SET_FSINFO_TRAIL_SIGNATURE(x,val) FAT_SET_VAL32(x,508,val) -#define FAT_FSINFO_TRAIL_SIGNATURE_VALUE (0x000055AA) +#define FAT_FSINFO_TRAIL_SIGNATURE_VALUE (0xAA550000) /* * I read FSInfo sector from offset 484 to access the information, so offsets * of these fields a relative @@ -351,15 +351,31 @@ typedef struct fat_fs_info_s } fat_fs_info_t; /* - * if the name we looking for is file we store not only first data cluster - * number, but and cluster number and offset for directory entry for this - * name + * FAT position is a the cluster and the offset into the + * cluster. */ -typedef struct fat_auxiliary_s +typedef struct fat_pos_s { uint32_t cln; uint32_t ofs; -} fat_auxiliary_t; +} fat_pos_t; + +/* + * If the name we looking for is file we store not only first data cluster + * number, but and cluster number and offset for directory entry for this + * name. We also add the LFN start offset so we can delete it the whole + * file name. We can then use this to delete the file. + */ +typedef struct fat_dir_pos_s +{ + fat_pos_t sname; + fat_pos_t lname; +} fat_dir_pos_t; + +/* + * Set the long name entries to this value for a short file name. + */ +#define FAT_FILE_SHORT_NAME (0xffffffff) #define FAT_FAT_OFFSET(fat_type, cln) \ ((fat_type) & FAT_FAT12 ? ((cln) + ((cln) >> 1)) : \ @@ -380,6 +396,17 @@ typedef struct fat_auxiliary_s #define FAT_OP_TYPE_READ 0x1 #define FAT_OP_TYPE_GET 0x2 +static inline void +fat_dir_pos_init( + fat_dir_pos_t *dir_pos + ) +{ + dir_pos->sname.cln = 0; + dir_pos->sname.ofs = 0; + dir_pos->lname.cln = FAT_FILE_SHORT_NAME; + dir_pos->lname.ofs = FAT_FILE_SHORT_NAME; +} + static inline uint32_t fat_cluster_num_to_sector_num( rtems_filesystem_mount_table_entry_t *mt_entry, diff --git a/cpukit/libfs/src/dosfs/fat_file.c b/cpukit/libfs/src/dosfs/fat_file.c index 42204bacd7..b1a642f54b 100644 --- a/cpukit/libfs/src/dosfs/fat_file.c +++ b/cpukit/libfs/src/dosfs/fat_file.c @@ -33,20 +33,20 @@ #include "fat_file.h" static inline void -_hash_insert(Chain_Control *hash, uint32_t key1, uint32_t key2, +_hash_insert(rtems_chain_control *hash, uint32_t key1, uint32_t key2, fat_file_fd_t *el); static inline void -_hash_delete(Chain_Control *hash, uint32_t key1, uint32_t key2, +_hash_delete(rtems_chain_control *hash, uint32_t key1, uint32_t key2, fat_file_fd_t *el); static inline int _hash_search( rtems_filesystem_mount_table_entry_t *mt_entry, - Chain_Control *hash, + rtems_chain_control *hash, uint32_t key1, uint32_t key2, - fat_file_fd_t **ret + fat_file_fd_t **ret ); static off_t @@ -75,8 +75,7 @@ fat_file_lseek( * * PARAMETERS: * mt_entry - mount table entry - * cln - cluster num of the node - * ofs - offset of the node + * pos - cluster and offset of the node * fat_fd - placeholder for returned fat-file descriptor * * RETURNS: @@ -86,8 +85,7 @@ fat_file_lseek( int fat_file_open( rtems_filesystem_mount_table_entry_t *mt_entry, - uint32_t cln, - uint32_t ofs, + fat_dir_pos_t *dir_pos, fat_file_fd_t **fat_fd ) { @@ -97,7 +95,7 @@ fat_file_open( uint32_t key = 0; /* construct key */ - key = fat_construct_key(mt_entry, cln, ofs); + key = fat_construct_key(mt_entry, &dir_pos->sname); /* access "valid" hash table */ rc = _hash_search(mt_entry, fs_info->vhash, key, 0, &lfat_fd); @@ -116,10 +114,14 @@ fat_file_open( if ( lfat_fd == NULL ) rtems_set_errno_and_return_minus_one( ENOMEM ); + memset(lfat_fd, 0, sizeof(fat_file_fd_t)); + lfat_fd->links_num = 1; lfat_fd->flags &= ~FAT_FILE_REMOVED; lfat_fd->map.last_cln = FAT_UNDEFINED_VALUE; + lfat_fd->dir_pos = *dir_pos; + if ( rc != RC_OK ) lfat_fd->ino = key; else @@ -138,7 +140,6 @@ fat_file_open( } _hash_insert(fs_info->vhash, key, lfat_fd->ino, lfat_fd); - /* * other fields of fat-file descriptor will be initialized on upper * level @@ -203,7 +204,7 @@ fat_file_close( return rc; } - key = fat_construct_key(mt_entry, fat_fd->info_cln, fat_fd->info_ofs); + key = fat_construct_key(mt_entry, &fat_fd->dir_pos.sname); if (fat_fd->flags & FAT_FILE_REMOVED) { @@ -582,6 +583,8 @@ fat_file_extend( } } + fat_fd->fat_file_size = new_length; + return RC_OK; } @@ -736,7 +739,7 @@ fat_file_mark_removed( fat_fs_info_t *fs_info = mt_entry->fs_info; uint32_t key = 0; - key = fat_construct_key(mt_entry, fat_fd->info_cln, fat_fd->info_ofs); + key = fat_construct_key(mt_entry, &fat_fd->dir_pos.sname); _hash_delete(fs_info->vhash, key, fat_fd->ino, fat_fd); @@ -869,10 +872,10 @@ fat_file_size( * None */ static inline void -_hash_insert(Chain_Control *hash, uint32_t key1, uint32_t key2, +_hash_insert(rtems_chain_control *hash, uint32_t key1, uint32_t key2, fat_file_fd_t *el) { - _Chain_Append((hash) + ((key1) % FAT_HASH_MODULE), &(el)->link); + rtems_chain_append((hash) + ((key1) % FAT_HASH_MODULE), &(el)->link); } @@ -889,10 +892,10 @@ _hash_insert(Chain_Control *hash, uint32_t key1, uint32_t key2, * None */ static inline void -_hash_delete(Chain_Control *hash, uint32_t key1, uint32_t key2, +_hash_delete(rtems_chain_control *hash, uint32_t key1, uint32_t key2, fat_file_fd_t *el) { - _Chain_Extract(&(el)->link); + rtems_chain_extract(&(el)->link); } /* _hash_search -- @@ -912,20 +915,19 @@ _hash_delete(Chain_Control *hash, uint32_t key1, uint32_t key2, static inline int _hash_search( rtems_filesystem_mount_table_entry_t *mt_entry, - Chain_Control *hash, + rtems_chain_control *hash, uint32_t key1, uint32_t key2, fat_file_fd_t **ret ) { - uint32_t mod = (key1) % FAT_HASH_MODULE; - Chain_Node *the_node = ((Chain_Control *)((hash) + mod))->first; + uint32_t mod = (key1) % FAT_HASH_MODULE; + rtems_chain_node *the_node = ((rtems_chain_control *)((hash) + mod))->first; - for ( ; !_Chain_Is_tail((hash) + mod, the_node) ; ) + for ( ; !rtems_chain_is_tail((hash) + mod, the_node) ; ) { fat_file_fd_t *ffd = (fat_file_fd_t *)the_node; - uint32_t ck = - fat_construct_key(mt_entry, ffd->info_cln, ffd->info_ofs); + uint32_t ck = fat_construct_key(mt_entry, &ffd->dir_pos.sname); if ( (key1) == ck) { diff --git a/cpukit/libfs/src/dosfs/fat_file.h b/cpukit/libfs/src/dosfs/fat_file.h index 48b89c604e..01ab73ef98 100644 --- a/cpukit/libfs/src/dosfs/fat_file.h +++ b/cpukit/libfs/src/dosfs/fat_file.h @@ -20,6 +20,8 @@ #include <time.h> +#include "fat.h" + #ifdef __cplusplus extern "C" { #endif @@ -57,30 +59,27 @@ typedef struct fat_file_map_s */ typedef struct fat_file_fd_s { - Chain_Node link; /* - * fat-file descriptors organized into hash; - * collision lists are handled via link - * field - */ - uint32_t links_num; /* - * the number of fat_file_open call on - * this fat-file - */ - uint32_t ino; /* inode, file serial number :)))) */ - fat_file_type_t fat_file_type; - uint32_t size_limit; - uint32_t fat_file_size; /* length */ - uint32_t info_cln; - uint32_t cln; - uint16_t info_ofs; - unsigned char first_char; - uint8_t flags; - fat_file_map_t map; - time_t mtime; + rtems_chain_node link; /* + * fat-file descriptors organized into hash; + * collision lists are handled via link + * field + */ + uint32_t links_num; /* + * the number of fat_file_open call on + * this fat-file + */ + uint32_t ino; /* inode, file serial number :)))) */ + fat_file_type_t fat_file_type; + uint32_t size_limit; + uint32_t fat_file_size; /* length */ + uint32_t cln; + fat_dir_pos_t dir_pos; + uint8_t flags; + fat_file_map_t map; + time_t mtime; } fat_file_fd_t; - #define FAT_FILE_REMOVED 0x01 #define FAT_FILE_IS_REMOVED(p)\ @@ -101,8 +100,8 @@ typedef struct fat_file_fd_s #define FAT_ROOTDIR_CLUSTER_NUM 0x01 #define FAT_FD_OF_ROOT_DIR(fat_fd) \ - ((fat_fd->info_cln == FAT_ROOTDIR_CLUSTER_NUM ) && \ - (fat_fd->info_ofs == 0)) + ((fat_fd->dir_pos.sname.cln == FAT_ROOTDIR_CLUSTER_NUM) && \ + (fat_fd->dir_pos.sname.ofs == 0)) #define FAT_EOF 0x00 @@ -122,19 +121,17 @@ typedef struct fat_file_fd_s static inline uint32_t fat_construct_key( rtems_filesystem_mount_table_entry_t *mt_entry, - uint32_t cl, - uint32_t ofs) + fat_pos_t *pos) { - return ( ((fat_cluster_num_to_sector512_num(mt_entry, cl) + - (ofs >> FAT_SECTOR512_BITS)) << 4) + - ((ofs >> 5) & (FAT_DIRENTRIES_PER_SEC512 - 1)) ); + return ( ((fat_cluster_num_to_sector512_num(mt_entry, pos->cln) + + (pos->ofs >> FAT_SECTOR512_BITS)) << 4) + + ((pos->ofs >> 5) & (FAT_DIRENTRIES_PER_SEC512 - 1)) ); } /* Prototypes for "fat-file" operations */ int fat_file_open(rtems_filesystem_mount_table_entry_t *mt_entry, - uint32_t cln, - uint32_t ofs, + fat_dir_pos_t *dir_pos, fat_file_fd_t **fat_fd); int diff --git a/cpukit/libfs/src/dosfs/msdos.h b/cpukit/libfs/src/dosfs/msdos.h index a1afcba8dc..374210d9b7 100644 --- a/cpukit/libfs/src/dosfs/msdos.h +++ b/cpukit/libfs/src/dosfs/msdos.h @@ -84,8 +84,10 @@ typedef rtems_filesystem_node_types_t msdos_node_type_t; #define MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE 32 /* 32 bytes */ #define MSDOS_DIR_NAME(x) (char *)((x) + 0) +#define MSDOS_DIR_ENTRY_TYPE(x) (uint8_t *)((x) + 0) #define MSDOS_DIR_ATTR(x) (uint8_t *)((x) + 11) #define MSDOS_DIR_NT_RES(x) (uint8_t *)((x) + 12) +#define MSDOS_DIR_LFN_CHECKSUM(x) (uint8_t *)((x) + 13) #define MSDOS_DIR_CRT_TIME_TENTH(x) (uint8_t *)((x) + 13) #define MSDOS_DIR_CRT_TIME(x) (uint16_t *)((x) + 14) #define MSDOS_DIR_CRT_DATE(x) (uint16_t *)((x) + 16) @@ -121,6 +123,19 @@ typedef rtems_filesystem_node_types_t msdos_node_type_t; #define MSDOS_ATTR_VOLUME_ID 0x08 #define MSDOS_ATTR_DIRECTORY 0x10 #define MSDOS_ATTR_ARCHIVE 0x20 +#define MSDOS_ATTR_LFN (MSDOS_ATTR_READ_ONLY | \ + MSDOS_ATTR_HIDDEN | \ + MSDOS_ATTR_SYSTEM | \ + MSDOS_ATTR_VOLUME_ID) +#define MSDOS_ATTR_LFN_MASK (MSDOS_ATTR_READ_ONLY | \ + MSDOS_ATTR_HIDDEN | \ + MSDOS_ATTR_SYSTEM | \ + MSDOS_ATTR_VOLUME_ID | \ + MSDOS_ATTR_DIRECTORY | \ + MSDOS_ATTR_ARCHIVE) + +#define MSDOS_LAST_LONG_ENTRY 0x40 +#define MSDOS_LAST_LONG_ENTRY_MASK 0x3F #define MSDOS_DT_2SECONDS_MASK 0x1F /* seconds divided by 2 */ #define MSDOS_DT_2SECONDS_SHIFT 0 @@ -144,22 +159,35 @@ typedef rtems_filesystem_node_types_t msdos_node_type_t; #define MSDOS_THIS_DIR_ENTRY_EMPTY 0xE5 #define MSDOS_THIS_DIR_ENTRY_AND_REST_EMPTY 0x00 +/* + * Number of characters per directory entry for a long filename. + */ +#define MSDOS_LFN_LEN_PER_ENTRY (13) /* * Macros for names parsing and formatting */ -#define msdos_is_valid_name_char(_ch) (1) #define msdos_is_separator(_ch) rtems_filesystem_is_separator(_ch) #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_LNF_LEN (255) #define MSDOS_NAME_MAX MSDOS_SHORT_NAME_LEN #define MSDOS_NAME_MAX_WITH_DOT (MSDOS_NAME_MAX + 1) +#define MSDOS_NAME_MAX_LFN_WITH_DOT (260) -#define MSDOS_DOT_NAME ". " /* ".", padded to MSDOS_NAME chars */ -#define MSDOS_DOTDOT_NAME ".. " /* "..", padded to MSDOS_NAME chars */ + +extern const char const* MSDOS_DOT_NAME; /* ".", padded to MSDOS_NAME chars */ +extern const char const* MSDOS_DOTDOT_NAME; /* ".", padded to MSDOS_NAME chars */ + +typedef enum msdos_name_types_e +{ + MSDOS_NAME_INVALID = 0, /* Unknown name type. Has invalid characters. */ + MSDOS_NAME_SHORT, /* Name can be short. */ + MSDOS_NAME_LONG /* Name is long; cannot be short. */ +} msdos_name_type_t; typedef enum msdos_token_types_e { @@ -258,9 +286,9 @@ ssize_t msdos_file_write( size_t count /* IN */ ); -off_t msdos_file_lseek( +rtems_off64_t msdos_file_lseek( rtems_libio_t *iop, /* IN */ - off_t offset, /* IN */ + rtems_off64_t offset, /* IN */ int whence /* IN */ ); @@ -272,7 +300,7 @@ int msdos_file_stat( int msdos_file_ftruncate( rtems_libio_t *iop, /* IN */ - off_t length /* IN */ + rtems_off64_t length /* IN */ ); int msdos_file_sync(rtems_libio_t *iop); @@ -285,6 +313,12 @@ int msdos_file_ioctl( void *buffer /* IN */ ); +int +msdos_dir_chmod( + rtems_filesystem_location_info_t *pathloc, /* IN */ + mode_t mode /* IN */ +); + int msdos_file_rmnod(rtems_filesystem_location_info_t *pathloc /* IN */); int msdos_file_link( @@ -308,12 +342,18 @@ ssize_t msdos_dir_read( size_t count /* IN */ ); -off_t msdos_dir_lseek( +rtems_off64_t msdos_dir_lseek( rtems_libio_t *iop, /* IN */ - off_t offset, /* IN */ + rtems_off64_t offset, /* IN */ int whence /* IN */ ); +int +msdos_file_chmod( + rtems_filesystem_location_info_t *pathloc, /* IN */ + mode_t mode /* IN */ +); + int msdos_dir_rmnod(rtems_filesystem_location_info_t *pathloc /* IN */); int msdos_dir_sync(rtems_libio_t *iop); @@ -324,31 +364,39 @@ int msdos_dir_stat( ); int msdos_creat_node(rtems_filesystem_location_info_t *parent_loc, - msdos_node_type_t type, - char *name, - mode_t mode, - const fat_file_fd_t *link_fd); + msdos_node_type_t type, + const char *name, + int name_len, + mode_t mode, + const fat_file_fd_t *link_fd); /* Misc prototypes */ -msdos_token_types_t msdos_get_token(const char *path, - char *token, - int *token_len); +msdos_token_types_t msdos_get_token(const char *path, + const char **token, + int *token_len); int msdos_find_name( rtems_filesystem_location_info_t *parent_loc, - char *name + const char *name, + int name_len ); int msdos_get_name_node( rtems_filesystem_location_info_t *parent_loc, - char *name, - fat_auxiliary_t *paux, + bool create_node, + const char *name, + int name_len, + msdos_name_type_t name_type, + fat_dir_pos_t *dir_pos, char *name_dir_entry ); int msdos_dir_info_remove(rtems_filesystem_location_info_t *pathloc); -int msdos_filename_unix2dos(char *un, int unlen, char *dn); +msdos_name_type_t msdos_long_to_short(const char *lfn, int lfn_len, + char* sfn, int sfn_len); + +int msdos_filename_unix2dos(const char *un, int unlen, char *dn); void msdos_date_unix2dos( unsigned int tsp, unsigned short *ddp, @@ -368,9 +416,8 @@ int msdos_set_file_size( int msdos_set_first_char4file_name( rtems_filesystem_mount_table_entry_t *mt_entry, - uint32_t cl, - uint32_t ofs, - unsigned char first_char + fat_dir_pos_t *dir_pos, + unsigned char first_char ); int msdos_set_dir_wrt_time_and_date( @@ -388,8 +435,11 @@ int msdos_dir_is_empty( int msdos_find_name_in_fat_file( rtems_filesystem_mount_table_entry_t *mt_entry, fat_file_fd_t *fat_fd, - char *name, - fat_auxiliary_t *paux, + bool create_node, + const char *name, + int name_len, + msdos_name_type_t name_type, + fat_dir_pos_t *dir_pos, char *name_dir_entry ); @@ -397,14 +447,14 @@ int msdos_find_node_by_cluster_num_in_fat_file( rtems_filesystem_mount_table_entry_t *mt_entry, fat_file_fd_t *fat_fd, uint32_t cl4find, - fat_auxiliary_t *paux, + fat_dir_pos_t *dir_pos, char *dir_entry ); int msdos_get_dotdot_dir_info_cluster_num_and_offset( rtems_filesystem_mount_table_entry_t *mt_entry, uint32_t cln, - fat_auxiliary_t *paux, + fat_dir_pos_t *dir_pos, char *dir_entry ); diff --git a/cpukit/libfs/src/dosfs/msdos_conv.c b/cpukit/libfs/src/dosfs/msdos_conv.c index b30822600b..bcc27539f9 100644 --- a/cpukit/libfs/src/dosfs/msdos_conv.c +++ b/cpukit/libfs/src/dosfs/msdos_conv.c @@ -169,6 +169,39 @@ msdos_date_dos2unix(unsigned int dd, unsigned int dt) } static const uint8_t msdos_map[] = { + 0, 0, 0, 0, 0, 0, 0, 0, /* 00-07 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 08-0f */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 10-17 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 18-1f */ + 0, '!', 0, '#', '$', '%', '&', '\'', /* 20-27 */ + '(', ')', 0, '+', 0, '-', 0, 0, /* 28-2f */ + '0', '1', '2', '3', '4', '5', '6', '7', /* 30-37 */ + '8', '9', 0, 0, 0, 0, 0, 0, /* 38-3f */ + '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', /* 40-47 */ + 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', /* 48-4f */ + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', /* 50-57 */ + 'X', 'Y', 'Z', 0, 0, 0, '^', '_', /* 58-5f */ + '`', 'A', 'B', 'C', 'D', 'E', 'F', 'G', /* 60-67 */ + 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', /* 68-6f */ + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', /* 70-77 */ + 'X', 'Y', 'Z', '{', 0, '}', '~', 0, /* 78-7f */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 80-87 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 88-8f */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 90-97 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 98-9f */ + 0, 0xad, 0xbd, 0x9c, 0xcf, 0xbe, 0xdd, 0xf5, /* a0-a7 */ + 0xf9, 0xb8, 0xa6, 0xae, 0xaa, 0xf0, 0xa9, 0xee, /* a8-af */ + 0xf8, 0xf1, 0xfd, 0xfc, 0xef, 0xe6, 0xf4, 0xfa, /* b0-b7 */ + 0xf7, 0xfb, 0xa7, 0xaf, 0xac, 0xab, 0xf3, 0xa8, /* b8-bf */ + 0xb7, 0xb5, 0xb6, 0xc7, 0x8e, 0x8f, 0x92, 0x80, /* c0-c7 */ + 0xd4, 0x90, 0xd2, 0xd3, 0xde, 0xd6, 0xd7, 0xd8, /* c8-cf */ + 0xd1, 0xa5, 0xe3, 0xe0, 0xe2, 0xe5, 0x99, 0x9e, /* d0-d7 */ + 0x9d, 0xeb, 0xe9, 0xea, 0x9a, 0xed, 0xe8, 0xe1, /* d8-df */ + 0xb7, 0xb5, 0xb6, 0xc7, 0x8e, 0x8f, 0x92, 0x80, /* e0-e7 */ + 0xd4, 0x90, 0xd2, 0xd3, 0xde, 0xd6, 0xd7, 0xd8, /* e8-ef */ + 0xd1, 0xa5, 0xe3, 0xe0, 0xe2, 0xe5, 0x99, 0xf6, /* f0-f7 */ + 0x9d, 0xeb, 0xe9, 0xea, 0x9a, 0xed, 0xe8, 0x98, /* f8-ff */ +#if OLD_TABLE /* 00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 08 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 10 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -201,13 +234,14 @@ static const uint8_t msdos_map[] = { /* E8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* F0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* F8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +#endif }; /* * Convert a unix filename to a DOS filename. Return -1 if wrong name is * supplied. */ int -msdos_filename_unix2dos(char *un, int unlen, char *dn) +msdos_filename_unix2dos(const char *un, int unlen, char *dn) { int i; uint8_t c; @@ -233,6 +267,14 @@ msdos_filename_unix2dos(char *un, int unlen, char *dn) return 0; } + /* + * Remove any dots from the start of a file name. + */ + while (unlen && (*un == '.')) { + un++; + unlen--; + } + /* * Copy the unix filename into the dos filename string upto the end * of string, a '.', or 8 characters. Whichever happens first stops @@ -240,8 +282,9 @@ msdos_filename_unix2dos(char *un, int unlen, char *dn) * upper case. */ for (i = 0; i <= 7 && unlen && (c = *un) && c != '.'; i++) { - if ((dn[i] = msdos_map[c]) == 0) - return -1; + if (msdos_map[c] == 0) + break; + dn[i] = msdos_map[c]; un++; unlen--; } @@ -264,8 +307,9 @@ msdos_filename_unix2dos(char *un, int unlen, char *dn) * Filenames in this form are probably inaccessable under dos. */ for (i = 8; i <= 10 && unlen && (c = *un); i++) { - if ((dn[i] = msdos_map[c]) == 0) - return -1; + if (msdos_map[c] == 0) + break; + dn[i] = msdos_map[c]; un++; unlen--; } diff --git a/cpukit/libfs/src/dosfs/msdos_create.c b/cpukit/libfs/src/dosfs/msdos_create.c index c790dd740f..bbdf137600 100644 --- a/cpukit/libfs/src/dosfs/msdos_create.c +++ b/cpukit/libfs/src/dosfs/msdos_create.c @@ -17,6 +17,7 @@ #include <errno.h> #include <assert.h> +#include <stdio.h> #include <stdlib.h> #include <string.h> #include <rtems/libio_.h> @@ -29,7 +30,14 @@ #include "msdos.h" /* msdos_creat_node -- - * Create a new node. If a new node is file, FAT 32 Bytes Directory + * Create a new node. Determine if the name is a long name. If long we to + * scan the directory to create a short entry. + * + * + + + + * If a new node is file, FAT 32 Bytes Directory * Entry Structure is initialized, free space is found in parent * directory and structure is written to the disk. In case of directory, * all above steps present and also new cluster is allocated for a @@ -48,52 +56,55 @@ * */ int -msdos_creat_node( - rtems_filesystem_location_info_t *parent_loc, - msdos_node_type_t type, - char *name, - mode_t mode, - const fat_file_fd_t *link_fd - ) +msdos_creat_node(rtems_filesystem_location_info_t *parent_loc, + msdos_node_type_t type, + const char *name, + int name_len, + mode_t mode, + const fat_file_fd_t *link_fd) { - int rc = RC_OK; - ssize_t ret = 0; - msdos_fs_info_t *fs_info = parent_loc->mt_entry->fs_info; - fat_file_fd_t *parent_fat_fd = parent_loc->node_access; - fat_file_fd_t *fat_fd = NULL; - time_t time_ret = 0; - uint16_t time_val = 0; - uint16_t date = 0; - fat_auxiliary_t aux; - char new_node [MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE]; - char dot_dotdot[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE * 2]; - char link_node [MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE]; - uint32_t sec = 0; - uint32_t byte = 0; - - memset(new_node, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE); + int rc = RC_OK; + ssize_t ret = 0; + msdos_fs_info_t *fs_info = parent_loc->mt_entry->fs_info; + fat_file_fd_t *parent_fat_fd = parent_loc->node_access; + fat_file_fd_t *fat_fd = NULL; + time_t time_ret = 0; + uint16_t time_val = 0; + uint16_t date = 0; + fat_dir_pos_t dir_pos; + msdos_name_type_t name_type; + char short_node[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE]; + char dot_dotdot[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE * 2]; + char link_node[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE]; + uint32_t sec = 0; + uint32_t byte = 0; + + fat_dir_pos_init(&dir_pos); + + memset(short_node, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE); memset(dot_dotdot, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE * 2); - /* set up name */ - strncpy(MSDOS_DIR_NAME(new_node), name, MSDOS_NAME_MAX); + name_type = msdos_long_to_short (name, name_len, + MSDOS_DIR_NAME(short_node), + MSDOS_NAME_MAX); /* fill reserved field */ - *MSDOS_DIR_NT_RES(new_node) = MSDOS_RES_NT_VALUE; + *MSDOS_DIR_NT_RES(short_node) = MSDOS_RES_NT_VALUE; /* set up last write date and time */ time_ret = time(NULL); if ( time_ret == -1 ) return -1; - msdos_date_unix2dos(time_ret, &time_val, &date); - *MSDOS_DIR_WRITE_TIME(new_node) = CT_LE_W(time_val); - *MSDOS_DIR_WRITE_DATE(new_node) = CT_LE_W(date); + msdos_date_unix2dos(time_ret, &date, &time_val); + *MSDOS_DIR_WRITE_TIME(short_node) = CT_LE_W(time_val); + *MSDOS_DIR_WRITE_DATE(short_node) = CT_LE_W(date); /* initialize directory/file size */ - *MSDOS_DIR_FILE_SIZE(new_node) = MSDOS_INIT_DIR_SIZE; + *MSDOS_DIR_FILE_SIZE(short_node) = MSDOS_INIT_DIR_SIZE; - if (type == MSDOS_DIRECTORY){ - *MSDOS_DIR_ATTR(new_node) |= MSDOS_ATTR_DIRECTORY; + if (type == MSDOS_DIRECTORY) { + *MSDOS_DIR_ATTR(short_node) |= MSDOS_ATTR_DIRECTORY; } else if (type == MSDOS_HARD_LINK) { /* @@ -105,51 +116,52 @@ msdos_creat_node( * read the original directory entry */ sec = fat_cluster_num_to_sector_num(parent_loc->mt_entry, - link_fd->info_cln); - sec += (link_fd->info_ofs >> fs_info->fat.vol.sec_log2); - byte = (link_fd->info_ofs & (fs_info->fat.vol.bps - 1)); + link_fd->dir_pos.sname.cln); + sec += (link_fd->dir_pos.sname.ofs >> fs_info->fat.vol.sec_log2); + byte = (link_fd->dir_pos.sname.ofs & (fs_info->fat.vol.bps - 1)); ret = _fat_block_read(parent_loc->mt_entry, - sec, byte, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE, + sec, byte, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE, link_node); if (ret < 0) { - return -1; + return -1; } /* * copy various attributes */ - *MSDOS_DIR_ATTR(new_node) =*MSDOS_DIR_ATTR(link_node); - *MSDOS_DIR_CRT_TIME_TENTH(new_node)=*MSDOS_DIR_CRT_TIME_TENTH(link_node); - *MSDOS_DIR_CRT_TIME(new_node) =*MSDOS_DIR_CRT_TIME(link_node); - *MSDOS_DIR_CRT_DATE(new_node) =*MSDOS_DIR_CRT_DATE(link_node); + *MSDOS_DIR_ATTR(short_node) =*MSDOS_DIR_ATTR(link_node); + *MSDOS_DIR_CRT_TIME_TENTH(short_node)=*MSDOS_DIR_CRT_TIME_TENTH(link_node); + *MSDOS_DIR_CRT_TIME(short_node) =*MSDOS_DIR_CRT_TIME(link_node); + *MSDOS_DIR_CRT_DATE(short_node) =*MSDOS_DIR_CRT_DATE(link_node); /* * copy/set "file size", "first cluster" */ - *MSDOS_DIR_FILE_SIZE(new_node) =*MSDOS_DIR_FILE_SIZE(link_node); + *MSDOS_DIR_FILE_SIZE(short_node) =*MSDOS_DIR_FILE_SIZE(link_node); - *MSDOS_DIR_FIRST_CLUSTER_LOW(new_node) = + *MSDOS_DIR_FIRST_CLUSTER_LOW(short_node) = *MSDOS_DIR_FIRST_CLUSTER_LOW(link_node); - *MSDOS_DIR_FIRST_CLUSTER_HI(new_node) = + *MSDOS_DIR_FIRST_CLUSTER_HI(short_node) = *MSDOS_DIR_FIRST_CLUSTER_HI(link_node); /* * set "archive bit" due to changes */ - *MSDOS_DIR_ATTR(new_node) |= MSDOS_ATTR_ARCHIVE; + *MSDOS_DIR_ATTR(short_node) |= MSDOS_ATTR_ARCHIVE; /* * set "last access" date to today */ - *MSDOS_DIR_LAST_ACCESS_DATE(new_node) = CT_LE_W(date); + *MSDOS_DIR_LAST_ACCESS_DATE(short_node) = CT_LE_W(date); } else { /* regular file... */ - *MSDOS_DIR_ATTR(new_node) |= MSDOS_ATTR_ARCHIVE; + *MSDOS_DIR_ATTR(short_node) |= MSDOS_ATTR_ARCHIVE; } /* * find free space in the parent directory and write new initialized * FAT 32 Bytes Directory Entry Structure to the disk */ - rc = msdos_get_name_node(parent_loc, NULL, &aux, new_node); + rc = msdos_get_name_node(parent_loc, true, name, name_len, + name_type, &dir_pos, short_node); if ( rc != RC_OK ) return rc; @@ -160,7 +172,7 @@ msdos_creat_node( if (type == MSDOS_DIRECTORY) { /* open new directory as fat-file */ - rc = fat_file_open(parent_loc->mt_entry, aux.cln, aux.ofs, &fat_fd); + rc = fat_file_open(parent_loc->mt_entry, &dir_pos, &fat_fd); if (rc != RC_OK) goto err; @@ -168,8 +180,6 @@ msdos_creat_node( * we opened fat-file for node we just created, so initialize fat-file * descritor */ - fat_fd->info_cln = aux.cln; - fat_fd->info_ofs = aux.ofs; fat_fd->fat_file_size = 0; fat_fd->fat_file_type = FAT_DIRECTORY; fat_fd->size_limit = MSDOS_MAX_DIR_LENGHT; @@ -178,9 +188,9 @@ msdos_creat_node( * dot and dotdot entries are identical to new node except the * names */ - memcpy(DOT_NODE_P(dot_dotdot), new_node, + memcpy(DOT_NODE_P(dot_dotdot), short_node, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE); - memcpy(DOTDOT_NODE_P(dot_dotdot), new_node, + memcpy(DOTDOT_NODE_P(dot_dotdot), short_node, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE); memcpy(MSDOS_DIR_NAME(DOT_NODE_P(dot_dotdot)), MSDOS_DOT_NAME, MSDOS_NAME_MAX); @@ -253,9 +263,8 @@ error: fat_file_close(parent_loc->mt_entry, fat_fd); err: - /* mark 32bytes structure on the disk as free */ - msdos_set_first_char4file_name(parent_loc->mt_entry, aux.cln, aux.ofs, - 0xE5); + /* mark the used 32bytes structure on the disk as free */ + msdos_set_first_char4file_name(parent_loc->mt_entry, &dir_pos, 0xE5); return rc; } @@ -287,21 +296,21 @@ err: */ int msdos_file_link(rtems_filesystem_location_info_t *to_loc, - rtems_filesystem_location_info_t *par_loc, - const char *token + rtems_filesystem_location_info_t *par_loc, + const char *name ) { int rc = RC_OK; rtems_status_code sc = RTEMS_SUCCESSFUL; msdos_fs_info_t *fs_info = to_loc->mt_entry->fs_info; fat_file_fd_t *to_fat_fd = to_loc->node_access; - char new_name[ MSDOS_NAME_MAX + 1 ]; + const char *token; int len; /* * check spelling and format new node name */ - if (MSDOS_NAME != msdos_get_token(token, new_name, &len)) { + if (MSDOS_NAME != msdos_get_token(name, &token, &len)) { rtems_set_errno_and_return_minus_one(ENAMETOOLONG); } /* @@ -324,8 +333,8 @@ msdos_file_link(rtems_filesystem_location_info_t *to_loc, * create new directory entry as "hard link", * copying relevant info from existing file */ - rc = msdos_creat_node(par_loc,MSDOS_HARD_LINK,new_name,S_IFREG, - to_loc->node_access); + rc = msdos_creat_node(par_loc,MSDOS_HARD_LINK,name,len,S_IFREG, + to_loc->node_access); /* * set file size and first cluster number of old entry to 0 */ diff --git a/cpukit/libfs/src/dosfs/msdos_dir.c b/cpukit/libfs/src/dosfs/msdos_dir.c index 92dbf0435f..b897a192e3 100644 --- a/cpukit/libfs/src/dosfs/msdos_dir.c +++ b/cpukit/libfs/src/dosfs/msdos_dir.c @@ -14,6 +14,7 @@ #include "config.h" #endif +#include <ctype.h> #include <stdlib.h> #include <unistd.h> #include <assert.h> @@ -145,7 +146,7 @@ msdos_format_dirent_with_dot(char *dst,const char *src) src_tmp = src; len = i; while (i-- > 0) { - *dst++ = *src_tmp++; + *dst++ = tolower(*src_tmp++); } /* * find last non-blank character of extension @@ -164,7 +165,7 @@ msdos_format_dirent_with_dot(char *dst,const char *src) len += i + 1; /* extension + dot */ src_tmp = src + MSDOS_SHORT_BASE_LEN; while (i-- > 0) { - *dst++ = *src_tmp++; + *dst++ = tolower(*src_tmp++); len++; } } @@ -210,6 +211,9 @@ msdos_dir_read(rtems_libio_t *iop, void *buffer, size_t count) uint32_t j = 0, i = 0; uint32_t bts2rd = 0; uint32_t cur_cln = 0; + uint32_t lfn_start = FAT_FILE_SHORT_NAME; + uint8_t lfn_checksum = 0; + int lfn_entries = 0; /* * cast start and count - protect against using sizes that are not exact @@ -253,80 +257,211 @@ msdos_dir_read(rtems_libio_t *iop, void *buffer, size_t count) for (i = 0; i < ret; i += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE) { - if ((*MSDOS_DIR_NAME(fs_info->cl_buf + i)) == + char* entry = (char*) fs_info->cl_buf + i; + + /* + * Is this directory from here on empty ? + */ + if ((*MSDOS_DIR_ENTRY_TYPE(entry)) == MSDOS_THIS_DIR_ENTRY_AND_REST_EMPTY) { rtems_semaphore_release(fs_info->vol_sema); return cmpltd; } - /* have to look at the DIR_NAME as "raw" 8-bit data */ - if ((*(uint8_t *)MSDOS_DIR_NAME(fs_info->cl_buf + i)) == - MSDOS_THIS_DIR_ENTRY_EMPTY) + /* Is the directory entry empty */ + if ((*MSDOS_DIR_ENTRY_TYPE(entry)) == MSDOS_THIS_DIR_ENTRY_EMPTY) continue; - /* - * skip active entries until get the entry to start from - */ - if (start) - { - start--; + /* Is the directory entry empty a volume label */ + if (((*MSDOS_DIR_ATTR(entry)) & MSDOS_ATTR_VOLUME_ID) && + ((*MSDOS_DIR_ATTR(entry) & MSDOS_ATTR_LFN_MASK) != MSDOS_ATTR_LFN)) continue; - } /* - * Move the entry to the return buffer - * - * unfortunately there is no method to extract ino except to - * open fat-file descriptor :( ... so, open it + * Check the attribute to see if the entry is for a long file + * name. */ - - /* get number of cluster we are working with */ - rc = fat_file_ioctl(iop->pathinfo.mt_entry, fat_fd, F_CLU_NUM, - j * bts2rd, &cur_cln); - if (rc != RC_OK) + if ((*MSDOS_DIR_ATTR(entry) & MSDOS_ATTR_LFN_MASK) == + MSDOS_ATTR_LFN) { - rtems_semaphore_release(fs_info->vol_sema); - return rc; + int o; + char* p; + int q; + + /* + * Is this is the first entry of a LFN ? + */ + if (lfn_start == FAT_FILE_SHORT_NAME) + { + /* + * The first entry must have the last long entry flag set. + */ + if ((*MSDOS_DIR_ENTRY_TYPE(entry) & + MSDOS_LAST_LONG_ENTRY) == 0) + continue; + + /* + * Remember the start location of the long file name. + */ + lfn_start = + ((j * bts2rd) + i) / MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE; + + /* + * Get the number of entries so we can count down and + * also the checksum of the short entry. + */ + lfn_entries = (*MSDOS_DIR_ENTRY_TYPE(entry) & + MSDOS_LAST_LONG_ENTRY_MASK); + lfn_checksum = *MSDOS_DIR_LFN_CHECKSUM(entry); + memset (tmp_dirent.d_name, 0, sizeof(tmp_dirent.d_name)); + } + + /* + * If the entry number or the check sum do not match + * forget this series of long directory entries. These could + * be orphaned entries depending on the history of the + * disk. + */ + if ((lfn_entries != (*MSDOS_DIR_ENTRY_TYPE(entry) & + MSDOS_LAST_LONG_ENTRY_MASK)) || + (lfn_checksum != *MSDOS_DIR_LFN_CHECKSUM(entry))) + { + lfn_start = FAT_FILE_SHORT_NAME; + continue; + } + + /* + * Extract the file name into the directory entry. The data is + * stored in UNICODE characters (16bit). No translation is + * currently supported. + * + * The DOS maximum length is 255 characters without the + * trailing nul character. We need to range check the length to + * fit in the directory entry name field. + */ + + lfn_entries--; + p = entry + 1; + o = lfn_entries * MSDOS_LFN_LEN_PER_ENTRY; + + for (q = 0; q < MSDOS_LFN_LEN_PER_ENTRY; q++) + { + if (o >= (sizeof(tmp_dirent.d_name) - 1)) + break; + + tmp_dirent.d_name[o++] = *p; + + if (*p == '\0') + break; + + switch (q) + { + case 4: + p += 5; + break; + case 10: + p += 4; + break; + default: + p += 2; + break; + } + } } - - rc = fat_file_open(iop->pathinfo.mt_entry, cur_cln, i, - &tmp_fat_fd); - if (rc != RC_OK) + else { - rtems_semaphore_release(fs_info->vol_sema); - return rc; + fat_dir_pos_t dir_pos; + + /* + * Skip active entries until get the entry to start from. + */ + if (start) + { + lfn_start = FAT_FILE_SHORT_NAME; + start--; + continue; + } + + /* + * Move the entry to the return buffer + * + * unfortunately there is no method to extract ino except to + * open fat-file descriptor :( ... so, open it + */ + + /* get number of cluster we are working with */ + rc = fat_file_ioctl(iop->pathinfo.mt_entry, fat_fd, F_CLU_NUM, + j * bts2rd, &cur_cln); + if (rc != RC_OK) + { + rtems_semaphore_release(fs_info->vol_sema); + return rc; + } + + fat_dir_pos_init(&dir_pos); + dir_pos.sname.cln = cur_cln; + dir_pos.sname.ofs = i; + rc = fat_file_open(iop->pathinfo.mt_entry, &dir_pos, &tmp_fat_fd); + if (rc != RC_OK) + { + rtems_semaphore_release(fs_info->vol_sema); + return rc; + } + + /* fill in dirent structure */ + /* XXX: from what and in what d_off should be computed ?! */ + tmp_dirent.d_off = start + cmpltd; + tmp_dirent.d_reclen = sizeof(struct dirent); + tmp_dirent.d_ino = tmp_fat_fd->ino; + + /* + * If a long file name check if the correct number of + * entries have been found and if the checksum is correct. + * If not return the short file name. + */ + if (lfn_start != FAT_FILE_SHORT_NAME) + { + uint8_t cs = 0; + uint8_t* p = (uint8_t*) entry; + int i; + + for (i = 0; i < 11; i++, p++) + cs = ((cs & 1) ? 0x80 : 0) + (cs >> 1) + *p; + + if (lfn_entries || (lfn_checksum != cs)) + lfn_start = FAT_FILE_SHORT_NAME; + } + + if (lfn_start == FAT_FILE_SHORT_NAME) + { + /* + * 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, entry); /* src text */ + } + else + { + tmp_dirent.d_namlen = strlen(tmp_dirent.d_name); + } + + memcpy(buffer + cmpltd, &tmp_dirent, sizeof(struct dirent)); + + iop->offset = iop->offset + sizeof(struct dirent); + cmpltd += (sizeof(struct dirent)); + count -= (sizeof(struct dirent)); + + /* inode number extracted, close fat-file */ + rc = fat_file_close(iop->pathinfo.mt_entry, tmp_fat_fd); + if (rc != RC_OK) + { + rtems_semaphore_release(fs_info->vol_sema); + return rc; + } } - - tmp_fat_fd->info_cln = cur_cln; - tmp_fat_fd->info_ofs = i; - - /* fill in dirent structure */ - /* XXX: from what and in what d_off should be computed ?! */ - tmp_dirent.d_off = start + cmpltd; - tmp_dirent.d_reclen = sizeof(struct dirent); - tmp_dirent.d_ino = tmp_fat_fd->ino; - /* - * 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, - (char *) fs_info->cl_buf + i); /* src text */ - memcpy(buffer + cmpltd, &tmp_dirent, sizeof(struct dirent)); - - iop->offset = iop->offset + sizeof(struct dirent); - cmpltd += (sizeof(struct dirent)); - count -= (sizeof(struct dirent)); - - /* inode number extracted, close fat-file */ - rc = fat_file_close(iop->pathinfo.mt_entry, tmp_fat_fd); - if (rc != RC_OK) - { - rtems_semaphore_release(fs_info->vol_sema); - return rc; - } - + if (count <= 0) break; } @@ -363,8 +498,8 @@ msdos_dir_read(rtems_libio_t *iop, void *buffer, size_t count) * RC_OK on success, or -1 if error occured (errno * set apropriately). */ -off_t -msdos_dir_lseek(rtems_libio_t *iop, off_t offset, int whence) +rtems_off64_t +msdos_dir_lseek(rtems_libio_t *iop, rtems_off64_t offset, int whence) { switch (whence) { @@ -471,6 +606,24 @@ msdos_dir_sync(rtems_libio_t *iop) return rc; } +/* msdos_dir_chmod -- + * Change the attributes of the directory. This currently does + * nothing and returns no error. + * + * PARAMETERS: + * pathloc - node description + * mode - the new mode + * + * RETURNS: + * RC_OK always + */ +int +msdos_dir_chmod(rtems_filesystem_location_info_t *pathloc, + mode_t mode) +{ + return RC_OK; +} + /* msdos_dir_rmnod -- * Remove directory node. * @@ -498,7 +651,7 @@ msdos_dir_rmnod(rtems_filesystem_location_info_t *pathloc) rtems_set_errno_and_return_minus_one(EIO); /* - * We deny attemp to delete open directory (if directory is current + * We deny attempts to delete open directory (if directory is current * directory we assume it is open one) */ if (fat_fd->links_num > 1) @@ -538,8 +691,7 @@ msdos_dir_rmnod(rtems_filesystem_location_info_t *pathloc) */ /* mark file removed */ - rc = msdos_set_first_char4file_name(pathloc->mt_entry, fat_fd->info_cln, - fat_fd->info_ofs, + rc = msdos_set_first_char4file_name(pathloc->mt_entry, &fat_fd->dir_pos, MSDOS_THIS_DIR_ENTRY_EMPTY); if (rc != RC_OK) { diff --git a/cpukit/libfs/src/dosfs/msdos_eval.c b/cpukit/libfs/src/dosfs/msdos_eval.c index 81cae010ad..5eabedb2a4 100644 --- a/cpukit/libfs/src/dosfs/msdos_eval.c +++ b/cpukit/libfs/src/dosfs/msdos_eval.c @@ -82,9 +82,9 @@ msdos_eval_path( fat_file_fd_t *fat_fd = NULL; rtems_filesystem_location_info_t newloc; int i = 0; - int len = 0; + int token_len = 0; msdos_token_types_t type = MSDOS_CURRENT_DIR; - char token[MSDOS_NAME_MAX + 1]; + const char *token; sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT, MSDOS_VOLUME_SEMAPHORE_TIMEOUT); @@ -106,8 +106,8 @@ msdos_eval_path( while ((type != MSDOS_NO_MORE_PATH) && (type != MSDOS_INVALID_TOKEN)) { - type = msdos_get_token(&pathname[i], token, &len); - i += len; + type = msdos_get_token(&pathname[i], &token, &token_len); + i += token_len; fat_fd = pathloc->node_access; @@ -149,13 +149,13 @@ msdos_eval_path( goto err; rtems_semaphore_release(fs_info->vol_sema); - return (*pathloc->ops->evalpath_h)(&(pathname[i-len]), + return (*pathloc->ops->evalpath_h)(&(pathname[i-token_len]), flags, pathloc); } } else { - rc = msdos_find_name(pathloc, token); + rc = msdos_find_name(pathloc, token, token_len); if (rc != RC_OK) { if (rc == MSDOS_NAME_NOT_FOUND_ERR) @@ -183,7 +183,7 @@ msdos_eval_path( * Otherwise find the token name in the present location and * set the node access to the point we have found. */ - rc = msdos_find_name(pathloc, token); + rc = msdos_find_name(pathloc, token, token_len); if (rc != RC_OK) { if (rc == MSDOS_NAME_NOT_FOUND_ERR) @@ -264,8 +264,8 @@ msdos_eval4make( rtems_filesystem_location_info_t newloc; msdos_token_types_t type; int i = 0; - int len; - char token[ MSDOS_NAME_MAX + 1 ]; + int token_len; + const char *token; bool done = false; sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT, @@ -288,8 +288,8 @@ msdos_eval4make( while (!done) { - type = msdos_get_token(&path[i], token, &len); - i += len; + type = msdos_get_token(&path[i], &token, &token_len); + i += token_len; fat_fd = pathloc->node_access; switch (type) @@ -330,13 +330,13 @@ msdos_eval4make( goto err; rtems_semaphore_release(fs_info->vol_sema); - return (*pathloc->ops->evalformake_h)(&path[i-len], + return (*pathloc->ops->evalformake_h)(&path[i-token_len], pathloc, name); } } else { - rc = msdos_find_name(pathloc, token); + rc = msdos_find_name(pathloc, token, token_len); if (rc != RC_OK) { if (rc == MSDOS_NAME_NOT_FOUND_ERR) @@ -361,10 +361,10 @@ msdos_eval4make( } /* - * Otherwise find the token name in the present location and + * Otherwise find the token name in the present location and * set the node access to the point we have found. */ - rc = msdos_find_name(pathloc, token); + rc = msdos_find_name(pathloc, token, token_len); if (rc) { if (rc != MSDOS_NAME_NOT_FOUND_ERR) @@ -396,7 +396,7 @@ msdos_eval4make( } } - *name = &path[i - len]; + *name = &path[i - token_len]; /* * We have evaluated the path as far as we can. diff --git a/cpukit/libfs/src/dosfs/msdos_file.c b/cpukit/libfs/src/dosfs/msdos_file.c index 471d4a04dc..817897f845 100644 --- a/cpukit/libfs/src/dosfs/msdos_file.c +++ b/cpukit/libfs/src/dosfs/msdos_file.c @@ -223,8 +223,8 @@ msdos_file_write(rtems_libio_t *iop,const void *buffer, size_t count) * new offset on success, or -1 if error occured (errno set * appropriately). */ -off_t -msdos_file_lseek(rtems_libio_t *iop, off_t offset, int whence) +rtems_off64_t +msdos_file_lseek(rtems_libio_t *iop, rtems_off64_t offset, int whence) { int rc = RC_OK; rtems_status_code sc = RTEMS_SUCCESSFUL; @@ -302,7 +302,7 @@ msdos_file_stat( * RC_OK on success, or -1 if error occured (errno set appropriately). */ int -msdos_file_ftruncate(rtems_libio_t *iop, off_t length) +msdos_file_ftruncate(rtems_libio_t *iop, rtems_off64_t length) { int rc = RC_OK; rtems_status_code sc = RTEMS_SUCCESSFUL; @@ -444,6 +444,24 @@ msdos_file_ioctl(rtems_libio_t *iop,uint32_t command, void *buffer) return rc; } +/* msdos_file_chmod -- + * Change the attributes of the file. This currently does + * nothing and returns no error. + * + * PARAMETERS: + * pathloc - node description + * mode - the new mode + * + * RETURNS: + * RC_OK always + */ +int +msdos_file_chmod(rtems_filesystem_location_info_t *pathloc, + mode_t mode) +{ + return RC_OK; +} + /* msdos_file_rmnod -- * Remove node associated with a file - set up first name character to * predefined value(and write it to the disk), and mark fat-file which @@ -469,8 +487,8 @@ msdos_file_rmnod(rtems_filesystem_location_info_t *pathloc) rtems_set_errno_and_return_minus_one(EIO); /* mark file removed */ - rc = msdos_set_first_char4file_name(pathloc->mt_entry, fat_fd->info_cln, - fat_fd->info_ofs, + rc = msdos_set_first_char4file_name(pathloc->mt_entry, + &fat_fd->dir_pos, MSDOS_THIS_DIR_ENTRY_EMPTY); if (rc != RC_OK) { diff --git a/cpukit/libfs/src/dosfs/msdos_format.c b/cpukit/libfs/src/dosfs/msdos_format.c index 1d012c29f5..7e72b5e089 100644 --- a/cpukit/libfs/src/dosfs/msdos_format.c +++ b/cpukit/libfs/src/dosfs/msdos_format.c @@ -31,6 +31,7 @@ #include <unistd.h> #include <errno.h> #include <stdlib.h> +#include <stdio.h> #include <ctype.h> #include <assert.h> @@ -65,6 +66,58 @@ typedef struct { uint32_t vol_id; } msdos_format_param_t; +/* + * Formatted output. + */ +static void +msdos_format_printf (const msdos_format_request_param_t *rqdata, + int info_level, + const char *format, ...) +{ + va_list args; + va_start (args, format); + if (rqdata->info_level >= info_level) + { + vfprintf (stdout, format, args); + fflush (stdout); + } +} + +/*=========================================================================*\ +| Function: | +\*-------------------------------------------------------------------------*/ +static int msdos_format_read_sec +( +/*-------------------------------------------------------------------------*\ +| Purpose: | +| function to read a sector | ++---------------------------------------------------------------------------+ +| Input Parameters: | +\*-------------------------------------------------------------------------*/ + int fd, /* file descriptor index */ + uint32_t start_sector, /* sector number to write to */ + uint32_t sector_size, /* size of sector */ + char *buffer /* buffer with read data into */ + ) +/*-------------------------------------------------------------------------*\ +| Return Value: | +| 0, if success, -1 and errno if failed | +\*=========================================================================*/ +{ + int ret_val = 0; + + if (0 > lseek(fd,((off_t)start_sector)*sector_size,SEEK_SET)) { + ret_val = -1; + } + if (ret_val == 0) { + if (0 > read(fd,buffer,sector_size)) { + ret_val = -1; + } + } + + return ret_val; +} + /*=========================================================================*\ | Function: | \*-------------------------------------------------------------------------*/ @@ -100,7 +153,7 @@ static int msdos_format_write_sec return ret_val; } -/*=========================================================================*\ +/*=========================================================================* \ | Function: | \*-------------------------------------------------------------------------*/ static int msdos_format_fill_sectors @@ -111,6 +164,7 @@ static int msdos_format_fill_sectors +---------------------------------------------------------------------------+ | Input Parameters: | \*-------------------------------------------------------------------------*/ + const msdos_format_request_param_t *rqdata, int fd, /* file descriptor index */ uint32_t start_sector, /* sector number to fill to */ uint32_t sector_cnt, /* number of sectors to fill to */ @@ -124,7 +178,9 @@ static int msdos_format_fill_sectors { int ret_val = 0; char *fill_buffer = NULL; - + uint32_t total_sectors = sector_cnt; + int last_percent = -1; + /* * allocate and fill buffer */ @@ -138,15 +194,31 @@ static int msdos_format_fill_sectors memset(fill_buffer,fill_byte,sector_size); } } + + msdos_format_printf (rqdata, MSDOS_FMT_INFO_LEVEL_DETAIL, + "Filling : "); /* * write to consecutive sectors */ while ((ret_val == 0) && (sector_cnt > 0)) { + int percent = (sector_cnt * 100) / total_sectors; + if (percent != last_percent) { + if ((percent & 1) == 0) + msdos_format_printf (rqdata, MSDOS_FMT_INFO_LEVEL_DETAIL, "."); + last_percent = percent; + } ret_val = msdos_format_write_sec(fd,start_sector,sector_size,fill_buffer); start_sector++; sector_cnt--; } + + msdos_format_printf (rqdata, MSDOS_FMT_INFO_LEVEL_DETAIL, "\n"); + + if (ret_val) + msdos_format_printf (rqdata, MSDOS_FMT_INFO_LEVEL_INFO, + "filling error on sector: %d\n", start_sector); + /* * cleanup */ @@ -311,7 +383,8 @@ static int msdos_format_determine_fmt_params uint32_t fatdata_sect_cnt; uint32_t onebit; uint32_t sectors_per_cluster_adj = 0; - + uint64_t total_size = 0; + memset(fmt_params,0,sizeof(*fmt_params)); /* * this one is fixed in this implementation. @@ -320,6 +393,10 @@ static int msdos_format_determine_fmt_params if (ret_val == 0) { fmt_params->bytes_per_sector = dd->block_size; fmt_params->totl_sector_cnt = dd->size; + total_size = dd->block_size * dd->size; + msdos_format_printf (rqdata, MSDOS_FMT_INFO_LEVEL_DETAIL, + "bytes per sector: %d\ntotal sectors: %d\ntotal size: %lu\n", + dd->block_size, dd->size, total_size); } /* * determine number of FATs @@ -336,6 +413,11 @@ static int msdos_format_determine_fmt_params ret_val = EINVAL; } } + + if (ret_val == 0) + msdos_format_printf (rqdata, MSDOS_FMT_INFO_LEVEL_DETAIL, + "number of fats: %d\n", fmt_params->fat_num); + /* * Now we get sort of a loop when determining things: * The FAT type (FAT12/16/32) is determined ONLY from the @@ -396,21 +478,26 @@ static int msdos_format_determine_fmt_params * are a compromise concerning capacity and efficency */ if (fmt_params->totl_sector_cnt - < ((uint32_t)FAT_FAT12_MAX_CLN)*8) { - fmt_params->fattype = FAT_FAT12; - /* start trying with small clusters */ - fmt_params->sectors_per_cluster = 2; + < ((uint32_t)FAT_FAT12_MAX_CLN)*8) { + fmt_params->fattype = FAT_FAT12; + /* start trying with small clusters */ + fmt_params->sectors_per_cluster = 2; } else if (fmt_params->totl_sector_cnt - < ((uint32_t)FAT_FAT16_MAX_CLN)*32) { - fmt_params->fattype = FAT_FAT16; - /* start trying with small clusters */ - fmt_params->sectors_per_cluster = 2; + < ((uint32_t)FAT_FAT16_MAX_CLN)*32) { + fmt_params->fattype = FAT_FAT16; + /* start trying with small clusters */ + fmt_params->sectors_per_cluster = 2; } else { - fmt_params->fattype = FAT_FAT32; - /* start trying with small clusters... */ - fmt_params->sectors_per_cluster = 1; + uint32_t gigs = (total_size + (1024 * 1024 * 1024)) / (1024 * 1024 * 1024); + int b; + fmt_params->fattype = FAT_FAT32; + /* scale with the size of disk... */ + for (b = 31; b > 0; b--) + if ((gigs & (1 << b)) != 0) + break; + fmt_params->sectors_per_cluster = 1 << b; } } /* @@ -428,7 +515,7 @@ static int msdos_format_determine_fmt_params * sectors_per_cluster*bytes_per_sector must not be bigger than 32K */ for (onebit = 128;onebit >= 1;onebit = onebit>>1) { - if (fmt_params->sectors_per_cluster > onebit) { + if (fmt_params->sectors_per_cluster >= onebit) { fmt_params->sectors_per_cluster = onebit; if (fmt_params->sectors_per_cluster <= 32768L/fmt_params->bytes_per_sector) { @@ -440,6 +527,9 @@ static int msdos_format_determine_fmt_params } if (ret_val == 0) { + msdos_format_printf (rqdata, MSDOS_FMT_INFO_LEVEL_DETAIL, + "sectors per cluster: %d\n", fmt_params->sectors_per_cluster); + if (fmt_params->fattype == FAT_FAT32) { /* recommended: for FAT32, always set reserved sector count to 32 */ fmt_params->rsvd_sector_cnt = 32; @@ -649,9 +739,15 @@ static int msdos_format_gen_mbr total_sectors_num32 = fmt_params->totl_sector_cnt; } /* - * finally we are there: let's fill in the values into the MBR + * finally we are there: let's fill in the values into the MBR + * but first clear the MRB leaving the partition table. */ - memset(mbr,0,FAT_TOTAL_MBR_SIZE); +#define RTEMS_IDE_PARTITION_TABLE_OFFSET 0x1be +#define RTEMS_IDE_PARTITION_TABLE_SIZE (4 * 16) + memset(mbr,0,RTEMS_IDE_PARTITION_TABLE_OFFSET); + memset(mbr + RTEMS_IDE_PARTITION_TABLE_OFFSET + RTEMS_IDE_PARTITION_TABLE_SIZE, + 0, + FAT_TOTAL_MBR_SIZE - (RTEMS_IDE_PARTITION_TABLE_OFFSET + RTEMS_IDE_PARTITION_TABLE_SIZE)); /* * FIXME: fill jmpBoot and Boot code... * with 0xEB,.... @@ -672,9 +768,9 @@ static int msdos_format_gen_mbr FAT_SET_BR_TOTAL_SECTORS_NUM16(mbr , total_sectors_num16); FAT_SET_BR_MEDIA(mbr , fmt_params->media_code); - FAT_SET_BR_SECTORS_PER_TRACK(mbr , 0); /* only needed for INT13... */ - FAT_SET_BR_NUMBER_OF_HEADS(mbr , 0); /* only needed for INT13... */ - FAT_SET_BR_HIDDEN_SECTORS(mbr , 0); /* only needed for INT13... */ + FAT_SET_BR_SECTORS_PER_TRACK(mbr , 255); /* only needed for INT13... */ + FAT_SET_BR_NUMBER_OF_HEADS(mbr , 6); /* only needed for INT13... */ + FAT_SET_BR_HIDDEN_SECTORS(mbr , 1); /* only needed for INT13... */ FAT_SET_BR_TOTAL_SECTORS_NUM32(mbr , total_sectors_num32); if (fmt_params->fattype != FAT_FAT32) { @@ -749,7 +845,6 @@ static int msdos_format_gen_fsinfo | 0, if success, -1 and errno if failed | \*=========================================================================*/ { - /* * clear fsinfo sector data */ @@ -760,9 +855,9 @@ static int msdos_format_gen_fsinfo FAT_SET_FSINFO_LEAD_SIGNATURE (fsinfo,FAT_FSINFO_LEAD_SIGNATURE_VALUE ); FAT_SET_FSINFO_STRUC_SIGNATURE(fsinfo,FAT_FSINFO_STRUC_SIGNATURE_VALUE); FAT_SET_FSINFO_TRAIL_SIGNATURE(fsinfo,FAT_FSINFO_TRAIL_SIGNATURE_VALUE); -/* - * write "empty" values for free cluster count and next cluster number - */ + /* + * write "empty" values for free cluster count and next cluster number + */ FAT_SET_FSINFO_FREE_CLUSTER_COUNT(fsinfo+FAT_FSI_INFO, 0xffffffff); FAT_SET_FSINFO_NEXT_FREE_CLUSTER (fsinfo+FAT_FSI_INFO, @@ -800,9 +895,13 @@ int msdos_format int i; msdos_format_param_t fmt_params; + msdos_format_printf (rqdata, MSDOS_FMT_INFO_LEVEL_INFO, + "formating: %s\n", devname); /* * sanity check on device */ + msdos_format_printf (rqdata, MSDOS_FMT_INFO_LEVEL_DETAIL, + "stat check: %s\n", devname); if (ret_val == 0) { rc = stat(devname, &stat_buf); ret_val = rc; @@ -828,7 +927,9 @@ int msdos_format * open device for writing */ if (ret_val == 0) { - fd = open(devname, O_WRONLY); + msdos_format_printf (rqdata, MSDOS_FMT_INFO_LEVEL_DETAIL, + "open device\n"); + fd = open(devname, O_RDWR); if (fd == -1) { ret_val= -1; @@ -848,7 +949,8 @@ int msdos_format (rqdata != NULL) && !(rqdata->quick_format)) { ret_val = msdos_format_fill_sectors - (fd, + (rqdata, + fd, 0, /* start sector */ fmt_params.totl_sector_cnt, /* sector count */ fmt_params.bytes_per_sector, @@ -858,27 +960,45 @@ int msdos_format * create master boot record */ if (ret_val == 0) { - ret_val = msdos_format_gen_mbr(tmp_sec,&fmt_params); - } - /* - * write master boot record to disk - * also write copy of MBR to disk - */ - if (ret_val == 0) { - ret_val = msdos_format_write_sec(fd, - 0, - fmt_params.bytes_per_sector, - tmp_sec); - } - if ((ret_val == 0) && - (fmt_params.mbr_copy_sec != 0)) { /* - * write copy of MBR + * Read the current MBR to obtain the partition table. */ - ret_val = msdos_format_write_sec(fd, - fmt_params.mbr_copy_sec , - fmt_params.bytes_per_sector, - tmp_sec); + msdos_format_printf (rqdata, MSDOS_FMT_INFO_LEVEL_DETAIL, + "read MRB sector\n"); + ret_val = msdos_format_read_sec(fd, + 0, + fmt_params.bytes_per_sector, + tmp_sec); + if (ret_val == 0) { + msdos_format_printf (rqdata, MSDOS_FMT_INFO_LEVEL_DETAIL, + "generate MRB sector\n"); + ret_val = msdos_format_gen_mbr(tmp_sec,&fmt_params); + } + + /* + * write master boot record to disk + * also write copy of MBR to disk + */ + if (ret_val == 0) { + msdos_format_printf (rqdata, MSDOS_FMT_INFO_LEVEL_DETAIL, + "write MRB sector\n"); + ret_val = msdos_format_write_sec(fd, + 0, + fmt_params.bytes_per_sector, + tmp_sec); + } + if ((ret_val == 0) && + (fmt_params.mbr_copy_sec != 0)) { + /* + * write copy of MBR + */ + msdos_format_printf (rqdata, MSDOS_FMT_INFO_LEVEL_DETAIL, + "write back up MRB sector\n"); + ret_val = msdos_format_write_sec(fd, + fmt_params.mbr_copy_sec , + fmt_params.bytes_per_sector, + tmp_sec); + } } /* * for FAT32: initialize info sector on disk @@ -903,7 +1023,8 @@ int msdos_format */ if (ret_val == 0) { ret_val = msdos_format_fill_sectors - (fd, + (rqdata, + fd, fmt_params.rsvd_sector_cnt, /* start sector */ fmt_params.fat_num*fmt_params.sectors_per_fat,/* sector count */ fmt_params.bytes_per_sector, @@ -915,7 +1036,8 @@ int msdos_format */ if (ret_val == 0) { ret_val = msdos_format_fill_sectors - (fd, + (rqdata, + fd, fmt_params.root_dir_start_sec, /* start sector */ fmt_params.root_dir_fmt_sec_cnt, /* sector count */ fmt_params.bytes_per_sector, diff --git a/cpukit/libfs/src/dosfs/msdos_handlers_dir.c b/cpukit/libfs/src/dosfs/msdos_handlers_dir.c index e42f72ab16..66e4e8c531 100644 --- a/cpukit/libfs/src/dosfs/msdos_handlers_dir.c +++ b/cpukit/libfs/src/dosfs/msdos_handlers_dir.c @@ -26,7 +26,7 @@ const rtems_filesystem_file_handlers_r msdos_dir_handlers = { NULL, /* msdos_dir_ioctl */ msdos_dir_lseek, msdos_dir_stat, - NULL, + msdos_dir_chmod, NULL, /* msdos_dir_ftruncate */ NULL, msdos_dir_sync, diff --git a/cpukit/libfs/src/dosfs/msdos_handlers_file.c b/cpukit/libfs/src/dosfs/msdos_handlers_file.c index 6ad6d1850d..5dd89849c7 100644 --- a/cpukit/libfs/src/dosfs/msdos_handlers_file.c +++ b/cpukit/libfs/src/dosfs/msdos_handlers_file.c @@ -26,7 +26,7 @@ const rtems_filesystem_file_handlers_r msdos_file_handlers = { msdos_file_ioctl, msdos_file_lseek, msdos_file_stat, - NULL, + msdos_file_chmod, msdos_file_ftruncate, NULL, msdos_file_sync, diff --git a/cpukit/libfs/src/dosfs/msdos_init.c b/cpukit/libfs/src/dosfs/msdos_init.c index 8642cead0a..1af639c286 100644 --- a/cpukit/libfs/src/dosfs/msdos_init.c +++ b/cpukit/libfs/src/dosfs/msdos_init.c @@ -42,7 +42,8 @@ const rtems_filesystem_operations_table msdos_ops = { }; /* msdos_initialize -- - * MSDOS filesystem initialization + * MSDOS filesystem initialization. Called when mounting an + * MSDOS filesystem. * * PARAMETERS: * temp_mt_entry - mount table entry diff --git a/cpukit/libfs/src/dosfs/msdos_initsupp.c b/cpukit/libfs/src/dosfs/msdos_initsupp.c index 42495c7622..72e762d081 100644 --- a/cpukit/libfs/src/dosfs/msdos_initsupp.c +++ b/cpukit/libfs/src/dosfs/msdos_initsupp.c @@ -57,6 +57,7 @@ msdos_initialize_support( rtems_status_code sc = RTEMS_SUCCESSFUL; msdos_fs_info_t *fs_info = NULL; fat_file_fd_t *fat_fd = NULL; + fat_dir_pos_t root_pos; uint32_t cl_buf_size; fs_info = (msdos_fs_info_t *)calloc(1, sizeof(msdos_fs_info_t)); @@ -79,7 +80,9 @@ msdos_initialize_support( * open fat-file which correspondes to root directory * (so inode number 0x00000010 is always used for root directory) */ - rc = fat_file_open(temp_mt_entry, FAT_ROOTDIR_CLUSTER_NUM, 0, &fat_fd); + fat_dir_pos_init(&root_pos); + root_pos.sname.cln = FAT_ROOTDIR_CLUSTER_NUM; + rc = fat_file_open(temp_mt_entry, &root_pos, &fat_fd); if (rc != RC_OK) { fat_shutdown_drive(temp_mt_entry); @@ -90,8 +93,6 @@ msdos_initialize_support( /* again: unfortunately "fat-file" is just almost fat file :( */ fat_fd->fat_file_type = FAT_DIRECTORY; fat_fd->size_limit = MSDOS_MAX_DIR_LENGHT; - fat_fd->info_cln = FAT_ROOTDIR_CLUSTER_NUM; - fat_fd->info_ofs = 0; fat_fd->cln = fs_info->fat.vol.rdir_cl; fat_fd->map.file_cln = 0; diff --git a/cpukit/libfs/src/dosfs/msdos_misc.c b/cpukit/libfs/src/dosfs/msdos_misc.c index abf5eedbd4..17928077e4 100644 --- a/cpukit/libfs/src/dosfs/msdos_misc.c +++ b/cpukit/libfs/src/dosfs/msdos_misc.c @@ -18,6 +18,7 @@ #endif #include <stdlib.h> +#include <ctype.h> #include <sys/time.h> #include <unistd.h> #include <string.h> @@ -30,6 +31,189 @@ #include "msdos.h" + +#include <stdio.h> + +/* + * External strings. Saves spave this way. + */ +const char const* MSDOS_DOT_NAME = ". "; +const char const* MSDOS_DOTDOT_NAME = ".. "; + +/* msdos_is_valid_name_char -- + * Routine to check the character in a file or directory name. + * The characters support in the short file name are letters, + * digits, or characters with code points values greater than + * 127 (not sure what this last is) plus the following special + * characters "$%'-_@~`!(){}^#&". The must be uppercase. + * + * The following 6 characters are allowed in a long names, + * " +,;=[]" including a space and lower case letters. + * + * PARAMETERS: + * ch - character to check. + * + * RETURNS: + * MSDOS_NAME_INVALID - Not valid in a long or short name. + * MSDOS_NAME_SHORT - Valid in a short name or long name. + * MSDOS_NAME_LONG - Valid in a long name only. + * + */ +static msdos_name_type_t +msdos_is_valid_name_char(const char ch) +{ + if (strchr(" +,;=[]", ch) != NULL) + return MSDOS_NAME_LONG; + + if ((ch == '.') || isalnum(ch) || + (strchr("$%'-_@~`!(){}^#&", ch) != NULL)) + return MSDOS_NAME_SHORT; + + return MSDOS_NAME_INVALID; +} + +/* msdos_short_hex_number -- + * Routine to set the hex number in the SFN. + * + * PARAMETERS: + * name - name to change + * num - number to set + * + * RETURNS: + * nothing + * + */ +static void +msdos_short_name_hex(char* sfn, int num) +{ + static const char* hex = "0123456789ABCDEF"; + char* c = MSDOS_DIR_NAME(sfn); + int i; + for (i = 0; i < 3; i++, c++) + if ((*c == ' ') || (*c == '.')) + *c = '~'; + *c++ = '~'; + for (i = 0; i < 4; i++, c++) + *c = hex[(num >> ((3 - i) * 4)) & 0xf]; +} + +/* msdos_name_type -- + * Routine the type of file name. + * + * PARAMETERS: + * name - name to check + * + * RETURNS: + * true the name is long, else the name is short. + * + */ +static msdos_name_type_t +msdos_name_type(const char *name, int name_len) +{ + bool dot = false; + bool lowercase = false; + bool uppercase = false; + int dot_at = 0; + int count = 0; + + while (*name && (count < name_len)) + { + msdos_name_type_t type = msdos_is_valid_name_char(*name); + + if ((type == MSDOS_NAME_INVALID) || (type == MSDOS_NAME_LONG)) + return type; + + if (dot) + { + if ((*name == '.') || ((count - dot_at) > 3)) + return MSDOS_NAME_LONG; + } + else + { + if (count >= 8) + return MSDOS_NAME_LONG; + } + + if (*name == '.') + { + dot = true; + dot_at = count; + } + else if ((*name >= 'A') && (*name <= 'Z')) + uppercase = true; + else if ((*name >= 'a') && (*name <= 'z')) + lowercase = true; + + count++; + name++; + } + + if (lowercase && uppercase) + return MSDOS_NAME_LONG; + + return MSDOS_NAME_SHORT; +} + +/* msdos_long_to_short -- + * Routine to creates a short name from a long. Start the end of the + * + * PARAMETERS: + * name - name to check + * + * RETURNS: + * true the name is long, else the name is short. + * + */ +msdos_name_type_t +msdos_long_to_short(const char *lfn, int lfn_len, char* sfn, int sfn_len) +{ + msdos_name_type_t type; + int i; + + /* + * Fill with spaces. This is how a short directory entry is padded. + */ + memset (sfn, ' ', sfn_len); + + /* + * Handle '.' and '..' specially. + */ + if ((lfn[0] == '.') && (lfn_len == 1)) + { + sfn[0] = '.'; + return MSDOS_NAME_SHORT; + } + + if ((lfn[0] == '.') && (lfn[1] == '.') && (lfn_len == 2)) + { + sfn[0] = sfn[1] = '.'; + return MSDOS_NAME_SHORT; + } + + /* + * Filenames with only blanks and dots are not allowed! + */ + for (i = 0; i < lfn_len; i++) + if ((lfn[i] != ' ') && (lfn[i] == '.')) + break; + + if (i > lfn_len) + return MSDOS_NAME_INVALID; + + /* + * Is this a short name ? + */ + + type = msdos_name_type (lfn, lfn_len); + + if (type == MSDOS_NAME_INVALID) + return MSDOS_NAME_INVALID; + + msdos_filename_unix2dos (lfn, lfn_len, sfn); + + return type; +} + /* msdos_get_token -- * Routine to get a token (name or separator) from the path. * @@ -43,35 +227,34 @@ * */ msdos_token_types_t -msdos_get_token(const char *path, char *ret_token, int *token_len) +msdos_get_token(const char *path, const char **ret_token, int *ret_token_len) { - int rc = RC_OK; - register int i = 0; msdos_token_types_t type = MSDOS_NAME; - char token[MSDOS_NAME_MAX_WITH_DOT+1]; - register char c; + int i = 0; + + *ret_token = NULL; + *ret_token_len = 0; /* - * Copy a name into token. (Remember NULL is a token.) + * Check for a separator. */ - c = path[i]; - while ( (!msdos_is_separator(c)) && (i <= MSDOS_NAME_MAX_WITH_DOT) ) + while (!msdos_is_separator(path[i])) { - token[i] = c; - if ( i == MSDOS_NAME_MAX_WITH_DOT ) + if ( !msdos_is_valid_name_char(path[i]) ) return MSDOS_INVALID_TOKEN; - if ( !msdos_is_valid_name_char(c) ) + ++i; + if ( i == MSDOS_NAME_MAX_LFN_WITH_DOT ) return MSDOS_INVALID_TOKEN; - c = path [++i]; } + *ret_token = path; + /* - * Copy a seperator into token. + * If it is just a separator then it is the current dir. */ if ( i == 0 ) { - token[i] = c; - if ( token[i] != '\0' ) + if ( *path != '\0' ) { i++; type = MSDOS_CURRENT_DIR; @@ -79,13 +262,11 @@ msdos_get_token(const char *path, char *ret_token, int *token_len) else type = MSDOS_NO_MORE_PATH; } - else if (token[ i-1 ] != '\0') - token[i] = '\0'; /* - * Set token_len to the number of characters copied. + * Set the token and token_len to the token start and length. */ - *token_len = i; + *ret_token_len = i; /* * If we copied something that was not a seperator see if @@ -93,25 +274,19 @@ msdos_get_token(const char *path, char *ret_token, int *token_len) */ if ( type == MSDOS_NAME ) { - if ( strcmp( token, "..") == 0 ) + if ((i == 2) && ((*ret_token)[0] == '.') && ((*ret_token)[1] == '.')) { - strcpy(ret_token, MSDOS_DOTDOT_NAME); type = MSDOS_UP_DIR; return type; } - if ( strcmp( token, "." ) == 0 ) + if ((i == 1) && ((*ret_token)[0] == '.')) { - strcpy(ret_token, MSDOS_DOT_NAME); type = MSDOS_CURRENT_DIR; return type; } - - rc = msdos_filename_unix2dos(token, *token_len, ret_token); - if ( rc != RC_OK ) - return MSDOS_INVALID_TOKEN; } - ret_token[MSDOS_NAME_MAX] = '\0'; + return type; } @@ -133,50 +308,61 @@ msdos_get_token(const char *path, char *ret_token, int *token_len) int msdos_find_name( rtems_filesystem_location_info_t *parent_loc, - char *name + const char *name, + int name_len ) { - int rc = RC_OK; - msdos_fs_info_t *fs_info = parent_loc->mt_entry->fs_info; - fat_file_fd_t *fat_fd = NULL; - fat_auxiliary_t aux; - unsigned short time_val = 0; - unsigned short date = 0; - char node_entry[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE]; + int rc = RC_OK; + msdos_fs_info_t *fs_info = parent_loc->mt_entry->fs_info; + fat_file_fd_t *fat_fd = NULL; + msdos_name_type_t name_type; + fat_dir_pos_t dir_pos; + unsigned short time_val = 0; + unsigned short date = 0; + char node_entry[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE]; memset(node_entry, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE); + name_type = msdos_long_to_short (name, + name_len, + MSDOS_DIR_NAME(node_entry), + MSDOS_NAME_MAX); + /* * find the node which correspondes to the name in the directory pointed by * 'parent_loc' */ - rc = msdos_get_name_node(parent_loc, name, &aux, node_entry); + rc = msdos_get_name_node(parent_loc, false, name, name_len, name_type, + &dir_pos, node_entry); if (rc != RC_OK) return rc; + if (((*MSDOS_DIR_ATTR(node_entry)) & MSDOS_ATTR_VOLUME_ID) || + ((*MSDOS_DIR_ATTR(node_entry) & MSDOS_ATTR_LFN_MASK) == MSDOS_ATTR_LFN)) + return MSDOS_NAME_NOT_FOUND_ERR; + /* open fat-file corresponded to the found node */ - rc = fat_file_open(parent_loc->mt_entry, aux.cln, aux.ofs, &fat_fd); + rc = fat_file_open(parent_loc->mt_entry, &dir_pos, &fat_fd); if (rc != RC_OK) return rc; + fat_fd->dir_pos = dir_pos; + /* - * I don't like this if, but: we should do it , or should write new file + * I don't like this if, but: we should do it, or should write new file * size and first cluster num to the disk after each write operation - * (even if one byte is written - that is TOO non-optimize) because + * (even if one byte is written - that is TOO slow) because * otherwise real values of these fields stored in fat-file descriptor - * may be accidentely rewritten with wrong values stored on the disk + * may be accidentally rewritten with wrong values stored on the disk */ if (fat_fd->links_num == 1) { - fat_fd->info_cln = aux.cln; - fat_fd->info_ofs = aux.ofs; fat_fd->cln = MSDOS_EXTRACT_CLUSTER_NUM(node_entry); - fat_fd->first_char = *MSDOS_DIR_NAME(node_entry); time_val = *MSDOS_DIR_WRITE_TIME(node_entry); date = *MSDOS_DIR_WRITE_DATE(node_entry); - fat_fd->mtime = msdos_date_dos2unix(CF_LE_W(time_val), CF_LE_W(date)); + fat_fd->mtime = msdos_date_dos2unix(CF_LE_W(date), CF_LE_W(time_val)); if ((*MSDOS_DIR_ATTR(node_entry)) & MSDOS_ATTR_DIRECTORY) { @@ -227,7 +413,7 @@ msdos_find_name( } /* msdos_get_name_node -- - * This routine is used in two ways: for a new mode creation (a) or for + * This routine is used in two ways: for a new node creation (a) or for * search the node which correspondes to the name parameter (b). * In case (a) 'name' should be set up to NULL and 'name_dir_entry' should * point to initialized 32 bytes structure described a new node. @@ -247,7 +433,7 @@ msdos_find_name( * name - NULL or name to find * paux - identify a node location on the disk - * cluster num and offset inside the cluster - * name_dir_entry - node to create/placeholder for found node (IN/OUT) + * short_dir_entry - node to create/placeholder for found node (IN/OUT) * * RETURNS: * RC_OK, filled aux_struct_ptr and name_dir_entry on success, or -1 if @@ -257,90 +443,63 @@ msdos_find_name( int msdos_get_name_node( rtems_filesystem_location_info_t *parent_loc, - char *name, - fat_auxiliary_t *paux, + bool create_node, + const char *name, + int name_len, + msdos_name_type_t name_type, + fat_dir_pos_t *dir_pos, char *name_dir_entry ) { int rc = RC_OK; - ssize_t ret = 0; - msdos_fs_info_t *fs_info = parent_loc->mt_entry->fs_info; fat_file_fd_t *fat_fd = parent_loc->node_access; uint32_t dotdot_cln = 0; - /* find name in fat-file which correspondes to the directory */ - rc = msdos_find_name_in_fat_file(parent_loc->mt_entry, fat_fd, name, paux, - name_dir_entry); + /* find name in fat-file which corresponds to the directory */ + rc = msdos_find_name_in_fat_file(parent_loc->mt_entry, fat_fd, + create_node, name, name_len, name_type, + dir_pos, name_dir_entry); if ((rc != RC_OK) && (rc != MSDOS_NAME_NOT_FOUND_ERR)) return rc; - /* if we search for valid name and name not found -> return */ - if ((rc == MSDOS_NAME_NOT_FOUND_ERR) && (name != NULL)) - return rc; - - /* - * if we try to create new entry and the directory is not big enough - * currently - try to enlarge directory - */ - if ((rc == MSDOS_NAME_NOT_FOUND_ERR) && (name == NULL)) + if (!create_node) { - ret = fat_file_write(parent_loc->mt_entry, fat_fd, - fat_fd->fat_file_size, - MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE, - (uint8_t *)name_dir_entry); - if (ret == -1) - return -1; - - /* on success directory is enlarged by a new cluster */ - fat_fd->fat_file_size += fs_info->fat.vol.bpc; - - /* get cluster num where a new node located */ - rc = fat_file_ioctl(parent_loc->mt_entry, fat_fd, F_CLU_NUM, - fat_fd->fat_file_size - 1, &paux->cln); - - if (rc != RC_OK) + /* if we search for valid name and name not found -> return */ + if (rc == MSDOS_NAME_NOT_FOUND_ERR) return rc; /* - * if new cluster allocated succesfully then new node is at very - * beginning of the cluster (offset is computed in bytes) + * if we have deal with ".." - it is a special case :((( + * + * Really, we should return cluster num and offset not of ".." slot, but + * slot which correspondes to real directory name. */ - paux->ofs = 0; - return RC_OK; - } - - /* - * if we have deal with ".." - it is a special case :((( - * - * Really, we should return cluster num and offset not of ".." slot, but - * slot which correspondes to real directory name. - */ - if ((rc == RC_OK) && (name != NULL)) - { - if (strncmp(name, MSDOS_DOTDOT_NAME, MSDOS_SHORT_NAME_LEN) == 0) + if (rc == RC_OK) { - dotdot_cln = MSDOS_EXTRACT_CLUSTER_NUM((name_dir_entry)); - - /* are we right under root dir ? */ - if (dotdot_cln == 0) - { - /* - * we can relax about first_char field - it never should be - * used for root dir - */ - paux->cln = FAT_ROOTDIR_CLUSTER_NUM; - paux->ofs = 0; - } - else + if (strncmp(name, "..", 2) == 0) { - rc = msdos_get_dotdot_dir_info_cluster_num_and_offset( - parent_loc->mt_entry, - dotdot_cln, - paux, - name_dir_entry - ); - if (rc != RC_OK) - return rc; + dotdot_cln = MSDOS_EXTRACT_CLUSTER_NUM((name_dir_entry)); + + /* are we right under root dir ? */ + if (dotdot_cln == 0) + { + /* + * we can relax about first_char field - it never should be + * used for root dir + */ + fat_dir_pos_init(dir_pos); + dir_pos->sname.cln = FAT_ROOTDIR_CLUSTER_NUM; + } + else + { + rc = + msdos_get_dotdot_dir_info_cluster_num_and_offset(parent_loc->mt_entry, + dotdot_cln, + dir_pos, + name_dir_entry); + if (rc != RC_OK) + return rc; + } } } } @@ -380,7 +539,7 @@ int msdos_get_dotdot_dir_info_cluster_num_and_offset( rtems_filesystem_mount_table_entry_t *mt_entry, uint32_t cln, - fat_auxiliary_t *paux, + fat_dir_pos_t *dir_pos, char *dir_entry ) { @@ -391,18 +550,13 @@ msdos_get_dotdot_dir_info_cluster_num_and_offset( char dotdot_node[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE]; uint32_t cl4find = 0; - memset(dot_node, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE); - memset(dotdot_node, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE); - /* * open fat-file corresponded to ".." */ - rc = fat_file_open(mt_entry, paux->cln, paux->ofs, &fat_fd); + rc = fat_file_open(mt_entry, dir_pos, &fat_fd); if (rc != RC_OK) return rc; - fat_fd->info_cln = paux->cln; - fat_fd->info_ofs = paux->ofs; fat_fd->cln = cln; fat_fd->fat_file_type = FAT_DIRECTORY; fat_fd->size_limit = MSDOS_MAX_DIR_LENGHT; @@ -418,8 +572,10 @@ msdos_get_dotdot_dir_info_cluster_num_and_offset( } /* find "." node in opened directory */ - rc = msdos_find_name_in_fat_file(mt_entry, fat_fd, MSDOS_DOT_NAME, paux, - dot_node); + memset(dot_node, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE); + msdos_long_to_short(".", 1, dot_node, MSDOS_SHORT_NAME_LEN); + rc = msdos_find_name_in_fat_file(mt_entry, fat_fd, false, ".", 1, + MSDOS_NAME_SHORT, dir_pos, dot_node); if (rc != RC_OK) { @@ -428,7 +584,10 @@ msdos_get_dotdot_dir_info_cluster_num_and_offset( } /* find ".." node in opened directory */ - rc = msdos_find_name_in_fat_file(mt_entry, fat_fd, MSDOS_DOTDOT_NAME, paux, + memset(dotdot_node, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE); + msdos_long_to_short("..", 2, dotdot_node, MSDOS_SHORT_NAME_LEN); + rc = msdos_find_name_in_fat_file(mt_entry, fat_fd, false, "..", 2, + MSDOS_NAME_SHORT, dir_pos, dotdot_node); if (rc != RC_OK) @@ -450,18 +609,15 @@ msdos_get_dotdot_dir_info_cluster_num_and_offset( * we handle root dir for all FAT types in the same way with the * ordinary directories ( through fat_file_* calls ) */ - paux->cln = FAT_ROOTDIR_CLUSTER_NUM; - paux->ofs = 0; + fat_dir_pos_init(dir_pos); + dir_pos->sname.cln = FAT_ROOTDIR_CLUSTER_NUM; } /* open fat-file corresponded to second ".." */ - rc = fat_file_open(mt_entry, paux->cln, paux->ofs, &fat_fd); + rc = fat_file_open(mt_entry, dir_pos, &fat_fd); if (rc != RC_OK) return rc; - fat_fd->info_cln = paux->cln; - fat_fd->info_ofs = paux->ofs; - if ((MSDOS_EXTRACT_CLUSTER_NUM(dotdot_node)) == 0) fat_fd->cln = fs_info->fat.vol.rdir_cl; else @@ -482,7 +638,7 @@ msdos_get_dotdot_dir_info_cluster_num_and_offset( /* in this directory find slot with specified cluster num */ rc = msdos_find_node_by_cluster_num_in_fat_file(mt_entry, fat_fd, cl4find, - paux, dir_entry); + dir_pos, dir_entry); if (rc != RC_OK) { fat_file_close(mt_entry, fat_fd); @@ -518,16 +674,16 @@ msdos_set_dir_wrt_time_and_date( uint32_t sec = 0; uint32_t byte = 0; - msdos_date_unix2dos(fat_fd->mtime, &time_val, &date); + msdos_date_unix2dos(fat_fd->mtime, &date, &time_val); /* * calculate input for _fat_block_write: convert (cluster num, offset) to * (sector num, new offset) */ - sec = fat_cluster_num_to_sector_num(mt_entry, fat_fd->info_cln); - sec += (fat_fd->info_ofs >> fs_info->fat.vol.sec_log2); + sec = fat_cluster_num_to_sector_num(mt_entry, fat_fd->dir_pos.sname.cln); + sec += (fat_fd->dir_pos.sname.ofs >> fs_info->fat.vol.sec_log2); /* byte points to start of 32bytes structure */ - byte = fat_fd->info_ofs & (fs_info->fat.vol.bps - 1); + byte = fat_fd->dir_pos.sname.ofs & (fs_info->fat.vol.bps - 1); time_val = CT_LE_W(time_val); ret1 = _fat_block_write(mt_entry, sec, byte + MSDOS_FILE_WTIME_OFFSET, @@ -572,10 +728,10 @@ msdos_set_first_cluster_num( * calculate input for _fat_block_write: convert (cluster num, offset) to * (sector num, new offset) */ - sec = fat_cluster_num_to_sector_num(mt_entry, fat_fd->info_cln); - sec += (fat_fd->info_ofs >> fs_info->fat.vol.sec_log2); + sec = fat_cluster_num_to_sector_num(mt_entry, fat_fd->dir_pos.sname.cln); + sec += (fat_fd->dir_pos.sname.ofs >> fs_info->fat.vol.sec_log2); /* byte from points to start of 32bytes structure */ - byte = fat_fd->info_ofs & (fs_info->fat.vol.bps - 1); + byte = fat_fd->dir_pos.sname.ofs & (fs_info->fat.vol.bps - 1); le_cl_low = CT_LE_W((uint16_t )(new_cln & 0x0000FFFF)); ret1 = _fat_block_write(mt_entry, sec, @@ -615,9 +771,9 @@ msdos_set_file_size( uint32_t sec = 0; uint32_t byte = 0; - sec = fat_cluster_num_to_sector_num(mt_entry, fat_fd->info_cln); - sec += (fat_fd->info_ofs >> fs_info->fat.vol.sec_log2); - byte = (fat_fd->info_ofs & (fs_info->fat.vol.bps - 1)); + sec = fat_cluster_num_to_sector_num(mt_entry, fat_fd->dir_pos.sname.cln); + sec += (fat_fd->dir_pos.sname.ofs >> fs_info->fat.vol.sec_log2); + byte = (fat_fd->dir_pos.sname.ofs & (fs_info->fat.vol.bps - 1)); le_new_length = CT_LE_L((fat_fd->fat_file_size)); ret = _fat_block_write(mt_entry, sec, byte + MSDOS_FILE_SIZE_OFFSET, 4, @@ -650,25 +806,58 @@ msdos_set_file_size( int msdos_set_first_char4file_name( rtems_filesystem_mount_table_entry_t *mt_entry, - uint32_t cl, - uint32_t ofs, + fat_dir_pos_t *dir_pos, unsigned char fchar ) { - ssize_t ret = 0; + ssize_t ret; msdos_fs_info_t *fs_info = mt_entry->fs_info; - uint32_t sec = 0; - uint32_t byte = 0; + uint32_t dir_block_size; + fat_pos_t start = dir_pos->lname; + fat_pos_t end = dir_pos->sname; - sec = fat_cluster_num_to_sector_num(mt_entry, cl); - sec += (ofs >> fs_info->fat.vol.sec_log2); - byte = (ofs & (fs_info->fat.vol.bps - 1)); + if ((end.cln == fs_info->fat.vol.rdir_cl) && + (fs_info->fat.vol.type & (FAT_FAT12 | FAT_FAT16))) + dir_block_size = fs_info->fat.vol.rdir_size; + else + dir_block_size = fs_info->fat.vol.bpc; + + if (dir_pos->lname.cln == FAT_FILE_SHORT_NAME) + start = dir_pos->sname; - ret = _fat_block_write(mt_entry, sec, byte + MSDOS_FILE_NAME_OFFSET, 1, - &fchar); - if ( ret < 0) + /* + * We handle the changes directly due the way the short file + * name code was written rather than use the fat_file_write + * interface. + */ + while (true) + { + uint32_t sec = (fat_cluster_num_to_sector_num(mt_entry, start.cln) + + (start.ofs >> fs_info->fat.vol.sec_log2)); + uint32_t byte = (start.ofs & (fs_info->fat.vol.bps - 1));; + + ret = _fat_block_write(mt_entry, sec, byte + MSDOS_FILE_NAME_OFFSET, 1, + &fchar); + if (ret < 0) return -1; + if ((start.cln == end.cln) && (start.ofs == end.ofs)) + break; + + start.ofs += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE; + if (start.ofs >= dir_block_size) + { + int rc; + if ((end.cln == fs_info->fat.vol.rdir_cl) && + (fs_info->fat.vol.type & (FAT_FAT12 | FAT_FAT16))) + break; + rc = fat_get_fat_cluster(mt_entry, start.cln, &start.cln); + if ( rc != RC_OK ) + return rc; + start.ofs = 0; + } + } + return RC_OK; } @@ -713,21 +902,39 @@ msdos_dir_is_empty( i < fs_info->fat.vol.bps; i += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE) { - if (((*(uint8_t *)MSDOS_DIR_NAME(fs_info->cl_buf + i)) == + char* entry = (char*) fs_info->cl_buf + i; + + /* + * If the entry is empty, a long file name entry, or '.' or '..' + * then consider it as empty. + * + * Just ignore long file name entries. They must have a short entry to + * be valid. + */ + if (((*MSDOS_DIR_ENTRY_TYPE(entry)) == MSDOS_THIS_DIR_ENTRY_EMPTY) || - (strncmp(MSDOS_DIR_NAME((fs_info->cl_buf + i)), MSDOS_DOT_NAME, + ((*MSDOS_DIR_ATTR(entry) & MSDOS_ATTR_LFN_MASK) == + MSDOS_ATTR_LFN) || + (strncmp(MSDOS_DIR_NAME((entry)), MSDOS_DOT_NAME, MSDOS_SHORT_NAME_LEN) == 0) || - (strncmp(MSDOS_DIR_NAME((fs_info->cl_buf + i)), + (strncmp(MSDOS_DIR_NAME((entry)), MSDOS_DOTDOT_NAME, MSDOS_SHORT_NAME_LEN) == 0)) continue; - if ((*MSDOS_DIR_NAME(fs_info->cl_buf + i)) == + /* + * Nothing more to look at. + */ + if ((*MSDOS_DIR_NAME(entry)) == MSDOS_THIS_DIR_ENTRY_AND_REST_EMPTY) { *ret_val = true; return RC_OK; } + + /* + * Short file name entries mean not empty. + */ return RC_OK; } j++; @@ -736,20 +943,15 @@ msdos_dir_is_empty( return RC_OK; } - -/* msdos_find_name_in_fat_file -- - * This routine is used in two ways: for a new mode creation (a) or for - * search the node which correspondes to the 'name' parameter (b). - * In case (a) name should be set up to NULL and 'name_dir_entry' should - * point to initialized 32 bytes structure described a new node. - * In case (b) 'name' should contain a valid string. +/* msdos_create_name_in_fat_file -- + * This routine creates an entry in the fat file for the file name + * provided by the user. The directory entry passed is the short + * file name and is added as it. If the file name is long a long + * file name set of entries is added. * - * (a): reading fat-file corresponded to directory we are going to create - * node in. If found free slot write contents of name_dir_entry into - * it. - * - * (b): reading fat-file corresponded to directory and trying to find slot - * with the name field == name parameter + * Scan the directory for the file and if not found add the new entry. + * When scanning remember the offset in the file where the directory + * entry can be added. * * PARAMETERS: * mt_entry - mount table entry @@ -764,111 +966,610 @@ msdos_dir_is_empty( * appropriately) * */ +#define MSDOS_FIND_PRINT 0 int msdos_find_name_in_fat_file( rtems_filesystem_mount_table_entry_t *mt_entry, fat_file_fd_t *fat_fd, - char *name, - fat_auxiliary_t *paux, + bool create_node, + const char *name, + int name_len, + msdos_name_type_t name_type, + fat_dir_pos_t *dir_pos, char *name_dir_entry - ) + ) { - int rc = RC_OK; ssize_t ret = 0; msdos_fs_info_t *fs_info = mt_entry->fs_info; - uint32_t i = 0, j = 0; + uint32_t dir_offset = 0; + uint32_t dir_entry = 0; uint32_t bts2rd = 0; - + fat_pos_t lfn_start; + bool lfn_matched = false; + uint8_t lfn_checksum = 0; + int lfn_entries = 0; + int lfn_entry = 0; + uint32_t empty_space_offset = 0; + uint32_t empty_space_entry = 0; + uint32_t empty_space_count = 0; + bool empty_space_found = false; + uint32_t entries_per_block; + bool read_cluster = false; + + assert(name_len > 0); + + fat_dir_pos_init(dir_pos); + + lfn_start.cln = lfn_start.ofs = FAT_FILE_SHORT_NAME; + + /* + * If the file name is long how many short directory + * entries are needed ? + */ + if (name_type == MSDOS_NAME_LONG) + lfn_entries = ((name_len - 1) + MSDOS_LFN_LEN_PER_ENTRY) / MSDOS_LFN_LEN_PER_ENTRY; + if (FAT_FD_OF_ROOT_DIR(fat_fd) && - (fs_info->fat.vol.type & (FAT_FAT12 | FAT_FAT16))) + (fs_info->fat.vol.type & (FAT_FAT12 | FAT_FAT16))) bts2rd = fat_fd->fat_file_size; else bts2rd = fs_info->fat.vol.bpc; - while ((ret = fat_file_read(mt_entry, fat_fd, (j * bts2rd), bts2rd, - fs_info->cl_buf)) != FAT_EOF) + entries_per_block = bts2rd / MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE; + +#if MSDOS_FIND_PRINT + printf ("MSFS:[1] cn:%i ebp:%li bts2rd:%li lfne:%d nl:%i n:%s\n", + create_node, entries_per_block, bts2rd, lfn_entries, name_len, name); +#endif + /* + * Scan the directory seeing if the file is present. While + * doing this see if a suitable location can be found to + * create the entry if the name is not found. + */ + while ((ret = fat_file_read(mt_entry, fat_fd, (dir_offset * bts2rd), + bts2rd, fs_info->cl_buf)) != FAT_EOF) { + bool remainder_empty = false; +#if MSDOS_FIND_PRINT + printf ("MSFS:[2] dir_offset:%li\n", dir_offset); +#endif + if (ret < MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE) rtems_set_errno_and_return_minus_one(EIO); assert(ret == bts2rd); /* have to look at the DIR_NAME as "raw" 8-bit data */ - for (i = 0; i < bts2rd; i += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE) + for (dir_entry = 0; + dir_entry < bts2rd; + dir_entry += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE) { - /* is the entry empty ? */ - if (((*(uint8_t *)MSDOS_DIR_NAME(fs_info->cl_buf + i)) == - MSDOS_THIS_DIR_ENTRY_AND_REST_EMPTY) || - ((*(uint8_t *)MSDOS_DIR_NAME(fs_info->cl_buf + i)) == - MSDOS_THIS_DIR_ENTRY_EMPTY)) + char* entry = (char*) fs_info->cl_buf + dir_entry; + + /* + * See if the entry is empty or the remainder of the directory is + * empty ? Localise to make the code read better. + */ + bool entry_empty = (*MSDOS_DIR_ENTRY_TYPE(entry) == + MSDOS_THIS_DIR_ENTRY_EMPTY); + remainder_empty = (*MSDOS_DIR_ENTRY_TYPE(entry) == + MSDOS_THIS_DIR_ENTRY_AND_REST_EMPTY); +#if MSDOS_FIND_PRINT + printf ("MSFS:[3] re:%i ee:%i do:%li de:%li(%ld)\n", + remainder_empty, entry_empty, dir_offset, + dir_entry, (dir_entry / MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)); +#endif + /* + * Remember where the we are, ie the start, so we can come back + * to here and write the long file name if this is the start of + * a series of empty entries. If empty_space_count is 0 then + * we are currently not inside an empty series of entries. It + * is a count of empty entries. + */ + if (empty_space_count == 0) { - /* whether we are looking for an empty entry */ - if (name == NULL) - { - /* get current cluster number */ - rc = fat_file_ioctl(mt_entry, fat_fd, F_CLU_NUM, - j * bts2rd, &paux->cln); - if (rc != RC_OK) - return rc; - - /* offset is computed in bytes */ - paux->ofs = i; - - /* write new node entry */ - ret = fat_file_write(mt_entry, fat_fd, j * bts2rd + i, - MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE, - (uint8_t *)name_dir_entry); - if (ret != MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE) - return -1; - - /* - * we don't update fat_file_size here - it should not - * increase - */ - return RC_OK; - } + empty_space_entry = dir_entry; + empty_space_offset = dir_offset; + } + if (remainder_empty) + { +#if MSDOS_FIND_PRINT + printf ("MSFS:[3.1] cn:%i esf:%i\n", create_node, empty_space_found); +#endif /* - * if name != NULL and there is no more entries in the + * If just looking and there is no more entries in the * directory - return name-not-found */ - if (((*MSDOS_DIR_NAME(fs_info->cl_buf + i)) == - MSDOS_THIS_DIR_ENTRY_AND_REST_EMPTY)) + if (!create_node) return MSDOS_NAME_NOT_FOUND_ERR; + + /* + * Lets go and write the directory entries. If we have not found + * any available space add the remaining number of entries to any that + * we may have already found that are just before this entry. If more + * are needed FAT_EOF is returned by the read and we extend the file. + */ + if (!empty_space_found) + { + empty_space_count += + entries_per_block - (dir_entry / MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE); + empty_space_found = true; +#if MSDOS_FIND_PRINT + printf ("MSFS:[3.2] esf:%i esc%i\n", empty_space_found, empty_space_count); +#endif + } + break; + } + else if (entry_empty) + { + if (create_node) + { + /* + * Remainder is not empty so is this entry empty ? + */ + empty_space_count++; + + if (empty_space_count == (lfn_entries + 1)) + empty_space_found = true; + } +#if MSDOS_FIND_PRINT + printf ("MSFS:[4.1] esc:%li esf:%i\n", + empty_space_count, empty_space_found); +#endif } else { - /* entry not empty and name != NULL -> compare names */ - if (name != NULL) + /* + * A valid entry so handle it. + * + * If empty space has not been found we need to start the + * count again. + */ + if (create_node && !empty_space_found) + { + empty_space_entry = 0; + empty_space_count = 0; + } + + /* + * Check the attribute to see if the entry is for a long + * file name. + */ + if ((*MSDOS_DIR_ATTR(entry) & MSDOS_ATTR_LFN_MASK) == + MSDOS_ATTR_LFN) { - if (strncmp(MSDOS_DIR_NAME((fs_info->cl_buf + i)), name, - MSDOS_SHORT_NAME_LEN) == 0) + char* p; + int o; + int i; +#if MSDOS_FIND_PRINT + printf ("MSFS:[4.2] lfn:%c entry:%i checksum:%i\n", + lfn_start.cln == FAT_FILE_SHORT_NAME ? 't' : 'f', + *MSDOS_DIR_ENTRY_TYPE(entry) & MSDOS_LAST_LONG_ENTRY_MASK, + *MSDOS_DIR_LFN_CHECKSUM(entry)); +#endif + /* + * If we are not already processing a LFN see if this is + * the first entry of a LFN ? + */ + if (lfn_start.cln == FAT_FILE_SHORT_NAME) { + lfn_matched = false; + + /* + * The first entry must have the last long entry + * flag set. + */ + if ((*MSDOS_DIR_ENTRY_TYPE(entry) & + MSDOS_LAST_LONG_ENTRY) == 0) + continue; + + /* + * Does the number of entries in the LFN directory + * entry match the number we expect for this + * file name. Note we do not know the number of + * characters in the entry so this is check further + * on when the characters are checked. + */ + if (lfn_entries != (*MSDOS_DIR_ENTRY_TYPE(entry) & + MSDOS_LAST_LONG_ENTRY_MASK)) + continue; + /* - * we get the entry we looked for - fill auxiliary - * structure and copy all 32 bytes of the entry + * Get the checksum of the short entry. */ - rc = fat_file_ioctl(mt_entry, fat_fd, F_CLU_NUM, - j * bts2rd, &paux->cln); + lfn_start.cln = dir_offset; + lfn_start.ofs = dir_entry; + lfn_entry = lfn_entries; + lfn_checksum = *MSDOS_DIR_LFN_CHECKSUM(entry); + +#if MSDOS_FIND_PRINT + printf ("MSFS:[4.3] lfn_checksum:%i\n", + *MSDOS_DIR_LFN_CHECKSUM(entry)); +#endif + } + + /* + * If the entry number or the check sum do not match + * forget this series of long directory entries. These + * could be orphaned entries depending on the history + * of the disk. + */ + if ((lfn_entry != (*MSDOS_DIR_ENTRY_TYPE(entry) & + MSDOS_LAST_LONG_ENTRY_MASK)) || + (lfn_checksum != *MSDOS_DIR_LFN_CHECKSUM(entry))) + { +#if MSDOS_FIND_PRINT + printf ("MSFS:[4.4] no match\n"); +#endif + lfn_start.cln = FAT_FILE_SHORT_NAME; + continue; + } + + lfn_entry--; + o = lfn_entry * MSDOS_LFN_LEN_PER_ENTRY; + p = entry + 1; + +#if MSDOS_FIND_PRINT + printf ("MSFS:[5] lfne:%i\n", lfn_entry); +#endif + for (i = 0; i < MSDOS_LFN_LEN_PER_ENTRY; i++) + { +#if MSDOS_FIND_PRINT > 1 + printf ("MSFS:[6] o:%i i:%i *p:%c(%02x) name[o + i]:%c(%02x)\n", + o, i, *p, *p, name[o + i], name[o + i]); +#endif + if (*p == '\0') + { + /* + * If this is the first entry, ie the last part of the + * long file name and the length does not match then + * the file names do not match. + */ + if (((lfn_entry + 1) == lfn_entries) && + ((o + i) != name_len)) + lfn_start.cln = FAT_FILE_SHORT_NAME; + break; + } + + if (((o + i) >= name_len) || (*p != name[o + i])) + { + lfn_start.cln = FAT_FILE_SHORT_NAME; + break; + } + + switch (i) + { + case 4: + p += 5; + break; + case 10: + p += 4; + break; + default: + p += 2; + break; + } + } + + lfn_matched = ((lfn_entry == 0) && + (lfn_start.cln != FAT_FILE_SHORT_NAME)); + +#if MSDOS_FIND_PRINT + printf ("MSFS:[8.1] lfn_matched:%i\n", lfn_matched); +#endif + } + else + { + /* + * SFN entry found. + * + * If a LFN has been found and it matched check the + * entries have all been found and the checksum is + * correct. If this is the case return the short file + * name entry. + */ + if (lfn_matched) + { + uint8_t cs = 0; + uint8_t* p = (uint8_t*) MSDOS_DIR_NAME(entry); + int i; + + for (i = 0; i < MSDOS_SHORT_NAME_LEN; i++, p++) + cs = ((cs & 1) ? 0x80 : 0) + (cs >> 1) + *p; + + if (lfn_entry || (lfn_checksum != cs)) + lfn_matched = false; + } + + /* + * If the long file names matched or the file name is + * short and they match then we have the entry. We will not + * match a long file name against a short file name because + * a long file name that generates a matching short file + * name is not a long file name. + */ + if (lfn_matched || + ((name_type == MSDOS_NAME_SHORT) && + (lfn_start.cln == FAT_FILE_SHORT_NAME) && + (memcmp(MSDOS_DIR_NAME(entry), + MSDOS_DIR_NAME(name_dir_entry), + MSDOS_SHORT_NAME_LEN) == 0))) + { + /* + * We get the entry we looked for - fill the position + * structure and the 32 bytes of the short entry + */ + int rc = fat_file_ioctl(mt_entry, fat_fd, F_CLU_NUM, + dir_offset * bts2rd, + &dir_pos->sname.cln); if (rc != RC_OK) return rc; - /* offset is computed in bytes */ - paux->ofs = i; - memcpy(name_dir_entry,(fs_info->cl_buf + i), + dir_pos->sname.ofs = dir_entry; + + if (lfn_start.cln != FAT_FILE_SHORT_NAME) + { + rc = fat_file_ioctl(mt_entry, fat_fd, F_CLU_NUM, + lfn_start.cln * bts2rd, + &lfn_start.cln); + if (rc != RC_OK) + return rc; + } + + dir_pos->lname.cln = lfn_start.cln; + dir_pos->lname.ofs = lfn_start.ofs; + + memcpy(name_dir_entry, entry, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE); return RC_OK; } + + lfn_start.cln = FAT_FILE_SHORT_NAME; + lfn_matched = false; } } } - j++; + + if (remainder_empty) + break; + + dir_offset++; } - return MSDOS_NAME_NOT_FOUND_ERR; + + /* + * If we are not to create the entry return a not found error. + */ + if (!create_node) + return MSDOS_NAME_NOT_FOUND_ERR; + +#if MSDOS_FIND_PRINT + printf ("MSFS:[8.1] WRITE do:%ld esc:%ld eso:%ld ese:%ld\n", + dir_offset, empty_space_count, empty_space_offset, empty_space_entry); +#endif + + /* + * If a long file name calculate the checksum of the short file name + * data to place in each long file name entry. First set the short + * file name to the slot of the SFN entry. This will mean no clashes + * in this directory. + */ + lfn_checksum = 0; + if (name_type == MSDOS_NAME_LONG) + { + uint8_t* p = (uint8_t*) MSDOS_DIR_NAME(name_dir_entry); + int i; + int slot = (((empty_space_offset * bts2rd) + empty_space_entry) / + MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE) + lfn_entries + 1; + + msdos_short_name_hex(MSDOS_DIR_NAME(name_dir_entry), slot); + + for (i = 0; i < 11; i++, p++) + lfn_checksum = + ((lfn_checksum & 1) ? 0x80 : 0) + (lfn_checksum >> 1) + *p; + } + + /* + * If there is no space available then extend the file. The + * empty_space_count is a count of empty entries in the currently + * read cluster so if 0 there is no space. Note, dir_offset will + * be at the next cluster so we can just make empty_space_offset + * that value. + */ + if (empty_space_count == 0) + { + read_cluster = true; + empty_space_offset = dir_offset; + empty_space_entry = 0; + } + + /* + * Have we read past the empty block ? If so go back and read it again. + */ + if (dir_offset != empty_space_offset) + read_cluster = true; + + /* + * Handle the entry writes. + */ + lfn_start.cln = lfn_start.ofs = FAT_FILE_SHORT_NAME; + lfn_entry = 0; + +#if MSDOS_FIND_PRINT + printf ("MSFS:[9] read_cluster:%d eso:%ld ese:%ld\n", + read_cluster, empty_space_offset, empty_space_entry); +#endif + + /* + * The one more is the short entry. + */ + while (lfn_entry < (lfn_entries + 1)) + { + int length = 0; + + if (read_cluster) + { + uint32_t new_length; +#if MSDOS_FIND_PRINT + printf ("MSFS:[9.1] eso:%li\n", empty_space_offset); +#endif + ret = fat_file_read(mt_entry, fat_fd, + (empty_space_offset * bts2rd), bts2rd, + fs_info->cl_buf); + + if (ret != bts2rd) + { + if (ret != FAT_EOF) + rtems_set_errno_and_return_minus_one(EIO); + +#if MSDOS_FIND_PRINT + printf ("MSFS:[9.2] extending file:%li\n", empty_space_offset); +#endif + ret = fat_file_extend (mt_entry, fat_fd, empty_space_offset * bts2rd, + &new_length); + + if (ret != RC_OK) + return ret; + +#if MSDOS_FIND_PRINT + printf ("MSFS:[9.3] extended: %d <-> %d\n", new_length, empty_space_offset * bts2rd); +#endif + if (new_length != (empty_space_offset * bts2rd)) + rtems_set_errno_and_return_minus_one(EIO); + + memset(fs_info->cl_buf, 0, bts2rd); + + ret = fat_file_write(mt_entry, fat_fd, + empty_space_offset * bts2rd, + bts2rd, fs_info->cl_buf); +#if MSDOS_FIND_PRINT + printf ("MSFS:[9.4] clear write: %d\n", ret); +#endif + if (ret != bts2rd) + rtems_set_errno_and_return_minus_one(EIO); + } + } + +#if MSDOS_FIND_PRINT + printf ("MSFS:[10] eso:%li\n", empty_space_offset); +#endif + + for (dir_entry = empty_space_entry; + dir_entry < bts2rd; + dir_entry += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE) + { + char* entry = (char*) fs_info->cl_buf + dir_entry; + char* p; + const char* n; + int i; + + length += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE; + lfn_entry++; + +#if MSDOS_FIND_PRINT + printf ("MSFS:[10] de:%li(%li) length:%i lfn_entry:%i\n", + dir_entry, (dir_entry / MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE), + length, lfn_entry); +#endif + /* + * Time to write the short file name entry. + */ + if (lfn_entry == (lfn_entries + 1)) + { + /* get current cluster number */ + int rc = fat_file_ioctl(mt_entry, fat_fd, F_CLU_NUM, + empty_space_offset * bts2rd, + &dir_pos->sname.cln); + if (rc != RC_OK) + return rc; + + dir_pos->sname.ofs = dir_entry; + + if (lfn_start.cln != FAT_FILE_SHORT_NAME) + { + rc = fat_file_ioctl(mt_entry, fat_fd, F_CLU_NUM, + lfn_start.cln * bts2rd, + &lfn_start.cln); + if (rc != RC_OK) + return rc; + } + + dir_pos->lname.cln = lfn_start.cln; + dir_pos->lname.ofs = lfn_start.ofs; + + /* write new node entry */ + memcpy (entry, (uint8_t *) name_dir_entry, + MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE); + break; + } + + /* + * This is a long file name and we need to write + * a long file name entry. See if this is the + * first entry written and if so remember the + * the location of the long file name. + */ + if (lfn_start.cln == FAT_FILE_SHORT_NAME) + { + lfn_start.cln = empty_space_offset; + lfn_start.ofs = dir_entry; + } + + /* + * Clear the entry before loading the data. + */ + memset (entry, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE); + + *MSDOS_DIR_LFN_CHECKSUM(entry) = lfn_checksum; + + p = entry + 1; + n = name + (lfn_entries - lfn_entry) * MSDOS_LFN_LEN_PER_ENTRY; + + for (i = 0; i < MSDOS_LFN_LEN_PER_ENTRY; i++) + { + *p = *n; + if (*n != 0) + n++; + + switch (i) + { + case 4: + p += 5; + break; + case 10: + p += 4; + break; + default: + p += 2; + break; + } + } + + *MSDOS_DIR_ENTRY_TYPE(entry) = (lfn_entries - lfn_entry) + 1; + if (lfn_entry == 1) + *MSDOS_DIR_ENTRY_TYPE(entry) |= MSDOS_LAST_LONG_ENTRY; + *MSDOS_DIR_ATTR(entry) |= MSDOS_ATTR_LFN; + } + + ret = fat_file_write(mt_entry, fat_fd, + (empty_space_offset * bts2rd) + empty_space_entry, + length, fs_info->cl_buf + empty_space_entry); + if (ret != length) + rtems_set_errno_and_return_minus_one(EIO); + + empty_space_offset++; + empty_space_entry = 0; + read_cluster = true; + } + + return 0; } /* msdos_find_node_by_cluster_num_in_fat_file -- * Find node with specified number of cluster in fat-file. * + * Note, not updated in the LFN change because it is only used + * for . and .. entries and these are always short. + * * PARAMETERS: * mt_entry - mount table entry * fat_fd - fat-file descriptor @@ -885,7 +1586,7 @@ int msdos_find_node_by_cluster_num_in_fat_file( rtems_filesystem_mount_table_entry_t *mt_entry, fat_file_fd_t *fat_fd, uint32_t cl4find, - fat_auxiliary_t *paux, + fat_dir_pos_t *dir_pos, char *dir_entry ) { @@ -911,28 +1612,32 @@ int msdos_find_node_by_cluster_num_in_fat_file( for (i = 0; i < bts2rd; i += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE) { + char* entry = (char*) fs_info->cl_buf + i; + /* if this and all rest entries are empty - return not-found */ - if ((*MSDOS_DIR_NAME(fs_info->cl_buf + i)) == + if ((*MSDOS_DIR_ENTRY_TYPE(entry)) == MSDOS_THIS_DIR_ENTRY_AND_REST_EMPTY) return MSDOS_NAME_NOT_FOUND_ERR; - /* have to look at the DIR_NAME as "raw" 8-bit data */ /* if this entry is empty - skip it */ - if ((*(uint8_t *)MSDOS_DIR_NAME(fs_info->cl_buf + i)) == + if ((*MSDOS_DIR_ENTRY_TYPE(entry)) == MSDOS_THIS_DIR_ENTRY_EMPTY) continue; /* if get a non-empty entry - compare clusters num */ - if (MSDOS_EXTRACT_CLUSTER_NUM((fs_info->cl_buf + i)) == cl4find) + if (MSDOS_EXTRACT_CLUSTER_NUM(entry) == cl4find) { /* on success fill aux structure and copy all 32 bytes */ rc = fat_file_ioctl(mt_entry, fat_fd, F_CLU_NUM, j * bts2rd, - &paux->cln); + &dir_pos->sname.cln); if (rc != RC_OK) return rc; - paux->ofs = i; - memcpy(dir_entry, fs_info->cl_buf + i, + dir_pos->sname.ofs = i; + dir_pos->lname.cln = FAT_FILE_SHORT_NAME; + dir_pos->lname.ofs = FAT_FILE_SHORT_NAME; + + memcpy(dir_entry, entry, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE); return RC_OK; } diff --git a/cpukit/libfs/src/dosfs/msdos_mknod.c b/cpukit/libfs/src/dosfs/msdos_mknod.c index ac2a142cce..421d873136 100644 --- a/cpukit/libfs/src/dosfs/msdos_mknod.c +++ b/cpukit/libfs/src/dosfs/msdos_mknod.c @@ -36,7 +36,7 @@ * determines type of the node to be created and creates it. * * PARAMETERS: - * token - non-formatted name of a new node + * name - file name to create * mode - node type * dev - dev * pathloc - parent directory description @@ -46,7 +46,7 @@ * */ int msdos_mknod( - const char *token, + const char *name, mode_t mode, dev_t dev, rtems_filesystem_location_info_t *pathloc @@ -56,12 +56,7 @@ int msdos_mknod( rtems_status_code sc = RTEMS_SUCCESSFUL; msdos_fs_info_t *fs_info = pathloc->mt_entry->fs_info; msdos_token_types_t type = 0; - char new_name[ MSDOS_NAME_MAX + 1 ]; - int len; - - /* check spelling and format new node name */ - msdos_get_token(token, new_name, &len); - + /* * Figure out what type of msdos node this is. */ @@ -82,7 +77,7 @@ int msdos_mknod( rtems_set_errno_and_return_minus_one(EIO); /* Create an MSDOS node */ - rc = msdos_creat_node(pathloc, type, new_name, mode, NULL); + rc = msdos_creat_node(pathloc, type, name, strlen(name), mode, NULL); rtems_semaphore_release(fs_info->vol_sema); return rc; diff --git a/cpukit/libfs/src/imfs/deviceio.c b/cpukit/libfs/src/imfs/deviceio.c index 62b1381233..70cb936425 100644 --- a/cpukit/libfs/src/imfs/deviceio.c +++ b/cpukit/libfs/src/imfs/deviceio.c @@ -206,12 +206,14 @@ int device_ioctl( /* * device_lseek * - * This handler eats all lseek() operations. + * This handler eats all lseek() operations and does not create + * an error. It assumes all devices can handle the seek. The + * writes fail. */ -off_t device_lseek( +rtems_off64_t device_lseek( rtems_libio_t *iop, - off_t offset, + rtems_off64_t offset, int whence ) { @@ -232,7 +234,7 @@ off_t device_lseek( int device_ftruncate( rtems_libio_t *iop, - off_t length + rtems_off64_t length ) { return 0; diff --git a/cpukit/libfs/src/imfs/imfs.h b/cpukit/libfs/src/imfs/imfs.h index 808a6f0cb7..355e494248 100644 --- a/cpukit/libfs/src/imfs/imfs.h +++ b/cpukit/libfs/src/imfs/imfs.h @@ -98,15 +98,15 @@ typedef uint8_t *block_p; typedef block_p *block_ptr; typedef struct { - off_t size; /* size of file in bytes */ - block_ptr indirect; /* array of 128 data blocks pointers */ - block_ptr doubly_indirect; /* 128 indirect blocks */ - block_ptr triply_indirect; /* 128 doubly indirect blocks */ + rtems_off64_t size; /* size of file in bytes */ + block_ptr indirect; /* array of 128 data blocks pointers */ + block_ptr doubly_indirect; /* 128 indirect blocks */ + block_ptr triply_indirect; /* 128 doubly indirect blocks */ } IMFS_memfile_t; typedef struct { - off_t size; /* size of file in bytes */ - block_p direct; /* pointer to file image */ + rtems_off64_t size; /* size of file in bytes */ + block_p direct; /* pointer to file image */ } IMFS_linearfile_t; /* @@ -380,7 +380,7 @@ extern int IMFS_memfile_remove( extern int memfile_ftruncate( rtems_libio_t *iop, /* IN */ - off_t length /* IN */ + rtems_off64_t length /* IN */ ); extern int imfs_dir_open( @@ -400,9 +400,9 @@ extern ssize_t imfs_dir_read( size_t count /* IN */ ); -extern off_t imfs_dir_lseek( +extern rtems_off64_t imfs_dir_lseek( rtems_libio_t *iop, /* IN */ - off_t offset, /* IN */ + rtems_off64_t offset, /* IN */ int whence /* IN */ ); @@ -444,9 +444,9 @@ extern int memfile_ioctl( void *buffer /* IN */ ); -extern off_t memfile_lseek( +extern rtems_off64_t memfile_lseek( rtems_libio_t *iop, /* IN */ - off_t offset, /* IN */ + rtems_off64_t offset, /* IN */ int whence /* IN */ ); @@ -483,15 +483,15 @@ extern int device_ioctl( void *buffer /* IN */ ); -extern off_t device_lseek( +extern rtems_off64_t device_lseek( rtems_libio_t *iop, /* IN */ - off_t offset, /* IN */ + rtems_off64_t offset, /* IN */ int whence /* IN */ ); extern int device_ftruncate( rtems_libio_t *iop, /* IN */ - off_t length /* IN */ + rtems_off64_t length /* IN */ ); extern int IMFS_utime( diff --git a/cpukit/libfs/src/imfs/imfs_directory.c b/cpukit/libfs/src/imfs/imfs_directory.c index 519d534fe0..1107da9221 100644 --- a/cpukit/libfs/src/imfs/imfs_directory.c +++ b/cpukit/libfs/src/imfs/imfs_directory.c @@ -182,9 +182,9 @@ int imfs_dir_close( * SEEK_END - N/A --> This will cause an assert. */ -off_t imfs_dir_lseek( +rtems_off64_t imfs_dir_lseek( rtems_libio_t *iop, - off_t offset, + rtems_off64_t offset, int whence ) { diff --git a/cpukit/libfs/src/imfs/imfs_fifo.c b/cpukit/libfs/src/imfs/imfs_fifo.c index 5d3cf466c6..f02cfd31c6 100644 --- a/cpukit/libfs/src/imfs/imfs_fifo.c +++ b/cpukit/libfs/src/imfs/imfs_fifo.c @@ -119,10 +119,10 @@ int IMFS_fifo_ioctl( IMFS_FIFO_RETURN(err); } -off_t IMFS_fifo_lseek( +rtems_off64_t IMFS_fifo_lseek( rtems_libio_t *iop, - off_t offset, - int whence + rtems_off64_t offset, + int whence ) { off_t err = pipe_lseek(LIBIO2PIPE(iop), offset, whence, iop); diff --git a/cpukit/libfs/src/imfs/memfile.c b/cpukit/libfs/src/imfs/memfile.c index 51ad8669bb..e9b4d70f97 100644 --- a/cpukit/libfs/src/imfs/memfile.c +++ b/cpukit/libfs/src/imfs/memfile.c @@ -214,9 +214,9 @@ int memfile_ioctl( * This routine processes the lseek() system call. */ -off_t memfile_lseek( +rtems_off64_t memfile_lseek( rtems_libio_t *iop, - off_t offset, + rtems_off64_t offset, int whence ) { @@ -251,7 +251,7 @@ off_t memfile_lseek( int memfile_ftruncate( rtems_libio_t *iop, - off_t length + rtems_off64_t length ) { IMFS_jnode_t *the_jnode; diff --git a/cpukit/libfs/src/nfsclient/src/nfs.c b/cpukit/libfs/src/nfsclient/src/nfs.c index 78c592a363..daafac8c87 100644 --- a/cpukit/libfs/src/nfsclient/src/nfs.c +++ b/cpukit/libfs/src/nfsclient/src/nfs.c @@ -2737,9 +2737,9 @@ static int nfs_file_ioctl( #define nfs_link_ioctl 0 #endif -static off_t nfs_file_lseek( +static rtems_off64_t nfs_file_lseek( rtems_libio_t *iop, - off_t length, + rtems_off64_t length, int whence ) { @@ -2770,9 +2770,9 @@ static off_t nfs_file_lseek( return iop->offset; } -static off_t nfs_dir_lseek( +static rtems_off64_t nfs_dir_lseek( rtems_libio_t *iop, - off_t length, + rtems_off64_t length, int whence ) { @@ -2818,29 +2818,29 @@ struct fattr { struct stat { - dev_t st_dev; - ino_t st_ino; - mode_t st_mode; - nlink_t st_nlink; - uid_t st_uid; - gid_t st_gid; - dev_t st_rdev; - off_t st_size; + dev_t st_dev; + ino_t st_ino; + mode_t st_mode; + nlink_t st_nlink; + uid_t st_uid; + gid_t st_gid; + dev_t st_rdev; + rtems_off64_t st_size; /* SysV/sco doesn't have the rest... But Solaris, eabi does. */ #if defined(__svr4__) && !defined(__PPC__) && !defined(__sun__) - time_t st_atime; - time_t st_mtime; - time_t st_ctime; + time_t st_atime; + time_t st_mtime; + time_t st_ctime; #else - time_t st_atime; - long st_spare1; - time_t st_mtime; - long st_spare2; - time_t st_ctime; - long st_spare3; - long st_blksize; - long st_blocks; - long st_spare4[2]; + time_t st_atime; + long st_spare1; + time_t st_mtime; + long st_spare2; + time_t st_ctime; + long st_spare3; + long st_blksize; + long st_blocks; + long st_spare4[2]; #endif }; #endif @@ -3009,7 +3009,7 @@ sattr arg; */ static int nfs_file_ftruncate( rtems_libio_t *iop, - off_t length + rtems_off64_t length ) { sattr arg; |