source: rtems/cpukit/libfs/src/dosfs/msdos_dir.c @ 6491f67

4.115
Last change on this file since 6491f67 was 6491f67, checked in by Sebastian Huber <sebastian.huber@…>, on 02/09/12 at 11:00:15

Moved empty test in front of busy tests

  • Property mode set to 100644
File size: 21.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.rtems.com/license/LICENSE.
10 *
11 *  @(#) $Id$
12 */
13#if HAVE_CONFIG_H
14#include "config.h"
15#endif
16
17#include <ctype.h>
18#include <stdlib.h>
19#include <unistd.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, uint32_t   flag,
49               uint32_t   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->pathinfo.node_access;
55
56    sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
57                                MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
58    if (sc != RTEMS_SUCCESSFUL)
59        rtems_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->pathinfo.node_access;
90
91    sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
92                                MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
93    if (sc != RTEMS_SUCCESSFUL)
94        rtems_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_format_dirent_with_dot --
108 *      This routine convert a (short) MSDOS filename as present on disk
109 *      (fixed 8+3 characters, filled with blanks, without separator dot)
110 *      to a "normal" format, with between 0 and 8 name chars,
111 *      a separating dot and up to 3 extension characters
112 *   Rules to work:
113 *      - copy any (0-8) "name" part characters that are non-blank
114 *      - if an extension exists, append a dot
115 *      - copy any (0-3) non-blank extension characters
116 *      - append a '\0' (dont count it for the rturn code
117 *
118 * PARAMETERS:
119 *     dst: pointer to destination char array (must be big enough)
120 *     src: pointer to source characters
121 *
122 *
123 * RETURNS:
124 *     the number of bytes (without trailing '\0'(written to destination
125 */
126static ssize_t
127msdos_format_dirent_with_dot(char *dst,const char *src)
128{
129  ssize_t len;
130  int i;
131  const char *src_tmp;
132
133  /*
134   * find last non-blank character of base name
135   */
136  for ((i       =       MSDOS_SHORT_BASE_LEN  ,
137        src_tmp = src + MSDOS_SHORT_BASE_LEN-1);
138       ((i > 0) &&
139        (*src_tmp == ' '));
140       i--,src_tmp--)
141    {};
142  /*
143   * copy base name to destination
144   */
145  src_tmp = src;
146  len = i;
147  while (i-- > 0) {
148    *dst++ = tolower((unsigned char)(*src_tmp++));
149  }
150  /*
151   * find last non-blank character of extension
152   */
153  for ((i       =                            MSDOS_SHORT_EXT_LEN  ,
154        src_tmp = src + MSDOS_SHORT_BASE_LEN+MSDOS_SHORT_EXT_LEN-1);
155       ((i > 0) &&
156        (*src_tmp == ' '));
157       i--,src_tmp--)
158    {};
159  /*
160   * extension is not empty
161   */
162  if (i > 0) {
163    *dst++ = '.'; /* append dot */
164    len += i + 1; /* extension + dot */
165    src_tmp = src + MSDOS_SHORT_BASE_LEN;
166    while (i-- > 0) {
167      *dst++ = tolower((unsigned char)(*src_tmp++));
168      len++;
169    }
170  }
171  *dst = '\0'; /* terminate string */
172
173  return len;
174}
175
176/*  msdos_dir_read --
177 *      This routine will read the next directory entry based on the directory
178 *      offset. The offset should be equal to -n- time the size of an
179 *      individual dirent structure. If n is not an integer multiple of the
180 *      sizeof a dirent structure, an integer division will be performed to
181 *      determine directory entry that will be returned in the buffer. Count
182 *      should reflect -m- times the sizeof dirent bytes to be placed in the
183 *      buffer.
184 *      If there are not -m- dirent elements from the current directory
185 *      position to the end of the exisiting file, the remaining entries will
186 *      be placed in the buffer and the returned value will be equal to
187 *      -m actual- times the size of a directory entry.
188 *
189 * PARAMETERS:
190 *     iop    - file control block
191 *     buffer - buffer provided by user
192 *     count  - count of bytes to read
193 *
194 * RETURNS:
195 *     the number of bytes read on success, or -1 if error occured (errno
196 *     set apropriately).
197 */
198ssize_t
199msdos_dir_read(rtems_libio_t *iop, void *buffer, size_t count)
200{
201    int                rc = RC_OK;
202    rtems_status_code  sc = RTEMS_SUCCESSFUL;
203    msdos_fs_info_t   *fs_info = iop->pathinfo.mt_entry->fs_info;
204    fat_file_fd_t     *fat_fd = iop->pathinfo.node_access;
205    fat_file_fd_t     *tmp_fat_fd = NULL;
206    struct dirent      tmp_dirent;
207    uint32_t           start = 0;
208    ssize_t            ret = 0;
209    uint32_t           cmpltd = 0;
210    uint32_t           j = 0, i = 0;
211    uint32_t           bts2rd = 0;
212    uint32_t           cur_cln = 0;
213    uint32_t           lfn_start = FAT_FILE_SHORT_NAME;
214    uint8_t            lfn_checksum = 0;
215    int                lfn_entries = 0;
216
217    /*
218     * cast start and count - protect against using sizes that are not exact
219     * multiples of the -dirent- size. These could result in unexpected
220     * results
221     */
222    start = iop->offset / sizeof(struct dirent);
223    count = (count / sizeof(struct dirent)) * sizeof(struct dirent);
224
225    /*
226     * optimization: we know that root directory for FAT12/16 volumes is
227     * sequential set of sectors and any cluster is sequential set of sectors
228     * too, so read such set of sectors is quick operation for low-level IO
229     * layer.
230     */
231    bts2rd = (FAT_FD_OF_ROOT_DIR(fat_fd) &&
232             (fs_info->fat.vol.type & (FAT_FAT12 | FAT_FAT16))) ?
233             fat_fd->fat_file_size                              :
234             fs_info->fat.vol.bpc;
235
236    sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
237                                MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
238    if (sc != RTEMS_SUCCESSFUL)
239        rtems_set_errno_and_return_minus_one(EIO);
240
241    while (count > 0)
242    {
243        /*
244         * fat-file is already opened by open call, so read it
245         * Always read directory fat-file from the beggining because of MSDOS
246         * directories feature :( - we should count elements currently
247         * present in the directory because there may be holes :)
248         */
249        ret = fat_file_read(iop->pathinfo.mt_entry, fat_fd, (j * bts2rd),
250                            bts2rd, fs_info->cl_buf);
251        if (ret < MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
252        {
253            rtems_semaphore_release(fs_info->vol_sema);
254            rtems_set_errno_and_return_minus_one(EIO);
255        }
256
257        for (i = 0; i < ret; i += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
258        {
259            char* entry = (char*) fs_info->cl_buf + i;
260
261            /*
262             * Is this directory from here on empty ?
263             */
264            if ((*MSDOS_DIR_ENTRY_TYPE(entry)) ==
265                MSDOS_THIS_DIR_ENTRY_AND_REST_EMPTY)
266            {
267                rtems_semaphore_release(fs_info->vol_sema);
268                return cmpltd;
269            }
270
271            /* Is the directory entry empty */
272            if ((*MSDOS_DIR_ENTRY_TYPE(entry)) == MSDOS_THIS_DIR_ENTRY_EMPTY)
273                continue;
274
275            /* Is the directory entry empty a volume label */
276            if (((*MSDOS_DIR_ATTR(entry)) & MSDOS_ATTR_VOLUME_ID) &&
277                ((*MSDOS_DIR_ATTR(entry) & MSDOS_ATTR_LFN_MASK) != MSDOS_ATTR_LFN))
278                continue;
279
280            /*
281             * Check the attribute to see if the entry is for a long file
282             * name.
283             */
284            if ((*MSDOS_DIR_ATTR(entry) & MSDOS_ATTR_LFN_MASK) ==
285                MSDOS_ATTR_LFN)
286            {
287                int   o;
288                char* p;
289                int   q;
290
291                /*
292                 * Is this is the first entry of a LFN ?
293                 */
294                if (lfn_start == FAT_FILE_SHORT_NAME)
295                {
296                    /*
297                     * The first entry must have the last long entry flag set.
298                     */
299                    if ((*MSDOS_DIR_ENTRY_TYPE(entry) &
300                         MSDOS_LAST_LONG_ENTRY) == 0)
301                        continue;
302
303                    /*
304                     * Remember the start location of the long file name.
305                     */
306                    lfn_start =
307                      ((j * bts2rd) + i) / MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE;
308
309                    /*
310                     * Get the number of entries so we can count down and
311                     * also the checksum of the short entry.
312                     */
313                    lfn_entries = (*MSDOS_DIR_ENTRY_TYPE(entry) &
314                                   MSDOS_LAST_LONG_ENTRY_MASK);
315                    lfn_checksum = *MSDOS_DIR_LFN_CHECKSUM(entry);
316                    memset (tmp_dirent.d_name, 0, sizeof(tmp_dirent.d_name));
317                }
318
319                /*
320                 * If the entry number or the check sum do not match
321                 * forget this series of long directory entries. These could
322                 * be orphaned entries depending on the history of the
323                 * disk.
324                 */
325                if ((lfn_entries != (*MSDOS_DIR_ENTRY_TYPE(entry) &
326                                     MSDOS_LAST_LONG_ENTRY_MASK)) ||
327                    (lfn_checksum != *MSDOS_DIR_LFN_CHECKSUM(entry)))
328                {
329                    lfn_start = FAT_FILE_SHORT_NAME;
330                    continue;
331                }
332
333                /*
334                 * Extract the file name into the directory entry. The data is
335                 * stored in UNICODE characters (16bit). No translation is
336                 * currently supported.
337                 *
338                 * The DOS maximum length is 255 characters without the
339                 * trailing nul character. We need to range check the length to
340                 * fit in the directory entry name field.
341                 */
342
343                lfn_entries--;
344                p = entry + 1;
345                o = lfn_entries * MSDOS_LFN_LEN_PER_ENTRY;
346
347                for (q = 0; q < MSDOS_LFN_LEN_PER_ENTRY; q++)
348                {
349                    if (o >= (sizeof(tmp_dirent.d_name) - 1))
350                        break;
351
352                    tmp_dirent.d_name[o++] = *p;
353
354                    if (*p == '\0')
355                        break;
356
357                    switch (q)
358                    {
359                        case 4:
360                            p += 5;
361                            break;
362                        case 10:
363                            p += 4;
364                            break;
365                        default:
366                            p += 2;
367                            break;
368                    }
369                }
370            }
371            else
372            {
373                fat_dir_pos_t dir_pos;
374
375                /*
376                 * Skip active entries until get the entry to start from.
377                 */
378                if (start)
379                {
380                    lfn_start = FAT_FILE_SHORT_NAME;
381                    start--;
382                    continue;
383                }
384
385                /*
386                 * Move the entry to the return buffer
387                 *
388                 * unfortunately there is no method to extract ino except to
389                 * open fat-file descriptor :( ... so, open it
390                 */
391
392                /* get number of cluster we are working with */
393                rc = fat_file_ioctl(iop->pathinfo.mt_entry, fat_fd, F_CLU_NUM,
394                                    j * bts2rd, &cur_cln);
395                if (rc != RC_OK)
396                {
397                    rtems_semaphore_release(fs_info->vol_sema);
398                    return rc;
399                }
400
401                fat_dir_pos_init(&dir_pos);
402                dir_pos.sname.cln = cur_cln;
403                dir_pos.sname.ofs = i;
404                rc = fat_file_open(iop->pathinfo.mt_entry, &dir_pos, &tmp_fat_fd);
405                if (rc != RC_OK)
406                {
407                    rtems_semaphore_release(fs_info->vol_sema);
408                    return rc;
409                }
410
411                /* fill in dirent structure */
412                /* XXX: from what and in what d_off should be computed ?! */
413                tmp_dirent.d_off = start + cmpltd;
414                tmp_dirent.d_reclen = sizeof(struct dirent);
415                tmp_dirent.d_ino = tmp_fat_fd->ino;
416
417                /*
418                 * If a long file name check if the correct number of
419                 * entries have been found and if the checksum is correct.
420                 * If not return the short file name.
421                 */
422                if (lfn_start != FAT_FILE_SHORT_NAME)
423                {
424                    uint8_t  cs = 0;
425                    uint8_t* p = (uint8_t*) entry;
426                    int      i;
427
428                    for (i = 0; i < 11; i++, p++)
429                        cs = ((cs & 1) ? 0x80 : 0) + (cs >> 1) + *p;
430
431                    if (lfn_entries || (lfn_checksum != cs))
432                        lfn_start = FAT_FILE_SHORT_NAME;
433                }
434
435                if (lfn_start == FAT_FILE_SHORT_NAME)
436                {
437                    /*
438                     * convert dir entry from fixed 8+3 format (without dot)
439                     * to 0..8 + 1dot + 0..3 format
440                     */
441                    tmp_dirent.d_namlen = msdos_format_dirent_with_dot(
442                        tmp_dirent.d_name, entry); /* src text */
443                }
444                else
445                {
446                    tmp_dirent.d_namlen = strlen(tmp_dirent.d_name);
447                }
448
449                memcpy(buffer + cmpltd, &tmp_dirent, sizeof(struct dirent));
450
451                iop->offset = iop->offset + sizeof(struct dirent);
452                cmpltd += (sizeof(struct dirent));
453                count -= (sizeof(struct dirent));
454
455                /* inode number extracted, close fat-file */
456                rc = fat_file_close(iop->pathinfo.mt_entry, tmp_fat_fd);
457                if (rc != RC_OK)
458                {
459                    rtems_semaphore_release(fs_info->vol_sema);
460                    return rc;
461                }
462            }
463
464            if (count <= 0)
465                break;
466        }
467        j++;
468    }
469
470    rtems_semaphore_release(fs_info->vol_sema);
471    return cmpltd;
472}
473
474/* msdos_dir_write --
475 *     no write for directory
476 */
477
478/* msdos_dir_lseek --
479 *
480 *  This routine will behave in one of three ways based on the state of
481 *  argument whence. Based on the state of its value the offset argument will
482 *  be interpreted using one of the following methods:
483 *
484 *     SEEK_SET - offset is the absolute byte offset from the start of the
485 *                logical start of the dirent sequence that represents the
486 *                directory
487 *     SEEK_CUR - offset is used as the relative byte offset from the current
488 *                directory position index held in the iop structure
489 *     SEEK_END - N/A --> This will cause an assert.
490 *
491 * PARAMETERS:
492 *     iop    - file control block
493 *     offset - offset
494 *     whence - predefine directive
495 *
496 * RETURNS:
497 *     RC_OK on success, or -1 if error occured (errno
498 *     set apropriately).
499 */
500off_t
501msdos_dir_lseek(rtems_libio_t *iop, off_t offset, int whence)
502{
503    if (iop->offset >= 0 && iop->offset <= iop->size) {
504        return 0;
505    } else {
506        rtems_set_errno_and_return_minus_one(EINVAL);
507    }
508}
509
510/* msdos_dir_stat --
511 *
512 * This routine will obtain the following information concerning the current
513 * directory:
514 *     st_dev      device id
515 *     st_ino      node serial number :)
516 *     st_mode     mode extracted from the node
517 *     st_size     total size in bytes
518 *     st_blksize  blocksize for filesystem I/O
519 *     st_blocks   number of blocks allocated
520 *     stat_mtime  time of last modification
521 *
522 * PARAMETERS:
523 *     loc - this directory
524 *     buf - stat buffer provided by user
525 *
526 * RETURNS:
527 *     RC_OK and filled stat buffer on success, or -1 if error occured (errno
528 *     set apropriately).
529 */
530int
531msdos_dir_stat(
532    rtems_filesystem_location_info_t *loc,
533    struct stat                      *buf
534    )
535{
536    rtems_status_code  sc = RTEMS_SUCCESSFUL;
537    msdos_fs_info_t   *fs_info = loc->mt_entry->fs_info;
538    fat_file_fd_t     *fat_fd = loc->node_access;
539
540    sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
541                                MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
542    if (sc != RTEMS_SUCCESSFUL)
543        rtems_set_errno_and_return_minus_one(EIO);
544
545    buf->st_dev = fs_info->fat.vol.dev;
546    buf->st_ino = fat_fd->ino;
547    buf->st_mode  = S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO;
548    buf->st_rdev = 0ll;
549    buf->st_size = fat_fd->fat_file_size;
550    buf->st_blocks = fat_fd->fat_file_size >> FAT_SECTOR512_BITS;
551    buf->st_blksize = fs_info->fat.vol.bps;
552    buf->st_mtime = fat_fd->mtime;
553
554    rtems_semaphore_release(fs_info->vol_sema);
555    return RC_OK;
556}
557
558/* msdos_dir_truncate --
559 *     No truncate for directory.
560 *
561 * PARAMETERS:
562 *
563 * RETURNS:
564 *
565 */
566
567/* msdos_dir_sync --
568 *     The following routine does a syncronization on a MSDOS directory node.
569 *     DIR_WrtTime, DIR_WrtDate and DIR_fileSize fields of 32 Bytes Directory
570 *     Entry Structure should not be updated for directories, so only call
571 *     to corresponding fat-file routine.
572 *
573 * PARAMETERS:
574 *     iop - file control block
575 *
576 * RETURNS:
577 *     RC_OK on success, or -1 if error occured (errno set apropriately).
578 */
579int
580msdos_dir_sync(rtems_libio_t *iop)
581{
582    int                rc = RC_OK;
583    rtems_status_code  sc = RTEMS_SUCCESSFUL;
584    fat_file_fd_t     *fat_fd = iop->pathinfo.node_access;
585    msdos_fs_info_t   *fs_info = iop->pathinfo.mt_entry->fs_info;
586
587    sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
588                                MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
589    if (sc != RTEMS_SUCCESSFUL)
590        rtems_set_errno_and_return_minus_one(EIO);
591
592    rc = fat_file_datasync(iop->pathinfo.mt_entry, fat_fd);
593
594    rtems_semaphore_release(fs_info->vol_sema);
595    return rc;
596}
597
598/* msdos_dir_chmod --
599 *     Change the attributes of the directory. This currently does
600 *     nothing and returns no error.
601 *
602 * PARAMETERS:
603 *     pathloc - node description
604 *     mode - the new mode
605 *
606 * RETURNS:
607 *     RC_OK always
608 */
609int
610msdos_dir_chmod(rtems_filesystem_location_info_t *pathloc,
611                mode_t                            mode)
612{
613  return RC_OK;
614}
615
616/* msdos_dir_rmnod --
617 *     Remove directory node.
618 *
619 *     Check that this directory node is not opened as fat-file, is empty and
620 *     not filesystem root node. If all this conditions met then delete.
621 *
622 * PARAMETERS:
623 *     pathloc - node description
624 *
625 * RETURNS:
626 *     RC_OK on success, or -1 if error occured (errno set apropriately).
627 */
628int
629msdos_dir_rmnod(rtems_filesystem_location_info_t *parent_pathloc,
630                rtems_filesystem_location_info_t *pathloc)
631{
632    int                rc = RC_OK;
633    rtems_status_code  sc = RTEMS_SUCCESSFUL;
634    msdos_fs_info_t   *fs_info = pathloc->mt_entry->fs_info;
635    fat_file_fd_t     *fat_fd = pathloc->node_access;
636    bool               is_empty = false;
637
638    sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
639                                MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
640    if (sc != RTEMS_SUCCESSFUL)
641        rtems_set_errno_and_return_minus_one(EIO);
642
643    /*
644     * You cannot remove a node that still has children
645     */
646    rc = msdos_dir_is_empty(pathloc->mt_entry, fat_fd, &is_empty);
647    if (rc != RC_OK)
648    {
649        rtems_semaphore_release(fs_info->vol_sema);
650        return rc;
651    }
652
653    if (!is_empty)
654    {
655        rtems_semaphore_release(fs_info->vol_sema);
656        rtems_set_errno_and_return_minus_one(ENOTEMPTY);
657    }
658
659    /*
660     * We deny attempts to delete open directory (if directory is current
661     * directory we assume it is open one)
662     */
663    if (fat_fd->links_num > 1)
664    {
665        rtems_semaphore_release(fs_info->vol_sema);
666        rtems_set_errno_and_return_minus_one(EBUSY);
667    }
668
669    /*
670     * You cannot remove the file system root node.
671     */
672    if (rtems_filesystem_is_root_location(pathloc))
673    {
674        rtems_semaphore_release(fs_info->vol_sema);
675        rtems_set_errno_and_return_minus_one(EBUSY);
676    }
677
678    /*
679     * You cannot remove a mountpoint.
680     * not used - mount() not implemenetd yet.
681     */
682
683    /* mark file removed */
684    rc = msdos_set_first_char4file_name(pathloc->mt_entry, &fat_fd->dir_pos,
685                                        MSDOS_THIS_DIR_ENTRY_EMPTY);
686    if (rc != RC_OK)
687    {
688        rtems_semaphore_release(fs_info->vol_sema);
689        return rc;
690    }
691
692    fat_file_mark_removed(pathloc->mt_entry, fat_fd);
693
694    rtems_semaphore_release(fs_info->vol_sema);
695    return rc;
696}
Note: See TracBrowser for help on using the repository browser.