summaryrefslogtreecommitdiffstats
path: root/c/src/libfs/src/dosfs/msdos_misc.c
diff options
context:
space:
mode:
Diffstat (limited to 'c/src/libfs/src/dosfs/msdos_misc.c')
-rw-r--r--c/src/libfs/src/dosfs/msdos_misc.c1087
1 files changed, 1087 insertions, 0 deletions
diff --git a/c/src/libfs/src/dosfs/msdos_misc.c b/c/src/libfs/src/dosfs/msdos_misc.c
new file mode 100644
index 0000000000..fe2779f7a8
--- /dev/null
+++ b/c/src/libfs/src/dosfs/msdos_misc.c
@@ -0,0 +1,1087 @@
+/*
+ * Miscellaneous routines implementation for MSDOS filesystem
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * @(#) $Id$
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <string.h>
+#include <assert.h>
+#include <rtems/libio_.h>
+
+#include "fat.h"
+#include "fat_fat_operations.h"
+#include "fat_file.h"
+
+#include "msdos.h"
+
+/* This copied from Linux */
+static int day_n[] = { 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0,0 };
+ /* JanFebMarApr May Jun Jul Aug Sep Oct Nov Dec */
+
+#undef CONFIG_ATARI
+
+/* MS-DOS "device special files" */
+static const char *reserved_names[] = {
+#ifndef CONFIG_ATARI /* GEMDOS is less stupid */
+ "CON ","PRN ","NUL ","AUX ",
+ "LPT1 ","LPT2 ","LPT3 ","LPT4 ",
+ "COM1 ","COM2 ","COM3 ","COM4 ",
+#endif
+ NULL };
+
+static char bad_chars[] = "*?<>|\"";
+#ifdef CONFIG_ATARI
+/* GEMDOS is less restrictive */
+static char bad_if_strict[] = " ";
+#else
+static char bad_if_strict[] = "+=,; ";
+#endif
+
+/* The following three functions copied from Linux */
+/*
+ * Formats an MS-DOS file name. Rejects invalid names
+ *
+ * conv is relaxed/normal/strict, name is proposed name,
+ * len is the length of the proposed name, res is the result name,
+ * dotsOK is if hidden files get dots.
+ */
+int
+msdos_format_name(char conv, const char *name, int len, char *res,
+ char dotsOK)
+{
+ char *walk;
+ const char **reserved;
+ unsigned char c;
+ int space;
+ if (name[0] == '.') { /* dotfile because . and .. already done */
+ if (!dotsOK) return -EINVAL;
+ /* Get rid of dot - test for it elsewhere */
+ name++; len--;
+ }
+#ifndef CONFIG_ATARI
+ space = 1; /* disallow names that _really_ start with a dot */
+#else
+ space = 0; /* GEMDOS does not care */
+#endif
+ c = 0;
+ for (walk = res; len && walk-res < 8; walk++) {
+ c = *name++;
+ len--;
+ if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL;
+ if (conv == 's' && strchr(bad_if_strict,c)) return -EINVAL;
+ if (c >= 'A' && c <= 'Z' && conv == 's') return -EINVAL;
+ if (c < ' ' || c == ':' || c == '\\') return -EINVAL;
+/* 0xE5 is legal as a first character, but we must substitute 0x05 */
+/* because 0xE5 marks deleted files. Yes, DOS really does this. */
+/* It seems that Microsoft hacked DOS to support non-US characters */
+/* after the 0xE5 character was already in use to mark deleted files. */
+ if((res==walk) && (c==0xE5)) c=0x05;
+ if (c == '.') break;
+ space = (c == ' ');
+ *walk = (c >= 'a' && c <= 'z') ? c-32 : c;
+ }
+ if (space) return -EINVAL;
+ if (conv == 's' && len && c != '.') {
+ c = *name++;
+ len--;
+ if (c != '.') return -EINVAL;
+ }
+ while (c != '.' && len--) c = *name++;
+ if (c == '.') {
+ while (walk-res < 8) *walk++ = ' ';
+ while (len > 0 && walk-res < MSDOS_NAME_MAX) {
+ c = *name++;
+ len--;
+ if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL;
+ if (conv == 's' && strchr(bad_if_strict,c))
+ return -EINVAL;
+ if (c < ' ' || c == ':' || c == '\\')
+ return -EINVAL;
+ if (c == '.') {
+ if (conv == 's')
+ return -EINVAL;
+ break;
+ }
+ if (c >= 'A' && c <= 'Z' && conv == 's') return -EINVAL;
+ space = c == ' ';
+ *walk++ = c >= 'a' && c <= 'z' ? c-32 : c;
+ }
+ if (space) return -EINVAL;
+ if (conv == 's' && len) return -EINVAL;
+ }
+ while (walk-res < MSDOS_NAME_MAX) *walk++ = ' ';
+ for (reserved = reserved_names; *reserved; reserved++)
+ if (!strncmp(res,*reserved,8)) return -EINVAL;
+ return 0;
+}
+
+/* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70) */
+unsigned int
+msdos_date_dos2unix(unsigned short time_val,unsigned short date)
+{
+ int month,year,secs;
+
+ month = ((date >> 5) & 15)-1;
+ year = date >> 9;
+ secs = (time_val & 31)*2+60*((time_val >> 5) & 63)+
+ (time_val >> 11)*3600+86400*
+ ((date & 31)-1+day_n[month]+(year/4)+year*365-((year & 3) == 0 &&
+ month < 2 ? 1 : 0)+3653);
+ /* days since 1.1.70 plus 80's leap day */
+
+ return secs;
+}
+
+
+/* Convert linear UNIX date to a MS-DOS time/date pair */
+void msdos_date_unix2dos(int unix_date,
+ unsigned short *time_val,
+ unsigned short *date)
+{
+ int day,year,nl_day,month;
+
+ *time_val = (unix_date % 60)/2+(((unix_date/60) % 60) << 5)+
+ (((unix_date/3600) % 24) << 11);
+ day = unix_date/86400-3652;
+ year = day/365;
+ if ((year+3)/4+365*year > day) year--;
+ day -= (year+3)/4+365*year;
+ if (day == 59 && !(year & 3)) {
+ nl_day = day;
+ month = 2;
+ }
+ else {
+ nl_day = (year & 3) || day <= 59 ? day : day-1;
+ for (month = 0; month < 12; month++)
+ if (day_n[month] > nl_day) break;
+ }
+ *date = nl_day-day_n[month-1]+1+(month << 5)+(year << 9);
+}
+
+
+/* msdos_get_token --
+ * Routine to get a token (name or separator) from the path.
+ *
+ * PARAMETERS:
+ * path - path to get token from
+ * ret_token - returned token
+ * token_len - length of returned token
+ *
+ * RETURNS:
+ * token type, token and token length
+ *
+ */
+msdos_token_types_t
+msdos_get_token(const char *path, char *ret_token, int *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;
+
+ /*
+ * Copy a name into token. (Remember NULL is a token.)
+ */
+ c = path[i];
+ while ( (!msdos_is_separator(c)) && (i <= MSDOS_NAME_MAX_WITH_DOT) )
+ {
+ token[i] = c;
+ if ( i == MSDOS_NAME_MAX_WITH_DOT )
+ return MSDOS_INVALID_TOKEN;
+ if ( !msdos_is_valid_name_char(c) )
+ return MSDOS_INVALID_TOKEN;
+ c = path [++i];
+ }
+
+ /*
+ * Copy a seperator into token.
+ */
+ if ( i == 0 )
+ {
+ token[i] = c;
+ if ( token[i] != '\0' )
+ {
+ i++;
+ type = MSDOS_CURRENT_DIR;
+ }
+ else
+ type = MSDOS_NO_MORE_PATH;
+ }
+ else if (token[ i-1 ] != '\0')
+ token[i] = '\0';
+
+ /*
+ * Set token_len to the number of characters copied.
+ */
+ *token_len = i;
+
+ /*
+ * If we copied something that was not a seperator see if
+ * it was a special name.
+ */
+ if ( type == MSDOS_NAME )
+ {
+ if ( strcmp( token, "..") == 0 )
+ {
+ strcpy(ret_token, MSDOS_DOTDOT_NAME);
+ type = MSDOS_UP_DIR;
+ return type;
+ }
+
+ if ( strcmp( token, "." ) == 0 )
+ {
+ strcpy(ret_token, MSDOS_DOT_NAME);
+ type = MSDOS_CURRENT_DIR;
+ return type;
+ }
+
+ rc = msdos_format_name('r', token, *token_len, ret_token, 0);
+ if ( rc != RC_OK )
+ return MSDOS_INVALID_TOKEN;
+ }
+ ret_token[MSDOS_NAME_MAX] = '\0';
+ return type;
+}
+
+
+/* msdos_find_name --
+ * Find the node which correspondes to the name, open fat-file which
+ * correspondes to the found node and close fat-file which correspondes
+ * to the node we searched in.
+ *
+ * PARAMETERS:
+ * parent_loc - parent node description
+ * name - name to find
+ *
+ * RETURNS:
+ * RC_OK and updated 'parent_loc' on success, or -1 if error
+ * occured (errno set apropriately)
+ *
+ */
+int
+msdos_find_name(
+ rtems_filesystem_location_info_t *parent_loc,
+ char *name
+ )
+{
+ 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;
+ unsigned char node_entry[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE];
+
+ memset(node_entry, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
+
+ /*
+ * 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);
+ if (rc != RC_OK)
+ return rc;
+
+ /* open fat-file corresponded to the found node */
+ rc = fat_file_open(parent_loc->mt_entry, aux.cln, aux.ofs, &fat_fd);
+ if (rc != RC_OK)
+ return rc;
+
+ /*
+ * 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
+ * otherwise real values of these fields stored in fat-file descriptor
+ * may be accidentely 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));
+
+ if ((*MSDOS_DIR_ATTR(node_entry)) & MSDOS_ATTR_DIRECTORY)
+ {
+ fat_fd->fat_file_type = FAT_DIRECTORY;
+ fat_fd->size_limit = MSDOS_MAX_DIR_LENGHT;
+
+ rc = fat_file_size(parent_loc->mt_entry, fat_fd);
+ if (rc != RC_OK)
+ {
+ fat_file_close(parent_loc->mt_entry, fat_fd);
+ return rc;
+ }
+ }
+ else
+ {
+ fat_fd->fat_file_size = CF_LE_L(*MSDOS_DIR_FILE_SIZE(node_entry));
+ fat_fd->fat_file_type = FAT_FILE;
+ fat_fd->size_limit = MSDOS_MAX_FILE_SIZE;
+ }
+
+ /* these data is not actual for zero-length fat-file */
+ fat_fd->map.file_cln = 0;
+ fat_fd->map.disk_cln = fat_fd->cln;
+
+ if ((fat_fd->fat_file_size != 0) &&
+ (fat_fd->fat_file_size <= fs_info->fat.vol.bpc))
+ {
+ fat_fd->map.last_cln = fat_fd->cln;
+ }
+ else
+ {
+ fat_fd->map.last_cln = FAT_UNDEFINED_VALUE;
+ }
+ }
+
+ /* close fat-file corresponded to the node we searched in */
+ rc = fat_file_close(parent_loc->mt_entry, parent_loc->node_access);
+ if (rc != RC_OK)
+ {
+ fat_file_close(parent_loc->mt_entry, fat_fd);
+ return rc;
+ }
+
+ /* update node_info_ptr field */
+ parent_loc->node_access = fat_fd;
+
+ return rc;
+}
+
+/* msdos_get_name_node --
+ * 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.
+ *
+ * (a): reading fat-file which correspondes to directory we are going to
+ * create node in. If free slot is found write contents of
+ * 'name_dir_entry' into it. If reach end of fat-file and no free
+ * slot found, write 32 bytes to the end of fat-file.
+ *
+ * (b): reading fat-file which correspondes to directory and trying to
+ * find slot with the name field == 'name' parameter
+ *
+ *
+ * PARAMETERS:
+ * parent_loc - node description to create node in or to find name in
+ * 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)
+ *
+ * RETURNS:
+ * RC_OK, filled aux_struct_ptr and name_dir_entry on success, or -1 if
+ * error occured (errno set apropriately)
+ *
+ */
+int
+msdos_get_name_node(
+ rtems_filesystem_location_info_t *parent_loc,
+ char *name,
+ fat_auxiliary_t *paux,
+ 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;
+ unsigned32 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);
+ 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))
+ {
+ ret = fat_file_write(parent_loc->mt_entry, fat_fd,
+ fat_fd->fat_file_size,
+ MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE,
+ 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)
+ return rc;
+
+ /*
+ * if new cluster allocated succesfully then new node is at very
+ * beginning of the cluster (offset is computed in bytes)
+ */
+ 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)
+ {
+ 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
+ {
+ 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;
+ }
+ }
+ }
+ return rc;
+}
+
+/*
+ * msdos_get_dotdot_dir_info_cluster_num_and_offset
+ *
+ * Unfortunately, in general, we cann't work here in fat-file ideologic
+ * (open fat_file "..", get ".." and ".", open "..", find an entry ...)
+ * because if we open
+ * fat-file ".." it may happend that we have two different fat-file
+ * descriptors ( for real name of directory and ".." name ) for a single
+ * file ( cluster num of both pointers to the same cluster )
+ * But...we do it because we protected by semaphore
+ *
+ */
+
+/* msdos_get_dotdot_dir_info_cluster_num_and_offset --
+ * Get cluster num and offset not of ".." slot, but slot which correspondes
+ * to real directory name.
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * cln - data cluster num extracted drom ".." slot
+ * paux - identify a node location on the disk -
+ * number of cluster and offset inside the cluster
+ * dir_entry - placeholder for found node
+ *
+ * RETURNS:
+ * RC_OK, filled 'paux' and 'dir_entry' on success, or -1 if error occured
+ * (errno set apropriately)
+ *
+ */
+int
+msdos_get_dotdot_dir_info_cluster_num_and_offset(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 cln,
+ fat_auxiliary_t *paux,
+ char *dir_entry
+ )
+{
+ int rc = RC_OK;
+ msdos_fs_info_t *fs_info = mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = NULL;
+ unsigned char dot_node[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE];
+ unsigned char dotdot_node[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE];
+ unsigned char cur_node[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE];
+ unsigned32 cl4find = 0;
+
+ memset(dot_node, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
+ memset(dotdot_node, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
+ memset(cur_node, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
+
+ /*
+ * open fat-file corresponded to ".."
+ */
+ rc = fat_file_open(mt_entry, paux->cln, paux->ofs, &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;
+
+ fat_fd->map.file_cln = 0;
+ fat_fd->map.disk_cln = fat_fd->cln;
+
+ rc = fat_file_size(mt_entry, fat_fd);
+ if (rc != RC_OK)
+ {
+ fat_file_close(mt_entry, fat_fd);
+ return rc;
+ }
+
+ /* find "." node in opened directory */
+ rc = msdos_find_name_in_fat_file(mt_entry, fat_fd, MSDOS_DOT_NAME, paux,
+ dot_node);
+
+ if (rc != RC_OK)
+ {
+ fat_file_close(mt_entry, fat_fd);
+ return rc;
+ }
+
+ /* find ".." node in opened directory */
+ rc = msdos_find_name_in_fat_file(mt_entry, fat_fd, MSDOS_DOTDOT_NAME, paux,
+ dotdot_node);
+
+ if (rc != RC_OK)
+ {
+ fat_file_close(mt_entry, fat_fd);
+ return rc;
+ }
+
+ cl4find = MSDOS_EXTRACT_CLUSTER_NUM(dot_node);
+
+ /* close fat-file corresponded to ".." directory */
+ rc = fat_file_close(mt_entry, fat_fd);
+ if ( rc != RC_OK )
+ return rc;
+
+ if ( (MSDOS_EXTRACT_CLUSTER_NUM(dotdot_node)) == 0)
+ {
+ /*
+ * 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;
+ }
+
+ /* open fat-file corresponded to second ".." */
+ rc = fat_file_open(mt_entry, paux->cln, paux->ofs, &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
+ fat_fd->cln = MSDOS_EXTRACT_CLUSTER_NUM(dotdot_node);
+
+ fat_fd->fat_file_type = FAT_DIRECTORY;
+ fat_fd->size_limit = MSDOS_MAX_DIR_LENGHT;
+
+ fat_fd->map.file_cln = 0;
+ fat_fd->map.disk_cln = fat_fd->cln;
+
+ rc = fat_file_size(mt_entry, fat_fd);
+ if (rc != RC_OK)
+ {
+ fat_file_close(mt_entry, fat_fd);
+ return rc;
+ }
+
+ /* 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);
+ if (rc != RC_OK)
+ {
+ fat_file_close(mt_entry, fat_fd);
+ return rc;
+ }
+ rc = fat_file_close(mt_entry, fat_fd);
+ return rc;
+}
+
+
+/* msdos_set_dir_wrt_time_and_date --
+ * Write last write date and time for a file to the disk (to corresponded
+ * 32bytes node)
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * fat_fd - fat-file descriptor
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured (errno set apropriately).
+ *
+ */
+int
+msdos_set_dir_wrt_time_and_date(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd
+ )
+{
+ ssize_t ret1 = 0, ret2 = 0;
+ msdos_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned short time_val;
+ unsigned short date;
+ unsigned32 sec = 0;
+ unsigned32 byte = 0;
+
+ msdos_date_unix2dos(fat_fd->mtime, &time_val, &date);
+
+ /*
+ * 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);
+ /* byte points to start of 32bytes structure */
+ byte = fat_fd->info_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,
+ 2, (char *)(&time_val));
+ date = CT_LE_W(date);
+ ret2 = _fat_block_write(mt_entry, sec, byte + MSDOS_FILE_WDATE_OFFSET,
+ 2, (char *)(&date));
+
+ if ( (ret1 < 0) || (ret2 < 0) )
+ return -1;
+
+ return RC_OK;
+}
+
+/* msdos_set_first_cluster_num --
+ * Write number of first cluster of the file to the disk (to corresponded
+ * 32bytes slot)
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * fat_fd - fat-file descriptor
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured
+ *
+ */
+int
+msdos_set_first_cluster_num(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd
+ )
+{
+ ssize_t ret1 = 0, ret2 = 0;
+ msdos_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 new_cln = fat_fd->cln;
+ unsigned16 le_cl_low = 0;
+ unsigned16 le_cl_hi = 0;
+ unsigned32 sec = 0;
+ unsigned32 byte = 0;
+
+ /*
+ * 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);
+ /* byte from points to start of 32bytes structure */
+ byte = fat_fd->info_ofs & (fs_info->fat.vol.bps - 1);
+
+ le_cl_low = CT_LE_W((unsigned16)(new_cln & 0x0000FFFF));
+ ret1 = _fat_block_write(mt_entry, sec,
+ byte + MSDOS_FIRST_CLUSTER_LOW_OFFSET, 2,
+ (char *)(&le_cl_low));
+ le_cl_hi = CT_LE_W((unsigned16)((new_cln & 0xFFFF0000) >> 16));
+ ret2 = _fat_block_write(mt_entry, sec,
+ byte + MSDOS_FIRST_CLUSTER_HI_OFFSET, 2,
+ (char *)(&le_cl_hi));
+ if ( (ret1 < 0) || (ret2 < 0) )
+ return -1;
+
+ return RC_OK;
+}
+
+
+/* msdos_set_file size --
+ * Write file size of the file to the disk (to corresponded 32bytes slot)
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * fat_fd - fat-file descriptor
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured (errno set apropriately).
+ *
+ */
+int
+msdos_set_file_size(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd
+ )
+{
+ ssize_t ret = 0;
+ msdos_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 le_new_length = 0;
+ unsigned32 sec = 0;
+ unsigned32 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));
+
+ le_new_length = CT_LE_L((fat_fd->fat_file_size));
+ ret = _fat_block_write(mt_entry, sec, byte + MSDOS_FILE_SIZE_OFFSET, 4,
+ (char *)(&le_new_length));
+ if ( ret < 0 )
+ return -1;
+
+ return RC_OK;
+}
+
+/*
+ * We should not check whether this routine is called for root dir - it
+ * never can happend
+ */
+
+/* msdos_set_first_char4file_name --
+ * Write first character of the name of the file to the disk (to
+ * corresponded 32bytes slot)
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * cl - number of cluster
+ * ofs - offset inside cluster
+ * fchar - character to set up
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured (errno set apropriately)
+ *
+ */
+int
+msdos_set_first_char4file_name(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 cl,
+ unsigned32 ofs,
+ unsigned char fchar
+ )
+{
+ ssize_t ret = 0;
+ msdos_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 sec = 0;
+ unsigned32 byte = 0;
+
+ 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));
+
+ ret = _fat_block_write(mt_entry, sec, byte + MSDOS_FILE_NAME_OFFSET, 1,
+ &fchar);
+ if ( ret < 0)
+ return -1;
+
+ return RC_OK;
+}
+
+/* msdos_dir_is_empty --
+ * Check whether directory which correspondes to the fat-file descriptor is
+ * empty.
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * fat_fd - fat-file descriptor
+ * ret_val - placeholder for result
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured
+ *
+ */
+int
+msdos_dir_is_empty(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd,
+ rtems_boolean *ret_val
+ )
+{
+ ssize_t ret = 0;
+ msdos_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 j = 0, i = 0;
+
+ /* dir is not empty */
+ *ret_val = FALSE;
+
+ while ((ret = fat_file_read(mt_entry, fat_fd, j * fs_info->fat.vol.bps,
+ fs_info->fat.vol.bps,
+ fs_info->cl_buf)) != FAT_EOF)
+ {
+ if (ret < MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
+ return -1;
+
+ assert(ret == fs_info->fat.vol.bps);
+
+ for (i = 0;
+ i < fs_info->fat.vol.bps;
+ i += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
+ {
+ if (((*MSDOS_DIR_NAME(fs_info->cl_buf + i)) ==
+ MSDOS_THIS_DIR_ENTRY_EMPTY) ||
+ (strncmp(MSDOS_DIR_NAME((fs_info->cl_buf + i)), MSDOS_DOT_NAME,
+ MSDOS_SHORT_NAME_LEN) == 0) ||
+ (strncmp(MSDOS_DIR_NAME((fs_info->cl_buf + i)),
+ MSDOS_DOTDOT_NAME,
+ MSDOS_SHORT_NAME_LEN) == 0))
+ continue;
+
+ if ((*MSDOS_DIR_NAME(fs_info->cl_buf + i)) ==
+ MSDOS_THIS_DIR_ENTRY_AND_REST_EMPTY)
+ {
+ *ret_val = TRUE;
+ return RC_OK;
+ }
+ return RC_OK;
+ }
+ j++;
+ }
+ *ret_val = TRUE;
+ 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.
+ *
+ * (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
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * fat_fd - fat-file descriptor
+ * name - NULL or name to find
+ * paux - identify a node location on the disk -
+ * number of cluster and offset inside the cluster
+ * name_dir_entry - node to create/placeholder for found node
+ *
+ * RETURNS:
+ * RC_OK on success, or error code if error occured (errno set
+ * appropriately)
+ *
+ */
+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,
+ char *name_dir_entry
+ )
+{
+ int rc = RC_OK;
+ ssize_t ret = 0;
+ msdos_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 i = 0, j = 0;
+ unsigned32 bts2rd = 0;
+
+ if (FAT_FD_OF_ROOT_DIR(fat_fd) &&
+ (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)
+ {
+ if (ret < MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
+ set_errno_and_return_minus_one(EIO);
+
+ assert(ret == bts2rd);
+
+ for (i = 0; i < bts2rd; i += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
+ {
+ /* is the entry empty ? */
+ if (((*MSDOS_DIR_NAME(fs_info->cl_buf + i)) ==
+ MSDOS_THIS_DIR_ENTRY_AND_REST_EMPTY) ||
+ ((*MSDOS_DIR_NAME(fs_info->cl_buf + i)) ==
+ MSDOS_THIS_DIR_ENTRY_EMPTY))
+ {
+ /* 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,
+ 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;
+ }
+
+ /*
+ * if name != NULL 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))
+ return MSDOS_NAME_NOT_FOUND_ERR;
+ }
+ else
+ {
+ /* entry not empty and name != NULL -> compare names */
+ if (name != NULL)
+ {
+ if (strncmp(MSDOS_DIR_NAME((fs_info->cl_buf + i)), name,
+ MSDOS_SHORT_NAME_LEN) == 0)
+ {
+ /*
+ * we get the entry we looked for - fill auxiliary
+ * structure and copy all 32 bytes of the entry
+ */
+ 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;
+ memcpy(name_dir_entry,(fs_info->cl_buf + i),
+ MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
+ return RC_OK;
+ }
+ }
+ }
+ }
+ j++;
+ }
+ return MSDOS_NAME_NOT_FOUND_ERR;
+}
+
+/* msdos_find_node_by_cluster_num_in_fat_file --
+ * Find node with specified number of cluster in fat-file.
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * fat_fd - fat-file descriptor
+ * cl4find - number of cluster to find
+ * paux - identify a node location on the disk -
+ * cluster num and offset inside the cluster
+ * dir_entry - placeholder for found node
+ *
+ * RETURNS:
+ * RC_OK on success, or error code if error occured
+ *
+ */
+int
+msdos_find_node_by_cluster_num_in_fat_file(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd,
+ unsigned32 cl4find,
+ fat_auxiliary_t *paux,
+ char *dir_entry
+ )
+{
+ int rc = RC_OK;
+ ssize_t ret = 0;
+ msdos_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 bts2rd = 0;
+ unsigned32 i = 0, j = 0;
+
+ if (FAT_FD_OF_ROOT_DIR(fat_fd) &&
+ (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)
+ {
+ if ( ret < MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE )
+ set_errno_and_return_minus_one( EIO );
+
+ assert(ret == bts2rd);
+
+ for (i = 0; i < bts2rd; i += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
+ {
+ /* if this and all rest entries are empty - return not-found */
+ if ((*MSDOS_DIR_NAME(fs_info->cl_buf + i)) ==
+ MSDOS_THIS_DIR_ENTRY_AND_REST_EMPTY)
+ return MSDOS_NAME_NOT_FOUND_ERR;
+
+ /* if this entry is empty - skip it */
+ if ((*MSDOS_DIR_NAME(fs_info->cl_buf + i)) ==
+ 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)
+ {
+ /* 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);
+ if (rc != RC_OK)
+ return rc;
+
+ paux->ofs = i;
+ memcpy(dir_entry, fs_info->cl_buf + i,
+ MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
+ return RC_OK;
+ }
+ }
+ j++;
+ }
+ return MSDOS_NAME_NOT_FOUND_ERR;
+}