source: rtems/cpukit/libfs/src/dosfs/msdos_create.c @ 3c96bee

4.115
Last change on this file since 3c96bee was d2e0bb3, checked in by Ralf Kirchner <ralf.kirchner@…>, on 05/22/13 at 10:16:18

dosfs: UTF-8 Support: UI, backwards compatibility

User interface and backwards compatibility for UTF-8 support in the FAT
file system. Purpose of UTF-8 support is to permit file names and
directory names with characters from all kinds of languages (Czech,
Chinese, Arabian, Hebrew, Korean, ...). This commit does not yet
support multibyte characters. It only contains the user interface and
the backwards compatibility.

  • Property mode set to 100644
File size: 9.5 KB
Line 
1/**
2 * @file
3 *
4 * @brief Create a new MSDOS FileSystem node
5 * @ingroup libfs_msdos MSDOS FileSystem
6 */
7
8/*
9 * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
10 * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
11 *
12 * The license and distribution terms for this file may be
13 * found in the file LICENSE in this distribution or at
14 * http://www.rtems.com/license/LICENSE.
15 *
16 */
17#if HAVE_CONFIG_H
18#include "config.h"
19#endif
20
21#include <errno.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <rtems/libio_.h>
26#include <time.h>
27
28#include "fat.h"
29#include "fat_fat_operations.h"
30#include "fat_file.h"
31
32#include "msdos.h"
33
34/* msdos_creat_node --
35 *     Create a new node. Determine if the name is a long name. If long we to
36 *     scan the directory to create a short entry.
37 *
38 *
39
40
41
42 *     If a new node is file, FAT 32 Bytes Directory
43 *     Entry Structure is initialized, free space is found in parent
44 *     directory and structure is written to the disk. In case of directory,
45 *     all above steps present and also new cluster is allocated for a
46 *     new directory and dot and dotdot nodes are created in alloceted cluster.
47 *
48 * PARAMETERS:
49 *     parent_loc - parent (directory we are going to create node in)
50 *     type       - new node type (file or directory)
51 *     name       - new node name
52 *     mode       - mode
53 *     link_info  - fs_info of existing node for a pseudo "hard-link"
54 *                  (see msdos_file.c, msdos_link for documentation)
55 *
56 * RETURNS:
57 *     RC_OK on success, or -1 if error occured (errno set appropriately).
58 *
59 */
60int
61msdos_creat_node(const rtems_filesystem_location_info_t  *parent_loc,
62                 msdos_node_type_t                        type,
63                 const char                              *name,
64                 int                                      name_len,
65                 mode_t                                   mode,
66                 const fat_file_fd_t                     *link_fd)
67{
68    int               rc = RC_OK;
69    ssize_t           ret = 0;
70    msdos_fs_info_t  *fs_info = parent_loc->mt_entry->fs_info;
71    fat_file_fd_t    *parent_fat_fd = parent_loc->node_access;
72    fat_file_fd_t    *fat_fd = NULL;
73    time_t            time_ret = 0;
74    uint16_t          time_val = 0;
75    uint16_t          date = 0;
76    fat_dir_pos_t     dir_pos;
77    msdos_name_type_t name_type;
78    char              short_node[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE];
79    char              dot_dotdot[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE * 2];
80    char              link_node[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE];
81    uint32_t          sec = 0;
82    uint32_t          byte = 0;
83
84    fat_dir_pos_init(&dir_pos);
85
86    memset(short_node, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
87    memset(dot_dotdot, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE * 2);
88
89    if (name_len > MSDOS_NAME_MAX_LFN_WITH_DOT) {
90        rtems_set_errno_and_return_minus_one(ENAMETOOLONG);
91    }
92
93    name_type = msdos_long_to_short (fs_info->converter,
94                                     name, name_len,
95                                     MSDOS_DIR_NAME(short_node),
96                                     MSDOS_NAME_MAX);
97    if (name_type == MSDOS_NAME_INVALID) {
98        rtems_set_errno_and_return_minus_one(EINVAL);
99    }
100
101    /* fill reserved field */
102    *MSDOS_DIR_NT_RES(short_node) = MSDOS_RES_NT_VALUE;
103
104    /* set up last write date and time */
105    time_ret = time(NULL);
106    if ( time_ret == -1 )
107        return -1;
108
109    msdos_date_unix2dos(time_ret, &date, &time_val);
110    *MSDOS_DIR_CRT_TIME(short_node) = CT_LE_W(time_val);
111    *MSDOS_DIR_CRT_DATE(short_node) = CT_LE_W(date);
112    *MSDOS_DIR_WRITE_TIME(short_node) = CT_LE_W(time_val);
113    *MSDOS_DIR_WRITE_DATE(short_node) = CT_LE_W(date);
114    *MSDOS_DIR_LAST_ACCESS_DATE(short_node) = CT_LE_W(date);
115
116    /* initialize directory/file size */
117    *MSDOS_DIR_FILE_SIZE(short_node) = MSDOS_INIT_DIR_SIZE;
118
119    if (type == MSDOS_DIRECTORY) {
120      *MSDOS_DIR_ATTR(short_node) |= MSDOS_ATTR_DIRECTORY;
121    }
122    else if (type == MSDOS_HARD_LINK) {
123      /*
124       * when we establish a (temporary) hard link,
125       * we must copy some information from the original
126       * node to the newly created
127       */
128      /*
129       * read the original directory entry
130       */
131      sec = fat_cluster_num_to_sector_num(&fs_info->fat,
132                                          link_fd->dir_pos.sname.cln);
133      sec += (link_fd->dir_pos.sname.ofs >> fs_info->fat.vol.sec_log2);
134      byte = (link_fd->dir_pos.sname.ofs & (fs_info->fat.vol.bps - 1));
135
136      ret = _fat_block_read(&fs_info->fat,
137                            sec, byte, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE,
138                            link_node);
139      if (ret < 0) {
140          return -1;
141      }
142      /*
143       * copy various attributes
144       */
145      *MSDOS_DIR_ATTR(short_node)          =*MSDOS_DIR_ATTR(link_node);
146      *MSDOS_DIR_CRT_TIME_TENTH(short_node)=*MSDOS_DIR_CRT_TIME_TENTH(link_node);
147      *MSDOS_DIR_CRT_TIME(short_node)      =*MSDOS_DIR_CRT_TIME(link_node);
148      *MSDOS_DIR_CRT_DATE(short_node)      =*MSDOS_DIR_CRT_DATE(link_node);
149
150      /*
151       * copy/set "file size", "first cluster"
152       */
153      *MSDOS_DIR_FILE_SIZE(short_node)     =*MSDOS_DIR_FILE_SIZE(link_node);
154
155      *MSDOS_DIR_FIRST_CLUSTER_LOW(short_node) =
156           *MSDOS_DIR_FIRST_CLUSTER_LOW(link_node);
157      *MSDOS_DIR_FIRST_CLUSTER_HI(short_node) =
158           *MSDOS_DIR_FIRST_CLUSTER_HI(link_node);
159      /*
160       * set "archive bit" due to changes
161       */
162      *MSDOS_DIR_ATTR(short_node) |= MSDOS_ATTR_ARCHIVE;
163    }
164    else { /* regular file... */
165        *MSDOS_DIR_ATTR(short_node) |= MSDOS_ATTR_ARCHIVE;
166    }
167
168    /*
169     * find free space in the parent directory and write new initialized
170     * FAT 32 Bytes Directory Entry Structure to the disk
171     */
172    rc = msdos_get_name_node(parent_loc, true, name, name_len,
173                             name_type, &dir_pos, short_node);
174    if ( rc != RC_OK )
175        return rc;
176
177    /*
178     * if we create a new file we are done, if directory there are more steps
179     * to do
180     */
181    if (type == MSDOS_DIRECTORY)
182    {
183        /* open new directory as fat-file */
184        rc = fat_file_open(&fs_info->fat, &dir_pos, &fat_fd);
185        if (rc != RC_OK)
186            goto err;
187
188        /*
189         * we opened fat-file for node we just created, so initialize fat-file
190         * descritor
191         */
192        fat_fd->fat_file_size = 0;
193        fat_fd->fat_file_type = FAT_DIRECTORY;
194        fat_fd->size_limit = MSDOS_MAX_DIR_LENGHT;
195
196        /*
197         * dot and dotdot entries are identical to new node except the
198         * names
199         */
200        memcpy(DOT_NODE_P(dot_dotdot), short_node,
201               MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
202        memcpy(DOTDOT_NODE_P(dot_dotdot), short_node,
203               MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
204        memcpy(MSDOS_DIR_NAME(DOT_NODE_P(dot_dotdot)), MSDOS_DOT_NAME,
205               MSDOS_NAME_MAX);
206        memcpy(MSDOS_DIR_NAME(DOTDOT_NODE_P(dot_dotdot)), MSDOS_DOTDOT_NAME,
207               MSDOS_NAME_MAX);
208
209        /* set up cluster num for dotdot entry */
210        /*
211         * here we can ommit FAT32 condition because for all FAT types dirs
212         * right under root dir should contain 0 in dotdot entry but for
213         * FAT12/16 parent_fat_fd->cluster_num always contains such value
214         */
215        if ((FAT_FD_OF_ROOT_DIR(parent_fat_fd)) &&
216            (fs_info->fat.vol.type & FAT_FAT32))
217        {
218            *MSDOS_DIR_FIRST_CLUSTER_LOW(DOTDOT_NODE_P(dot_dotdot)) = 0x0000;
219            *MSDOS_DIR_FIRST_CLUSTER_HI(DOTDOT_NODE_P(dot_dotdot)) = 0x0000;
220        }
221        else
222        {
223            *MSDOS_DIR_FIRST_CLUSTER_LOW(DOTDOT_NODE_P(dot_dotdot)) =
224                CT_LE_W((uint16_t  )((parent_fat_fd->cln) & 0x0000FFFF));
225            *MSDOS_DIR_FIRST_CLUSTER_HI(DOTDOT_NODE_P(dot_dotdot)) =
226                CT_LE_W((uint16_t  )(((parent_fat_fd->cln) & 0xFFFF0000)>>16));
227        }
228
229        /*
230         * write dot and dotdot entries to new fat-file: currently fat-file
231         * correspondes to a new node is zero length, so it will be extended
232         * by one cluster and entries will be written
233         */
234        ret = fat_file_write(&fs_info->fat, fat_fd, 0,
235                             MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE * 2,
236                             (uint8_t *)dot_dotdot);
237        if (ret < 0)
238        {
239            rc = -1;
240            goto error;
241        }
242
243        /* increment fat-file size by cluster size */
244        fat_fd->fat_file_size += fs_info->fat.vol.bpc;
245
246        /* set up cluster num for dot entry */
247        *MSDOS_DIR_FIRST_CLUSTER_LOW(DOT_NODE_P(dot_dotdot)) =
248                CT_LE_W((uint16_t  )((fat_fd->cln) & 0x0000FFFF));
249        *MSDOS_DIR_FIRST_CLUSTER_HI(DOT_NODE_P(dot_dotdot)) =
250                CT_LE_W((uint16_t  )(((fat_fd->cln) & 0xFFFF0000) >> 16));
251
252        /* rewrite dot entry */
253        ret = fat_file_write(&fs_info->fat, fat_fd, 0,
254                             MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE,
255                             (uint8_t *)DOT_NODE_P(dot_dotdot));
256        if (ret < 0)
257        {
258            rc = -1;
259            goto error;
260        }
261
262        /* write first cluster num of a new directory to disk */
263        rc = msdos_set_first_cluster_num(parent_loc->mt_entry, fat_fd);
264        if (rc != RC_OK)
265            goto error;
266
267        fat_file_close(&fs_info->fat, fat_fd);
268    }
269    return RC_OK;
270
271error:
272    fat_file_close(&fs_info->fat, fat_fd);
273
274err:
275    /* mark the used 32bytes structure on the disk as free */
276    msdos_set_first_char4file_name(parent_loc->mt_entry, &dir_pos, 0xE5);
277    return rc;
278}
Note: See TracBrowser for help on using the repository browser.