Rev 2852 | Rev 2856 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 2852 | Rev 2855 | ||
---|---|---|---|
1 | /* |
1 | /* |
2 | * Copyright (c) 2008 Jakub Jermar |
2 | * Copyright (c) 2008 Jakub Jermar |
3 | * All rights reserved. |
3 | * All rights reserved. |
4 | * |
4 | * |
5 | * Redistribution and use in source and binary forms, with or without |
5 | * Redistribution and use in source and binary forms, with or without |
6 | * modification, are permitted provided that the following conditions |
6 | * modification, are permitted provided that the following conditions |
7 | * are met: |
7 | * are met: |
8 | * |
8 | * |
9 | * - Redistributions of source code must retain the above copyright |
9 | * - Redistributions of source code must retain the above copyright |
10 | * notice, this list of conditions and the following disclaimer. |
10 | * notice, this list of conditions and the following disclaimer. |
11 | * - Redistributions in binary form must reproduce the above copyright |
11 | * - Redistributions in binary form must reproduce the above copyright |
12 | * notice, this list of conditions and the following disclaimer in the |
12 | * notice, this list of conditions and the following disclaimer in the |
13 | * documentation and/or other materials provided with the distribution. |
13 | * documentation and/or other materials provided with the distribution. |
14 | * - The name of the author may not be used to endorse or promote products |
14 | * - The name of the author may not be used to endorse or promote products |
15 | * derived from this software without specific prior written permission. |
15 | * derived from this software without specific prior written permission. |
16 | * |
16 | * |
17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
18 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
18 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
19 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
19 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
20 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
20 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
21 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
21 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
22 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
22 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
23 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
23 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
24 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
24 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
26 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | */ |
27 | */ |
28 | 28 | ||
29 | /** @addtogroup fs |
29 | /** @addtogroup fs |
30 | * @{ |
30 | * @{ |
31 | */ |
31 | */ |
32 | 32 | ||
33 | /** |
33 | /** |
34 | * @file fat_ops.c |
34 | * @file fat_ops.c |
35 | * @brief Implementation of VFS operations for the FAT file system server. |
35 | * @brief Implementation of VFS operations for the FAT file system server. |
36 | */ |
36 | */ |
37 | 37 | ||
38 | #include "fat.h" |
38 | #include "fat.h" |
39 | #include "../../vfs/vfs.h" |
39 | #include "../../vfs/vfs.h" |
40 | #include <libfs.h> |
40 | #include <libfs.h> |
41 | #include <ipc/ipc.h> |
41 | #include <ipc/ipc.h> |
42 | #include <async.h> |
42 | #include <async.h> |
43 | #include <errno.h> |
43 | #include <errno.h> |
44 | #include <string.h> |
44 | #include <string.h> |
45 | #include <byteorder.h> |
45 | #include <byteorder.h> |
46 | #include <libadt/hash_table.h> |
46 | #include <libadt/hash_table.h> |
47 | #include <libadt/list.h> |
47 | #include <libadt/list.h> |
48 | #include <assert.h> |
48 | #include <assert.h> |
49 | 49 | ||
50 | #define BS_BLOCK 0 |
50 | #define BS_BLOCK 0 |
51 | 51 | ||
52 | #define FIN_KEY_DEV_HANDLE 0 |
52 | #define FIN_KEY_DEV_HANDLE 0 |
53 | #define FIN_KEY_INDEX 1 |
53 | #define FIN_KEY_INDEX 1 |
54 | 54 | ||
55 | /** Hash table of FAT in-core nodes. */ |
55 | /** Hash table of FAT in-core nodes. */ |
56 | hash_table_t fin_hash; |
56 | hash_table_t fin_hash; |
57 | 57 | ||
58 | /** List of free FAT in-core nodes. */ |
58 | /** List of free FAT in-core nodes. */ |
59 | link_t ffn_head; |
59 | link_t ffn_head; |
60 | 60 | ||
61 | #define FAT_NAME_LEN 8 |
61 | #define FAT_NAME_LEN 8 |
62 | #define FAT_EXT_LEN 3 |
62 | #define FAT_EXT_LEN 3 |
63 | 63 | ||
64 | #define FAT_PAD ' ' |
64 | #define FAT_PAD ' ' |
65 | 65 | ||
66 | #define FAT_DENTRY_UNUSED 0x00 |
66 | #define FAT_DENTRY_UNUSED 0x00 |
67 | #define FAT_DENTRY_E5_ESC 0x05 |
67 | #define FAT_DENTRY_E5_ESC 0x05 |
68 | #define FAT_DENTRY_DOT 0x2e |
68 | #define FAT_DENTRY_DOT 0x2e |
69 | #define FAT_DENTRY_ERASED 0xe5 |
69 | #define FAT_DENTRY_ERASED 0xe5 |
70 | 70 | ||
71 | static void dentry_name_canonify(fat_dentry_t *d, char *buf) |
71 | static void dentry_name_canonify(fat_dentry_t *d, char *buf) |
72 | { |
72 | { |
73 | int i; |
73 | int i; |
74 | 74 | ||
75 | for (i = 0; i < FAT_NAME_LEN; i++) { |
75 | for (i = 0; i < FAT_NAME_LEN; i++) { |
76 | if (d->name[i] == FAT_PAD) { |
76 | if (d->name[i] == FAT_PAD) { |
77 | buf++; |
77 | buf++; |
78 | break; |
78 | break; |
79 | } |
79 | } |
80 | if (d->name[i] == FAT_DENTRY_E5_ESC) |
80 | if (d->name[i] == FAT_DENTRY_E5_ESC) |
81 | *buf++ = 0xe5; |
81 | *buf++ = 0xe5; |
82 | else |
82 | else |
83 | *buf++ = d->name[i]; |
83 | *buf++ = d->name[i]; |
84 | } |
84 | } |
85 | if (d->ext[0] != FAT_PAD) |
85 | if (d->ext[0] != FAT_PAD) |
86 | *buf++ = '.'; |
86 | *buf++ = '.'; |
87 | for (i = 0; i < FAT_EXT_LEN; i++) { |
87 | for (i = 0; i < FAT_EXT_LEN; i++) { |
88 | if (d->ext[i] == FAT_PAD) { |
88 | if (d->ext[i] == FAT_PAD) { |
89 | *buf = '\0'; |
89 | *buf = '\0'; |
90 | return; |
90 | return; |
91 | } |
91 | } |
92 | if (d->ext[i] == FAT_DENTRY_E5_ESC) |
92 | if (d->ext[i] == FAT_DENTRY_E5_ESC) |
93 | *buf++ = 0xe5; |
93 | *buf++ = 0xe5; |
94 | else |
94 | else |
95 | *buf++ = d->ext[i]; |
95 | *buf++ = d->ext[i]; |
96 | } |
96 | } |
97 | } |
97 | } |
98 | 98 | ||
99 | /* TODO and also move somewhere else */ |
99 | /* TODO and also move somewhere else */ |
100 | typedef struct { |
100 | typedef struct { |
101 | void *data; |
101 | void *data; |
102 | } block_t; |
102 | } block_t; |
103 | 103 | ||
104 | static block_t *block_get(dev_handle_t dev_handle, off_t offset) |
104 | static block_t *block_get(dev_handle_t dev_handle, off_t offset) |
105 | { |
105 | { |
106 | return NULL; /* TODO */ |
106 | return NULL; /* TODO */ |
107 | } |
107 | } |
108 | 108 | ||
109 | static block_t *fat_block_get(dev_handle_t dev_handle, fs_index_t index, |
109 | static block_t *fat_block_get(dev_handle_t dev_handle, fs_index_t index, |
110 | off_t offset) { |
110 | off_t offset) { |
111 | return NULL; /* TODO */ |
111 | return NULL; /* TODO */ |
112 | } |
112 | } |
113 | 113 | ||
114 | static void block_put(block_t *block) |
114 | static void block_put(block_t *block) |
115 | { |
115 | { |
116 | /* TODO */ |
116 | /* TODO */ |
117 | } |
117 | } |
118 | 118 | ||
119 | static void fat_node_initialize(fat_node_t *node) |
119 | static void fat_node_initialize(fat_node_t *node) |
120 | { |
120 | { |
121 | node->type = 0; |
121 | node->type = 0; |
122 | node->index = 0; |
122 | node->index = 0; |
123 | node->pindex = 0; |
123 | node->pindex = 0; |
124 | node->dev_handle = 0; |
124 | node->dev_handle = 0; |
125 | link_initialize(&node->fin_link); |
125 | link_initialize(&node->fin_link); |
126 | link_initialize(&node->ffn_link); |
126 | link_initialize(&node->ffn_link); |
127 | node->size = 0; |
127 | node->size = 0; |
128 | node->lnkcnt = 0; |
128 | node->lnkcnt = 0; |
129 | node->refcnt = 0; |
129 | node->refcnt = 0; |
130 | node->dirty = false; |
130 | node->dirty = false; |
131 | } |
131 | } |
132 | 132 | ||
133 | static uint16_t fat_bps_get(dev_handle_t dev_handle) |
133 | static uint16_t fat_bps_get(dev_handle_t dev_handle) |
134 | { |
134 | { |
135 | block_t *bb; |
135 | block_t *bb; |
136 | uint16_t bps; |
136 | uint16_t bps; |
137 | 137 | ||
138 | bb = block_get(dev_handle, BS_BLOCK); |
138 | bb = block_get(dev_handle, BS_BLOCK); |
139 | assert(bb != NULL); |
139 | assert(bb != NULL); |
140 | bps = uint16_t_le2host(((fat_bs_t *)bb->data)->bps); |
140 | bps = uint16_t_le2host(((fat_bs_t *)bb->data)->bps); |
141 | block_put(bb); |
141 | block_put(bb); |
142 | 142 | ||
143 | return bps; |
143 | return bps; |
144 | } |
144 | } |
145 | 145 | ||
146 | typedef enum { |
146 | typedef enum { |
147 | FAT_DENTRY_SKIP, |
147 | FAT_DENTRY_SKIP, |
148 | FAT_DENTRY_LAST, |
148 | FAT_DENTRY_LAST, |
149 | FAT_DENTRY_VALID |
149 | FAT_DENTRY_VALID |
150 | } fat_dentry_clsf_t; |
150 | } fat_dentry_clsf_t; |
151 | 151 | ||
152 | static fat_dentry_clsf_t fat_classify_dentry(fat_dentry_t *d) |
152 | static fat_dentry_clsf_t fat_classify_dentry(fat_dentry_t *d) |
153 | { |
153 | { |
154 | if (d->attr & FAT_ATTR_VOLLABEL) { |
154 | if (d->attr & FAT_ATTR_VOLLABEL) { |
155 | /* volume label entry */ |
155 | /* volume label entry */ |
156 | return FAT_DENTRY_SKIP; |
156 | return FAT_DENTRY_SKIP; |
157 | } |
157 | } |
158 | if (d->name[0] == FAT_DENTRY_ERASED) { |
158 | if (d->name[0] == FAT_DENTRY_ERASED) { |
159 | /* not-currently-used entry */ |
159 | /* not-currently-used entry */ |
160 | return FAT_DENTRY_SKIP; |
160 | return FAT_DENTRY_SKIP; |
161 | } |
161 | } |
162 | if (d->name[0] == FAT_DENTRY_UNUSED) { |
162 | if (d->name[0] == FAT_DENTRY_UNUSED) { |
163 | /* never used entry */ |
163 | /* never used entry */ |
164 | return FAT_DENTRY_LAST; |
164 | return FAT_DENTRY_LAST; |
165 | } |
165 | } |
166 | if (d->name[0] == FAT_DENTRY_DOT) { |
166 | if (d->name[0] == FAT_DENTRY_DOT) { |
167 | /* |
167 | /* |
168 | * Most likely '.' or '..'. |
168 | * Most likely '.' or '..'. |
169 | * It cannot occur in a regular file name. |
169 | * It cannot occur in a regular file name. |
170 | */ |
170 | */ |
171 | return FAT_DENTRY_SKIP; |
171 | return FAT_DENTRY_SKIP; |
172 | } |
172 | } |
173 | return FAT_DENTRY_VALID; |
173 | return FAT_DENTRY_VALID; |
174 | } |
174 | } |
175 | 175 | ||
176 | static void fat_sync_node(fat_node_t *node) |
176 | static void fat_sync_node(fat_node_t *node) |
177 | { |
177 | { |
178 | /* TODO */ |
178 | /* TODO */ |
179 | } |
179 | } |
180 | 180 | ||
181 | /** Instantiate a FAT in-core node. |
181 | /** Instantiate a FAT in-core node. |
182 | * |
182 | * |
183 | * FAT stores the info necessary for instantiation of a node in the parent of |
183 | * FAT stores the info necessary for instantiation of a node in the parent of |
184 | * that node. This design necessitated the addition of the parent node index |
184 | * that node. This design necessitated the addition of the parent node index |
185 | * parameter to this otherwise generic libfs API. |
185 | * parameter to this otherwise generic libfs API. |
186 | */ |
186 | */ |
187 | static void * |
187 | static void * |
188 | fat_node_get(dev_handle_t dev_handle, fs_index_t index, fs_index_t pindex) |
188 | fat_node_get(dev_handle_t dev_handle, fs_index_t index, fs_index_t pindex) |
189 | { |
189 | { |
190 | link_t *lnk; |
190 | link_t *lnk; |
191 | fat_node_t *node = NULL; |
191 | fat_node_t *node = NULL; |
192 | block_t *b; |
192 | block_t *b; |
193 | unsigned bps; |
193 | unsigned bps; |
194 | unsigned dps; |
194 | unsigned dps; |
195 | fat_dentry_t *d; |
195 | fat_dentry_t *d; |
196 | unsigned i, j; |
196 | unsigned i, j; |
197 | 197 | ||
198 | unsigned long key[] = { |
198 | unsigned long key[] = { |
199 | [FIN_KEY_DEV_HANDLE] = dev_handle, |
199 | [FIN_KEY_DEV_HANDLE] = dev_handle, |
200 | [FIN_KEY_INDEX] = index |
200 | [FIN_KEY_INDEX] = index |
201 | }; |
201 | }; |
202 | 202 | ||
203 | lnk = hash_table_find(&fin_hash, key); |
203 | lnk = hash_table_find(&fin_hash, key); |
204 | if (lnk) { |
204 | if (lnk) { |
205 | /* |
205 | /* |
206 | * The in-core node was found in the hash table. |
206 | * The in-core node was found in the hash table. |
207 | */ |
207 | */ |
208 | node = hash_table_get_instance(lnk, fat_node_t, fin_link); |
208 | node = hash_table_get_instance(lnk, fat_node_t, fin_link); |
209 | if (!node->refcnt++) |
209 | if (!node->refcnt++) |
210 | list_remove(&node->ffn_link); |
210 | list_remove(&node->ffn_link); |
211 | return (void *) node; |
211 | return (void *) node; |
212 | } |
212 | } |
213 | 213 | ||
214 | bps = fat_bps_get(dev_handle); |
214 | bps = fat_bps_get(dev_handle); |
215 | dps = bps / sizeof(fat_dentry_t); |
215 | dps = bps / sizeof(fat_dentry_t); |
216 | 216 | ||
217 | if (!list_empty(&ffn_head)) { |
217 | if (!list_empty(&ffn_head)) { |
218 | /* |
218 | /* |
219 | * We are going to reuse a node from the free list. |
219 | * We are going to reuse a node from the free list. |
220 | */ |
220 | */ |
221 | lnk = ffn_head.next; |
221 | lnk = ffn_head.next; |
222 | list_remove(lnk); |
222 | list_remove(lnk); |
223 | node = list_get_instance(lnk, fat_node_t, ffn_link); |
223 | node = list_get_instance(lnk, fat_node_t, ffn_link); |
224 | assert(!node->refcnt); |
224 | assert(!node->refcnt); |
225 | if (node->dirty) |
225 | if (node->dirty) |
226 | fat_sync_node(node); |
226 | fat_sync_node(node); |
227 | key[FIN_KEY_DEV_HANDLE] = node->dev_handle; |
227 | key[FIN_KEY_DEV_HANDLE] = node->dev_handle; |
228 | key[FIN_KEY_INDEX] = node->index; |
228 | key[FIN_KEY_INDEX] = node->index; |
229 | hash_table_remove(&fin_hash, key, sizeof(key)/sizeof(*key)); |
229 | hash_table_remove(&fin_hash, key, sizeof(key)/sizeof(*key)); |
230 | } else { |
230 | } else { |
231 | /* |
231 | /* |
232 | * We need to allocate a new node. |
232 | * We need to allocate a new node. |
233 | */ |
233 | */ |
234 | node = malloc(sizeof(fat_node_t)); |
234 | node = malloc(sizeof(fat_node_t)); |
235 | if (!node) |
235 | if (!node) |
236 | return NULL; |
236 | return NULL; |
237 | } |
237 | } |
238 | fat_node_initialize(node); |
238 | fat_node_initialize(node); |
239 | node->refcnt++; |
239 | node->refcnt++; |
240 | node->lnkcnt++; |
240 | node->lnkcnt++; |
241 | node->dev_handle = dev_handle; |
241 | node->dev_handle = dev_handle; |
242 | node->index = index; |
242 | node->index = index; |
243 | node->pindex = pindex; |
243 | node->pindex = pindex; |
244 | 244 | ||
245 | /* |
245 | /* |
246 | * Because of the design of the FAT file system, we have no clue about |
246 | * Because of the design of the FAT file system, we have no clue about |
247 | * how big (i.e. how many directory entries it contains) is the parent |
247 | * how big (i.e. how many directory entries it contains) is the parent |
248 | * of the node we are trying to instantiate. However, we know that it |
248 | * of the node we are trying to instantiate. However, we know that it |
249 | * must contain a directory entry for our node of interest. We simply |
249 | * must contain a directory entry for our node of interest. We simply |
250 | * scan the parent until we find it. |
250 | * scan the parent until we find it. |
251 | */ |
251 | */ |
252 | for (i = 0; ; i++) { |
252 | for (i = 0; ; i++) { |
253 | b = fat_block_get(node->dev_handle, node->pindex, i); |
253 | b = fat_block_get(node->dev_handle, node->pindex, i); |
254 | for (j = 0; j < dps; j++) { |
254 | for (j = 0; j < dps; j++) { |
255 | d = ((fat_dentry_t *)b->data) + j; |
255 | d = ((fat_dentry_t *)b->data) + j; |
256 | if (d->firstc == node->index) |
256 | if (d->firstc == node->index) |
257 | goto found; |
257 | goto found; |
258 | } |
258 | } |
259 | block_put(b); |
259 | block_put(b); |
260 | } |
260 | } |
261 | 261 | ||
262 | found: |
262 | found: |
263 | if (!(d->attr & (FAT_ATTR_SUBDIR | FAT_ATTR_VOLLABEL))) |
263 | if (!(d->attr & (FAT_ATTR_SUBDIR | FAT_ATTR_VOLLABEL))) |
264 | node->type = FAT_FILE; |
264 | node->type = FAT_FILE; |
265 | if ((d->attr & FAT_ATTR_SUBDIR) || !index) |
265 | if ((d->attr & FAT_ATTR_SUBDIR) || !index) |
266 | node->type = FAT_DIRECTORY; |
266 | node->type = FAT_DIRECTORY; |
267 | assert((node->type == FAT_FILE) || (node->type == FAT_DIRECTORY)); |
267 | assert((node->type == FAT_FILE) || (node->type == FAT_DIRECTORY)); |
268 | 268 | ||
269 | node->size = uint32_t_le2host(d->size); |
269 | node->size = uint32_t_le2host(d->size); |
270 | block_put(b); |
270 | block_put(b); |
271 | 271 | ||
272 | key[FIN_KEY_DEV_HANDLE] = node->dev_handle; |
272 | key[FIN_KEY_DEV_HANDLE] = node->dev_handle; |
273 | key[FIN_KEY_INDEX] = node->index; |
273 | key[FIN_KEY_INDEX] = node->index; |
274 | hash_table_insert(&fin_hash, key, &node->fin_link); |
274 | hash_table_insert(&fin_hash, key, &node->fin_link); |
275 | 275 | ||
276 | return node; |
276 | return node; |
277 | } |
277 | } |
278 | 278 | ||
279 | static void fat_node_put(void *node) |
279 | static void fat_node_put(void *node) |
280 | { |
280 | { |
- | 281 | fat_node_t *nodep = (fat_node_t *)node; |
|
- | 282 | ||
281 | /* TODO */ |
283 | if (nodep->refcnt-- == 1) |
- | 284 | list_append(&nodep->ffn_link, &ffn_head); |
|
282 | } |
285 | } |
283 | 286 | ||
284 | static void *fat_match(void *prnt, const char *component) |
287 | static void *fat_match(void *prnt, const char *component) |
285 | { |
288 | { |
286 | fat_node_t *parentp = (fat_node_t *)prnt; |
289 | fat_node_t *parentp = (fat_node_t *)prnt; |
287 | char name[FAT_NAME_LEN + 1 + FAT_EXT_LEN + 1]; |
290 | char name[FAT_NAME_LEN + 1 + FAT_EXT_LEN + 1]; |
288 | unsigned i, j; |
291 | unsigned i, j; |
289 | unsigned bps; /* bytes per sector */ |
292 | unsigned bps; /* bytes per sector */ |
290 | unsigned dps; /* dentries per sector */ |
293 | unsigned dps; /* dentries per sector */ |
291 | unsigned blocks; |
294 | unsigned blocks; |
292 | fat_dentry_t *d; |
295 | fat_dentry_t *d; |
293 | block_t *b; |
296 | block_t *b; |
294 | 297 | ||
295 | bps = fat_bps_get(parentp->dev_handle); |
298 | bps = fat_bps_get(parentp->dev_handle); |
296 | dps = bps / sizeof(fat_dentry_t); |
299 | dps = bps / sizeof(fat_dentry_t); |
297 | blocks = parentp->size / bps + (parentp->size % bps != 0); |
300 | blocks = parentp->size / bps + (parentp->size % bps != 0); |
298 | for (i = 0; i < blocks; i++) { |
301 | for (i = 0; i < blocks; i++) { |
299 | unsigned dentries; |
302 | unsigned dentries; |
300 | 303 | ||
301 | b = fat_block_get(parentp->dev_handle, parentp->index, i); |
304 | b = fat_block_get(parentp->dev_handle, parentp->index, i); |
302 | dentries = (i == blocks - 1) ? |
305 | dentries = (i == blocks - 1) ? |
303 | parentp->size % sizeof(fat_dentry_t) : |
306 | parentp->size % sizeof(fat_dentry_t) : |
304 | dps; |
307 | dps; |
305 | for (j = 0; j < dentries; j++) { |
308 | for (j = 0; j < dentries; j++) { |
306 | d = ((fat_dentry_t *)b->data) + j; |
309 | d = ((fat_dentry_t *)b->data) + j; |
307 | switch (fat_classify_dentry(d)) { |
310 | switch (fat_classify_dentry(d)) { |
308 | case FAT_DENTRY_SKIP: |
311 | case FAT_DENTRY_SKIP: |
309 | continue; |
312 | continue; |
310 | case FAT_DENTRY_LAST: |
313 | case FAT_DENTRY_LAST: |
311 | block_put(b); |
314 | block_put(b); |
312 | return NULL; |
315 | return NULL; |
313 | default: |
316 | default: |
314 | case FAT_DENTRY_VALID: |
317 | case FAT_DENTRY_VALID: |
315 | dentry_name_canonify(d, name); |
318 | dentry_name_canonify(d, name); |
316 | break; |
319 | break; |
317 | } |
320 | } |
318 | if (strcmp(name, component) == 0) { |
321 | if (strcmp(name, component) == 0) { |
319 | /* hit */ |
322 | /* hit */ |
320 | void *node = fat_node_get(parentp->dev_handle, |
323 | void *node = fat_node_get(parentp->dev_handle, |
321 | (fs_index_t)uint16_t_le2host(d->firstc), |
324 | (fs_index_t)uint16_t_le2host(d->firstc), |
322 | parentp->index); |
325 | parentp->index); |
323 | block_put(b); |
326 | block_put(b); |
324 | return node; |
327 | return node; |
325 | } |
328 | } |
326 | } |
329 | } |
327 | block_put(b); |
330 | block_put(b); |
328 | } |
331 | } |
329 | 332 | ||
330 | return NULL; |
333 | return NULL; |
331 | } |
334 | } |
332 | 335 | ||
333 | static fs_index_t fat_index_get(void *node) |
336 | static fs_index_t fat_index_get(void *node) |
334 | { |
337 | { |
335 | fat_node_t *fnodep = (fat_node_t *)node; |
338 | fat_node_t *fnodep = (fat_node_t *)node; |
336 | if (!fnodep) |
339 | if (!fnodep) |
337 | return 0; |
340 | return 0; |
338 | return fnodep->index; |
341 | return fnodep->index; |
339 | } |
342 | } |
340 | 343 | ||
341 | static size_t fat_size_get(void *node) |
344 | static size_t fat_size_get(void *node) |
342 | { |
345 | { |
343 | return ((fat_node_t *)node)->size; |
346 | return ((fat_node_t *)node)->size; |
344 | } |
347 | } |
345 | 348 | ||
346 | static unsigned fat_lnkcnt_get(void *node) |
349 | static unsigned fat_lnkcnt_get(void *node) |
347 | { |
350 | { |
348 | return ((fat_node_t *)node)->lnkcnt; |
351 | return ((fat_node_t *)node)->lnkcnt; |
349 | } |
352 | } |
350 | 353 | ||
351 | static bool fat_has_children(void *node) |
354 | static bool fat_has_children(void *node) |
352 | { |
355 | { |
353 | fat_node_t *nodep = (fat_node_t *)node; |
356 | fat_node_t *nodep = (fat_node_t *)node; |
354 | unsigned bps; |
357 | unsigned bps; |
355 | unsigned dps; |
358 | unsigned dps; |
356 | unsigned blocks; |
359 | unsigned blocks; |
357 | block_t *b; |
360 | block_t *b; |
358 | unsigned i, j; |
361 | unsigned i, j; |
359 | 362 | ||
360 | if (nodep->type != FAT_DIRECTORY) |
363 | if (nodep->type != FAT_DIRECTORY) |
361 | return false; |
364 | return false; |
362 | 365 | ||
363 | bps = fat_bps_get(nodep->dev_handle); |
366 | bps = fat_bps_get(nodep->dev_handle); |
364 | dps = bps / sizeof(fat_dentry_t); |
367 | dps = bps / sizeof(fat_dentry_t); |
365 | 368 | ||
366 | blocks = nodep->size / bps + (nodep->size % bps != 0); |
369 | blocks = nodep->size / bps + (nodep->size % bps != 0); |
367 | 370 | ||
368 | for (i = 0; i < blocks; i++) { |
371 | for (i = 0; i < blocks; i++) { |
369 | unsigned dentries; |
372 | unsigned dentries; |
370 | fat_dentry_t *d; |
373 | fat_dentry_t *d; |
371 | 374 | ||
372 | b = fat_block_get(nodep->dev_handle, nodep->index, i); |
375 | b = fat_block_get(nodep->dev_handle, nodep->index, i); |
373 | dentries = (i == blocks - 1) ? |
376 | dentries = (i == blocks - 1) ? |
374 | nodep->size % sizeof(fat_dentry_t) : |
377 | nodep->size % sizeof(fat_dentry_t) : |
375 | dps; |
378 | dps; |
376 | for (j = 0; j < dentries; j++) { |
379 | for (j = 0; j < dentries; j++) { |
377 | d = ((fat_dentry_t *)b->data) + j; |
380 | d = ((fat_dentry_t *)b->data) + j; |
378 | switch (fat_classify_dentry(d)) { |
381 | switch (fat_classify_dentry(d)) { |
379 | case FAT_DENTRY_SKIP: |
382 | case FAT_DENTRY_SKIP: |
380 | continue; |
383 | continue; |
381 | case FAT_DENTRY_LAST: |
384 | case FAT_DENTRY_LAST: |
382 | block_put(b); |
385 | block_put(b); |
383 | return false; |
386 | return false; |
384 | default: |
387 | default: |
385 | case FAT_DENTRY_VALID: |
388 | case FAT_DENTRY_VALID: |
386 | block_put(b); |
389 | block_put(b); |
387 | return true; |
390 | return true; |
388 | } |
391 | } |
389 | block_put(b); |
392 | block_put(b); |
390 | return true; |
393 | return true; |
391 | } |
394 | } |
392 | block_put(b); |
395 | block_put(b); |
393 | } |
396 | } |
394 | 397 | ||
395 | return false; |
398 | return false; |
396 | } |
399 | } |
397 | 400 | ||
398 | static void *fat_root_get(dev_handle_t dev_handle) |
401 | static void *fat_root_get(dev_handle_t dev_handle) |
399 | { |
402 | { |
400 | return fat_node_get(dev_handle, 0, 0); |
403 | return fat_node_get(dev_handle, 0, 0); |
401 | } |
404 | } |
402 | 405 | ||
403 | static char fat_plb_get_char(unsigned pos) |
406 | static char fat_plb_get_char(unsigned pos) |
404 | { |
407 | { |
405 | return fat_reg.plb_ro[pos % PLB_SIZE]; |
408 | return fat_reg.plb_ro[pos % PLB_SIZE]; |
406 | } |
409 | } |
407 | 410 | ||
408 | static bool fat_is_directory(void *node) |
411 | static bool fat_is_directory(void *node) |
409 | { |
412 | { |
410 | return ((fat_node_t *)node)->type == FAT_DIRECTORY; |
413 | return ((fat_node_t *)node)->type == FAT_DIRECTORY; |
411 | } |
414 | } |
412 | 415 | ||
413 | static bool fat_is_file(void *node) |
416 | static bool fat_is_file(void *node) |
414 | { |
417 | { |
415 | return ((fat_node_t *)node)->type == FAT_FILE; |
418 | return ((fat_node_t *)node)->type == FAT_FILE; |
416 | } |
419 | } |
417 | 420 | ||
418 | /** libfs operations */ |
421 | /** libfs operations */ |
419 | libfs_ops_t fat_libfs_ops = { |
422 | libfs_ops_t fat_libfs_ops = { |
420 | .match = fat_match, |
423 | .match = fat_match, |
421 | .node_get = fat_node_get, |
424 | .node_get = fat_node_get, |
422 | .node_put = fat_node_put, |
425 | .node_put = fat_node_put, |
423 | .create = NULL, |
426 | .create = NULL, |
424 | .destroy = NULL, |
427 | .destroy = NULL, |
425 | .link = NULL, |
428 | .link = NULL, |
426 | .unlink = NULL, |
429 | .unlink = NULL, |
427 | .index_get = fat_index_get, |
430 | .index_get = fat_index_get, |
428 | .size_get = fat_size_get, |
431 | .size_get = fat_size_get, |
429 | .lnkcnt_get = fat_lnkcnt_get, |
432 | .lnkcnt_get = fat_lnkcnt_get, |
430 | .has_children = fat_has_children, |
433 | .has_children = fat_has_children, |
431 | .root_get = fat_root_get, |
434 | .root_get = fat_root_get, |
432 | .plb_get_char = fat_plb_get_char, |
435 | .plb_get_char = fat_plb_get_char, |
433 | .is_directory = fat_is_directory, |
436 | .is_directory = fat_is_directory, |
434 | .is_file = fat_is_file |
437 | .is_file = fat_is_file |
435 | }; |
438 | }; |
436 | 439 | ||
437 | void fat_lookup(ipc_callid_t rid, ipc_call_t *request) |
440 | void fat_lookup(ipc_callid_t rid, ipc_call_t *request) |
438 | { |
441 | { |
439 | libfs_lookup(&fat_libfs_ops, fat_reg.fs_handle, rid, request); |
442 | libfs_lookup(&fat_libfs_ops, fat_reg.fs_handle, rid, request); |
440 | } |
443 | } |
441 | 444 | ||
442 | /** |
445 | /** |
443 | * @} |
446 | * @} |
444 | */ |
447 | */ |
445 | 448 |