summaryrefslogtreecommitdiffstats
path: root/cpukit/libfs/src/dosfs/msdos_create.c
diff options
context:
space:
mode:
Diffstat (limited to 'cpukit/libfs/src/dosfs/msdos_create.c')
-rw-r--r--cpukit/libfs/src/dosfs/msdos_create.c267
1 files changed, 267 insertions, 0 deletions
diff --git a/cpukit/libfs/src/dosfs/msdos_create.c b/cpukit/libfs/src/dosfs/msdos_create.c
new file mode 100644
index 0000000000..ec5862a178
--- /dev/null
+++ b/cpukit/libfs/src/dosfs/msdos_create.c
@@ -0,0 +1,267 @@
+/*
+ * Routine to create a new MSDOS filesystem node
+ *
+ * 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.rtems.com/license/LICENSE.
+ *
+ * @(#) $Id$
+ *
+ */
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <rtems/libio_.h>
+#include <time.h>
+
+#include "fat.h"
+#include "fat_fat_operations.h"
+#include "fat_file.h"
+
+#include "msdos.h"
+
+/* msdos_creat_node --
+ * 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
+ * new directory and dot and dotdot nodes are created in alloceted cluster.
+ *
+ * PARAMETERS:
+ * parent_loc - parent (directory we are going to create node in)
+ * type - new node type (file or directory)
+ * name - new node name
+ * mode - mode
+ * link_info - fs_info of existing node for a pseudo "hard-link"
+ * (see msdos_file.c, msdos_link for documentation)
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured (errno set appropriately).
+ *
+ */
+int
+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_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);
+
+ name_type = msdos_long_to_short (name, name_len,
+ MSDOS_DIR_NAME(short_node),
+ MSDOS_NAME_MAX);
+
+ /* fill reserved field */
+ *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, &date, &time_val);
+ *MSDOS_DIR_CRT_TIME(short_node) = CT_LE_W(time_val);
+ *MSDOS_DIR_CRT_DATE(short_node) = CT_LE_W(date);
+ *MSDOS_DIR_WRITE_TIME(short_node) = CT_LE_W(time_val);
+ *MSDOS_DIR_WRITE_DATE(short_node) = CT_LE_W(date);
+ *MSDOS_DIR_LAST_ACCESS_DATE(short_node) = CT_LE_W(date);
+
+ /* initialize directory/file size */
+ *MSDOS_DIR_FILE_SIZE(short_node) = MSDOS_INIT_DIR_SIZE;
+
+ if (type == MSDOS_DIRECTORY) {
+ *MSDOS_DIR_ATTR(short_node) |= MSDOS_ATTR_DIRECTORY;
+ }
+ else if (type == MSDOS_HARD_LINK) {
+ /*
+ * when we establish a (temporary) hard link,
+ * we must copy some information from the original
+ * node to the newly created
+ */
+ /*
+ * read the original directory entry
+ */
+ sec = fat_cluster_num_to_sector_num(parent_loc->mt_entry,
+ 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,
+ link_node);
+ if (ret < 0) {
+ return -1;
+ }
+ /*
+ * copy various attributes
+ */
+ *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(short_node) =*MSDOS_DIR_FILE_SIZE(link_node);
+
+ *MSDOS_DIR_FIRST_CLUSTER_LOW(short_node) =
+ *MSDOS_DIR_FIRST_CLUSTER_LOW(link_node);
+ *MSDOS_DIR_FIRST_CLUSTER_HI(short_node) =
+ *MSDOS_DIR_FIRST_CLUSTER_HI(link_node);
+ /*
+ * set "archive bit" due to changes
+ */
+ *MSDOS_DIR_ATTR(short_node) |= MSDOS_ATTR_ARCHIVE;
+ }
+ else { /* regular file... */
+ *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, true, name, name_len,
+ name_type, &dir_pos, short_node);
+ if ( rc != RC_OK )
+ return rc;
+
+ /*
+ * if we create a new file we are done, if directory there are more steps
+ * to do
+ */
+ if (type == MSDOS_DIRECTORY)
+ {
+ /* open new directory as fat-file */
+ rc = fat_file_open(parent_loc->mt_entry, &dir_pos, &fat_fd);
+ if (rc != RC_OK)
+ goto err;
+
+ /*
+ * we opened fat-file for node we just created, so initialize fat-file
+ * descritor
+ */
+ fat_fd->fat_file_size = 0;
+ fat_fd->fat_file_type = FAT_DIRECTORY;
+ fat_fd->size_limit = MSDOS_MAX_DIR_LENGHT;
+
+ /*
+ * dot and dotdot entries are identical to new node except the
+ * names
+ */
+ memcpy(DOT_NODE_P(dot_dotdot), short_node,
+ MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
+ 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);
+ memcpy(MSDOS_DIR_NAME(DOTDOT_NODE_P(dot_dotdot)), MSDOS_DOTDOT_NAME,
+ MSDOS_NAME_MAX);
+
+ /* set up cluster num for dotdot entry */
+ /*
+ * here we can ommit FAT32 condition because for all FAT types dirs
+ * right under root dir should contain 0 in dotdot entry but for
+ * FAT12/16 parent_fat_fd->cluster_num always contains such value
+ */
+ if ((FAT_FD_OF_ROOT_DIR(parent_fat_fd)) &&
+ (fs_info->fat.vol.type & FAT_FAT32))
+ {
+ *MSDOS_DIR_FIRST_CLUSTER_LOW(DOTDOT_NODE_P(dot_dotdot)) = 0x0000;
+ *MSDOS_DIR_FIRST_CLUSTER_HI(DOTDOT_NODE_P(dot_dotdot)) = 0x0000;
+ }
+ else
+ {
+ *MSDOS_DIR_FIRST_CLUSTER_LOW(DOTDOT_NODE_P(dot_dotdot)) =
+ CT_LE_W((uint16_t )((parent_fat_fd->cln) & 0x0000FFFF));
+ *MSDOS_DIR_FIRST_CLUSTER_HI(DOTDOT_NODE_P(dot_dotdot)) =
+ CT_LE_W((uint16_t )(((parent_fat_fd->cln) & 0xFFFF0000)>>16));
+ }
+
+ /*
+ * write dot and dotdot entries to new fat-file: currently fat-file
+ * correspondes to a new node is zero length, so it will be extended
+ * by one cluster and entries will be written
+ */
+ ret = fat_file_write(parent_loc->mt_entry, fat_fd, 0,
+ MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE * 2,
+ (uint8_t *)dot_dotdot);
+ if (ret < 0)
+ {
+ rc = -1;
+ goto error;
+ }
+
+ /* increment fat-file size by cluster size */
+ fat_fd->fat_file_size += fs_info->fat.vol.bpc;
+
+ /* set up cluster num for dot entry */
+ *MSDOS_DIR_FIRST_CLUSTER_LOW(DOT_NODE_P(dot_dotdot)) =
+ CT_LE_W((uint16_t )((fat_fd->cln) & 0x0000FFFF));
+ *MSDOS_DIR_FIRST_CLUSTER_HI(DOT_NODE_P(dot_dotdot)) =
+ CT_LE_W((uint16_t )(((fat_fd->cln) & 0xFFFF0000) >> 16));
+
+ /* rewrite dot entry */
+ ret = fat_file_write(parent_loc->mt_entry, fat_fd, 0,
+ MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE,
+ (uint8_t *)DOT_NODE_P(dot_dotdot));
+ if (ret < 0)
+ {
+ rc = -1;
+ goto error;
+ }
+
+ /* write first cluster num of a new directory to disk */
+ rc = msdos_set_first_cluster_num(parent_loc->mt_entry, fat_fd);
+ if (rc != RC_OK)
+ goto error;
+
+ fat_file_close(parent_loc->mt_entry, fat_fd);
+ }
+ return RC_OK;
+
+error:
+ fat_file_close(parent_loc->mt_entry, fat_fd);
+
+err:
+ /* mark the used 32bytes structure on the disk as free */
+ msdos_set_first_char4file_name(parent_loc->mt_entry, &dir_pos, 0xE5);
+ return rc;
+}