source: rtems/cpukit/libfs/src/dosfs/fat_fat_operations.c @ 897fe13

4.104.114.84.95
Last change on this file since 897fe13 was 897fe13, checked in by Joel Sherrill <joel.sherrill@…>, on Oct 22, 2003 at 4:31:17 PM

2003-10-22 Joel Sherrill <joel@…>

PR 440/filesystem

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