Subversion Repositories HelenOS

Rev

Rev 3504 | Rev 3507 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 3504 Rev 3506
Line 33... Line 33...
33
/**
33
/**
34
 * @file    fat_fat.c
34
 * @file    fat_fat.c
35
 * @brief   Functions that manipulate the file allocation tables.
35
 * @brief   Functions that manipulate the file allocation tables.
36
 */
36
 */
37
 
37
 
-
 
38
#include "fat_fat.h"
-
 
39
#include "fat_dentry.h"
-
 
40
#include "fat.h"
-
 
41
#include "../../vfs/vfs.h"
-
 
42
#include <libfs.h>
-
 
43
#include <errno.h>
-
 
44
#include <byteorder.h>
-
 
45
#include <align.h>
-
 
46
#include <assert.h>
-
 
47
 
-
 
48
block_t *
-
 
49
_fat_block_get(dev_handle_t dev_handle, fat_cluster_t firstc, off_t offset)
-
 
50
{
-
 
51
    block_t *bb;
-
 
52
    block_t *b;
-
 
53
    unsigned bps;
-
 
54
    unsigned spc;
-
 
55
    unsigned rscnt;     /* block address of the first FAT */
-
 
56
    unsigned fatcnt;
-
 
57
    unsigned rde;
-
 
58
    unsigned rds;       /* root directory size */
-
 
59
    unsigned sf;
-
 
60
    unsigned ssa;       /* size of the system area */
-
 
61
    unsigned clusters;
-
 
62
    fat_cluster_t clst = firstc;
-
 
63
    unsigned i;
-
 
64
 
-
 
65
    bb = block_get(dev_handle, BS_BLOCK, BS_SIZE);
-
 
66
    bps = uint16_t_le2host(FAT_BS(bb)->bps);
-
 
67
    spc = FAT_BS(bb)->spc;
-
 
68
    rscnt = uint16_t_le2host(FAT_BS(bb)->rscnt);
-
 
69
    fatcnt = FAT_BS(bb)->fatcnt;
-
 
70
    rde = uint16_t_le2host(FAT_BS(bb)->root_ent_max);
-
 
71
    sf = uint16_t_le2host(FAT_BS(bb)->sec_per_fat);
-
 
72
    block_put(bb);
-
 
73
 
-
 
74
    rds = (sizeof(fat_dentry_t) * rde) / bps;
-
 
75
    rds += ((sizeof(fat_dentry_t) * rde) % bps != 0);
-
 
76
    ssa = rscnt + fatcnt * sf + rds;
-
 
77
 
-
 
78
    if (firstc == FAT_CLST_ROOT) {
-
 
79
        /* root directory special case */
-
 
80
        assert(offset < rds);
-
 
81
        b = block_get(dev_handle, rscnt + fatcnt * sf + offset, bps);
-
 
82
        return b;
-
 
83
    }
-
 
84
 
-
 
85
    clusters = offset / spc;
-
 
86
    for (i = 0; i < clusters; i++) {
-
 
87
        unsigned fsec;  /* sector offset relative to FAT1 */
-
 
88
        unsigned fidx;  /* FAT1 entry index */
-
 
89
 
-
 
90
        assert(clst >= FAT_CLST_FIRST && clst < FAT_CLST_BAD);
-
 
91
        fsec = (clst * sizeof(fat_cluster_t)) / bps;
-
 
92
        fidx = clst % (bps / sizeof(fat_cluster_t));
-
 
93
        /* read FAT1 */
-
 
94
        b = block_get(dev_handle, rscnt + fsec, bps);
-
 
95
        clst = uint16_t_le2host(((fat_cluster_t *)b->data)[fidx]);
-
 
96
        assert(clst != FAT_CLST_BAD);
-
 
97
        assert(clst < FAT_CLST_LAST1);
-
 
98
        block_put(b);
-
 
99
    }
-
 
100
 
-
 
101
    b = block_get(dev_handle, ssa + (clst - FAT_CLST_FIRST) * spc +
-
 
102
        offset % spc, bps);
-
 
103
 
-
 
104
    return b;
-
 
105
}
-
 
106
 
-
 
107
/** Return number of blocks allocated to a file.
-
 
108
 *
-
 
109
 * @param dev_handle    Device handle of the device with the file.
-
 
110
 * @param firstc    First cluster of the file.
-
 
111
 *
-
 
112
 * @return      Number of blocks allocated to the file.
-
 
113
 */
-
 
114
uint16_t
-
 
115
_fat_blcks_get(dev_handle_t dev_handle, fat_cluster_t firstc)
-
 
116
{
-
 
117
    block_t *bb;
-
 
118
    block_t *b;
-
 
119
    unsigned bps;
-
 
120
    unsigned spc;
-
 
121
    unsigned rscnt;     /* block address of the first FAT */
-
 
122
    unsigned clusters = 0;
-
 
123
    fat_cluster_t clst = firstc;
-
 
124
 
-
 
125
    bb = block_get(dev_handle, BS_BLOCK, BS_SIZE);
-
 
126
    bps = uint16_t_le2host(FAT_BS(bb)->bps);
-
 
127
    spc = FAT_BS(bb)->spc;
-
 
128
    rscnt = uint16_t_le2host(FAT_BS(bb)->rscnt);
-
 
129
    block_put(bb);
-
 
130
 
-
 
131
    if (firstc == FAT_CLST_RES0) {
-
 
132
        /* No space allocated to the file. */
-
 
133
        return 0;
-
 
134
    }
-
 
135
 
-
 
136
    while (clst < FAT_CLST_LAST1) {
-
 
137
        unsigned fsec;  /* sector offset relative to FAT1 */
-
 
138
        unsigned fidx;  /* FAT1 entry index */
-
 
139
 
-
 
140
        assert(clst >= FAT_CLST_FIRST);
-
 
141
        fsec = (clst * sizeof(fat_cluster_t)) / bps;
-
 
142
        fidx = clst % (bps / sizeof(fat_cluster_t));
-
 
143
        /* read FAT1 */
-
 
144
        b = block_get(dev_handle, rscnt + fsec, bps);
-
 
145
        clst = uint16_t_le2host(((fat_cluster_t *)b->data)[fidx]);
-
 
146
        assert(clst != FAT_CLST_BAD);
-
 
147
        block_put(b);
-
 
148
        clusters++;
-
 
149
    }
-
 
150
 
-
 
151
    return clusters * spc;
-
 
152
}
-
 
153
 
-
 
154
uint16_t fat_bps_get(dev_handle_t dev_handle)
-
 
155
{
-
 
156
    block_t *bb;
-
 
157
    uint16_t bps;
-
 
158
   
-
 
159
    bb = block_get(dev_handle, BS_BLOCK, BS_SIZE);
-
 
160
    assert(bb != NULL);
-
 
161
    bps = uint16_t_le2host(FAT_BS(bb)->bps);
-
 
162
    block_put(bb);
-
 
163
 
-
 
164
    return bps;
-
 
165
}
-
 
166
 
-
 
167
/** Fill the gap between EOF and a new file position.
-
 
168
 *
-
 
169
 * @param nodep     FAT node with the gap.
-
 
170
 * @param mcl       First cluster in an independent cluster chain that will
-
 
171
 *          be later appended to the end of the node's own cluster
-
 
172
 *          chain. If pos is still in the last allocated cluster,
-
 
173
 *          this argument is ignored.
-
 
174
 * @param pos       Position in the last node block.
-
 
175
 */
-
 
176
void fat_fill_gap(fat_node_t *nodep, fat_cluster_t mcl, off_t pos)
-
 
177
{
-
 
178
    uint16_t bps;
-
 
179
    unsigned spc;
-
 
180
    block_t *bb, *b;
-
 
181
    off_t o, boundary;
-
 
182
 
-
 
183
    bb = block_get(nodep->idx->dev_handle, BS_BLOCK, BS_SIZE);
-
 
184
    bps = uint16_t_le2host(FAT_BS(bb)->bps);
-
 
185
    spc = FAT_BS(bb)->spc;
-
 
186
    block_put(bb);
-
 
187
   
-
 
188
    boundary = ROUND_UP(nodep->size, bps * spc);
-
 
189
 
-
 
190
    /* zero out already allocated space */
-
 
191
    for (o = nodep->size - 1; o < pos && o < boundary;
-
 
192
        o = ALIGN_DOWN(o + bps, bps)) {
-
 
193
        b = fat_block_get(nodep, o / bps);
-
 
194
        memset(b->data + o % bps, 0, bps - o % bps);
-
 
195
        b->dirty = true;        /* need to sync node */
-
 
196
        block_put(b);
-
 
197
    }
-
 
198
   
-
 
199
    if (o >= pos)
-
 
200
        return;
-
 
201
   
-
 
202
    /* zero out the initial part of the new cluster chain */
-
 
203
    for (o = boundary; o < pos; o += bps) {
-
 
204
        b = _fat_block_get(nodep->idx->dev_handle, mcl,
-
 
205
            (o - boundary) / bps);
-
 
206
        memset(b->data, 0, min(bps, pos - o));
-
 
207
        b->dirty = true;        /* need to sync node */
-
 
208
        block_put(b);
-
 
209
    }
-
 
210
}
-
 
211
 
-
 
212
void
-
 
213
fat_mark_cluster(dev_handle_t dev_handle, unsigned fatno, fat_cluster_t clst,
-
 
214
    fat_cluster_t value)
-
 
215
{
-
 
216
    /* TODO */
-
 
217
}
-
 
218
 
-
 
219
void
-
 
220
fat_alloc_shadow_clusters(dev_handle_t dev_handle, fat_cluster_t *lifo,
-
 
221
    unsigned nclsts)
-
 
222
{
-
 
223
    /* TODO */
-
 
224
}
-
 
225
 
-
 
226
int
-
 
227
fat_alloc_clusters(dev_handle_t dev_handle, unsigned nclsts, fat_cluster_t *mcl,
-
 
228
    fat_cluster_t *lcl)
-
 
229
{
-
 
230
    uint16_t bps;
-
 
231
    uint16_t rscnt;
-
 
232
    uint16_t sf;
-
 
233
    block_t *bb, *blk;
-
 
234
    fat_cluster_t *lifo;    /* stack for storing free cluster numbers */
-
 
235
    unsigned found = 0; /* top of the free cluster number stack */
-
 
236
    unsigned b, c, cl;
-
 
237
 
-
 
238
    lifo = (fat_cluster_t *) malloc(nclsts * sizeof(fat_cluster_t));
-
 
239
    if (lifo)
-
 
240
        return ENOMEM;
-
 
241
   
-
 
242
    bb = block_get(dev_handle, BS_BLOCK, BS_SIZE);
-
 
243
    bps = uint16_t_le2host(FAT_BS(bb)->bps);
-
 
244
    rscnt = uint16_t_le2host(FAT_BS(bb)->rscnt);
-
 
245
    sf = uint16_t_le2host(FAT_BS(bb)->sec_per_fat);
-
 
246
    block_put(bb);
-
 
247
   
-
 
248
    /*
-
 
249
     * Search FAT1 for unused clusters.
-
 
250
     */
-
 
251
    for (b = 0, cl = 0; b < sf; blk++) {
-
 
252
        blk = block_get(dev_handle, rscnt + b, bps);
-
 
253
        for (c = 0; c < bps / sizeof(fat_cluster_t); c++, cl++) {
-
 
254
            fat_cluster_t *clst = (fat_cluster_t *)blk->data + c;
-
 
255
            if (*clst == FAT_CLST_RES0) {
-
 
256
                /*
-
 
257
                 * The cluster is free. Put it into our stack
-
 
258
                 * of found clusters and mark it as non-free.
-
 
259
                 */
-
 
260
                lifo[found] = cl;
-
 
261
                if (found == 0)
-
 
262
                    *clst = FAT_CLST_LAST1;
-
 
263
                else
-
 
264
                    *clst = lifo[found - 1];
-
 
265
                blk->dirty = true;  /* need to sync block */
-
 
266
                if (++found == nclsts) {
-
 
267
                    /* we are almost done */
-
 
268
                    block_put(blk);
-
 
269
                    /* update the shadow copies of FAT */
-
 
270
                    fat_alloc_shadow_clusters(dev_handle,
-
 
271
                        lifo, nclsts);
-
 
272
                    *mcl = lifo[found - 1];
-
 
273
                    *lcl = lifo[0];
-
 
274
                    free(lifo);
-
 
275
                    return EOK;
-
 
276
                }
-
 
277
            }
-
 
278
        }
-
 
279
        block_put(blk);
-
 
280
    }
-
 
281
 
-
 
282
    /*
-
 
283
     * We could not find enough clusters. Now we need to free the clusters
-
 
284
     * we have allocated so far.
-
 
285
     */
-
 
286
    while (found--)
-
 
287
        fat_mark_cluster(dev_handle, FAT1, lifo[found], FAT_CLST_RES0);
-
 
288
   
-
 
289
    free(lifo);
-
 
290
    return ENOSPC;
-
 
291
}
-
 
292
 
-
 
293
void fat_append_clusters(fat_node_t *nodep, fat_cluster_t mcl)
-
 
294
{
-
 
295
}
38
 
296
 
39
/**
297
/**
40
 * @}
298
 * @}
41
 */
299
 */