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

4.104.115
Last change on this file since 7baa484 was 7baa484, checked in by Chris Johns <chrisj@…>, on 06/12/09 at 01:53:33

2009-06-12 Chris Johns <chrisj@…>

  • libblock/src/bdbuf.c: Update comments.
  • libblock/src/bdpart.c, libblock/src/ide_part_table.c: Get the device from the rdev field of the stat buf.
  • libcsupport/include/rtems/libio.h: Add a path length to evalpath handler. Add parent locations to rmmod and unlink handlers.
  • libcsupport/include/rtems/libio_.h: Add a path length to rtems_filesystem_evaluate_path. Add rtems_filesystem_evaluate_relative_path, rtems_filesystem_dirname, and rtems_filesystem_prefix_separators. Remove rtems_filesystem_evaluate_parent.
  • libcsupport/src/base_fs.c, libcsupport/src/chdir.c, libcsupport/src/chmod.c, libcsupport/src/chown.c, libcsupport/src/chroot.c, libcsupport/src/fchdir.c, libcsupport/src/link.c, libcsupport/src/mount.c, libcsupport/src/open.c, libcsupport/src/privateenv.c, libcsupport/src/readlink.c, libcsupport/src/unmount.c, libcsupport/src/utime.c, libcsupport/src/unmount.c, libcsupport/src/utime.c, libfs/src/devfs/devfs.h, libfs/src/devfs/devfs_eval.c, libfs/src/devfs/devstat.c, libfs/src/dosfs/msdos_create.c, libfs/src/dosfs/msdos_misc.c, libfs/src/imfs/imfs.h, libfs/src/imfs/imfs_eval.c, libfs/src/imfs/imfs_load_tar.c, libfs/src/imfs/ioman.c, libfs/src/pipe/pipe.c, libmisc/fsmount/fsmount.c, libnetworking/lib/ftpfs.c: Add the length parameter to the eval call.
  • libcsupport/src/eval.c: Add rtems_filesystem_prefix_separators, rtems_filesystem_dirname, rtems_filesystem_evaluate_relative_path. Add the length parameter to the eval call.
  • libcsupport/src/rmdir.c: Find the parent pathloc then the node pathloc from that node. Remove the call to find the parent given the node pathloc.
  • libcsupport/src/stat.c: Add the length parameter to the eval call. Set the device into the rdev field.
  • libcsupport/src/unlink.c: Find the parent pathloc then the node pathloc from that node. Remove the call to find the parent given the node pathloc.
  • libfs/src/dosfs/fat.c, libfs/src/dosfs/msdos_format.c: Get the disk device number from the stat rdev field.
  • libfs/src/dosfs/msdos.h: Add the length parameter to the eval call. Add the parent pathloc to the rmnod handler.
  • libfs/src/dosfs/msdos_dir.c: Add the parent pathloc to the rmnod handler.
  • libfs/src/dosfs/msdos_eval.c: Add the length parameter to the eval and token call.
  • libfs/src/imfs/imfs_directory.c: Add the parent pathloc to the rmnod handler.
  • libfs/src/imfs/imfs_fchmod.c: Do not test the mode flags for only the allowed flags. Add the missing flags spec'ed in the POSIX standard.
  • libfs/src/imfs/imfs_fsunmount.c, libfs/src/imfs/imfs_rmnod.c, libfs/src/imfs/imfs_unlink.c, libfs/src/imfs/memfile.c: Add the parent node. Currently ignored in the IMFS.
  • libfs/src/imfs/imfs_stat.c: Return the device number in the rdev field.
  • libfs/src/imfs/imfs_mknod.c, libfs/src/imfs/imfs_symlink.c : Add the length parameter to the token call.
  • libfs/src/nfsclient/src/nfs.c: Add the length parameter to the eval call and parent node to the rmnod and unlink command.
  • libmisc/shell/internal.h: Remove the libc mounter decl to make public.
  • libmisc/shell/main_mount.c: Add support for hooking external mount support for new file systems.
  • libmisc/shell/shell.h: Add helper functions for the mount command.
  • Property mode set to 100644
File size: 12.0 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 <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23#include <rtems/libio_.h>
24#include <time.h>
25
26#include "fat.h"
27#include "fat_fat_operations.h"
28#include "fat_file.h"
29
30#include "msdos.h"
31
32/* msdos_creat_node --
33 *     Create a new node. Determine if the name is a long name. If long we to
34 *     scan the directory to create a short entry.
35 *
36 *
37
38
39
40 *     If a new node is file, FAT 32 Bytes Directory
41 *     Entry Structure is initialized, free space is found in parent
42 *     directory and structure is written to the disk. In case of directory,
43 *     all above steps present and also new cluster is allocated for a
44 *     new directory and dot and dotdot nodes are created in alloceted cluster.
45 *
46 * PARAMETERS:
47 *     parent_loc - parent (directory we are going to create node in)
48 *     type       - new node type (file or directory)
49 *     name       - new node name
50 *     mode       - mode
51 *     link_info  - fs_info of existing node for a pseudo "hard-link"
52 *                  (see msdos_file.c, msdos_link for documentation)
53 *
54 * RETURNS:
55 *     RC_OK on success, or -1 if error occured (errno set appropriately).
56 *
57 */
58int
59msdos_creat_node(rtems_filesystem_location_info_t  *parent_loc,
60                 msdos_node_type_t                  type,
61                 const char                        *name,
62                 int                                name_len,
63                 mode_t                             mode,
64                 const fat_file_fd_t               *link_fd)
65{
66    int               rc = RC_OK;
67    ssize_t           ret = 0;
68    msdos_fs_info_t  *fs_info = parent_loc->mt_entry->fs_info;
69    fat_file_fd_t    *parent_fat_fd = parent_loc->node_access;
70    fat_file_fd_t    *fat_fd = NULL;
71    time_t            time_ret = 0;
72    uint16_t          time_val = 0;
73    uint16_t          date = 0;
74    fat_dir_pos_t     dir_pos;
75    msdos_name_type_t name_type;
76    char              short_node[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE];
77    char              dot_dotdot[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE * 2];
78    char              link_node[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE];
79    uint32_t          sec = 0;
80    uint32_t          byte = 0;
81
82    fat_dir_pos_init(&dir_pos);
83   
84    memset(short_node, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
85    memset(dot_dotdot, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE * 2);
86
87    name_type = msdos_long_to_short (name, name_len,
88                                     MSDOS_DIR_NAME(short_node),
89                                     MSDOS_NAME_MAX);
90
91    /* fill reserved field */
92    *MSDOS_DIR_NT_RES(short_node) = MSDOS_RES_NT_VALUE;
93
94    /* set up last write date and time */
95    time_ret = time(NULL);
96    if ( time_ret == -1 )
97        return -1;
98
99    msdos_date_unix2dos(time_ret, &date, &time_val);
100    *MSDOS_DIR_WRITE_TIME(short_node) = CT_LE_W(time_val);
101    *MSDOS_DIR_WRITE_DATE(short_node) = CT_LE_W(date);
102
103    /* initialize directory/file size */
104    *MSDOS_DIR_FILE_SIZE(short_node) = MSDOS_INIT_DIR_SIZE;
105
106    if (type == MSDOS_DIRECTORY) {
107      *MSDOS_DIR_ATTR(short_node) |= MSDOS_ATTR_DIRECTORY;
108    }
109    else if (type == MSDOS_HARD_LINK) {
110      /*
111       * when we establish a (temporary) hard link,
112       * we must copy some information from the original
113       * node to the newly created
114       */
115      /*
116       * read the original directory entry
117       */
118      sec = fat_cluster_num_to_sector_num(parent_loc->mt_entry,
119                                          link_fd->dir_pos.sname.cln);
120      sec += (link_fd->dir_pos.sname.ofs >> fs_info->fat.vol.sec_log2);
121      byte = (link_fd->dir_pos.sname.ofs & (fs_info->fat.vol.bps - 1));
122
123      ret = _fat_block_read(parent_loc->mt_entry,
124                            sec, byte, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE,
125                            link_node);
126      if (ret < 0) {
127          return -1;
128      }
129      /*
130       * copy various attributes
131       */
132      *MSDOS_DIR_ATTR(short_node)          =*MSDOS_DIR_ATTR(link_node);
133      *MSDOS_DIR_CRT_TIME_TENTH(short_node)=*MSDOS_DIR_CRT_TIME_TENTH(link_node);
134      *MSDOS_DIR_CRT_TIME(short_node)      =*MSDOS_DIR_CRT_TIME(link_node);
135      *MSDOS_DIR_CRT_DATE(short_node)      =*MSDOS_DIR_CRT_DATE(link_node);
136
137      /*
138       * copy/set "file size", "first cluster"
139       */
140      *MSDOS_DIR_FILE_SIZE(short_node)     =*MSDOS_DIR_FILE_SIZE(link_node);
141
142      *MSDOS_DIR_FIRST_CLUSTER_LOW(short_node) =
143           *MSDOS_DIR_FIRST_CLUSTER_LOW(link_node);
144      *MSDOS_DIR_FIRST_CLUSTER_HI(short_node) =
145           *MSDOS_DIR_FIRST_CLUSTER_HI(link_node);
146      /*
147       * set "archive bit" due to changes
148       */
149      *MSDOS_DIR_ATTR(short_node) |= MSDOS_ATTR_ARCHIVE;
150      /*
151       * set "last access" date to today
152       */
153      *MSDOS_DIR_LAST_ACCESS_DATE(short_node) = CT_LE_W(date);
154    }
155    else { /* regular file... */
156        *MSDOS_DIR_ATTR(short_node) |= MSDOS_ATTR_ARCHIVE;
157    }
158
159    /*
160     * find free space in the parent directory and write new initialized
161     * FAT 32 Bytes Directory Entry Structure to the disk
162     */
163    rc = msdos_get_name_node(parent_loc, true, name, name_len,
164                             name_type, &dir_pos, short_node);
165    if ( rc != RC_OK )
166        return rc;
167
168    /*
169     * if we create a new file we are done, if directory there are more steps
170     * to do
171     */
172    if (type == MSDOS_DIRECTORY)
173    {
174        /* open new directory as fat-file */
175        rc = fat_file_open(parent_loc->mt_entry, &dir_pos, &fat_fd);
176        if (rc != RC_OK)
177            goto err;
178
179        /*
180         * we opened fat-file for node we just created, so initialize fat-file
181         * descritor
182         */
183        fat_fd->fat_file_size = 0;
184        fat_fd->fat_file_type = FAT_DIRECTORY;
185        fat_fd->size_limit = MSDOS_MAX_DIR_LENGHT;
186
187        /*
188         * dot and dotdot entries are identical to new node except the
189         * names
190         */
191        memcpy(DOT_NODE_P(dot_dotdot), short_node,
192               MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
193        memcpy(DOTDOT_NODE_P(dot_dotdot), short_node,
194               MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
195        memcpy(MSDOS_DIR_NAME(DOT_NODE_P(dot_dotdot)), MSDOS_DOT_NAME,
196               MSDOS_NAME_MAX);
197        memcpy(MSDOS_DIR_NAME(DOTDOT_NODE_P(dot_dotdot)), MSDOS_DOTDOT_NAME,
198               MSDOS_NAME_MAX);
199
200        /* set up cluster num for dotdot entry */
201        /*
202         * here we can ommit FAT32 condition because for all FAT types dirs
203         * right under root dir should contain 0 in dotdot entry but for
204         * FAT12/16 parent_fat_fd->cluster_num always contains such value
205         */
206        if ((FAT_FD_OF_ROOT_DIR(parent_fat_fd)) &&
207            (fs_info->fat.vol.type & FAT_FAT32))
208        {
209            *MSDOS_DIR_FIRST_CLUSTER_LOW(DOTDOT_NODE_P(dot_dotdot)) = 0x0000;
210            *MSDOS_DIR_FIRST_CLUSTER_HI(DOTDOT_NODE_P(dot_dotdot)) = 0x0000;
211        }
212        else
213        {
214            *MSDOS_DIR_FIRST_CLUSTER_LOW(DOTDOT_NODE_P(dot_dotdot)) =
215                CT_LE_W((uint16_t  )((parent_fat_fd->cln) & 0x0000FFFF));
216            *MSDOS_DIR_FIRST_CLUSTER_HI(DOTDOT_NODE_P(dot_dotdot)) =
217                CT_LE_W((uint16_t  )(((parent_fat_fd->cln) & 0xFFFF0000)>>16));
218        }
219
220        /*
221         * write dot and dotdot entries to new fat-file: currently fat-file
222         * correspondes to a new node is zero length, so it will be extended
223         * by one cluster and entries will be written
224         */
225        ret = fat_file_write(parent_loc->mt_entry, fat_fd, 0,
226                             MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE * 2,
227                             (uint8_t *)dot_dotdot);
228        if (ret < 0)
229        {
230            rc = -1;
231            goto error;
232        }
233
234        /* increment fat-file size by cluster size */
235        fat_fd->fat_file_size += fs_info->fat.vol.bpc;
236
237        /* set up cluster num for dot entry */
238        *MSDOS_DIR_FIRST_CLUSTER_LOW(DOT_NODE_P(dot_dotdot)) =
239                CT_LE_W((uint16_t  )((fat_fd->cln) & 0x0000FFFF));
240        *MSDOS_DIR_FIRST_CLUSTER_HI(DOT_NODE_P(dot_dotdot)) =
241                CT_LE_W((uint16_t  )(((fat_fd->cln) & 0xFFFF0000) >> 16));
242
243        /* rewrite dot entry */
244        ret = fat_file_write(parent_loc->mt_entry, fat_fd, 0,
245                             MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE,
246                             (uint8_t *)DOT_NODE_P(dot_dotdot));
247        if (ret < 0)
248        {
249            rc = -1;
250            goto error;
251        }
252
253        /* write first cluster num of a new directory to disk */
254        rc = msdos_set_first_cluster_num(parent_loc->mt_entry, fat_fd);
255        if (rc != RC_OK)
256            goto error;
257
258        fat_file_close(parent_loc->mt_entry, fat_fd);
259    }
260    return RC_OK;
261
262error:
263    fat_file_close(parent_loc->mt_entry, fat_fd);
264
265err:
266    /* mark the used 32bytes structure on the disk as free */
267    msdos_set_first_char4file_name(parent_loc->mt_entry, &dir_pos, 0xE5);
268    return rc;
269}
270
271/* msdos_file_link --
272 *     Replacement for a file "link" operation.
273 *     MSDOS FAT FS does not support links, but this call is needed to
274 *     allow "rename" operations. The current NEWLIB rename performs a link
275 *     from the old to the new name and then deletes the old filename.
276 *
277 *     This pseudo-"link" operation will create a new directory entry,
278 *     copy the file size and cluster information from the "old"
279 *     to the "new" directory entry and then clear the file size and cluster
280 *     info from the "old" filename, leaving this file as
281 *     a valid, but empty entry.
282 *
283 *     When this "link" call is part of a "rename" sequence, the "old"
284 *     entry will be deleted in a subsequent "rmnod" call
285 *
286 *     This function has been implemented by Thomas Doerfler,
287 *     <Thomas.Doerfler@imd-systems.de>
288 *
289 * PARAMETERS:
290 *     to_loc     - node description for "existing" node
291 *     par_loc    - node description for "new" node
292 *     token      - name of new node
293 *
294 * RETURNS:
295 *     RC_OK on success, or -1 if error occured (errno set appropriately)
296 */
297int
298msdos_file_link(rtems_filesystem_location_info_t *to_loc,
299                rtems_filesystem_location_info_t *par_loc,
300                const char                       *name
301)
302{
303    int                rc = RC_OK;
304    rtems_status_code  sc = RTEMS_SUCCESSFUL;
305    msdos_fs_info_t   *fs_info     = to_loc->mt_entry->fs_info;
306    fat_file_fd_t     *to_fat_fd   = to_loc->node_access;
307    const char        *token;
308    int                len;
309
310    /*
311     * check spelling and format new node name
312     */
313    if (MSDOS_NAME != msdos_get_token(name, strlen(name), &token, &len)) {
314      rtems_set_errno_and_return_minus_one(ENAMETOOLONG);
315    }
316    /*
317     * verify, that the existing node can be linked to
318     * check that nodes are in same FS/volume?
319     */
320    if (to_loc->mt_entry->fs_info != par_loc->mt_entry->fs_info) {
321      rtems_set_errno_and_return_minus_one(EXDEV);
322    }
323    /*
324     * lock volume
325     */
326    sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
327                                MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
328    if (sc != RTEMS_SUCCESSFUL)
329        rtems_set_errno_and_return_minus_one(EIO);
330
331
332    /*
333     * create new directory entry as "hard link",
334     * copying relevant info from existing file
335     */
336    rc = msdos_creat_node(par_loc,MSDOS_HARD_LINK,name,len,S_IFREG,
337                          to_loc->node_access);
338    /*
339     * set file size and first cluster number of old entry to 0
340     */
341    if (rc == RC_OK) {
342      to_fat_fd->fat_file_size = 0;
343      to_fat_fd->cln           = FAT_EOF;
344      rc = msdos_set_first_cluster_num(to_loc->mt_entry, to_fat_fd);
345      if (rc == RC_OK) {
346          rc = msdos_set_file_size(par_loc->mt_entry, to_fat_fd);
347      }
348    }
349    /*
350     * FIXME: check error/abort handling
351     */
352    rtems_semaphore_release(fs_info->vol_sema);
353    return rc;
354}
Note: See TracBrowser for help on using the repository browser.