source: rtems/cpukit/libfs/src/dosfs/fat.c @ d63a2c2

4.104.114.84.95
Last change on this file since d63a2c2 was 3239698, checked in by Ralf Corsepius <ralf.corsepius@…>, on 04/15/04 at 13:26:21

Remove stray white spaces.

  • Property mode set to 100644
File size: 19.7 KB
Line 
1/*
2 * fat.c
3 *
4 * Low-level operations on a volume with FAT filesystem
5 *
6 * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
7 * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
8 *
9 * @(#) $Id$
10 */
11
12#if HAVE_CONFIG_H
13#include "config.h"
14#endif
15
16#include <sys/types.h>
17#include <sys/stat.h>
18#include <fcntl.h>
19#include <unistd.h>
20#include <errno.h>
21#include <stdlib.h>
22#include <assert.h>
23
24#include <rtems/libio_.h>
25
26#include "fat.h"
27#include "fat_fat_operations.h"
28
29/* _fat_block_read --
30 *     This function reads 'count' bytes from device filesystem is mounted on,
31 *     starts at 'start+offset' position where 'start' computed in sectors
32 *     and 'offset' is offset inside sector (reading may cross sectors
33 *     boundary; in this case assumed we want to read sequential sector(s))
34 *
35 * PARAMETERS:
36 *     mt_entry - mount table entry
37 *     start    - sector num to start read from
38 *     offset   - offset inside sector 'start'
39 *     count    - count of bytes to read
40 *     buff     - buffer provided by user
41 *
42 * RETURNS:
43 *     bytes read on success, or -1 if error occured
44 *     and errno set appropriately
45 */
46ssize_t
47_fat_block_read(
48    rtems_filesystem_mount_table_entry_t *mt_entry,
49    uint32_t                              start,
50    uint32_t                              offset,
51    uint32_t                              count,
52    void                                 *buff
53    )
54{
55    int                     rc = RC_OK;
56    register fat_fs_info_t *fs_info = mt_entry->fs_info;
57    ssize_t                 cmpltd = 0;
58    uint32_t                blk = start;
59    uint32_t                ofs = offset;
60    bdbuf_buffer           *block = NULL;
61    uint32_t                c = 0;
62 
63    while (count > 0)
64    {
65        rc = fat_buf_access(fs_info, blk, FAT_OP_TYPE_READ, &block);
66        if (rc != RC_OK)
67            return -1;
68
69        c = MIN(count, (fs_info->vol.bps - ofs));
70        memcpy((buff + cmpltd), (block->buffer + ofs), c);
71
72        count -= c;
73        cmpltd += c;
74        blk++;
75        ofs = 0;
76    }
77    return cmpltd;
78}
79
80/* _fat_block_write --
81 *     This function write 'count' bytes to device filesystem is mounted on,
82 *     starts at 'start+offset' position where 'start' computed in sectors
83 *     and 'offset' is offset inside sector (writing may cross sectors
84 *     boundary; in this case assumed we want to write sequential sector(s))
85 *
86 * PARAMETERS:
87 *     mt_entry - mount table entry
88 *     start    - sector num to start read from
89 *     offset   - offset inside sector 'start'
90 *     count    - count of bytes to write
91 *     buff     - buffer provided by user
92 *
93 * RETURNS:
94 *     bytes written on success, or -1 if error occured
95 *     and errno set appropriately
96 */
97ssize_t
98_fat_block_write(
99    rtems_filesystem_mount_table_entry_t *mt_entry,
100    uint32_t                              start,
101    uint32_t                              offset,
102    uint32_t                              count,
103    const void                           *buff)
104{
105    int            rc = RC_OK;
106    fat_fs_info_t *fs_info = mt_entry->fs_info;
107    ssize_t        cmpltd = 0;
108    uint32_t       blk  = start;
109    uint32_t       ofs = offset;
110    bdbuf_buffer  *block = NULL;
111    uint32_t       c = 0;
112 
113    while(count > 0)
114    {
115        c = MIN(count, (fs_info->vol.bps - ofs));
116
117        if (c == fs_info->vol.bps)
118            rc = fat_buf_access(fs_info, blk, FAT_OP_TYPE_GET, &block);
119        else
120            rc = fat_buf_access(fs_info, blk, FAT_OP_TYPE_READ, &block);
121        if (rc != RC_OK)
122            return -1;
123   
124        memcpy((block->buffer + ofs), (buff + cmpltd), c);
125
126        fat_buf_mark_modified(fs_info);
127
128        count -= c;
129        cmpltd +=c;
130        blk++;
131        ofs = 0;
132    }
133    return cmpltd;
134}
135
136
137
138
139/* fat_cluster_read --
140 *     wrapper for reading a whole cluster at once
141 *
142 * PARAMETERS:
143 *     mt_entry - mount table entry
144 *     cln      - number of cluster to read
145 *     buff     - buffer provided by user
146 *
147 * RETURNS:
148 *     bytes read on success, or -1 if error occured
149 *     and errno set appropriately
150 */
151ssize_t
152fat_cluster_read(
153    rtems_filesystem_mount_table_entry_t *mt_entry,
154    uint32_t                              cln,
155    void                                 *buff
156    )
157{
158    fat_fs_info_t *fs_info = mt_entry->fs_info;
159    uint32_t       fsec = 0;
160 
161    fsec = fat_cluster_num_to_sector_num(mt_entry, cln);
162
163    return _fat_block_read(mt_entry, fsec, 0,
164                           fs_info->vol.spc << fs_info->vol.sec_log2, buff);
165}                 
166
167/* fat_cluster_write --
168 *     wrapper for writting a whole cluster at once
169 *
170 * PARAMETERS:
171 *     mt_entry - mount table entry
172 *     cln      - number of cluster to write
173 *     buff     - buffer provided by user
174 *
175 * RETURNS:
176 *     bytes written on success, or -1 if error occured
177 *     and errno set appropriately
178 */
179ssize_t
180fat_cluster_write(
181    rtems_filesystem_mount_table_entry_t *mt_entry,
182    uint32_t                              cln,
183    const void                           *buff
184    )
185{
186    fat_fs_info_t *fs_info = mt_entry->fs_info;
187    uint32_t       fsec = 0;
188 
189    fsec = fat_cluster_num_to_sector_num(mt_entry, cln);
190 
191    return _fat_block_write(mt_entry, fsec, 0,
192                          fs_info->vol.spc << fs_info->vol.sec_log2, buff);
193}                 
194
195/* fat_init_volume_info --
196 *     Get inforamtion about volume on which filesystem is mounted on
197 *
198 * PARAMETERS:
199 *     mt_entry - mount table entry
200 *
201 * RETURNS:
202 *     RC_OK on success, or -1 if error occured
203 *     and errno set appropriately
204 */
205int
206fat_init_volume_info(rtems_filesystem_mount_table_entry_t *mt_entry)
207{
208    int                 rc = RC_OK;
209    fat_fs_info_t      *fs_info = mt_entry->fs_info;     
210    register fat_vol_t *vol = &fs_info->vol;
211    uint32_t            data_secs = 0;
212    char                boot_rec[FAT_MAX_BPB_SIZE];
213    char                fs_info_sector[FAT_USEFUL_INFO_SIZE];
214    ssize_t             ret = 0;
215    int                 fd;
216    struct stat         stat_buf;
217    int                 i = 0;
218
219    rc = stat(mt_entry->dev, &stat_buf);
220    if (rc == -1)
221        return rc;
222
223    /* rtmes feature: no block devices, all are character devices */   
224    if (!S_ISCHR(stat_buf.st_mode))
225        set_errno_and_return_minus_one(ENOTBLK);   
226
227    /* check that  device is registred as block device and lock it */
228    vol->dd = rtems_disk_lookup(stat_buf.st_dev);
229    if (vol->dd == NULL)
230        set_errno_and_return_minus_one(ENOTBLK);
231       
232    vol->dev = stat_buf.st_dev;
233
234    fd = open(mt_entry->dev, O_RDONLY);
235    if (fd == -1)
236    {
237        rtems_disk_release(vol->dd);
238        return -1;
239    }   
240 
241    ret = read(fd, (void *)boot_rec, FAT_MAX_BPB_SIZE);
242    if ( ret != FAT_MAX_BPB_SIZE )
243    {
244        close(fd);
245        rtems_disk_release(vol->dd);
246        set_errno_and_return_minus_one( EIO );
247    }
248    close(fd);
249
250    vol->bps = FAT_BR_BYTES_PER_SECTOR(boot_rec);
251 
252    if ( (vol->bps != 512)  &&
253         (vol->bps != 1024) &&
254         (vol->bps != 2048) &&
255         (vol->bps != 4096))
256    {     
257        rtems_disk_release(vol->dd);
258        set_errno_and_return_minus_one( EINVAL );
259    }   
260
261    for (vol->sec_mul = 0, i = (vol->bps >> FAT_SECTOR512_BITS); (i & 1) == 0;
262         i >>= 1, vol->sec_mul++);
263    for (vol->sec_log2 = 0, i = vol->bps; (i & 1) == 0;
264         i >>= 1, vol->sec_log2++);
265
266    vol->spc = FAT_BR_SECTORS_PER_CLUSTER(boot_rec);
267    /*
268     * "sectors per cluster" of zero is invalid
269     * (and would hang the following loop)
270     */
271    if (vol->spc == 0)
272    {
273        rtems_disk_release(vol->dd);
274        set_errno_and_return_minus_one(EINVAL);
275    }   
276
277    for (vol->spc_log2 = 0, i = vol->spc; (i & 1) == 0;
278         i >>= 1, vol->spc_log2++);
279 
280    /*
281     * "bytes per cluster" value greater than 32K is invalid
282     */
283    if ((vol->bpc = vol->bps << vol->spc_log2) > MS_BYTES_PER_CLUSTER_LIMIT)
284    {
285        rtems_disk_release(vol->dd);
286        set_errno_and_return_minus_one(EINVAL);
287    }   
288
289    for (vol->bpc_log2 = 0, i = vol->bpc; (i & 1) == 0;
290         i >>= 1, vol->bpc_log2++);
291
292    vol->fats = FAT_BR_FAT_NUM(boot_rec);
293    vol->fat_loc = FAT_BR_RESERVED_SECTORS_NUM(boot_rec);
294
295    vol->rdir_entrs = FAT_BR_FILES_PER_ROOT_DIR(boot_rec);
296   
297    /* calculate the count of sectors occupied by the root directory */
298    vol->rdir_secs = ((vol->rdir_entrs * FAT_DIRENTRY_SIZE) + (vol->bps - 1)) /
299                     vol->bps;
300
301    vol->rdir_size = vol->rdir_secs << vol->sec_log2;
302
303    if ( (FAT_BR_SECTORS_PER_FAT(boot_rec)) != 0)
304        vol->fat_length = FAT_BR_SECTORS_PER_FAT(boot_rec);
305    else
306        vol->fat_length = FAT_BR_SECTORS_PER_FAT32(boot_rec);
307 
308    vol->data_fsec = vol->fat_loc + vol->fats * vol->fat_length +
309                     vol->rdir_secs;
310
311    /* for  FAT12/16 root dir starts at(sector) */
312    vol->rdir_loc = vol->fat_loc + vol->fats * vol->fat_length;
313 
314    if ( (FAT_BR_TOTAL_SECTORS_NUM16(boot_rec)) != 0)
315        vol->tot_secs = FAT_BR_TOTAL_SECTORS_NUM16(boot_rec);
316    else
317        vol->tot_secs = FAT_BR_TOTAL_SECTORS_NUM32(boot_rec);
318 
319    data_secs = vol->tot_secs - vol->data_fsec;
320 
321    vol->data_cls = data_secs / vol->spc;
322
323    /* determine FAT type at least */
324    if ( vol->data_cls < FAT_FAT12_MAX_CLN)
325    {
326        vol->type = FAT_FAT12;
327        vol->mask = FAT_FAT12_MASK;
328        vol->eoc_val = FAT_FAT12_EOC;
329    }
330    else
331    {
332        if ( vol->data_cls < FAT_FAT16_MAX_CLN)
333        {
334            vol->type = FAT_FAT16;
335            vol->mask = FAT_FAT16_MASK;
336            vol->eoc_val = FAT_FAT16_EOC;
337        }
338        else
339        {
340            vol->type = FAT_FAT32;
341            vol->mask = FAT_FAT32_MASK;
342            vol->eoc_val = FAT_FAT32_EOC;
343        }
344    }
345 
346    if (vol->type == FAT_FAT32)
347    {
348        vol->rdir_cl = FAT_BR_FAT32_ROOT_CLUSTER(boot_rec);
349     
350        vol->mirror = FAT_BR_EXT_FLAGS(boot_rec) & FAT_BR_EXT_FLAGS_MIRROR;
351        if (vol->mirror)
352            vol->afat = FAT_BR_EXT_FLAGS(boot_rec) & FAT_BR_EXT_FLAGS_FAT_NUM;
353        else
354            vol->afat = 0;
355
356        vol->info_sec = FAT_BR_FAT32_FS_INFO_SECTOR(boot_rec);
357        if( vol->info_sec == 0 )
358        {
359            rtems_disk_release(vol->dd);
360            set_errno_and_return_minus_one( EINVAL );
361        }   
362        else
363        {
364            ret = _fat_block_read(mt_entry, vol->info_sec , 0,
365                                  FAT_FSI_LEADSIG_SIZE, fs_info_sector);
366            if ( ret < 0 )
367            {
368                rtems_disk_release(vol->dd);
369                return -1;
370            }   
371     
372            if (FAT_FSINFO_LEAD_SIGNATURE(fs_info_sector) !=
373                FAT_FSINFO_LEAD_SIGNATURE_VALUE)
374            {   
375                rtems_disk_release(vol->dd);
376                set_errno_and_return_minus_one( EINVAL );
377            }   
378            else
379            {
380                ret = _fat_block_read(mt_entry, vol->info_sec , FAT_FSI_INFO,
381                                      FAT_USEFUL_INFO_SIZE, fs_info_sector);
382                if ( ret < 0 )
383                {
384                    rtems_disk_release(vol->dd);
385                    return -1;
386                }   
387                   
388                vol->free_cls = FAT_FSINFO_FREE_CLUSTER_COUNT(fs_info_sector);
389                vol->next_cl = FAT_FSINFO_NEXT_FREE_CLUSTER(fs_info_sector);
390                rc = fat_fat32_update_fsinfo_sector(mt_entry, 0xFFFFFFFF,
391                                                    0xFFFFFFFF);
392                if ( rc != RC_OK )
393                {
394                    rtems_disk_release(vol->dd);
395                    return rc;
396                }   
397            }
398        }
399    }
400    else
401    {
402        vol->rdir_cl = 0;
403        vol->mirror = 0;
404        vol->afat = 0;
405        vol->free_cls = 0xFFFFFFFF;
406        vol->next_cl = 0xFFFFFFFF;
407    }
408    vol->afat_loc = vol->fat_loc + vol->fat_length * vol->afat;
409
410    /* set up collection of fat-files fd */
411    fs_info->vhash = calloc(FAT_HASH_SIZE, sizeof(Chain_Control));
412    if ( fs_info->vhash == NULL )
413    {
414        rtems_disk_release(vol->dd);
415        set_errno_and_return_minus_one( ENOMEM );
416    }   
417
418    for (i = 0; i < FAT_HASH_SIZE; i++)
419        _Chain_Initialize_empty(fs_info->vhash + i);
420
421    fs_info->rhash = calloc(FAT_HASH_SIZE, sizeof(Chain_Control));
422    if ( fs_info->rhash == NULL )
423    {
424        rtems_disk_release(vol->dd);
425        free(fs_info->vhash);
426        set_errno_and_return_minus_one( ENOMEM );
427    }
428    for (i = 0; i < FAT_HASH_SIZE; i++)
429        _Chain_Initialize_empty(fs_info->rhash + i);
430 
431    fs_info->uino_pool_size = FAT_UINO_POOL_INIT_SIZE;
432    fs_info->uino_base = (vol->tot_secs << vol->sec_mul) << 4;
433    fs_info->index = 0;
434    fs_info->uino = (char *)calloc(fs_info->uino_pool_size, sizeof(char));
435    if ( fs_info->uino == NULL )
436    {
437        rtems_disk_release(vol->dd);
438        free(fs_info->vhash);
439        free(fs_info->rhash);
440        set_errno_and_return_minus_one( ENOMEM );
441    }
442    fs_info->sec_buf = (char *)calloc(vol->bps, sizeof(char));
443    if (fs_info->sec_buf == NULL)
444    {
445        rtems_disk_release(vol->dd);
446        free(fs_info->vhash);
447        free(fs_info->rhash);
448        free(fs_info->uino);
449        set_errno_and_return_minus_one( ENOMEM );
450    }
451   
452    return RC_OK; 
453}
454
455/* fat_shutdown_drive --
456 *     Free all allocated resources and synchronize all necessary data
457 *
458 * PARAMETERS:
459 *     mt_entry - mount table entry
460 *
461 * RETURNS:
462 *     RC_OK on success, or -1 if error occured
463 *     and errno set appropriately
464 */
465int
466fat_shutdown_drive(rtems_filesystem_mount_table_entry_t *mt_entry)
467{
468    int            rc = RC_OK;
469    fat_fs_info_t *fs_info = mt_entry->fs_info;
470    int            i = 0;
471
472    if (fs_info->vol.type & FAT_FAT32)
473    {
474        rc = fat_fat32_update_fsinfo_sector(mt_entry, fs_info->vol.free_cls,
475                                            fs_info->vol.next_cl);
476        if ( rc != RC_OK )
477            rc = -1;
478    } 
479
480    fat_buf_release(fs_info);
481   
482    if (rtems_bdbuf_syncdev(fs_info->vol.dev) != RTEMS_SUCCESSFUL)
483        rc = -1;
484
485    for (i = 0; i < FAT_HASH_SIZE; i++)
486    {
487        Chain_Node    *node = NULL;
488        Chain_Control *the_chain = fs_info->vhash + i;
489   
490        while ( (node = _Chain_Get(the_chain)) != NULL )
491            free(node);
492    }   
493
494    for (i = 0; i < FAT_HASH_SIZE; i++)
495    {
496        Chain_Node    *node = NULL;
497        Chain_Control *the_chain = fs_info->rhash + i;
498
499        while ( (node = _Chain_Get(the_chain)) != NULL )
500            free(node);
501    }   
502
503    free(fs_info->vhash);
504    free(fs_info->rhash); 
505
506    free(fs_info->uino);
507    free(fs_info->sec_buf);
508    rtems_disk_release(fs_info->vol.dd);
509
510    if (rc)
511        errno = EIO;
512    return rc;
513}
514
515/* fat_init_clusters_chain --
516 *     Zeroing contents of all clusters in the chain
517 *
518 * PARAMETERS:
519 *     mt_entry          - mount table entry
520 *     start_cluster_num - num of first cluster in the chain
521 *
522 * RETURNS:
523 *     RC_OK on success, or -1 if error occured
524 *     and errno set appropriately
525 */
526int
527fat_init_clusters_chain(
528    rtems_filesystem_mount_table_entry_t *mt_entry,
529    uint32_t                              start_cln
530    )
531{
532    int                     rc = RC_OK;
533    ssize_t                 ret = 0;
534    register fat_fs_info_t *fs_info = mt_entry->fs_info;
535    uint32_t                cur_cln = start_cln;
536    char                   *buf;
537 
538    buf = calloc(fs_info->vol.bpc, sizeof(char));
539    if ( buf == NULL )
540        set_errno_and_return_minus_one( EIO );
541
542    while ((cur_cln & fs_info->vol.mask) < fs_info->vol.eoc_val)
543    {
544        ret = fat_cluster_write(mt_entry, cur_cln, buf);
545        if ( ret == -1 )
546        {
547            free(buf);
548            return -1;
549        }
550
551        rc  = fat_get_fat_cluster(mt_entry, cur_cln, &cur_cln);
552        if ( rc != RC_OK )
553        {
554            free(buf);
555            return rc;
556        }
557       
558    }
559    free(buf);
560    return rc;
561}                       
562 
563#define FAT_UNIQ_INO_BASE 0x0FFFFF00
564
565#define FAT_UNIQ_INO_IS_BUSY(index, arr) \
566  (((arr)[((index)>>3)]>>((index) & (8-1))) & 0x01)
567
568#define FAT_SET_UNIQ_INO_BUSY(index, arr) \
569  ((arr)[((index)>>3)] |= (0x01<<((index) & (8-1))))
570
571#define FAT_SET_UNIQ_INO_FREE(index, arr) \
572  ((arr)[((index)>>3)] &= (~(0x01<<((index) & (8-1)))))
573
574/* fat_get_unique_ino --
575 *     Allocate unique ino from unique ino pool
576 *
577 * PARAMETERS:
578 *     mt_entry - mount table entry
579 *
580 * RETURNS:
581 *     unique inode number on success, or 0 if there is no free unique inode
582 *     number in the pool
583 *
584 * ATTENTION:
585 *     0 means FAILED !!!
586 *     
587 */
588uint32_t 
589fat_get_unique_ino(rtems_filesystem_mount_table_entry_t *mt_entry)
590{
591    register fat_fs_info_t *fs_info = mt_entry->fs_info;
592    uint32_t                j = 0;
593    rtems_boolean           resrc_unsuff = FALSE;
594
595    while (!resrc_unsuff)
596    { 
597        for (j = 0; j < fs_info->uino_pool_size; j++)
598        {
599            if (!FAT_UNIQ_INO_IS_BUSY(fs_info->index, fs_info->uino))
600            {
601                FAT_SET_UNIQ_INO_BUSY(fs_info->index, fs_info->uino);
602                return (fs_info->uino_base + fs_info->index);           
603            }
604            fs_info->index++;
605            if (fs_info->index >= fs_info->uino_pool_size)
606                fs_info->index = 0;
607        }
608
609        if ((fs_info->uino_pool_size << 1) < (0x0FFFFFFF - fs_info->uino_base))
610        {
611            fs_info->uino_pool_size <<= 1;
612            fs_info->uino = realloc(fs_info->uino, fs_info->uino_pool_size);
613            if (fs_info->uino != NULL)
614                fs_info->index = fs_info->uino_pool_size;
615            else   
616                resrc_unsuff = TRUE;
617        }
618        else
619            resrc_unsuff = TRUE;
620    }   
621    return 0;
622}
623
624/* fat_free_unique_ino --
625 *     Return unique ino to unique ino pool
626 *
627 * PARAMETERS:
628 *     mt_entry - mount table entry
629 *     ino      - inode number to free
630 *
631 * RETURNS:
632 *     None
633 */
634void
635fat_free_unique_ino(
636    rtems_filesystem_mount_table_entry_t *mt_entry,
637    uint32_t                              ino
638    )
639{
640    fat_fs_info_t *fs_info = mt_entry->fs_info;
641   
642    FAT_SET_UNIQ_INO_FREE((ino - fs_info->uino_base), fs_info->uino);
643}
644
645/* fat_ino_is_unique --
646 *     Test whether ino is from unique ino pool
647 *
648 * PARAMETERS:
649 *     mt_entry - mount table entry
650 *     ino   - ino to be tested
651 *
652 * RETURNS:
653 *     TRUE if ino is allocated from unique ino pool, FALSE otherwise
654 */
655inline rtems_boolean
656fat_ino_is_unique(
657    rtems_filesystem_mount_table_entry_t *mt_entry,
658    uint32_t                              ino
659    )
660{
661    fat_fs_info_t *fs_info = mt_entry->fs_info;
662   
663    return (ino >= fs_info->uino_base);
664}
665
666/* fat_fat32_update_fsinfo_sector --
667 *     Synchronize fsinfo sector for FAT32 volumes
668 *
669 * PARAMETERS:
670 *     mt_entry   - mount table entry
671 *     free_count - count of free clusters
672 *     next_free  - the next free cluster num
673 *
674 * RETURNS:
675 *     RC_OK on success, or -1 if error occured (errno set appropriately)
676 */
677int
678fat_fat32_update_fsinfo_sector(
679    rtems_filesystem_mount_table_entry_t *mt_entry,
680    uint32_t                              free_count,
681    uint32_t                              next_free
682    )
683{
684    ssize_t                 ret1 = 0, ret2 = 0;
685    register fat_fs_info_t *fs_info = mt_entry->fs_info;
686    uint32_t                le_free_count = 0;
687    uint32_t                le_next_free = 0;
688
689    le_free_count = CT_LE_L(free_count);
690    le_next_free = CT_LE_L(next_free);
691
692    ret1 = _fat_block_write(mt_entry,
693                            fs_info->vol.info_sec,
694                            FAT_FSINFO_FREE_CLUSTER_COUNT_OFFSET,
695                            4,
696                            (char *)(&le_free_count));
697
698    ret2 = _fat_block_write(mt_entry,
699                            fs_info->vol.info_sec,
700                            FAT_FSINFO_NEXT_FREE_CLUSTER_OFFSET,
701                            4,
702                            (char *)(&le_next_free));
703
704    if ( (ret1 < 0) || (ret2 < 0) )
705        return -1;
706
707    return RC_OK;
708}
Note: See TracBrowser for help on using the repository browser.