source: rtems/cpukit/libfs/src/dosfs/msdos_create.c @ 040ed0b4

4.115
Last change on this file since 040ed0b4 was c499856, checked in by Chris Johns <chrisj@…>, on 03/20/14 at 21:10:47

Change all references of rtems.com to rtems.org.

  • 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.org/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.