Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:16

0001 /**
0002  * @file
0003  *
0004  * @ingroup libfs_msdos MSDOS FileSystem
0005  *
0006  * @brief Create a new MSDOS FileSystem node
0007  */
0008 
0009 /*
0010  * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
0011  * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
0012  *
0013  * The license and distribution terms for this file may be
0014  * found in the file LICENSE in this distribution or at
0015  * http://www.rtems.org/license/LICENSE.
0016  *
0017  */
0018 #ifdef HAVE_CONFIG_H
0019 #include "config.h"
0020 #endif
0021 
0022 #include <errno.h>
0023 #include <stdio.h>
0024 #include <stdlib.h>
0025 #include <string.h>
0026 #include <rtems/libio_.h>
0027 #include <time.h>
0028 
0029 #include "fat.h"
0030 #include "fat_fat_operations.h"
0031 #include "fat_file.h"
0032 
0033 #include "msdos.h"
0034 
0035 /* msdos_creat_node --
0036  *     Create a new node. Determine if the name is a long name. If long we to
0037  *     scan the directory to create a short entry.
0038  *
0039  *
0040 
0041 
0042 
0043  *     If a new node is file, FAT 32 Bytes Directory
0044  *     Entry Structure is initialized, free space is found in parent
0045  *     directory and structure is written to the disk. In case of directory,
0046  *     all above steps present and also new cluster is allocated for a
0047  *     new directory and dot and dotdot nodes are created in alloceted cluster.
0048  *
0049  * PARAMETERS:
0050  *     parent_loc - parent (directory we are going to create node in)
0051  *     type       - new node type (file or directory)
0052  *     name       - new node name
0053  *     mode       - mode
0054  *     link_info  - fs_info of existing node for a pseudo "hard-link"
0055  *                  (see msdos_file.c, msdos_link for documentation)
0056  *
0057  * RETURNS:
0058  *     RC_OK on success, or -1 if error occurred (errno set appropriately).
0059  *
0060  */
0061 int
0062 msdos_creat_node(const rtems_filesystem_location_info_t  *parent_loc,
0063                  fat_file_type_t                          type,
0064                  const char                              *name,
0065                  int                                      name_len,
0066                  mode_t                                   mode,
0067                  fat_file_fd_t                           *link_fd)
0068 {
0069     int               rc = RC_OK;
0070     ssize_t           ret = 0;
0071     msdos_fs_info_t  *fs_info = parent_loc->mt_entry->fs_info;
0072     fat_file_fd_t    *parent_fat_fd = parent_loc->node_access;
0073     fat_file_fd_t    *fat_fd = NULL;
0074     time_t            now;
0075     uint16_t          time_val = 0;
0076     uint16_t          date = 0;
0077     fat_dir_pos_t     dir_pos;
0078     msdos_name_type_t name_type;
0079     char              short_node[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE];
0080     char              dot_dotdot[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE * 2];
0081     char              link_node[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE];
0082     uint32_t          sec = 0;
0083     uint32_t          byte = 0;
0084 
0085     fat_dir_pos_init(&dir_pos);
0086 
0087     memset(short_node, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
0088     memset(dot_dotdot, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE * 2);
0089 
0090     if (name_len > MSDOS_NAME_MAX_LFN_WITH_DOT) {
0091         rtems_set_errno_and_return_minus_one(ENAMETOOLONG);
0092     }
0093 
0094     name_type = msdos_long_to_short (fs_info->converter,
0095                                      name, name_len,
0096                                      MSDOS_DIR_NAME(short_node),
0097                                      MSDOS_NAME_MAX);
0098     if (name_type == MSDOS_NAME_INVALID) {
0099         rtems_set_errno_and_return_minus_one(EINVAL);
0100     }
0101 
0102     /* fill reserved field */
0103     *MSDOS_DIR_NT_RES(short_node) = MSDOS_RES_NT_VALUE;
0104 
0105     /* set up last write date and time */
0106     now = time(NULL);
0107     fat_file_set_ctime_mtime(parent_fat_fd, now);
0108 
0109     msdos_date_unix2dos(now, &date, &time_val);
0110     *MSDOS_DIR_CRT_TIME(short_node) = CT_LE_W(time_val);
0111     *MSDOS_DIR_CRT_DATE(short_node) = CT_LE_W(date);
0112     *MSDOS_DIR_WRITE_TIME(short_node) = CT_LE_W(time_val);
0113     *MSDOS_DIR_WRITE_DATE(short_node) = CT_LE_W(date);
0114     *MSDOS_DIR_LAST_ACCESS_DATE(short_node) = CT_LE_W(date);
0115 
0116     /* initialize directory/file size */
0117     *MSDOS_DIR_FILE_SIZE(short_node) = MSDOS_INIT_DIR_SIZE;
0118 
0119     if (type == FAT_DIRECTORY) {
0120       *MSDOS_DIR_ATTR(short_node) |= MSDOS_ATTR_DIRECTORY;
0121     }
0122     else if (type == FAT_HARD_LINK) {
0123       /*
0124        * when we establish a (temporary) hard link,
0125        * we must copy some information from the original
0126        * node to the newly created
0127        */
0128       /*
0129        * read the original directory entry
0130        */
0131       sec = fat_cluster_num_to_sector_num(&fs_info->fat,
0132                                           link_fd->dir_pos.sname.cln);
0133       sec += (link_fd->dir_pos.sname.ofs >> fs_info->fat.vol.sec_log2);
0134       byte = (link_fd->dir_pos.sname.ofs & (fs_info->fat.vol.bps - 1));
0135 
0136       ret = _fat_block_read(&fs_info->fat,
0137                             sec, byte, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE,
0138                             link_node);
0139       if (ret < 0) {
0140           return -1;
0141       }
0142       /*
0143        * copy various attributes
0144        */
0145       *MSDOS_DIR_ATTR(short_node)          =*MSDOS_DIR_ATTR(link_node);
0146       *MSDOS_DIR_CRT_TIME_TENTH(short_node)=*MSDOS_DIR_CRT_TIME_TENTH(link_node);
0147       *MSDOS_DIR_CRT_TIME(short_node)      =*MSDOS_DIR_CRT_TIME(link_node);
0148       *MSDOS_DIR_CRT_DATE(short_node)      =*MSDOS_DIR_CRT_DATE(link_node);
0149 
0150       /*
0151        * copy/set "file size", "first cluster"
0152        */
0153       *MSDOS_DIR_FILE_SIZE(short_node)     =*MSDOS_DIR_FILE_SIZE(link_node);
0154 
0155       *MSDOS_DIR_FIRST_CLUSTER_LOW(short_node) =
0156            *MSDOS_DIR_FIRST_CLUSTER_LOW(link_node);
0157       *MSDOS_DIR_FIRST_CLUSTER_HI(short_node) =
0158            *MSDOS_DIR_FIRST_CLUSTER_HI(link_node);
0159       /*
0160        * set "archive bit" due to changes
0161        */
0162       *MSDOS_DIR_ATTR(short_node) |= MSDOS_ATTR_ARCHIVE;
0163     }
0164     else { /* regular file... */
0165         *MSDOS_DIR_ATTR(short_node) |= MSDOS_ATTR_ARCHIVE;
0166     }
0167 
0168     /*
0169      * find free space in the parent directory and write new initialized
0170      * FAT 32 Bytes Directory Entry Structure to the disk
0171      */
0172     rc = msdos_get_name_node(parent_loc, true, name, name_len,
0173                              name_type, &dir_pos, short_node);
0174     if ( rc != RC_OK )
0175         return rc;
0176 
0177     /*
0178      * if it is performing a rename, update also the inode to prevent issues
0179      * in case the fat file descriptor is opened not only for the rename operation.
0180      */
0181     if ( type == FAT_HARD_LINK )
0182     {
0183         rc = fat_file_get_new_inode_for(&fs_info->fat, &dir_pos, link_fd);
0184         if ( rc != RC_OK )
0185             return rc;
0186     }
0187 
0188     /*
0189      * if we create a new file we are done, if directory there are more steps
0190      * to do
0191      */
0192     if (type == FAT_DIRECTORY)
0193     {
0194         uint32_t unused;
0195 
0196         /* open new directory as fat-file */
0197         rc = fat_file_open(&fs_info->fat, &dir_pos, &fat_fd);
0198         if (rc != RC_OK)
0199             goto err;
0200 
0201         /*
0202          * we opened fat-file for node we just created, so initialize fat-file
0203          * descritor
0204          */
0205         fat_fd->fat_file_type = FAT_DIRECTORY;
0206         fat_fd->size_limit = MSDOS_MAX_DIR_LENGTH;
0207         fat_file_set_ctime_mtime(fat_fd, now);
0208 
0209         /* extend it to contain exactly one cluster */
0210         rc = fat_file_extend(&fs_info->fat,
0211                              fat_fd,
0212                              true,
0213                              fs_info->fat.vol.bpc,
0214                              &unused);
0215         if (rc != RC_OK)
0216             goto error;
0217 
0218         /*
0219          * dot and dotdot entries are identical to new node except the
0220          * names
0221          */
0222         memcpy(DOT_NODE_P(dot_dotdot), short_node,
0223                MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
0224         memcpy(DOTDOT_NODE_P(dot_dotdot), short_node,
0225                MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
0226         memcpy(MSDOS_DIR_NAME(DOT_NODE_P(dot_dotdot)), MSDOS_DOT_NAME,
0227                MSDOS_NAME_MAX);
0228         memcpy(MSDOS_DIR_NAME(DOTDOT_NODE_P(dot_dotdot)), MSDOS_DOTDOT_NAME,
0229                MSDOS_NAME_MAX);
0230 
0231         /* set up cluster num for dotdot entry */
0232         /*
0233          * here we can ommit FAT32 condition because for all FAT types dirs
0234          * right under root dir should contain 0 in dotdot entry but for
0235          * FAT12/16 parent_fat_fd->cluster_num always contains such value
0236          */
0237         if ((FAT_FD_OF_ROOT_DIR(parent_fat_fd)) &&
0238             (fs_info->fat.vol.type & FAT_FAT32))
0239         {
0240             *MSDOS_DIR_FIRST_CLUSTER_LOW(DOTDOT_NODE_P(dot_dotdot)) = 0x0000;
0241             *MSDOS_DIR_FIRST_CLUSTER_HI(DOTDOT_NODE_P(dot_dotdot)) = 0x0000;
0242         }
0243         else
0244         {
0245             *MSDOS_DIR_FIRST_CLUSTER_LOW(DOTDOT_NODE_P(dot_dotdot)) =
0246                 CT_LE_W((uint16_t  )((parent_fat_fd->cln) & 0x0000FFFF));
0247             *MSDOS_DIR_FIRST_CLUSTER_HI(DOTDOT_NODE_P(dot_dotdot)) =
0248                 CT_LE_W((uint16_t  )(((parent_fat_fd->cln) & 0xFFFF0000)>>16));
0249         }
0250 
0251         /* set up cluster num for dot entry */
0252         *MSDOS_DIR_FIRST_CLUSTER_LOW(DOT_NODE_P(dot_dotdot)) =
0253                 CT_LE_W((uint16_t  )((fat_fd->cln) & 0x0000FFFF));
0254         *MSDOS_DIR_FIRST_CLUSTER_HI(DOT_NODE_P(dot_dotdot)) =
0255                 CT_LE_W((uint16_t  )(((fat_fd->cln) & 0xFFFF0000) >> 16));
0256 
0257         /* write dot and dotdot entries */
0258         ret = fat_file_write(&fs_info->fat, fat_fd, 0,
0259                              MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE * 2,
0260                              (uint8_t *)dot_dotdot);
0261         if (ret < 0)
0262         {
0263             rc = -1;
0264             goto error;
0265         }
0266 
0267         /* write first cluster num of a new directory to disk */
0268         rc = fat_file_write_first_cluster_num(&fs_info->fat, fat_fd);
0269         if (rc != RC_OK)
0270             goto error;
0271 
0272         fat_file_close(&fs_info->fat, fat_fd);
0273     }
0274     return RC_OK;
0275 
0276 error:
0277     fat_file_close(&fs_info->fat, fat_fd);
0278 
0279 err:
0280     /* mark the used 32bytes structure on the disk as free */
0281     msdos_set_first_char4file_name(parent_loc->mt_entry, &dir_pos, 0xE5);
0282     return rc;
0283 }