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

4.104.114.84.95
Last change on this file since 3b44f153 was 3b44f153, checked in by Chris Johns <chrisj@…>, on Jul 2, 2003 at 2:08:43 PM

Comments have been updated.

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