source: rtems/cpukit/libfs/src/dosfs/fat_fat_operations.c @ 92b8547b

4.104.114.84.95
Last change on this file since 92b8547b was 92b8547b, checked in by Jennifer Averett <Jennifer.Averett@…>, on Aug 5, 2003 at 6:05:20 PM

2003-08-05 Thomas Doerfler <Thomas.Doerfler@…>

PR 439/filesystem

  • src/dosfs/fat_fat_operations.c: Improve write data speed for DOSFS FAT12/FAT16 systems
  • Property mode set to 100644
File size: 14.4 KB
Line 
1/*
2 *  fat_fat_operations.c
3 *
4 *  General operations on File Allocation Table
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_scan_fat_for_free_clusters --
30 *     Allocate chain of free clusters from Files Allocation Table
31 *
32 * PARAMETERS:
33 *     mt_entry - mount table entry
34 *     chain    - the number of the first allocated cluster (first cluster
35 *                in  the chain)
36 *     count    - count of clusters to allocate (chain length)
37 *
38 * RETURNS:
39 *     RC_OK on success, or error code if error occured (errno set
40 *     appropriately)
41 *
42 *     
43 */
44int 
45fat_scan_fat_for_free_clusters(
46    rtems_filesystem_mount_table_entry_t *mt_entry,
47    unsigned32                           *chain,
48    unsigned32                            count,
49    unsigned32                           *cls_added,
50    unsigned32                           *last_cl
51    )
52{
53    int            rc = RC_OK;
54    fat_fs_info_t *fs_info = mt_entry->fs_info;
55    unsigned32     cl4find = 2;
56    unsigned32     next_cln = 0;
57    unsigned32     save_cln = 0; 
58    unsigned32     data_cls_val = fs_info->vol.data_cls + 2;
59    unsigned32     i = 2;
60 
61    *cls_added = 0;   
62
63    if (count == 0)
64        return rc;
65       
66    /*if ((fs_info->vol.type & FAT_FAT32) &&
67        (fs_info->vol.next_cl != FAT_UNDEFINED_VALUE))*/
68    if (fs_info->vol.next_cl != FAT_UNDEFINED_VALUE)
69        cl4find = fs_info->vol.next_cl; 
70
71    /*
72     * fs_info->vol.data_cls is exactly the count of data clusters
73     * starting at cluster 2, so the maximum valid cluster number is
74     * (fs_info->vol.data_cls + 1)
75     */
76    while (i < data_cls_val)
77    {
78        rc = fat_get_fat_cluster(mt_entry, cl4find, &next_cln);
79        if ( rc != RC_OK )
80        {
81            if (*cls_added != 0)
82                fat_free_fat_clusters_chain(mt_entry, (*chain));
83            return rc;
84        }   
85
86        /*if ((next_cln & fs_info->vol.mask) == FAT_GENFAT_FREE)*/
87        if (next_cln == FAT_GENFAT_FREE)
88        {
89            /*
90             * We are enforced to process allocation of the first free cluster
91             * by separate 'if' statement because otherwise undo function
92             * wouldn't work properly
93             */
94            if (*cls_added == 0)
95            {
96                *chain = cl4find;
97                rc = fat_set_fat_cluster(mt_entry, cl4find, FAT_GENFAT_EOC);
98                if ( rc != RC_OK )
99                {
100                    /*
101                     * this is the first cluster we tried to allocate so no
102                     * cleanup activity needed
103                     */
104                     return rc; 
105                }
106            }
107            else
108            { 
109                /* set EOC value to new allocated cluster */
110                rc = fat_set_fat_cluster(mt_entry, cl4find, FAT_GENFAT_EOC);
111                if ( rc != RC_OK )
112                {
113                    /* cleanup activity */
114                    fat_free_fat_clusters_chain(mt_entry, (*chain));
115                    return rc; 
116                }
117
118                rc = fat_set_fat_cluster(mt_entry, save_cln, cl4find);
119                if ( rc != RC_OK )
120                {
121                    /* cleanup activity */
122                    fat_free_fat_clusters_chain(mt_entry, (*chain));
123                    /* trying to save last allocated cluster for future use */
124                    fat_set_fat_cluster(mt_entry, cl4find, FAT_GENFAT_FREE);
125                    fat_buf_release(fs_info);
126                    return rc; 
127                }
128            } 
129
130            save_cln = cl4find;
131            (*cls_added)++;
132
133            /* have we satisfied request ? */
134            if (*cls_added == count)
135            {
136                /*if (fs_info->vol.type & FAT_FAT32)
137                {*/
138                    fs_info->vol.next_cl = save_cln;
139                    if (fs_info->vol.free_cls != 0xFFFFFFFF)
140                        fs_info->vol.free_cls -= (*cls_added);
141                /*}*/
142                *last_cl = save_cln;   
143                fat_buf_release(fs_info);
144                return rc; 
145            } 
146        }
147        i++;
148        cl4find++; 
149        if (cl4find >= data_cls_val)
150            cl4find = 2;
151    }
152
153    /*if (fs_info->vol.type & FAT_FAT32)
154    {*/
155        fs_info->vol.next_cl = save_cln;
156        if (fs_info->vol.free_cls != 0xFFFFFFFF)
157            fs_info->vol.free_cls -= (*cls_added);   
158    /*}*/
159
160    *last_cl = save_cln;
161    fat_buf_release(fs_info);
162    return RC_OK;   
163} 
164
165/* fat_free_fat_clusters_chain --
166 *     Free chain of clusters in Files Allocation Table.
167 *
168 * PARAMETERS:
169 *     mt_entry - mount table entry
170 *     chain    - number of the first cluster in  the chain
171 *
172 * RETURNS:
173 *     RC_OK on success, or -1 if error occured (errno set appropriately)
174 */
175int 
176fat_free_fat_clusters_chain(
177    rtems_filesystem_mount_table_entry_t *mt_entry,
178    unsigned32                            chain
179    )
180{
181    int            rc = RC_OK, rc1 = RC_OK;
182    fat_fs_info_t *fs_info = mt_entry->fs_info;
183    unsigned32     cur_cln = chain; 
184    unsigned32     next_cln = 0; 
185    unsigned32     freed_cls_cnt = 0;
186   
187    while ((cur_cln & fs_info->vol.mask) < fs_info->vol.eoc_val)
188    {
189        rc = fat_get_fat_cluster(mt_entry, cur_cln, &next_cln);
190        if ( rc != RC_OK )
191        {
192            /*if ((fs_info->vol.type & FAT_FAT32) &&
193                (fs_info->vol.free_cls != FAT_UNDEFINED_VALUE))*/
194              if(fs_info->vol.free_cls != FAT_UNDEFINED_VALUE)
195                fs_info->vol.free_cls += freed_cls_cnt;
196
197            fat_buf_release(fs_info);   
198            return rc;
199        }   
200
201        rc = fat_set_fat_cluster(mt_entry, cur_cln, FAT_GENFAT_FREE);
202        if ( rc != RC_OK )
203            rc1 = rc;
204
205        freed_cls_cnt++;
206        cur_cln = next_cln;
207    }
208
209    /*if (fs_info->vol.type & FAT_FAT32)
210    {*/
211        fs_info->vol.next_cl = chain;
212        if (fs_info->vol.free_cls != FAT_UNDEFINED_VALUE)
213            fs_info->vol.free_cls += freed_cls_cnt;
214    /*}*/
215
216    fat_buf_release(fs_info);
217    if (rc1 != RC_OK)
218        return rc1;
219
220    return RC_OK; 
221}
222
223/* fat_get_fat_cluster --
224 *     Fetches the contents of the cluster (link to next cluster in the chain)
225 *     from Files Allocation Table.
226 *
227 * PARAMETERS:
228 *     mt_entry - mount table entry
229 *     cln      - number of cluster to fetch the contents from
230 *     ret_val  - contents of the cluster 'cln' (link to next cluster in
231 *                the chain)
232 *
233 * RETURNS:
234 *     RC_OK on success, or -1 if error occured
235 *     and errno set appropriately
236 */
237int
238fat_get_fat_cluster(
239    rtems_filesystem_mount_table_entry_t *mt_entry,
240    unsigned32                            cln,
241    unsigned32                           *ret_val
242    )
243{
244    int                     rc = RC_OK;
245    register fat_fs_info_t *fs_info = mt_entry->fs_info;
246    bdbuf_buffer           *block0 = NULL;
247    unsigned32              sec = 0;
248    unsigned32              ofs = 0;
249
250    /* sanity check */
251    if ( (cln < 2) || (cln > (fs_info->vol.data_cls + 1)) )
252        set_errno_and_return_minus_one(EIO);
253
254    sec = (FAT_FAT_OFFSET(fs_info->vol.type, cln) >> fs_info->vol.sec_log2) + 
255          fs_info->vol.afat_loc;
256    ofs = FAT_FAT_OFFSET(fs_info->vol.type, cln) & (fs_info->vol.bps - 1);
257
258    rc = fat_buf_access(fs_info, sec, FAT_OP_TYPE_READ, &block0);
259    if (rc != RC_OK)
260        return rc;
261
262    switch ( fs_info->vol.type )
263    {
264        case FAT_FAT12:
265            /*
266             * we are enforced in complex computations for FAT12 to escape CPU
267             * align problems for some architectures
268             */
269            *ret_val = (*((unsigned8 *)(block0->buffer + ofs)));
270            if ( ofs == (fs_info->vol.bps - 1) )
271            {
272                rc = fat_buf_access(fs_info, sec + 1, FAT_OP_TYPE_READ, 
273                                    &block0);
274                if (rc != RC_OK)
275                    return rc;
276
277                *ret_val |= (*((unsigned8 *)(block0->buffer)))<<8;
278            }
279            else
280            { 
281                *ret_val |= (*((unsigned8 *)(block0->buffer + ofs + 1)))<<8;
282            }
283
284            if ( FAT_CLUSTER_IS_ODD(cln) )
285                *ret_val = (*ret_val) >> FAT12_SHIFT;
286            else
287                *ret_val = (*ret_val) & FAT_FAT12_MASK;
288            break;
289
290        case FAT_FAT16:
291            *ret_val = *((unsigned16 *)(block0->buffer + ofs));
292            *ret_val = CF_LE_W(*ret_val);
293            break;
294
295        case FAT_FAT32:
296            *ret_val = *((unsigned32 *)(block0->buffer + ofs));
297            *ret_val = CF_LE_L(*ret_val);
298            break;
299
300        default:
301            set_errno_and_return_minus_one(EIO);
302            break;
303    }
304
305    return RC_OK;
306}
307
308/* fat_set_fat_cluster --
309 *     Set the contents of the cluster (link to next cluster in the chain)
310 *     from Files Allocation Table.
311 *
312 * PARAMETERS:
313 *     mt_entry - mount table entry
314 *     cln      - number of cluster to set contents to
315 *     in_val   - value to set
316 *
317 * RETURNS:
318 *     RC_OK on success, or -1 if error occured
319 *     and errno set appropriately
320 */
321int
322fat_set_fat_cluster(
323    rtems_filesystem_mount_table_entry_t *mt_entry,
324    unsigned32                            cln,
325    unsigned32                            in_val
326    )
327{
328    int                rc = RC_OK;
329    fat_fs_info_t     *fs_info = mt_entry->fs_info;
330    unsigned32         sec = 0;
331    unsigned32         ofs = 0;
332    unsigned16         fat16_clv = 0;
333    unsigned32         fat32_clv = 0;
334    bdbuf_buffer      *block0 = NULL; 
335
336    /* sanity check */
337    if ( (cln < 2) || (cln > (fs_info->vol.data_cls + 1)) )
338        set_errno_and_return_minus_one(EIO);
339
340    sec = (FAT_FAT_OFFSET(fs_info->vol.type, cln) >> fs_info->vol.sec_log2) + 
341          fs_info->vol.afat_loc;
342    ofs = FAT_FAT_OFFSET(fs_info->vol.type, cln) & (fs_info->vol.bps - 1);
343 
344    rc = fat_buf_access(fs_info, sec, FAT_OP_TYPE_READ, &block0);
345    if (rc != RC_OK)
346        return rc;
347
348    switch ( fs_info->vol.type )
349    {
350        case FAT_FAT12:
351            if ( FAT_CLUSTER_IS_ODD(cln) )
352            {
353#if 0
354              /*
355               * do not perform endian conversion explicitely,
356               * because following code will enforce little
357               * endian format implicitly!
358               */               
359                fat16_clv = CT_LE_W((((unsigned16)in_val) << FAT_FAT12_SHIFT));
360#else
361                fat16_clv = ((unsigned16)in_val) << FAT_FAT12_SHIFT;
362#endif
363                *((unsigned8 *)(block0->buffer + ofs)) = 
364                        (*((unsigned8 *)(block0->buffer + ofs))) & 0x0F;
365
366                *((unsigned8 *)(block0->buffer + ofs)) = 
367                        (*((unsigned8 *)(block0->buffer + ofs))) | 
368                        (unsigned8)(fat16_clv & 0x00FF);
369
370                fat_buf_mark_modified(fs_info);
371               
372                if ( ofs == (fs_info->vol.bps - 1) )
373                {
374                    rc = fat_buf_access(fs_info, sec + 1, FAT_OP_TYPE_READ, 
375                                        &block0);
376                    if (rc != RC_OK)
377                        return rc;
378
379                     *((unsigned8 *)(block0->buffer)) &= 0x00;
380 
381                     *((unsigned8 *)(block0->buffer)) = 
382                            (*((unsigned8 *)(block0->buffer))) | 
383                            (unsigned8)((fat16_clv & 0xFF00)>>8);
384                     
385                     fat_buf_mark_modified(fs_info);
386                }
387                else
388                {
389                    *((unsigned8 *)(block0->buffer + ofs + 1)) &= 0x00;
390             
391                    *((unsigned8 *)(block0->buffer + ofs + 1)) = 
392                            (*((unsigned8 *)(block0->buffer + ofs + 1))) | 
393                            (unsigned8)((fat16_clv & 0xFF00)>>8);
394                } 
395            }
396            else
397            {
398#if 0
399              /*
400               * do not perform endian conversion explicitely,
401               * because following code will enforce little
402               * endian format implicitly!
403               */               
404                fat16_clv = CT_LE_W((((unsigned16)in_val) & FAT_FAT12_MASK));
405#else
406                fat16_clv = ((unsigned16)in_val) & FAT_FAT12_MASK;
407#endif
408                *((unsigned8 *)(block0->buffer + ofs)) &= 0x00;
409
410                *((unsigned8 *)(block0->buffer + ofs)) = 
411                        (*((unsigned8 *)(block0->buffer + ofs))) | 
412                        (unsigned8)(fat16_clv & 0x00FF);
413                       
414                fat_buf_mark_modified(fs_info);         
415 
416                if ( ofs == (fs_info->vol.bps - 1) )
417                {
418                    rc = fat_buf_access(fs_info, sec + 1, FAT_OP_TYPE_READ, 
419                                        &block0);
420                    if (rc != RC_OK)
421                        return rc;
422
423                    *((unsigned8 *)(block0->buffer)) = 
424                            (*((unsigned8 *)(block0->buffer))) & 0xF0;
425 
426                    *((unsigned8 *)(block0->buffer)) = 
427                            (*((unsigned8 *)(block0->buffer))) | 
428                            (unsigned8)((fat16_clv & 0xFF00)>>8);
429                           
430                    fat_buf_mark_modified(fs_info);       
431                }
432                else
433                {
434                    *((unsigned8 *)(block0->buffer + ofs + 1)) =   
435                      (*((unsigned8 *)(block0->buffer + ofs + 1))) & 0xF0;
436
437                    *((unsigned8 *)(block0->buffer + ofs+1)) = 
438                           (*((unsigned8 *)(block0->buffer + ofs+1))) | 
439                           (unsigned8)((fat16_clv & 0xFF00)>>8);
440                } 
441            }
442            break;
443
444        case FAT_FAT16:
445            *((unsigned16 *)(block0->buffer + ofs)) = 
446                    (unsigned16)(CT_LE_W(in_val));
447            fat_buf_mark_modified(fs_info);       
448            break;
449
450        case FAT_FAT32:
451            fat32_clv = CT_LE_L((in_val & FAT_FAT32_MASK));
452
453            *((unsigned32 *)(block0->buffer + ofs)) = 
454            (*((unsigned32 *)(block0->buffer + ofs))) & (CT_LE_L(0xF0000000));
455
456            *((unsigned32 *)(block0->buffer + ofs)) = 
457                   fat32_clv | (*((unsigned32 *)(block0->buffer + ofs)));
458           
459            fat_buf_mark_modified(fs_info);
460            break;
461
462        default:
463            set_errno_and_return_minus_one(EIO);
464            break;
465
466    }
467
468    return RC_OK;
469}
Note: See TracBrowser for help on using the repository browser.