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

4.115
Last change on this file since a7eaaae8 was a7eaaae8, checked in by Sebastian Huber <sebastian.huber@…>, on Oct 20, 2014 at 7:33:34 AM

dosfs: Support ctime and mtime

Implement ctime and mtime updates according to POSIX. The ctime is
mapped to the FAT create time and date. The mtime is mapped to the FAT
last modified time and date. For the atime use the mtime for
simplicity.

  • 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            now;
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    now = time(NULL);
106    fat_file_set_ctime_mtime(parent_fat_fd, now);
107
108    msdos_date_unix2dos(now, &date, &time_val);
109    *MSDOS_DIR_CRT_TIME(short_node) = CT_LE_W(time_val);
110    *MSDOS_DIR_CRT_DATE(short_node) = CT_LE_W(date);
111    *MSDOS_DIR_WRITE_TIME(short_node) = CT_LE_W(time_val);
112    *MSDOS_DIR_WRITE_DATE(short_node) = CT_LE_W(date);
113    *MSDOS_DIR_LAST_ACCESS_DATE(short_node) = CT_LE_W(date);
114
115    /* initialize directory/file size */
116    *MSDOS_DIR_FILE_SIZE(short_node) = MSDOS_INIT_DIR_SIZE;
117
118    if (type == MSDOS_DIRECTORY) {
119      *MSDOS_DIR_ATTR(short_node) |= MSDOS_ATTR_DIRECTORY;
120    }
121    else if (type == MSDOS_HARD_LINK) {
122      /*
123       * when we establish a (temporary) hard link,
124       * we must copy some information from the original
125       * node to the newly created
126       */
127      /*
128       * read the original directory entry
129       */
130      sec = fat_cluster_num_to_sector_num(&fs_info->fat,
131                                          link_fd->dir_pos.sname.cln);
132      sec += (link_fd->dir_pos.sname.ofs >> fs_info->fat.vol.sec_log2);
133      byte = (link_fd->dir_pos.sname.ofs & (fs_info->fat.vol.bps - 1));
134
135      ret = _fat_block_read(&fs_info->fat,
136                            sec, byte, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE,
137                            link_node);
138      if (ret < 0) {
139          return -1;
140      }
141      /*
142       * copy various attributes
143       */
144      *MSDOS_DIR_ATTR(short_node)          =*MSDOS_DIR_ATTR(link_node);
145      *MSDOS_DIR_CRT_TIME_TENTH(short_node)=*MSDOS_DIR_CRT_TIME_TENTH(link_node);
146      *MSDOS_DIR_CRT_TIME(short_node)      =*MSDOS_DIR_CRT_TIME(link_node);
147      *MSDOS_DIR_CRT_DATE(short_node)      =*MSDOS_DIR_CRT_DATE(link_node);
148
149      /*
150       * copy/set "file size", "first cluster"
151       */
152      *MSDOS_DIR_FILE_SIZE(short_node)     =*MSDOS_DIR_FILE_SIZE(link_node);
153
154      *MSDOS_DIR_FIRST_CLUSTER_LOW(short_node) =
155           *MSDOS_DIR_FIRST_CLUSTER_LOW(link_node);
156      *MSDOS_DIR_FIRST_CLUSTER_HI(short_node) =
157           *MSDOS_DIR_FIRST_CLUSTER_HI(link_node);
158      /*
159       * set "archive bit" due to changes
160       */
161      *MSDOS_DIR_ATTR(short_node) |= MSDOS_ATTR_ARCHIVE;
162    }
163    else { /* regular file... */
164        *MSDOS_DIR_ATTR(short_node) |= MSDOS_ATTR_ARCHIVE;
165    }
166
167    /*
168     * find free space in the parent directory and write new initialized
169     * FAT 32 Bytes Directory Entry Structure to the disk
170     */
171    rc = msdos_get_name_node(parent_loc, true, name, name_len,
172                             name_type, &dir_pos, short_node);
173    if ( rc != RC_OK )
174        return rc;
175
176    /*
177     * if we create a new file we are done, if directory there are more steps
178     * to do
179     */
180    if (type == MSDOS_DIRECTORY)
181    {
182        /* open new directory as fat-file */
183        rc = fat_file_open(&fs_info->fat, &dir_pos, &fat_fd);
184        if (rc != RC_OK)
185            goto err;
186
187        /*
188         * we opened fat-file for node we just created, so initialize fat-file
189         * descritor
190         */
191        fat_fd->fat_file_size = 0;
192        fat_fd->fat_file_type = FAT_DIRECTORY;
193        fat_fd->size_limit = MSDOS_MAX_DIR_LENGHT;
194        fat_file_set_ctime_mtime(fat_fd, now);
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 = fat_file_write_first_cluster_num(&fs_info->fat, 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.