source: rtems/cpukit/libfs/src/dosfs/msdos_dir.c @ 2742cc3

Last change on this file since 2742cc3 was f36a7bfc, checked in by Joel Sherrill <joel.sherrill@…>, on 02/28/02 at 20:43:50

2002-02-28 Victor V. Vengerov <vvv@…>

  • DOS filesystem including FAT12, FAT16, and FAT32 support submitted.
  • src/dosfs, src/dosfs/Makefile.am, src/dosfs/stamp-h2.in, src/dosfs/config.h.in, src/dosfs/dosfs.h, src/dosfs/fat.c, src/dosfs/fat.h, src/dosfs/fat_fat_operations.c, src/dosfs/fat_fat_operations.h, src/dosfs/fat_file.c, src/dosfs/fat_file.h, src/dosfs/msdos.h, src/dosfs/msdos_create.c, src/dosfs/msdos_dir.c, src/dosfs/msdos_eval.c, src/dosfs/msdos_file.c, src/dosfs/msdos_free.c, src/dosfs/msdos_fsunmount.c, src/dosfs/msdos_handlers_dir.c, src/dosfs/msdos_handlers_file.c, src/dosfs/msdos_init.c, src/dosfs/msdos_initsupp.c, src/dosfs/msdos_misc.c, src/dosfs/msdos_mknod.c, src/dosfs/msdos_node_type.c, src/dosfs/.cvsignore: New files.
  • configure.ac, src/Makefile.am, wrapup/Makefile.am: Modified to reflect addition.
  • Property mode set to 100644
File size: 14.7 KB
Line 
1/*
2 *  MSDOS directory handlers implementation
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.OARcorp.com/rtems/license.html.
10 *
11 *  @(#) $Id$
12 */
13#if HAVE_CONFIG_H
14#include "config.h"
15#endif
16
17#include <stdlib.h>
18#include <unistd.h>
19#include <assert.h>
20#include <errno.h>
21#include <rtems/libio_.h>
22#include <sys/types.h>
23#include <sys/stat.h>
24
25#include <dirent.h>
26
27#include "fat.h"
28#include "fat_fat_operations.h"
29#include "fat_file.h"
30
31#include "msdos.h"
32
33/* msdos_dir_open --
34 *     Open fat-file which correspondes to the directory being opened and
35 *     set offset field of file control block to zero.
36 *
37 * PARAMETERS:
38 *     iop        - file control block
39 *     pathname   - name
40 *     flag       - flags
41 *     mode       - mode
42 *
43 * RETURNS:
44 *     RC_OK, if directory opened successfully, or -1 if error occured (errno
45 *     set apropriately)
46 */
47int
48msdos_dir_open(rtems_libio_t *iop, const char *pathname, unsigned32 flag,
49               unsigned32 mode)
50{
51    int                rc = RC_OK; 
52    rtems_status_code  sc = RTEMS_SUCCESSFUL;
53    msdos_fs_info_t   *fs_info = iop->pathinfo.mt_entry->fs_info;
54    fat_file_fd_t     *fat_fd = iop->file_info;
55
56    sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
57                                MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
58    if (sc != RTEMS_SUCCESSFUL)
59        set_errno_and_return_minus_one( EIO );
60 
61    rc = fat_file_reopen(fat_fd);
62    if (rc != RC_OK)
63    {
64        rtems_semaphore_release(fs_info->vol_sema);
65        return rc;
66    }
67
68    iop->offset = 0;
69    rtems_semaphore_release(fs_info->vol_sema);
70    return RC_OK;
71}
72
73/* msdos_dir_close --
74 *     Close  fat-file which correspondes to the directory being closed
75 *
76 * PARAMETERS:
77 *     iop - file control block
78 *
79 * RETURNS:
80 *     RC_OK, if directory closed successfully, or -1 if error occured (errno
81 *     set apropriately.
82 */
83int
84msdos_dir_close(rtems_libio_t *iop)
85{
86    int                rc = RC_OK;
87    rtems_status_code  sc = RTEMS_SUCCESSFUL;
88    msdos_fs_info_t   *fs_info = iop->pathinfo.mt_entry->fs_info;
89    fat_file_fd_t     *fat_fd = iop->file_info;
90
91    sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
92                                MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
93    if (sc != RTEMS_SUCCESSFUL)
94        set_errno_and_return_minus_one( EIO );
95 
96    rc = fat_file_close(iop->pathinfo.mt_entry, fat_fd);
97    if (rc != RC_OK)
98    {
99        rtems_semaphore_release(fs_info->vol_sema);
100        return rc;
101    }
102
103    rtems_semaphore_release(fs_info->vol_sema);
104    return RC_OK;
105}
106
107/*  msdos_dir_read --
108 *      This routine will read the next directory entry based on the directory
109 *      offset. The offset should be equal to -n- time the size of an
110 *      individual dirent structure. If n is not an integer multiple of the
111 *      sizeof a dirent structure, an integer division will be performed to
112 *      determine directory entry that will be returned in the buffer. Count
113 *      should reflect -m- times the sizeof dirent bytes to be placed in the
114 *      buffer.
115 *      If there are not -m- dirent elements from the current directory
116 *      position to the end of the exisiting file, the remaining entries will
117 *      be placed in the buffer and the returned value will be equal to
118 *      -m actual- times the size of a directory entry.
119 *
120 * PARAMETERS:
121 *     iop    - file control block
122 *     buffer - buffer provided by user
123 *     count  - count of bytes to read
124 *
125 * RETURNS:
126 *     the number of bytes read on success, or -1 if error occured (errno
127 *     set apropriately).
128 */
129ssize_t
130msdos_dir_read(rtems_libio_t *iop, void *buffer, unsigned32 count)
131{
132    int                rc = RC_OK;
133    rtems_status_code  sc = RTEMS_SUCCESSFUL;
134    msdos_fs_info_t   *fs_info = iop->pathinfo.mt_entry->fs_info;
135    fat_file_fd_t     *fat_fd = iop->file_info;
136    fat_file_fd_t     *tmp_fat_fd = NULL;
137    struct dirent      tmp_dirent;
138    unsigned32         start = 0;
139    ssize_t            ret = 0;
140    unsigned32         cmpltd = 0;
141    unsigned32         j = 0, i = 0;
142    unsigned32         bts2rd = 0;
143    unsigned32         cur_cln = 0;
144 
145    /*
146     * cast start and count - protect against using sizes that are not exact
147     * multiples of the -dirent- size. These could result in unexpected
148     * results
149     */
150    start = iop->offset / sizeof(struct dirent);
151    count = (count / sizeof(struct dirent)) * sizeof(struct dirent);           
152 
153    /*
154     * optimization: we know that root directory for FAT12/16 volumes is
155     * sequential set of sectors and any cluster is sequential set of sectors
156     * too, so read such set of sectors is quick operation for low-level IO
157     * layer.
158     */
159    bts2rd = (FAT_FD_OF_ROOT_DIR(fat_fd) &&
160             (fs_info->fat.vol.type & (FAT_FAT12 | FAT_FAT16))) ?
161             fat_fd->fat_file_size                              :
162             fs_info->fat.vol.bpc;     
163
164    sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
165                                MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
166    if (sc != RTEMS_SUCCESSFUL)
167        set_errno_and_return_minus_one(EIO);
168 
169    while (count > 0)
170    { 
171        /*
172         * fat-file is already opened by open call, so read it
173         * Always read directory fat-file from the beggining because of MSDOS
174         * directories feature :( - we should count elements currently
175         * present in the directory because there may be holes :)
176         */
177        ret = fat_file_read(iop->pathinfo.mt_entry, fat_fd, (j * bts2rd),
178                            bts2rd, fs_info->cl_buf);
179        if (ret < MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
180        {
181            rtems_semaphore_release(fs_info->vol_sema);
182            set_errno_and_return_minus_one(EIO);
183        }
184
185        for (i = 0; i < ret; i += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
186        {
187            if ((*MSDOS_DIR_NAME(fs_info->cl_buf + i)) ==
188                MSDOS_THIS_DIR_ENTRY_AND_REST_EMPTY)
189            {
190                rtems_semaphore_release(fs_info->vol_sema);         
191                return cmpltd;
192            } 
193           
194            if ((*MSDOS_DIR_NAME(fs_info->cl_buf + i)) ==
195                MSDOS_THIS_DIR_ENTRY_EMPTY)
196                continue;
197     
198            /*
199             * skip active entries until get the entry to start from
200             */
201            if (start)
202            {
203                start--; 
204                continue;
205            } 
206       
207            /*
208             * Move the entry to the return buffer
209             *
210             * unfortunately there is no method to extract ino except to
211             * open fat-file descriptor :( ... so, open it
212             */
213     
214            /* get number of cluster we are working with */
215            rc = fat_file_ioctl(iop->pathinfo.mt_entry, fat_fd, F_CLU_NUM,
216                                j * bts2rd, &cur_cln);
217            if (rc != RC_OK)
218            {
219                rtems_semaphore_release(fs_info->vol_sema);
220                return rc;
221            }
222
223            rc = fat_file_open(iop->pathinfo.mt_entry, cur_cln, i,
224                               &tmp_fat_fd);
225            if (rc != RC_OK)
226            {
227                rtems_semaphore_release(fs_info->vol_sema);
228                return rc;
229            }
230
231            tmp_fat_fd->info_cln = cur_cln;
232            tmp_fat_fd->info_ofs = i;
233
234            /* fill in dirent structure */
235            /* XXX: from what and in what d_off should be computed ?! */
236            tmp_dirent.d_off = start + cmpltd;
237            tmp_dirent.d_reclen = sizeof(struct dirent);
238            tmp_dirent.d_ino = tmp_fat_fd->ino;
239            tmp_dirent.d_namlen = MSDOS_SHORT_NAME_LEN;
240            memcpy(tmp_dirent.d_name, MSDOS_DIR_NAME((fs_info->cl_buf + i)),
241                   MSDOS_SHORT_NAME_LEN);
242     
243            /* d_name is null-terminated */
244            tmp_dirent.d_name[MSDOS_SHORT_NAME_LEN] = 0;       
245            memcpy(buffer + cmpltd, &tmp_dirent, sizeof(struct dirent));
246   
247            iop->offset = iop->offset + sizeof(struct dirent);
248            cmpltd += (sizeof(struct dirent));
249            count -= (sizeof(struct dirent));
250     
251            /* inode number extracted, close fat-file */
252            rc = fat_file_close(iop->pathinfo.mt_entry, tmp_fat_fd);
253            if (rc != RC_OK)
254            {
255                rtems_semaphore_release(fs_info->vol_sema);
256                return rc;
257            }
258
259            if (count <= 0)
260                break;
261        }
262        j++;
263    }
264
265    rtems_semaphore_release(fs_info->vol_sema);
266    return cmpltd;
267}
268
269/* msdos_dir_write --
270 *     no write for directory
271 */
272
273/* msdos_dir_lseek --
274 *
275 *  This routine will behave in one of three ways based on the state of
276 *  argument whence. Based on the state of its value the offset argument will
277 *  be interpreted using one of the following methods:
278 *
279 *     SEEK_SET - offset is the absolute byte offset from the start of the
280 *                logical start of the dirent sequence that represents the
281 *                directory
282 *     SEEK_CUR - offset is used as the relative byte offset from the current
283 *                directory position index held in the iop structure
284 *     SEEK_END - N/A --> This will cause an assert.
285 *
286 * PARAMETERS:
287 *     iop    - file control block
288 *     offset - offset
289 *     whence - predefine directive
290 *
291 * RETURNS:
292 *     RC_OK on success, or -1 if error occured (errno
293 *     set apropriately).
294 */
295int
296msdos_dir_lseek(rtems_libio_t *iop, off_t offset, int whence)
297{
298    switch (whence)
299    {
300        case SEEK_SET:
301        case SEEK_CUR:
302            break;
303        /*
304         * Movement past the end of the directory via lseek is not a
305         * permitted operation
306         */
307        case SEEK_END:
308        default:
309            set_errno_and_return_minus_one( EINVAL );
310            break;
311    }
312    return RC_OK;
313}
314
315/* msdos_dir_stat --
316 *
317 * This routine will obtain the following information concerning the current
318 * directory:
319 *     st_dev      device id
320 *     st_ino      node serial number :)
321 *     st_mode     mode extracted from the node
322 *     st_size     total size in bytes
323 *     st_blksize  blocksize for filesystem I/O
324 *     st_blocks   number of blocks allocated
325 *     stat_mtime  time of last modification
326 *
327 * PARAMETERS:
328 *     loc - this directory
329 *     buf - stat buffer provided by user
330 *
331 * RETURNS:
332 *     RC_OK and filled stat buffer on success, or -1 if error occured (errno
333 *     set apropriately).
334 */
335int
336msdos_dir_stat(
337    rtems_filesystem_location_info_t *loc,
338    struct stat                      *buf
339    )
340{
341    rtems_status_code  sc = RTEMS_SUCCESSFUL;
342    msdos_fs_info_t   *fs_info = loc->mt_entry->fs_info;
343    fat_file_fd_t     *fat_fd = loc->node_access;
344
345    sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
346                                MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
347    if (sc != RTEMS_SUCCESSFUL)
348        set_errno_and_return_minus_one(EIO);
349 
350    buf->st_dev = fs_info->fat.vol.dev;
351    buf->st_ino = fat_fd->ino;
352    buf->st_mode  = S_IFDIR;
353    buf->st_rdev = 0ll;
354    buf->st_size = fat_fd->fat_file_size;
355    buf->st_blocks = fat_fd->fat_file_size >> FAT_SECTOR512_BITS;
356    buf->st_blksize = fs_info->fat.vol.bps;
357    buf->st_mtime = fat_fd->mtime;
358 
359    rtems_semaphore_release(fs_info->vol_sema);
360    return RC_OK;
361}
362
363/* msdos_dir_truncate --
364 *     No truncate for directory.
365 *
366 * PARAMETERS:
367 *
368 * RETURNS:
369 *
370 */
371
372/* msdos_dir_sync --
373 *     The following routine does a syncronization on a MSDOS directory node.
374 *     DIR_WrtTime, DIR_WrtDate and DIR_fileSize fields of 32 Bytes Directory
375 *     Entry Structure(see M$ White Paper) should not be updated for
376 *     directories, so only call to corresponding fat-file routine.
377 *
378 * PARAMETERS:
379 *     iop - file control block
380 *
381 * RETURNS:
382 *     RC_OK on success, or -1 if error occured (errno set apropriately).
383 */
384int
385msdos_dir_sync(rtems_libio_t *iop)
386{
387    int                rc = RC_OK;
388    rtems_status_code  sc = RTEMS_SUCCESSFUL;
389    fat_file_fd_t     *fat_fd = iop->file_info;
390    msdos_fs_info_t   *fs_info = iop->pathinfo.mt_entry->fs_info;
391 
392    sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
393                                MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
394    if (sc != RTEMS_SUCCESSFUL)
395        set_errno_and_return_minus_one(EIO);
396 
397    rc = fat_file_datasync(iop->pathinfo.mt_entry, fat_fd);
398
399    rtems_semaphore_release(fs_info->vol_sema);
400    return rc;
401}
402
403/* msdos_dir_rmnod --
404 *     Remove directory node.
405 *
406 *     Check that this directory node is not opened as fat-file, is empty and
407 *     not filesystem root node. If all this conditions met then delete.
408 *
409 * PARAMETERS:
410 *     pathloc - node description
411 *
412 * RETURNS:
413 *     RC_OK on success, or -1 if error occured (errno set apropriately).
414 */
415int
416msdos_dir_rmnod(rtems_filesystem_location_info_t *pathloc)
417{
418    int                rc = RC_OK;
419    rtems_status_code  sc = RTEMS_SUCCESSFUL;
420    msdos_fs_info_t   *fs_info = pathloc->mt_entry->fs_info;
421    fat_file_fd_t     *fat_fd = pathloc->node_access;
422    rtems_boolean      is_empty = FALSE;
423 
424    sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
425                                MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
426    if (sc != RTEMS_SUCCESSFUL)
427        set_errno_and_return_minus_one(EIO);
428 
429    /*
430     * We deny attemp to delete open directory (if directory is current
431     * directory we assume it is open one)
432     */
433    if (fat_fd->links_num > 1)
434    {
435        rtems_semaphore_release(fs_info->vol_sema);
436        set_errno_and_return_minus_one(EBUSY);
437    }
438 
439    /*
440     * You cannot remove a node that still has children
441     */
442    rc = msdos_dir_is_empty(pathloc->mt_entry, fat_fd, &is_empty);
443    if (rc != RC_OK)
444    {
445        rtems_semaphore_release(fs_info->vol_sema);
446        return rc;
447    }
448
449    if (!is_empty)
450    {
451        rtems_semaphore_release(fs_info->vol_sema);
452        set_errno_and_return_minus_one(ENOTEMPTY);
453    }     
454
455    /*
456     * You cannot remove the file system root node.
457     */
458    if (pathloc->mt_entry->mt_fs_root.node_access == pathloc->node_access)
459    {
460        rtems_semaphore_release(fs_info->vol_sema);
461        set_errno_and_return_minus_one(EBUSY);
462    }
463
464    /*
465     * You cannot remove a mountpoint.
466     * not used - mount() not implemenetd yet.
467     */
468
469    /* mark file removed */
470    rc = msdos_set_first_char4file_name(pathloc->mt_entry, fat_fd->info_cln,
471                                        fat_fd->info_ofs,
472                                        MSDOS_THIS_DIR_ENTRY_EMPTY);
473    if (rc != RC_OK)
474    {
475        rtems_semaphore_release(fs_info->vol_sema);
476        return rc;
477    }
478
479    fat_file_mark_removed(pathloc->mt_entry, fat_fd);
480
481    rtems_semaphore_release(fs_info->vol_sema);
482    return rc;
483}
Note: See TracBrowser for help on using the repository browser.