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/src/dosfs/msdos_dir.c | |
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/src/dosfs/msdos_dir.c')
-rw-r--r-- | cpukit/libfs/src/dosfs/msdos_dir.c | 282 |
1 files changed, 217 insertions, 65 deletions
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) { |