source: rtems/cpukit/libfs/src/dosfs/fat_fat_operations.c @ 3c96bee

4.115
Last change on this file since 3c96bee was cd85e84, checked in by Sebastian Huber <sebastian.huber@…>, on 02/15/13 at 15:57:21

dosfs: Start scan with a valid data cluster

Simpify the loop. Set last cluster to an undefined value in case no
free cluster exists.

  • Property mode set to 100644
File size: 11.6 KB
Line 
1/**
2 * @file
3 *
4 * @brief General operations on File Allocation Table
5 * @ingroup libfs_ffo Fat Fat Operations
6 */
7
8/*
9 *  Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
10 *  Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
11 */
12
13#if HAVE_CONFIG_H
14#include "config.h"
15#endif
16
17#include <sys/types.h>
18#include <sys/stat.h>
19#include <fcntl.h>
20#include <unistd.h>
21#include <errno.h>
22#include <stdlib.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 *     fs_info  - FS info
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    fat_fs_info_t                        *fs_info,
47    uint32_t                             *chain,
48    uint32_t                              count,
49    uint32_t                             *cls_added,
50    uint32_t                             *last_cl,
51    bool                                  zero_fill
52    )
53{
54    int            rc = RC_OK;
55    uint32_t       cl4find = 2;
56    uint32_t       save_cln = FAT_UNDEFINED_VALUE;
57    uint32_t       data_cls_val = fs_info->vol.data_cls + 2;
58    uint32_t       i = 2;
59
60    if (fs_info->vol.next_cl - 2 < fs_info->vol.data_cls)
61        cl4find = fs_info->vol.next_cl;
62
63    *cls_added = 0;
64
65    /*
66     * fs_info->vol.data_cls is exactly the count of data clusters
67     * starting at cluster 2, so the maximum valid cluster number is
68     * (fs_info->vol.data_cls + 1)
69     */
70    while (*cls_added != count && i < data_cls_val)
71    {
72        uint32_t next_cln = 0;
73
74        rc = fat_get_fat_cluster(fs_info, cl4find, &next_cln);
75        if ( rc != RC_OK )
76        {
77            if (*cls_added != 0)
78                fat_free_fat_clusters_chain(fs_info, (*chain));
79            return rc;
80        }
81
82        if (next_cln == FAT_GENFAT_FREE)
83        {
84            /*
85             * We are enforced to process allocation of the first free cluster
86             * by separate 'if' statement because otherwise undo function
87             * wouldn't work properly
88             */
89            if (*cls_added == 0)
90            {
91                *chain = cl4find;
92                rc = fat_set_fat_cluster(fs_info, cl4find, FAT_GENFAT_EOC);
93                if ( rc != RC_OK )
94                {
95                    /*
96                     * this is the first cluster we tried to allocate so no
97                     * cleanup activity needed
98                     */
99                     return rc;
100                }
101            }
102            else
103            {
104                /* set EOC value to new allocated cluster */
105                rc = fat_set_fat_cluster(fs_info, cl4find, FAT_GENFAT_EOC);
106                if ( rc != RC_OK )
107                {
108                    /* cleanup activity */
109                    fat_free_fat_clusters_chain(fs_info, (*chain));
110                    return rc;
111                }
112
113                rc = fat_set_fat_cluster(fs_info, save_cln, cl4find);
114                if ( rc != RC_OK )
115                    goto cleanup;
116            }
117
118            if (zero_fill)
119            {
120                ssize_t bytes_written =
121                    fat_cluster_set(fs_info, cl4find, 0, fs_info->vol.bpc, 0);
122
123                if (fs_info->vol.bpc != bytes_written)
124                {
125                    rc = -1;
126                    goto cleanup;
127                }
128            }
129
130            save_cln = cl4find;
131            (*cls_added)++;
132        }
133        i++;
134        cl4find++;
135        if (cl4find >= data_cls_val)
136            cl4find = 2;
137    }
138
139    *last_cl = save_cln;
140    fs_info->vol.next_cl = save_cln;
141
142    if (fs_info->vol.free_cls != FAT_UNDEFINED_VALUE)
143        fs_info->vol.free_cls -= (*cls_added);
144
145    fat_buf_release(fs_info);
146
147    return RC_OK;
148
149cleanup:
150
151    /* cleanup activity */
152    fat_free_fat_clusters_chain(fs_info, (*chain));
153    /* trying to save last allocated cluster for future use */
154    fat_set_fat_cluster(fs_info, cl4find, FAT_GENFAT_FREE);
155    fat_buf_release(fs_info);
156    return rc;
157}
158
159/* fat_free_fat_clusters_chain --
160 *     Free chain of clusters in Files Allocation Table.
161 *
162 * PARAMETERS:
163 *     fs_info  - FS info
164 *     chain    - number of the first cluster in  the chain
165 *
166 * RETURNS:
167 *     RC_OK on success, or -1 if error occured (errno set appropriately)
168 */
169int
170fat_free_fat_clusters_chain(
171    fat_fs_info_t                        *fs_info,
172    uint32_t                              chain
173    )
174{
175    int            rc = RC_OK, rc1 = RC_OK;
176    uint32_t       cur_cln = chain;
177    uint32_t       next_cln = 0;
178    uint32_t       freed_cls_cnt = 0;
179
180    while ((cur_cln & fs_info->vol.mask) < fs_info->vol.eoc_val)
181    {
182        rc = fat_get_fat_cluster(fs_info, cur_cln, &next_cln);
183        if ( rc != RC_OK )
184        {
185              if(fs_info->vol.free_cls != FAT_UNDEFINED_VALUE)
186                fs_info->vol.free_cls += freed_cls_cnt;
187
188            fat_buf_release(fs_info);
189            return rc;
190        }
191
192        rc = fat_set_fat_cluster(fs_info, cur_cln, FAT_GENFAT_FREE);
193        if ( rc != RC_OK )
194            rc1 = rc;
195
196        freed_cls_cnt++;
197        cur_cln = next_cln;
198    }
199
200        fs_info->vol.next_cl = chain;
201        if (fs_info->vol.free_cls != FAT_UNDEFINED_VALUE)
202            fs_info->vol.free_cls += freed_cls_cnt;
203
204    fat_buf_release(fs_info);
205    if (rc1 != RC_OK)
206        return rc1;
207
208    return RC_OK;
209}
210
211/* fat_get_fat_cluster --
212 *     Fetches the contents of the cluster (link to next cluster in the chain)
213 *     from Files Allocation Table.
214 *
215 * PARAMETERS:
216 *     fs_info  - FS info
217 *     cln      - number of cluster to fetch the contents from
218 *     ret_val  - contents of the cluster 'cln' (link to next cluster in
219 *                the chain)
220 *
221 * RETURNS:
222 *     RC_OK on success, or -1 if error occured
223 *     and errno set appropriately
224 */
225int
226fat_get_fat_cluster(
227    fat_fs_info_t                        *fs_info,
228    uint32_t                              cln,
229    uint32_t                             *ret_val
230    )
231{
232    int                     rc = RC_OK;
233    uint8_t                *sec_buf;
234    uint32_t                sec = 0;
235    uint32_t                ofs = 0;
236
237    /* sanity check */
238    if ( (cln < 2) || (cln > (fs_info->vol.data_cls + 1)) )
239        rtems_set_errno_and_return_minus_one(EIO);
240
241    sec = (FAT_FAT_OFFSET(fs_info->vol.type, cln) >> fs_info->vol.sec_log2) +
242          fs_info->vol.afat_loc;
243    ofs = FAT_FAT_OFFSET(fs_info->vol.type, cln) & (fs_info->vol.bps - 1);
244
245    rc = fat_buf_access(fs_info, sec, FAT_OP_TYPE_READ, &sec_buf);
246    if (rc != RC_OK)
247        return rc;
248
249    switch ( fs_info->vol.type )
250    {
251        case FAT_FAT12:
252            /*
253             * we are enforced in complex computations for FAT12 to escape CPU
254             * align problems for some architectures
255             */
256            *ret_val = (*(sec_buf + ofs));
257            if ( ofs == (fs_info->vol.bps - 1) )
258            {
259                rc = fat_buf_access(fs_info, sec + 1, FAT_OP_TYPE_READ,
260                                    &sec_buf);
261                if (rc != RC_OK)
262                    return rc;
263
264                *ret_val |= *sec_buf << 8;
265            }
266            else
267            {
268                *ret_val |= *(sec_buf + ofs + 1) << 8;
269            }
270
271            if ( FAT_CLUSTER_IS_ODD(cln) )
272                *ret_val = (*ret_val) >> FAT12_SHIFT;
273            else
274                *ret_val = (*ret_val) & FAT_FAT12_MASK;
275            break;
276
277        case FAT_FAT16:
278            *ret_val = *((uint16_t   *)(sec_buf + ofs));
279            *ret_val = CF_LE_W(*ret_val);
280            break;
281
282        case FAT_FAT32:
283            *ret_val = *((uint32_t   *)(sec_buf + ofs));
284            *ret_val = CF_LE_L(*ret_val);
285            break;
286
287        default:
288            rtems_set_errno_and_return_minus_one(EIO);
289            break;
290    }
291
292    return RC_OK;
293}
294
295/* fat_set_fat_cluster --
296 *     Set the contents of the cluster (link to next cluster in the chain)
297 *     from Files Allocation Table.
298 *
299 * PARAMETERS:
300 *     fs_info  - FS info
301 *     cln      - number of cluster to set contents to
302 *     in_val   - value to set
303 *
304 * RETURNS:
305 *     RC_OK on success, or -1 if error occured
306 *     and errno set appropriately
307 */
308int
309fat_set_fat_cluster(
310    fat_fs_info_t                        *fs_info,
311    uint32_t                              cln,
312    uint32_t                              in_val
313    )
314{
315    int                 rc = RC_OK;
316    uint32_t            sec = 0;
317    uint32_t            ofs = 0;
318    uint16_t            fat16_clv = 0;
319    uint32_t            fat32_clv = 0;
320    uint8_t            *sec_buf = NULL;
321
322    /* sanity check */
323    if ( (cln < 2) || (cln > (fs_info->vol.data_cls + 1)) )
324        rtems_set_errno_and_return_minus_one(EIO);
325
326    sec = (FAT_FAT_OFFSET(fs_info->vol.type, cln) >> fs_info->vol.sec_log2) +
327          fs_info->vol.afat_loc;
328    ofs = FAT_FAT_OFFSET(fs_info->vol.type, cln) & (fs_info->vol.bps - 1);
329
330    rc = fat_buf_access(fs_info, sec, FAT_OP_TYPE_READ, &sec_buf);
331    if (rc != RC_OK)
332        return rc;
333
334    switch ( fs_info->vol.type )
335    {
336        case FAT_FAT12:
337            if ( FAT_CLUSTER_IS_ODD(cln) )
338            {
339                fat16_clv = ((uint16_t  )in_val) << FAT_FAT12_SHIFT;
340                *(sec_buf + ofs) &= 0x0F;
341
342                *(sec_buf + ofs) |= (uint8_t)(fat16_clv & 0x00F0);
343
344                fat_buf_mark_modified(fs_info);
345
346                if ( ofs == (fs_info->vol.bps - 1) )
347                {
348                    rc = fat_buf_access(fs_info, sec + 1, FAT_OP_TYPE_READ,
349                                        &sec_buf);
350                    if (rc != RC_OK)
351                        return rc;
352
353                     *sec_buf &= 0x00;
354
355                     *sec_buf |= (uint8_t)((fat16_clv & 0xFF00)>>8);
356
357                     fat_buf_mark_modified(fs_info);
358                }
359                else
360                {
361                    *(sec_buf + ofs + 1) &= 0x00;
362
363                    *(sec_buf + ofs + 1) |= (uint8_t  )((fat16_clv & 0xFF00)>>8);
364                }
365            }
366            else
367            {
368                fat16_clv = ((uint16_t  )in_val) & FAT_FAT12_MASK;
369                *(sec_buf + ofs) &= 0x00;
370
371                *(sec_buf + ofs) |= (uint8_t)(fat16_clv & 0x00FF);
372
373                fat_buf_mark_modified(fs_info);
374
375                if ( ofs == (fs_info->vol.bps - 1) )
376                {
377                    rc = fat_buf_access(fs_info, sec + 1, FAT_OP_TYPE_READ,
378                                        &sec_buf);
379                    if (rc != RC_OK)
380                        return rc;
381
382                    *sec_buf &= 0xF0;
383
384                    *sec_buf |= (uint8_t)((fat16_clv & 0xFF00)>>8);
385
386                    fat_buf_mark_modified(fs_info);
387                }
388                else
389                {
390                    *(sec_buf + ofs + 1) &= 0xF0;
391
392                    *(sec_buf + ofs+1) |= (uint8_t)((fat16_clv & 0xFF00)>>8);
393                }
394            }
395            break;
396
397        case FAT_FAT16:
398            *((uint16_t   *)(sec_buf + ofs)) =
399                    (uint16_t  )(CT_LE_W(in_val));
400            fat_buf_mark_modified(fs_info);
401            break;
402
403        case FAT_FAT32:
404            fat32_clv = CT_LE_L((in_val & FAT_FAT32_MASK));
405
406            *((uint32_t *)(sec_buf + ofs)) &= CT_LE_L(0xF0000000);
407
408            *((uint32_t *)(sec_buf + ofs)) |= fat32_clv;
409
410            fat_buf_mark_modified(fs_info);
411            break;
412
413        default:
414            rtems_set_errno_and_return_minus_one(EIO);
415            break;
416
417    }
418
419    return RC_OK;
420}
Note: See TracBrowser for help on using the repository browser.