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

4.104.114.84.9
Last change on this file since e197621 was e197621, checked in by Joel Sherrill <joel.sherrill@…>, on Aug 29, 2006 at 7:38:08 PM

2006-08-29 Joel Sherrill <joel@…>

  • libfs/src/dosfs/fat.h, libfs/src/dosfs/msdos.h, libfs/src/dosfs/msdos_create.c, libfs/src/dosfs/msdos_eval.c, libfs/src/dosfs/msdos_file.c, libfs/src/dosfs/msdos_free.c, libfs/src/dosfs/msdos_fsunmount.c, libfs/src/dosfs/msdos_init.c, libfs/src/dosfs/msdos_misc.c, libfs/src/dosfs/msdos_mknod.c, libfs/src/imfs/imfs_debug.c: Remove warnings.
  • Property mode set to 100644
File size: 11.4 KB
Line 
1/*
2 * Routine to create a new MSDOS filesystem node
3 *
4 * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
5 * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
6 *
7 * The license and distribution terms for this file may be
8 * found in the file LICENSE in this distribution or at
9 * http://www.rtems.com/license/LICENSE.
10 *
11 * @(#) $Id$
12 *
13 */
14#if HAVE_CONFIG_H
15#include "config.h"
16#endif
17
18#include <errno.h>
19#include <assert.h>
20#include <stdlib.h>
21#include <string.h>
22#include <rtems/libio_.h>
23#include <time.h>
24
25#include "fat.h"
26#include "fat_fat_operations.h"
27#include "fat_file.h"
28
29#include "msdos.h"
30
31/* msdos_creat_node --
32 *     Create a new node. If a new node is file, FAT 32 Bytes Directory
33 *     Entry Structure is initialized, free space is found in parent
34 *     directory and structure is written to the disk. In case of directory,
35 *     all above steps present and also new cluster is allocated for a
36 *     new directory and dot and dotdot nodes are created in alloceted cluster.
37 *
38 * PARAMETERS:
39 *     parent_loc - parent (directory we are going to create node in)
40 *     type       - new node type (file or directory)
41 *     name       - new node name
42 *     mode       - mode
43 *     link_info  - fs_info of existing node for a pseudo "hard-link"
44 *                  (see msdos_file.c, msdos_link for documentation)
45 *
46 * RETURNS:
47 *     RC_OK on success, or -1 if error occured (errno set appropriately).
48 *
49 */
50int
51msdos_creat_node(
52    rtems_filesystem_location_info_t  *parent_loc,
53    msdos_node_type_t                  type,
54    char                              *name,
55    mode_t                             mode,
56    const fat_file_fd_t               *link_fd
57    )
58{
59    int              rc = RC_OK;
60    ssize_t          ret = 0;
61    msdos_fs_info_t *fs_info = parent_loc->mt_entry->fs_info;
62    fat_file_fd_t   *parent_fat_fd = parent_loc->node_access;
63    fat_file_fd_t   *fat_fd = NULL;
64    time_t           time_ret = 0;
65    uint16_t         time_val = 0;
66    uint16_t         date = 0;
67    fat_auxiliary_t  aux;
68    char             new_node  [MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE];
69    char             dot_dotdot[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE * 2];
70    char             link_node [MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE];
71    uint32_t         sec = 0;
72    uint32_t         byte = 0;
73
74    memset(new_node, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
75    memset(dot_dotdot, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE * 2);
76
77    /* set up name */
78    strncpy(MSDOS_DIR_NAME(new_node), name, MSDOS_NAME_MAX);
79
80    /* fill reserved field */
81    *MSDOS_DIR_NT_RES(new_node) = MSDOS_RES_NT_VALUE;
82
83    /* set up last write date and time */
84    time_ret = time(NULL);
85    if ( time_ret == -1 )
86        return -1;
87
88    msdos_date_unix2dos(time_ret, &time_val, &date);
89    *MSDOS_DIR_WRITE_TIME(new_node) = CT_LE_W(time_val);
90    *MSDOS_DIR_WRITE_DATE(new_node) = CT_LE_W(date);
91
92    /* initialize directory/file size */
93    *MSDOS_DIR_FILE_SIZE(new_node) = MSDOS_INIT_DIR_SIZE;
94
95    if (type == MSDOS_DIRECTORY){
96        *MSDOS_DIR_ATTR(new_node) |= MSDOS_ATTR_DIRECTORY;
97    }
98    else if (type == MSDOS_HARD_LINK) {
99      /*
100       * when we establish a (temporary) hard link,
101       * we must copy some information from the original
102       * node to the newly created
103       */
104      /*
105       * read the original directory entry
106       */
107      sec = fat_cluster_num_to_sector_num(parent_loc->mt_entry,
108                                          link_fd->info_cln);
109      sec += (link_fd->info_ofs >> fs_info->fat.vol.sec_log2);
110      byte = (link_fd->info_ofs & (fs_info->fat.vol.bps - 1));
111
112      ret = _fat_block_read(parent_loc->mt_entry,
113                            sec, byte, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE,
114                            link_node);
115      if (ret < 0) {
116        return -1;
117      }
118      /*
119       * copy various attributes
120       */
121      *MSDOS_DIR_ATTR(new_node)          =*MSDOS_DIR_ATTR(link_node);
122      *MSDOS_DIR_CRT_TIME_TENTH(new_node)=*MSDOS_DIR_CRT_TIME_TENTH(link_node);
123      *MSDOS_DIR_CRT_TIME(new_node)      =*MSDOS_DIR_CRT_TIME(link_node);
124      *MSDOS_DIR_CRT_DATE(new_node)      =*MSDOS_DIR_CRT_DATE(link_node);
125
126      /*
127       * copy/set "file size", "first cluster"
128       */
129      *MSDOS_DIR_FILE_SIZE(new_node)     =*MSDOS_DIR_FILE_SIZE(link_node);
130
131      *MSDOS_DIR_FIRST_CLUSTER_LOW(new_node) =
132        *MSDOS_DIR_FIRST_CLUSTER_LOW(link_node);
133      *MSDOS_DIR_FIRST_CLUSTER_HI(new_node) =
134        *MSDOS_DIR_FIRST_CLUSTER_HI(link_node);
135      /*
136       * set "archive bit" due to changes
137       */
138      *MSDOS_DIR_ATTR(new_node) |= MSDOS_ATTR_ARCHIVE;
139      /*
140       * set "last access" date to today
141       */
142      *MSDOS_DIR_LAST_ACCESS_DATE(new_node) = CT_LE_W(date);
143    }
144    else { /* regular file... */
145        *MSDOS_DIR_ATTR(new_node) |= MSDOS_ATTR_ARCHIVE;
146    }
147
148    /*
149     * find free space in the parent directory and write new initialized
150     * FAT 32 Bytes Directory Entry Structure to the disk
151     */
152    rc = msdos_get_name_node(parent_loc, NULL, &aux, new_node);
153    if ( rc != RC_OK )
154        return rc;
155
156    /*
157     * if we create a new file we are done, if directory there are more steps
158     * to do
159     */
160    if (type == MSDOS_DIRECTORY)
161    {
162        /* open new directory as fat-file */
163        rc = fat_file_open(parent_loc->mt_entry, aux.cln, aux.ofs, &fat_fd);
164        if (rc != RC_OK)
165            goto err;
166
167        /*
168         * we opened fat-file for node we just created, so initialize fat-file
169         * descritor
170         */
171        fat_fd->info_cln = aux.cln;
172        fat_fd->info_ofs = aux.ofs;
173        fat_fd->fat_file_size = 0;
174        fat_fd->fat_file_type = FAT_DIRECTORY;
175        fat_fd->size_limit = MSDOS_MAX_DIR_LENGHT;
176
177        /*
178         * dot and dotdot entries are identical to new node except the
179         * names
180         */
181        memcpy(DOT_NODE_P(dot_dotdot), new_node,
182               MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
183        memcpy(DOTDOT_NODE_P(dot_dotdot), new_node,
184               MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
185        memcpy(MSDOS_DIR_NAME(DOT_NODE_P(dot_dotdot)), MSDOS_DOT_NAME,
186               MSDOS_NAME_MAX);
187        memcpy(MSDOS_DIR_NAME(DOTDOT_NODE_P(dot_dotdot)), MSDOS_DOTDOT_NAME,
188               MSDOS_NAME_MAX);
189
190        /* set up cluster num for dotdot entry */
191        /*
192         * here we can ommit FAT32 condition because for all FAT types dirs
193         * right under root dir should contain 0 in dotdot entry but for
194         * FAT12/16 parent_fat_fd->cluster_num always contains such value
195         */
196        if ((FAT_FD_OF_ROOT_DIR(parent_fat_fd)) &&
197            (fs_info->fat.vol.type & FAT_FAT32))
198        {
199            *MSDOS_DIR_FIRST_CLUSTER_LOW(DOTDOT_NODE_P(dot_dotdot)) = 0x0000;
200            *MSDOS_DIR_FIRST_CLUSTER_HI(DOTDOT_NODE_P(dot_dotdot)) = 0x0000;
201        }
202        else
203        {
204            *MSDOS_DIR_FIRST_CLUSTER_LOW(DOTDOT_NODE_P(dot_dotdot)) =
205                CT_LE_W((uint16_t  )((parent_fat_fd->cln) & 0x0000FFFF));
206            *MSDOS_DIR_FIRST_CLUSTER_HI(DOTDOT_NODE_P(dot_dotdot)) =
207                CT_LE_W((uint16_t  )(((parent_fat_fd->cln) & 0xFFFF0000)>>16));
208        }
209
210        /*
211         * write dot and dotdot entries to new fat-file: currently fat-file
212         * correspondes to a new node is zero length, so it will be extended
213         * by one cluster and entries will be written
214         */
215        ret = fat_file_write(parent_loc->mt_entry, fat_fd, 0,
216                             MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE * 2,
217                             (uint8_t *)dot_dotdot);
218        if (ret < 0)
219        {
220            rc = -1;
221            goto error;
222        }
223
224        /* increment fat-file size by cluster size */
225        fat_fd->fat_file_size += fs_info->fat.vol.bpc;
226
227        /* set up cluster num for dot entry */
228        *MSDOS_DIR_FIRST_CLUSTER_LOW(DOT_NODE_P(dot_dotdot)) =
229                CT_LE_W((uint16_t  )((fat_fd->cln) & 0x0000FFFF));
230        *MSDOS_DIR_FIRST_CLUSTER_HI(DOT_NODE_P(dot_dotdot)) =
231                CT_LE_W((uint16_t  )(((fat_fd->cln) & 0xFFFF0000) >> 16));
232
233        /* rewrite dot entry */
234        ret = fat_file_write(parent_loc->mt_entry, fat_fd, 0,
235                             MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE,
236                             (uint8_t *)DOT_NODE_P(dot_dotdot));
237        if (ret < 0)
238        {
239            rc = -1;
240            goto error;
241        }
242
243        /* write first cluster num of a new directory to disk */
244        rc = msdos_set_first_cluster_num(parent_loc->mt_entry, fat_fd);
245        if (rc != RC_OK)
246            goto error;
247
248        fat_file_close(parent_loc->mt_entry, fat_fd);
249    }
250    return RC_OK;
251
252error:
253    fat_file_close(parent_loc->mt_entry, fat_fd);
254
255err:
256    /* mark 32bytes structure on the disk as free */
257    msdos_set_first_char4file_name(parent_loc->mt_entry, aux.cln, aux.ofs,
258                                   0xE5);
259    return rc;
260}
261
262/* msdos_file_link --
263 *     Replacement for a file "link" operation.
264 *     MSDOS FAT FS does not support links, but this call is needed to
265 *     allow "rename" operations. The current NEWLIB rename performs a link
266 *     from the old to the new name and then deletes the old filename.
267 *
268 *     This pseudo-"link" operation will create a new directory entry,
269 *     copy the file size and cluster information from the "old"
270 *     to the "new" directory entry and then clear the file size and cluster
271 *     info from the "old" filename, leaving this file as
272 *     a valid, but empty entry.
273 *
274 *     When this "link" call is part of a "rename" sequence, the "old"
275 *     entry will be deleted in a subsequent "rmnod" call
276 *
277 *     This function has been implemented by Thomas Doerfler,
278 *     <Thomas.Doerfler@imd-systems.de>
279 *
280 * PARAMETERS:
281 *     to_loc     - node description for "existing" node
282 *     par_loc    - node description for "new" node
283 *     token      - name of new node
284 *
285 * RETURNS:
286 *     RC_OK on success, or -1 if error occured (errno set appropriately)
287 */
288int
289msdos_file_link(rtems_filesystem_location_info_t *to_loc,
290                rtems_filesystem_location_info_t *par_loc,
291                const char                       *token
292)
293{
294    int                rc = RC_OK;
295    rtems_status_code  sc = RTEMS_SUCCESSFUL;
296    msdos_fs_info_t   *fs_info     = to_loc->mt_entry->fs_info;
297    fat_file_fd_t     *to_fat_fd   = to_loc->node_access;
298    char               new_name[ MSDOS_NAME_MAX + 1 ];
299    int                len;
300
301    /*
302     * check spelling and format new node name
303     */
304    if (MSDOS_NAME != msdos_get_token(token, new_name, &len)) {
305      set_errno_and_return_minus_one(ENAMETOOLONG);
306    }
307    /*
308     * verify, that the existing node can be linked to
309     * check that nodes are in same FS/volume?
310     */
311    if (to_loc->mt_entry->fs_info != par_loc->mt_entry->fs_info) {
312      set_errno_and_return_minus_one(EXDEV);
313    }
314    /*
315     * lock volume
316     */
317    sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
318                                MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
319    if (sc != RTEMS_SUCCESSFUL)
320        set_errno_and_return_minus_one(EIO);
321
322
323    /*
324     * create new directory entry as "hard link",
325     * copying relevant info from existing file
326     */
327    rc = msdos_creat_node(par_loc,MSDOS_HARD_LINK,new_name,S_IFREG,
328                          to_loc->node_access);
329    /*
330     * set file size and first cluster number of old entry to 0
331     */
332    if (rc == RC_OK) {
333      to_fat_fd->fat_file_size = 0;
334      to_fat_fd->cln           = FAT_EOF;
335      rc = msdos_set_first_cluster_num(to_loc->mt_entry, to_fat_fd);
336      if (rc == RC_OK) {
337        rc = msdos_set_file_size(par_loc->mt_entry, to_fat_fd);
338      }
339    }
340    /*
341     * FIXME: check error/abort handling
342     */
343    rtems_semaphore_release(fs_info->vol_sema);
344    return rc;
345}
Note: See TracBrowser for help on using the repository browser.