Statistics
| Branch: | Revision:

scoutos / prex-0.9.0 / usr / server / fs / fatfs / fatfs_node.c @ 03e9c04a

History | View | Annotate | Download (8.72 KB)

1
/*
2
 * Copyright (c) 2005-2008, Kohsuke Ohtani
3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
7
 * are met:
8
 * 1. Redistributions of source code must retain the above copyright
9
 *    notice, this list of conditions and the following disclaimer.
10
 * 2. Redistributions in binary form must reproduce the above copyright
11
 *    notice, this list of conditions and the following disclaimer in the
12
 *    documentation and/or other materials provided with the distribution.
13
 * 3. Neither the name of the author nor the names of any co-contributors
14
 *    may be used to endorse or promote products derived from this software
15
 *    without specific prior written permission.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
 * SUCH DAMAGE.
28
 */
29

    
30
#include <sys/prex.h>
31
#include <sys/buf.h>
32

    
33
#include <ctype.h>
34
#include <string.h>
35
#include <unistd.h>
36
#include <errno.h>
37
#include <stdlib.h>
38

    
39
#include "fatfs.h"
40

    
41
/*
42
 * Read directory entry to buffer, with cache.
43
 */
44
static int
45
fat_read_dirent(struct fatfsmount *fmp, u_long sec)
46
{
47
        struct buf *bp;
48
        int error;
49

    
50
        if ((error = bread(fmp->dev, sec, &bp)) != 0)
51
                return error;
52
        memcpy(fmp->dir_buf, bp->b_data, SEC_SIZE);
53
        brelse(bp);
54
        return 0;
55
}
56

    
57
/*
58
 * Write directory entry from buffer.
59
 */
60
static int
61
fat_write_dirent(struct fatfsmount *fmp, u_long sec)
62
{
63
        struct buf *bp;
64

    
65
        bp = getblk(fmp->dev, sec);
66
        memcpy(bp->b_data, fmp->dir_buf, SEC_SIZE);
67
        return bwrite(bp);
68
}
69

    
70
/*
71
 * Find directory entry in specified sector.
72
 * The fat vnode data is filled if success.
73
 *
74
 * @fmp: fatfs mount point
75
 * @sec: sector#
76
 * @name: file name
77
 * @node: pointer to fat node
78
 */
79
static int
80
fat_lookup_dirent(struct fatfsmount *fmp, u_long sec, char *name,
81
                  struct fatfs_node *np)
82
{
83
        struct fat_dirent *de;
84
        int error, i;
85

    
86
        error = fat_read_dirent(fmp, sec);
87
        if (error)
88
                return error;
89

    
90
        de = (struct fat_dirent *)fmp->dir_buf;
91

    
92
        for (i = 0; i < DIR_PER_SEC; i++) {
93
                /* Find specific file or directory name */
94
                if (IS_EMPTY(de))
95
                        return ENOENT;
96
                if (!IS_VOL(de) &&
97
                    !fat_compare_name((char *)de->name, name)) {
98
                        /* Found. Fill the fat vnode data. */
99
                        *(&np->dirent) = *de;
100
                        np->sector = sec;
101
                        np->offset = sizeof(struct fat_dirent) * i;
102
                        DPRINTF(("fat_lookup_dirent: found sec=%d\n", sec));
103
                        return 0;
104
                }
105
                if (!IS_DELETED(de))
106
                        DPRINTF(("fat_lookup_dirent: %s\n", de->name));
107
                de++;
108
        }
109
        return EAGAIN;
110
}
111

    
112
/*
113
 * Find directory entry for specified name in directory.
114
 * The fat vnode data is filled if success.
115
 *
116
 * @dvp: vnode for directory.
117
 * @name: file name
118
 * @np: pointer to fat node
119
 */
120
int
121
fatfs_lookup_node(vnode_t dvp, char *name, struct fatfs_node *np)
122
{
123
        struct fatfsmount *fmp;
124
        char fat_name[12];
125
        u_long cl, sec;
126
        int i, error;
127

    
128
        if (name == NULL)
129
                return ENOENT;
130

    
131
        DPRINTF(("fat_lookup_denode: cl=%d name=%s\n", dvp->v_blkno, name));
132

    
133
        fat_convert_name(name, fat_name);
134
        *(fat_name + 11) = '\0';
135

    
136
        fmp = (struct fatfsmount *)dvp->v_mount->m_data;
137
        cl = dvp->v_blkno;
138
        if (cl == CL_ROOT) {
139
                /* Search entry in root directory */
140
                for (sec = fmp->root_start; sec < fmp->data_start; sec++) {
141
                        error = fat_lookup_dirent(fmp, sec, fat_name, np);
142
                        if (error != EAGAIN)
143
                                return error;
144
                }
145
        } else {
146
                /* Search entry in sub directory */
147
                while (!IS_EOFCL(fmp, cl)) {
148
                        sec = cl_to_sec(fmp, cl);
149
                        for (i = 0; i < fmp->sec_per_cl; i++) {
150
                                error = fat_lookup_dirent(fmp, sec, fat_name,
151
                                                   np);
152
                                if (error != EAGAIN)
153
                                        return error;
154
                                sec++;
155
                        }
156
                        error = fat_next_cluster(fmp, cl, &cl);
157
                        if (error)
158
                                return error;
159
                }
160
        }
161
        return ENOENT;
162
}
163

    
164
/*
165
 * Get directory entry for specified index in sector.
166
 * The directory entry is filled if success.
167
 *
168
 * @fmp: fatfs mount point
169
 * @sec: sector#
170
 * @target: target index
171
 * @index: current index
172
 * @np: pointer to fat node
173
 */
174
static int
175
fat_get_dirent(struct fatfsmount *fmp, u_long sec, int target, int *index,
176
               struct fatfs_node *np)
177
{
178
        struct fat_dirent *de;
179
        int error, i;
180

    
181
        error = fat_read_dirent(fmp, sec);
182
        if (error)
183
                return error;
184

    
185
        de = (struct fat_dirent *)fmp->dir_buf;
186
        for (i = 0; i < DIR_PER_SEC; i++) {
187
                if (IS_EMPTY(de))
188
                        return ENOENT;
189
                if (!IS_DELETED(de) && !IS_VOL(de)) {
190
                        /* valid file */
191
                        if (*index == target) {
192
                                *(&np->dirent) = *de;
193
                                np->sector = sec;
194
                                np->offset = sizeof(struct fat_dirent) * i;
195
                                DPRINTF(("fat_get_dirent: found index=%d\n", *index));
196
                                return 0;
197
                        }
198
                        (*index)++;
199
                }
200
                DPRINTF(("fat_get_dirent: %s\n", de->name));
201
                de++;
202
        }
203
        return EAGAIN;
204
}
205

    
206
/*
207
 * Get directory entry for specified index.
208
 *
209
 * @dvp: vnode for directory.
210
 * @index: index of the entry
211
 * @np: pointer to fat node
212
 */
213
int
214
fatfs_get_node(vnode_t dvp, int index, struct fatfs_node *np)
215
{
216
        struct fatfsmount *fmp;
217
        u_long cl, sec;
218
        int i, cur_index, error;
219

    
220
        fmp = (struct fatfsmount *)dvp->v_mount->m_data;
221
        cl = dvp->v_blkno;
222
        cur_index = 0;
223

    
224
        DPRINTF(("fatfs_get_node: index=%d\n", index));
225

    
226
        if (cl == CL_ROOT) {
227
                /* Get entry from the root directory */
228
                for (sec = fmp->root_start; sec < fmp->data_start; sec++) {
229
                        error = fat_get_dirent(fmp, sec, index, &cur_index, np);
230
                        if (error != EAGAIN)
231
                                return error;
232
                }
233
        } else {
234
                /* Get entry from the sub directory */
235
                while (!IS_EOFCL(fmp, cl)) {
236
                        sec = cl_to_sec(fmp, cl);
237
                        for (i = 0; i < fmp->sec_per_cl; i++) {
238
                                error = fat_get_dirent(fmp, sec, index,
239
                                                     &cur_index, np);
240
                                if (error != EAGAIN)
241
                                        return error;
242
                                sec++;
243
                        }
244
                        error = fat_next_cluster(fmp, cl, &cl);
245
                        if (error)
246
                                return error;
247
                }
248
        }
249
        return ENOENT;
250
}
251

    
252
/*
253
 * Find empty directory entry and put new entry on it.
254
 *
255
 * @fmp: fatfs mount point
256
 * @sec: sector#
257
 * @np: pointer to fat node
258
 */
259
static int
260
fat_add_dirent(struct fatfsmount *fmp, u_long sec, struct fatfs_node *np)
261
{
262
        struct fat_dirent *de;
263
        int error, i;
264

    
265
        error = fat_read_dirent(fmp, sec);
266
        if (error)
267
                return error;
268

    
269
        de = (struct fat_dirent *)fmp->dir_buf;
270
        for (i = 0; i < DIR_PER_SEC; i++) {
271
                if (IS_DELETED(de) || IS_EMPTY(de))
272
                        goto found;
273
                DPRINTF(("fat_add_dirent: scan %s\n", de->name));
274
                de++;
275
        }
276
        return ENOENT;
277

    
278
 found:
279
        DPRINTF(("fat_add_dirent: found. sec=%d\n", sec));
280
        memcpy(de, &np->dirent, sizeof(struct fat_dirent));
281
        error = fat_write_dirent(fmp, sec);
282
        return error;
283
}
284

    
285
/*
286
 * Find empty directory entry and put new entry on it.
287
 * This search is done only in directory of specified cluster.
288
 * @dvp: vnode for directory.
289
 * @np: pointer to fat node
290
 */
291
int
292
fatfs_add_node(vnode_t dvp, struct fatfs_node *np)
293
{
294
        struct fatfsmount *fmp;
295
        u_long cl, sec;
296
        int i, error;
297
        u_long next;
298

    
299
        fmp = (struct fatfsmount *)dvp->v_mount->m_data;
300
        cl = dvp->v_blkno;
301

    
302
        DPRINTF(("fatfs_add_node: cl=%d\n", cl));
303

    
304
        if (cl == CL_ROOT) {
305
                /* Add entry in root directory */
306
                for (sec = fmp->root_start; sec < fmp->data_start; sec++) {
307
                        error = fat_add_dirent(fmp, sec, np);
308
                        if (error != ENOENT)
309
                                return error;
310
                }
311
        } else {
312
                /* Search entry in sub directory */
313
                while (!IS_EOFCL(fmp, cl)) {
314
                        sec = cl_to_sec(fmp, cl);
315
                        for (i = 0; i < fmp->sec_per_cl; i++) {
316
                                error = fat_add_dirent(fmp, sec, np);
317
                                if (error != ENOENT)
318
                                        return error;
319
                                sec++;
320
                        }
321
                        error = fat_next_cluster(fmp, cl, &next);
322
                        if (error)
323
                                return error;
324
                        cl = next;
325
                }
326
                /* No entry found, add one more free cluster for directory */
327
                DPRINTF(("fatfs_add_node: expand dir\n"));
328
                error = fat_expand_dir(fmp, cl, &next);
329
                if (error)
330
                        return error;
331

    
332
                /* Initialize free cluster. */
333
                memset(fmp->dir_buf, 0, SEC_SIZE);
334
                sec = cl_to_sec(fmp, next);
335
                for (i = 0; i < fmp->sec_per_cl; i++) {
336
                        error = fat_write_dirent(fmp, sec);
337
                        if (error)
338
                                return error;
339
                        sec++;
340
                }
341
                /* Try again */
342
                sec = cl_to_sec(fmp, next);
343
                error = fat_add_dirent(fmp, sec, np);
344
                return error;
345
        }
346
        return ENOENT;
347
}
348

    
349
/*
350
 * Put directory entry.
351
 * @fmp: fat mount data
352
 * @np: pointer to fat node
353
 */
354
int
355
fatfs_put_node(struct fatfsmount *fmp, struct fatfs_node *np)
356
{
357
        int error;
358

    
359
        error = fat_read_dirent(fmp, np->sector);
360
        if (error)
361
                return error;
362

    
363
        memcpy(fmp->dir_buf + np->offset, &np->dirent,
364
               sizeof(struct fat_dirent));
365

    
366
        error = fat_write_dirent(fmp, np->sector);
367
        return error;
368
}
369