Rev 3516 | Rev 3521 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 3516 | Rev 3519 | ||
---|---|---|---|
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 "fat_dentry.h" |
39 | #include "fat_dentry.h" |
40 | #include "fat_fat.h" |
40 | #include "fat_fat.h" |
41 | #include "../../vfs/vfs.h" |
41 | #include "../../vfs/vfs.h" |
42 | #include <libfs.h> |
42 | #include <libfs.h> |
43 | #include <ipc/ipc.h> |
43 | #include <ipc/ipc.h> |
44 | #include <ipc/services.h> |
44 | #include <ipc/services.h> |
45 | #include <ipc/devmap.h> |
45 | #include <ipc/devmap.h> |
46 | #include <async.h> |
46 | #include <async.h> |
47 | #include <errno.h> |
47 | #include <errno.h> |
48 | #include <string.h> |
48 | #include <string.h> |
49 | #include <byteorder.h> |
49 | #include <byteorder.h> |
50 | #include <libadt/hash_table.h> |
50 | #include <libadt/hash_table.h> |
51 | #include <libadt/list.h> |
51 | #include <libadt/list.h> |
52 | #include <assert.h> |
52 | #include <assert.h> |
53 | #include <futex.h> |
53 | #include <futex.h> |
54 | #include <sys/mman.h> |
54 | #include <sys/mman.h> |
55 | #include <align.h> |
55 | #include <align.h> |
56 | 56 | ||
57 | /** Futex protecting the list of cached free FAT nodes. */ |
57 | /** Futex protecting the list of cached free FAT nodes. */ |
58 | static futex_t ffn_futex = FUTEX_INITIALIZER; |
58 | static futex_t ffn_futex = FUTEX_INITIALIZER; |
59 | 59 | ||
60 | /** List of cached free FAT nodes. */ |
60 | /** List of cached free FAT nodes. */ |
61 | static LIST_INITIALIZE(ffn_head); |
61 | static LIST_INITIALIZE(ffn_head); |
62 | 62 | ||
63 | static int dev_phone = -1; /* FIXME */ |
63 | static int dev_phone = -1; /* FIXME */ |
64 | static void *dev_buffer = NULL; /* FIXME */ |
64 | static void *dev_buffer = NULL; /* FIXME */ |
65 | 65 | ||
66 | block_t *block_get(dev_handle_t dev_handle, off_t offset, size_t bs) |
66 | block_t *block_get(dev_handle_t dev_handle, off_t offset, size_t bs) |
67 | { |
67 | { |
68 | /* FIXME */ |
68 | /* FIXME */ |
69 | block_t *b; |
69 | block_t *b; |
70 | off_t bufpos = 0; |
70 | off_t bufpos = 0; |
71 | size_t buflen = 0; |
71 | size_t buflen = 0; |
72 | off_t pos = offset * bs; |
72 | off_t pos = offset * bs; |
73 | 73 | ||
74 | assert(dev_phone != -1); |
74 | assert(dev_phone != -1); |
75 | assert(dev_buffer); |
75 | assert(dev_buffer); |
76 | 76 | ||
77 | b = malloc(sizeof(block_t)); |
77 | b = malloc(sizeof(block_t)); |
78 | if (!b) |
78 | if (!b) |
79 | return NULL; |
79 | return NULL; |
80 | 80 | ||
81 | b->data = malloc(bs); |
81 | b->data = malloc(bs); |
82 | if (!b->data) { |
82 | if (!b->data) { |
83 | free(b); |
83 | free(b); |
84 | return NULL; |
84 | return NULL; |
85 | } |
85 | } |
86 | b->size = bs; |
86 | b->size = bs; |
87 | 87 | ||
88 | if (!libfs_blockread(dev_phone, dev_buffer, &bufpos, &buflen, &pos, |
88 | if (!libfs_blockread(dev_phone, dev_buffer, &bufpos, &buflen, &pos, |
89 | b->data, bs, bs)) { |
89 | b->data, bs, bs)) { |
90 | free(b->data); |
90 | free(b->data); |
91 | free(b); |
91 | free(b); |
92 | return NULL; |
92 | return NULL; |
93 | } |
93 | } |
94 | 94 | ||
95 | return b; |
95 | return b; |
96 | } |
96 | } |
97 | 97 | ||
98 | void block_put(block_t *block) |
98 | void block_put(block_t *block) |
99 | { |
99 | { |
100 | /* FIXME */ |
100 | /* FIXME */ |
101 | free(block->data); |
101 | free(block->data); |
102 | free(block); |
102 | free(block); |
103 | } |
103 | } |
104 | 104 | ||
105 | static void fat_node_initialize(fat_node_t *node) |
105 | static void fat_node_initialize(fat_node_t *node) |
106 | { |
106 | { |
107 | futex_initialize(&node->lock, 1); |
107 | futex_initialize(&node->lock, 1); |
108 | node->idx = NULL; |
108 | node->idx = NULL; |
109 | node->type = 0; |
109 | node->type = 0; |
110 | link_initialize(&node->ffn_link); |
110 | link_initialize(&node->ffn_link); |
111 | node->size = 0; |
111 | node->size = 0; |
112 | node->lnkcnt = 0; |
112 | node->lnkcnt = 0; |
113 | node->refcnt = 0; |
113 | node->refcnt = 0; |
114 | node->dirty = false; |
114 | node->dirty = false; |
115 | } |
115 | } |
116 | 116 | ||
117 | static void fat_node_sync(fat_node_t *node) |
117 | static void fat_node_sync(fat_node_t *node) |
118 | { |
118 | { |
119 | /* TODO */ |
119 | block_t *bb, *b; |
- | 120 | fat_dentry_t *d; |
|
- | 121 | uint16_t bps; |
|
- | 122 | unsigned dps; |
|
- | 123 | ||
- | 124 | assert(node->dirty); |
|
- | 125 | ||
- | 126 | bb = block_get(node->idx->dev_handle, BS_BLOCK, BS_SIZE); |
|
- | 127 | bps = uint16_t_le2host(FAT_BS(bb)->bps); |
|
- | 128 | dps = bps / sizeof(fat_dentry_t); |
|
- | 129 | ||
- | 130 | /* Read the block that contains the dentry of interest. */ |
|
- | 131 | b = _fat_block_get(bb->data, node->idx->dev_handle, node->idx->pfc, |
|
- | 132 | (node->idx->pdi * sizeof(fat_dentry_t)) / bps); |
|
- | 133 | ||
- | 134 | d = ((fat_dentry_t *)b->data) + (node->idx->pdi % dps); |
|
- | 135 | ||
- | 136 | d->firstc = host2uint16_t_le(node->firstc); |
|
- | 137 | if (node->type == FAT_FILE) |
|
- | 138 | d->size = host2uint32_t_le(node->size); |
|
- | 139 | /* TODO: update other fields? (e.g time fields, attr field) */ |
|
- | 140 | ||
- | 141 | b->dirty = true; /* need to sync block */ |
|
- | 142 | block_put(b); |
|
- | 143 | block_put(bb); |
|
120 | } |
144 | } |
121 | 145 | ||
122 | /** Internal version of fat_node_get(). |
146 | /** Internal version of fat_node_get(). |
123 | * |
147 | * |
124 | * @param idxp Locked index structure. |
148 | * @param idxp Locked index structure. |
125 | */ |
149 | */ |
126 | static void *fat_node_get_core(fat_idx_t *idxp) |
150 | static void *fat_node_get_core(fat_idx_t *idxp) |
127 | { |
151 | { |
128 | block_t *bb, *b; |
152 | block_t *bb, *b; |
129 | fat_dentry_t *d; |
153 | fat_dentry_t *d; |
130 | fat_node_t *nodep = NULL; |
154 | fat_node_t *nodep = NULL; |
131 | unsigned bps; |
155 | unsigned bps; |
132 | unsigned dps; |
156 | unsigned dps; |
133 | 157 | ||
134 | if (idxp->nodep) { |
158 | if (idxp->nodep) { |
135 | /* |
159 | /* |
136 | * We are lucky. |
160 | * We are lucky. |
137 | * The node is already instantiated in memory. |
161 | * The node is already instantiated in memory. |
138 | */ |
162 | */ |
139 | futex_down(&idxp->nodep->lock); |
163 | futex_down(&idxp->nodep->lock); |
140 | if (!idxp->nodep->refcnt++) |
164 | if (!idxp->nodep->refcnt++) |
141 | list_remove(&idxp->nodep->ffn_link); |
165 | list_remove(&idxp->nodep->ffn_link); |
142 | futex_up(&idxp->nodep->lock); |
166 | futex_up(&idxp->nodep->lock); |
143 | return idxp->nodep; |
167 | return idxp->nodep; |
144 | } |
168 | } |
145 | 169 | ||
146 | /* |
170 | /* |
147 | * We must instantiate the node from the file system. |
171 | * We must instantiate the node from the file system. |
148 | */ |
172 | */ |
149 | 173 | ||
150 | assert(idxp->pfc); |
174 | assert(idxp->pfc); |
151 | 175 | ||
152 | futex_down(&ffn_futex); |
176 | futex_down(&ffn_futex); |
153 | if (!list_empty(&ffn_head)) { |
177 | if (!list_empty(&ffn_head)) { |
154 | /* Try to use a cached free node structure. */ |
178 | /* Try to use a cached free node structure. */ |
155 | fat_idx_t *idxp_tmp; |
179 | fat_idx_t *idxp_tmp; |
156 | nodep = list_get_instance(ffn_head.next, fat_node_t, ffn_link); |
180 | nodep = list_get_instance(ffn_head.next, fat_node_t, ffn_link); |
157 | if (futex_trydown(&nodep->lock) == ESYNCH_WOULD_BLOCK) |
181 | if (futex_trydown(&nodep->lock) == ESYNCH_WOULD_BLOCK) |
158 | goto skip_cache; |
182 | goto skip_cache; |
159 | idxp_tmp = nodep->idx; |
183 | idxp_tmp = nodep->idx; |
160 | if (futex_trydown(&idxp_tmp->lock) == ESYNCH_WOULD_BLOCK) { |
184 | if (futex_trydown(&idxp_tmp->lock) == ESYNCH_WOULD_BLOCK) { |
161 | futex_up(&nodep->lock); |
185 | futex_up(&nodep->lock); |
162 | goto skip_cache; |
186 | goto skip_cache; |
163 | } |
187 | } |
164 | list_remove(&nodep->ffn_link); |
188 | list_remove(&nodep->ffn_link); |
165 | futex_up(&ffn_futex); |
189 | futex_up(&ffn_futex); |
166 | if (nodep->dirty) |
190 | if (nodep->dirty) |
167 | fat_node_sync(nodep); |
191 | fat_node_sync(nodep); |
168 | idxp_tmp->nodep = NULL; |
192 | idxp_tmp->nodep = NULL; |
169 | futex_up(&nodep->lock); |
193 | futex_up(&nodep->lock); |
170 | futex_up(&idxp_tmp->lock); |
194 | futex_up(&idxp_tmp->lock); |
171 | } else { |
195 | } else { |
172 | skip_cache: |
196 | skip_cache: |
173 | /* Try to allocate a new node structure. */ |
197 | /* Try to allocate a new node structure. */ |
174 | futex_up(&ffn_futex); |
198 | futex_up(&ffn_futex); |
175 | nodep = (fat_node_t *)malloc(sizeof(fat_node_t)); |
199 | nodep = (fat_node_t *)malloc(sizeof(fat_node_t)); |
176 | if (!nodep) |
200 | if (!nodep) |
177 | return NULL; |
201 | return NULL; |
178 | } |
202 | } |
179 | fat_node_initialize(nodep); |
203 | fat_node_initialize(nodep); |
180 | 204 | ||
181 | bb = block_get(idxp->dev_handle, BS_BLOCK, BS_SIZE); |
205 | bb = block_get(idxp->dev_handle, BS_BLOCK, BS_SIZE); |
182 | bps = uint16_t_le2host(FAT_BS(bb)->bps); |
206 | bps = uint16_t_le2host(FAT_BS(bb)->bps); |
183 | dps = bps / sizeof(fat_dentry_t); |
207 | dps = bps / sizeof(fat_dentry_t); |
184 | 208 | ||
185 | /* Read the block that contains the dentry of interest. */ |
209 | /* Read the block that contains the dentry of interest. */ |
186 | b = _fat_block_get(bb->data, idxp->dev_handle, idxp->pfc, |
210 | b = _fat_block_get(bb->data, idxp->dev_handle, idxp->pfc, |
187 | (idxp->pdi * sizeof(fat_dentry_t)) / bps); |
211 | (idxp->pdi * sizeof(fat_dentry_t)) / bps); |
188 | assert(b); |
212 | assert(b); |
189 | 213 | ||
190 | d = ((fat_dentry_t *)b->data) + (idxp->pdi % dps); |
214 | d = ((fat_dentry_t *)b->data) + (idxp->pdi % dps); |
191 | if (d->attr & FAT_ATTR_SUBDIR) { |
215 | if (d->attr & FAT_ATTR_SUBDIR) { |
192 | /* |
216 | /* |
193 | * The only directory which does not have this bit set is the |
217 | * The only directory which does not have this bit set is the |
194 | * root directory itself. The root directory node is handled |
218 | * root directory itself. The root directory node is handled |
195 | * and initialized elsewhere. |
219 | * and initialized elsewhere. |
196 | */ |
220 | */ |
197 | nodep->type = FAT_DIRECTORY; |
221 | nodep->type = FAT_DIRECTORY; |
198 | /* |
222 | /* |
199 | * Unfortunately, the 'size' field of the FAT dentry is not |
223 | * Unfortunately, the 'size' field of the FAT dentry is not |
200 | * defined for the directory entry type. We must determine the |
224 | * defined for the directory entry type. We must determine the |
201 | * size of the directory by walking the FAT. |
225 | * size of the directory by walking the FAT. |
202 | */ |
226 | */ |
203 | nodep->size = bps * _fat_blcks_get(bb->data, idxp->dev_handle, |
227 | nodep->size = bps * _fat_blcks_get(bb->data, idxp->dev_handle, |
204 | uint16_t_le2host(d->firstc), NULL); |
228 | uint16_t_le2host(d->firstc), NULL); |
205 | } else { |
229 | } else { |
206 | nodep->type = FAT_FILE; |
230 | nodep->type = FAT_FILE; |
207 | nodep->size = uint32_t_le2host(d->size); |
231 | nodep->size = uint32_t_le2host(d->size); |
208 | } |
232 | } |
209 | nodep->firstc = uint16_t_le2host(d->firstc); |
233 | nodep->firstc = uint16_t_le2host(d->firstc); |
210 | nodep->lnkcnt = 1; |
234 | nodep->lnkcnt = 1; |
211 | nodep->refcnt = 1; |
235 | nodep->refcnt = 1; |
212 | 236 | ||
213 | block_put(b); |
237 | block_put(b); |
214 | block_put(bb); |
238 | block_put(bb); |
215 | 239 | ||
216 | /* Link the idx structure with the node structure. */ |
240 | /* Link the idx structure with the node structure. */ |
217 | nodep->idx = idxp; |
241 | nodep->idx = idxp; |
218 | idxp->nodep = nodep; |
242 | idxp->nodep = nodep; |
219 | 243 | ||
220 | return nodep; |
244 | return nodep; |
221 | } |
245 | } |
222 | 246 | ||
223 | /** Instantiate a FAT in-core node. */ |
247 | /** Instantiate a FAT in-core node. */ |
224 | static void *fat_node_get(dev_handle_t dev_handle, fs_index_t index) |
248 | static void *fat_node_get(dev_handle_t dev_handle, fs_index_t index) |
225 | { |
249 | { |
226 | void *node; |
250 | void *node; |
227 | fat_idx_t *idxp; |
251 | fat_idx_t *idxp; |
228 | 252 | ||
229 | idxp = fat_idx_get_by_index(dev_handle, index); |
253 | idxp = fat_idx_get_by_index(dev_handle, index); |
230 | if (!idxp) |
254 | if (!idxp) |
231 | return NULL; |
255 | return NULL; |
232 | /* idxp->lock held */ |
256 | /* idxp->lock held */ |
233 | node = fat_node_get_core(idxp); |
257 | node = fat_node_get_core(idxp); |
234 | futex_up(&idxp->lock); |
258 | futex_up(&idxp->lock); |
235 | return node; |
259 | return node; |
236 | } |
260 | } |
237 | 261 | ||
238 | static void fat_node_put(void *node) |
262 | static void fat_node_put(void *node) |
239 | { |
263 | { |
240 | fat_node_t *nodep = (fat_node_t *)node; |
264 | fat_node_t *nodep = (fat_node_t *)node; |
241 | 265 | ||
242 | futex_down(&nodep->lock); |
266 | futex_down(&nodep->lock); |
243 | if (!--nodep->refcnt) { |
267 | if (!--nodep->refcnt) { |
244 | futex_down(&ffn_futex); |
268 | futex_down(&ffn_futex); |
245 | list_append(&nodep->ffn_link, &ffn_head); |
269 | list_append(&nodep->ffn_link, &ffn_head); |
246 | futex_up(&ffn_futex); |
270 | futex_up(&ffn_futex); |
247 | } |
271 | } |
248 | futex_up(&nodep->lock); |
272 | futex_up(&nodep->lock); |
249 | } |
273 | } |
250 | 274 | ||
251 | static void *fat_create(int flags) |
275 | static void *fat_create(int flags) |
252 | { |
276 | { |
253 | return NULL; /* not supported at the moment */ |
277 | return NULL; /* not supported at the moment */ |
254 | } |
278 | } |
255 | 279 | ||
256 | static int fat_destroy(void *node) |
280 | static int fat_destroy(void *node) |
257 | { |
281 | { |
258 | return ENOTSUP; /* not supported at the moment */ |
282 | return ENOTSUP; /* not supported at the moment */ |
259 | } |
283 | } |
260 | 284 | ||
261 | static bool fat_link(void *prnt, void *chld, const char *name) |
285 | static bool fat_link(void *prnt, void *chld, const char *name) |
262 | { |
286 | { |
263 | return false; /* not supported at the moment */ |
287 | return false; /* not supported at the moment */ |
264 | } |
288 | } |
265 | 289 | ||
266 | static int fat_unlink(void *prnt, void *chld) |
290 | static int fat_unlink(void *prnt, void *chld) |
267 | { |
291 | { |
268 | return ENOTSUP; /* not supported at the moment */ |
292 | return ENOTSUP; /* not supported at the moment */ |
269 | } |
293 | } |
270 | 294 | ||
271 | static void *fat_match(void *prnt, const char *component) |
295 | static void *fat_match(void *prnt, const char *component) |
272 | { |
296 | { |
273 | fat_node_t *parentp = (fat_node_t *)prnt; |
297 | fat_node_t *parentp = (fat_node_t *)prnt; |
274 | char name[FAT_NAME_LEN + 1 + FAT_EXT_LEN + 1]; |
298 | char name[FAT_NAME_LEN + 1 + FAT_EXT_LEN + 1]; |
275 | unsigned i, j; |
299 | unsigned i, j; |
276 | unsigned bps; /* bytes per sector */ |
300 | unsigned bps; /* bytes per sector */ |
277 | unsigned dps; /* dentries per sector */ |
301 | unsigned dps; /* dentries per sector */ |
278 | unsigned blocks; |
302 | unsigned blocks; |
279 | fat_dentry_t *d; |
303 | fat_dentry_t *d; |
280 | block_t *bb, *b; |
304 | block_t *bb, *b; |
281 | 305 | ||
282 | futex_down(&parentp->idx->lock); |
306 | futex_down(&parentp->idx->lock); |
283 | bb = block_get(parentp->idx->dev_handle, BS_BLOCK, BS_SIZE); |
307 | bb = block_get(parentp->idx->dev_handle, BS_BLOCK, BS_SIZE); |
284 | bps = uint16_t_le2host(FAT_BS(bb)->bps); |
308 | bps = uint16_t_le2host(FAT_BS(bb)->bps); |
285 | dps = bps / sizeof(fat_dentry_t); |
309 | dps = bps / sizeof(fat_dentry_t); |
286 | blocks = parentp->size / bps + (parentp->size % bps != 0); |
310 | blocks = parentp->size / bps + (parentp->size % bps != 0); |
287 | for (i = 0; i < blocks; i++) { |
311 | for (i = 0; i < blocks; i++) { |
288 | unsigned dentries; |
312 | unsigned dentries; |
289 | 313 | ||
290 | b = fat_block_get(bb->data, parentp, i); |
314 | b = fat_block_get(bb->data, parentp, i); |
291 | dentries = (i == blocks - 1) ? |
315 | dentries = (i == blocks - 1) ? |
292 | parentp->size % sizeof(fat_dentry_t) : |
316 | parentp->size % sizeof(fat_dentry_t) : |
293 | dps; |
317 | dps; |
294 | for (j = 0; j < dentries; j++) { |
318 | for (j = 0; j < dentries; j++) { |
295 | d = ((fat_dentry_t *)b->data) + j; |
319 | d = ((fat_dentry_t *)b->data) + j; |
296 | switch (fat_classify_dentry(d)) { |
320 | switch (fat_classify_dentry(d)) { |
297 | case FAT_DENTRY_SKIP: |
321 | case FAT_DENTRY_SKIP: |
298 | continue; |
322 | continue; |
299 | case FAT_DENTRY_LAST: |
323 | case FAT_DENTRY_LAST: |
300 | block_put(b); |
324 | block_put(b); |
301 | block_put(bb); |
325 | block_put(bb); |
302 | futex_up(&parentp->idx->lock); |
326 | futex_up(&parentp->idx->lock); |
303 | return NULL; |
327 | return NULL; |
304 | default: |
328 | default: |
305 | case FAT_DENTRY_VALID: |
329 | case FAT_DENTRY_VALID: |
306 | dentry_name_canonify(d, name); |
330 | dentry_name_canonify(d, name); |
307 | break; |
331 | break; |
308 | } |
332 | } |
309 | if (stricmp(name, component) == 0) { |
333 | if (stricmp(name, component) == 0) { |
310 | /* hit */ |
334 | /* hit */ |
311 | void *node; |
335 | void *node; |
312 | /* |
336 | /* |
313 | * Assume tree hierarchy for locking. We |
337 | * Assume tree hierarchy for locking. We |
314 | * already have the parent and now we are going |
338 | * already have the parent and now we are going |
315 | * to lock the child. Never lock in the oposite |
339 | * to lock the child. Never lock in the oposite |
316 | * order. |
340 | * order. |
317 | */ |
341 | */ |
318 | fat_idx_t *idx = fat_idx_get_by_pos( |
342 | fat_idx_t *idx = fat_idx_get_by_pos( |
319 | parentp->idx->dev_handle, parentp->firstc, |
343 | parentp->idx->dev_handle, parentp->firstc, |
320 | i * dps + j); |
344 | i * dps + j); |
321 | futex_up(&parentp->idx->lock); |
345 | futex_up(&parentp->idx->lock); |
322 | if (!idx) { |
346 | if (!idx) { |
323 | /* |
347 | /* |
324 | * Can happen if memory is low or if we |
348 | * Can happen if memory is low or if we |
325 | * run out of 32-bit indices. |
349 | * run out of 32-bit indices. |
326 | */ |
350 | */ |
327 | block_put(b); |
351 | block_put(b); |
328 | block_put(bb); |
352 | block_put(bb); |
329 | return NULL; |
353 | return NULL; |
330 | } |
354 | } |
331 | node = fat_node_get_core(idx); |
355 | node = fat_node_get_core(idx); |
332 | futex_up(&idx->lock); |
356 | futex_up(&idx->lock); |
333 | block_put(b); |
357 | block_put(b); |
334 | block_put(bb); |
358 | block_put(bb); |
335 | return node; |
359 | return node; |
336 | } |
360 | } |
337 | } |
361 | } |
338 | block_put(b); |
362 | block_put(b); |
339 | } |
363 | } |
340 | block_put(bb); |
364 | block_put(bb); |
341 | 365 | ||
342 | futex_up(&parentp->idx->lock); |
366 | futex_up(&parentp->idx->lock); |
343 | return NULL; |
367 | return NULL; |
344 | } |
368 | } |
345 | 369 | ||
346 | static fs_index_t fat_index_get(void *node) |
370 | static fs_index_t fat_index_get(void *node) |
347 | { |
371 | { |
348 | fat_node_t *fnodep = (fat_node_t *)node; |
372 | fat_node_t *fnodep = (fat_node_t *)node; |
349 | if (!fnodep) |
373 | if (!fnodep) |
350 | return 0; |
374 | return 0; |
351 | return fnodep->idx->index; |
375 | return fnodep->idx->index; |
352 | } |
376 | } |
353 | 377 | ||
354 | static size_t fat_size_get(void *node) |
378 | static size_t fat_size_get(void *node) |
355 | { |
379 | { |
356 | return ((fat_node_t *)node)->size; |
380 | return ((fat_node_t *)node)->size; |
357 | } |
381 | } |
358 | 382 | ||
359 | static unsigned fat_lnkcnt_get(void *node) |
383 | static unsigned fat_lnkcnt_get(void *node) |
360 | { |
384 | { |
361 | return ((fat_node_t *)node)->lnkcnt; |
385 | return ((fat_node_t *)node)->lnkcnt; |
362 | } |
386 | } |
363 | 387 | ||
364 | static bool fat_has_children(void *node) |
388 | static bool fat_has_children(void *node) |
365 | { |
389 | { |
366 | fat_node_t *nodep = (fat_node_t *)node; |
390 | fat_node_t *nodep = (fat_node_t *)node; |
367 | unsigned bps; |
391 | unsigned bps; |
368 | unsigned dps; |
392 | unsigned dps; |
369 | unsigned blocks; |
393 | unsigned blocks; |
370 | block_t *bb, *b; |
394 | block_t *bb, *b; |
371 | unsigned i, j; |
395 | unsigned i, j; |
372 | 396 | ||
373 | if (nodep->type != FAT_DIRECTORY) |
397 | if (nodep->type != FAT_DIRECTORY) |
374 | return false; |
398 | return false; |
375 | 399 | ||
376 | futex_down(&nodep->idx->lock); |
400 | futex_down(&nodep->idx->lock); |
377 | bb = block_get(nodep->idx->dev_handle, BS_BLOCK, BS_SIZE); |
401 | bb = block_get(nodep->idx->dev_handle, BS_BLOCK, BS_SIZE); |
378 | bps = uint16_t_le2host(FAT_BS(bb)->bps); |
402 | bps = uint16_t_le2host(FAT_BS(bb)->bps); |
379 | dps = bps / sizeof(fat_dentry_t); |
403 | dps = bps / sizeof(fat_dentry_t); |
380 | 404 | ||
381 | blocks = nodep->size / bps + (nodep->size % bps != 0); |
405 | blocks = nodep->size / bps + (nodep->size % bps != 0); |
382 | 406 | ||
383 | for (i = 0; i < blocks; i++) { |
407 | for (i = 0; i < blocks; i++) { |
384 | unsigned dentries; |
408 | unsigned dentries; |
385 | fat_dentry_t *d; |
409 | fat_dentry_t *d; |
386 | 410 | ||
387 | b = fat_block_get(bb->data, nodep, i); |
411 | b = fat_block_get(bb->data, nodep, i); |
388 | dentries = (i == blocks - 1) ? |
412 | dentries = (i == blocks - 1) ? |
389 | nodep->size % sizeof(fat_dentry_t) : |
413 | nodep->size % sizeof(fat_dentry_t) : |
390 | dps; |
414 | dps; |
391 | for (j = 0; j < dentries; j++) { |
415 | for (j = 0; j < dentries; j++) { |
392 | d = ((fat_dentry_t *)b->data) + j; |
416 | d = ((fat_dentry_t *)b->data) + j; |
393 | switch (fat_classify_dentry(d)) { |
417 | switch (fat_classify_dentry(d)) { |
394 | case FAT_DENTRY_SKIP: |
418 | case FAT_DENTRY_SKIP: |
395 | continue; |
419 | continue; |
396 | case FAT_DENTRY_LAST: |
420 | case FAT_DENTRY_LAST: |
397 | block_put(b); |
421 | block_put(b); |
398 | block_put(bb); |
422 | block_put(bb); |
399 | futex_up(&nodep->idx->lock); |
423 | futex_up(&nodep->idx->lock); |
400 | return false; |
424 | return false; |
401 | default: |
425 | default: |
402 | case FAT_DENTRY_VALID: |
426 | case FAT_DENTRY_VALID: |
403 | block_put(b); |
427 | block_put(b); |
404 | block_put(bb); |
428 | block_put(bb); |
405 | futex_up(&nodep->idx->lock); |
429 | futex_up(&nodep->idx->lock); |
406 | return true; |
430 | return true; |
407 | } |
431 | } |
408 | block_put(b); |
432 | block_put(b); |
409 | block_put(bb); |
433 | block_put(bb); |
410 | futex_up(&nodep->idx->lock); |
434 | futex_up(&nodep->idx->lock); |
411 | return true; |
435 | return true; |
412 | } |
436 | } |
413 | block_put(b); |
437 | block_put(b); |
414 | } |
438 | } |
415 | block_put(bb); |
439 | block_put(bb); |
416 | 440 | ||
417 | futex_up(&nodep->idx->lock); |
441 | futex_up(&nodep->idx->lock); |
418 | return false; |
442 | return false; |
419 | } |
443 | } |
420 | 444 | ||
421 | static void *fat_root_get(dev_handle_t dev_handle) |
445 | static void *fat_root_get(dev_handle_t dev_handle) |
422 | { |
446 | { |
423 | return fat_node_get(dev_handle, 0); |
447 | return fat_node_get(dev_handle, 0); |
424 | } |
448 | } |
425 | 449 | ||
426 | static char fat_plb_get_char(unsigned pos) |
450 | static char fat_plb_get_char(unsigned pos) |
427 | { |
451 | { |
428 | return fat_reg.plb_ro[pos % PLB_SIZE]; |
452 | return fat_reg.plb_ro[pos % PLB_SIZE]; |
429 | } |
453 | } |
430 | 454 | ||
431 | static bool fat_is_directory(void *node) |
455 | static bool fat_is_directory(void *node) |
432 | { |
456 | { |
433 | return ((fat_node_t *)node)->type == FAT_DIRECTORY; |
457 | return ((fat_node_t *)node)->type == FAT_DIRECTORY; |
434 | } |
458 | } |
435 | 459 | ||
436 | static bool fat_is_file(void *node) |
460 | static bool fat_is_file(void *node) |
437 | { |
461 | { |
438 | return ((fat_node_t *)node)->type == FAT_FILE; |
462 | return ((fat_node_t *)node)->type == FAT_FILE; |
439 | } |
463 | } |
440 | 464 | ||
441 | /** libfs operations */ |
465 | /** libfs operations */ |
442 | libfs_ops_t fat_libfs_ops = { |
466 | libfs_ops_t fat_libfs_ops = { |
443 | .match = fat_match, |
467 | .match = fat_match, |
444 | .node_get = fat_node_get, |
468 | .node_get = fat_node_get, |
445 | .node_put = fat_node_put, |
469 | .node_put = fat_node_put, |
446 | .create = fat_create, |
470 | .create = fat_create, |
447 | .destroy = fat_destroy, |
471 | .destroy = fat_destroy, |
448 | .link = fat_link, |
472 | .link = fat_link, |
449 | .unlink = fat_unlink, |
473 | .unlink = fat_unlink, |
450 | .index_get = fat_index_get, |
474 | .index_get = fat_index_get, |
451 | .size_get = fat_size_get, |
475 | .size_get = fat_size_get, |
452 | .lnkcnt_get = fat_lnkcnt_get, |
476 | .lnkcnt_get = fat_lnkcnt_get, |
453 | .has_children = fat_has_children, |
477 | .has_children = fat_has_children, |
454 | .root_get = fat_root_get, |
478 | .root_get = fat_root_get, |
455 | .plb_get_char = fat_plb_get_char, |
479 | .plb_get_char = fat_plb_get_char, |
456 | .is_directory = fat_is_directory, |
480 | .is_directory = fat_is_directory, |
457 | .is_file = fat_is_file |
481 | .is_file = fat_is_file |
458 | }; |
482 | }; |
459 | 483 | ||
460 | void fat_mounted(ipc_callid_t rid, ipc_call_t *request) |
484 | void fat_mounted(ipc_callid_t rid, ipc_call_t *request) |
461 | { |
485 | { |
462 | dev_handle_t dev_handle = (dev_handle_t) IPC_GET_ARG1(*request); |
486 | dev_handle_t dev_handle = (dev_handle_t) IPC_GET_ARG1(*request); |
463 | block_t *bb; |
487 | block_t *bb; |
464 | uint16_t bps; |
488 | uint16_t bps; |
465 | uint16_t rde; |
489 | uint16_t rde; |
466 | int rc; |
490 | int rc; |
467 | 491 | ||
468 | /* |
492 | /* |
469 | * For now, we don't bother to remember dev_handle, dev_phone or |
493 | * For now, we don't bother to remember dev_handle, dev_phone or |
470 | * dev_buffer in some data structure. We use global variables because we |
494 | * dev_buffer in some data structure. We use global variables because we |
471 | * know there will be at most one mount on this file system. |
495 | * know there will be at most one mount on this file system. |
472 | * Of course, this is a huge TODO item. |
496 | * Of course, this is a huge TODO item. |
473 | */ |
497 | */ |
474 | dev_buffer = mmap(NULL, BS_SIZE, PROTO_READ | PROTO_WRITE, |
498 | dev_buffer = mmap(NULL, BS_SIZE, PROTO_READ | PROTO_WRITE, |
475 | MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); |
499 | MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); |
476 | 500 | ||
477 | if (!dev_buffer) { |
501 | if (!dev_buffer) { |
478 | ipc_answer_0(rid, ENOMEM); |
502 | ipc_answer_0(rid, ENOMEM); |
479 | return; |
503 | return; |
480 | } |
504 | } |
481 | 505 | ||
482 | dev_phone = ipc_connect_me_to(PHONE_NS, SERVICE_DEVMAP, |
506 | dev_phone = ipc_connect_me_to(PHONE_NS, SERVICE_DEVMAP, |
483 | DEVMAP_CONNECT_TO_DEVICE, dev_handle); |
507 | DEVMAP_CONNECT_TO_DEVICE, dev_handle); |
484 | 508 | ||
485 | if (dev_phone < 0) { |
509 | if (dev_phone < 0) { |
486 | munmap(dev_buffer, BS_SIZE); |
510 | munmap(dev_buffer, BS_SIZE); |
487 | ipc_answer_0(rid, dev_phone); |
511 | ipc_answer_0(rid, dev_phone); |
488 | return; |
512 | return; |
489 | } |
513 | } |
490 | 514 | ||
491 | rc = ipc_share_out_start(dev_phone, dev_buffer, |
515 | rc = ipc_share_out_start(dev_phone, dev_buffer, |
492 | AS_AREA_READ | AS_AREA_WRITE); |
516 | AS_AREA_READ | AS_AREA_WRITE); |
493 | if (rc != EOK) { |
517 | if (rc != EOK) { |
494 | munmap(dev_buffer, BS_SIZE); |
518 | munmap(dev_buffer, BS_SIZE); |
495 | ipc_answer_0(rid, rc); |
519 | ipc_answer_0(rid, rc); |
496 | return; |
520 | return; |
497 | } |
521 | } |
498 | 522 | ||
499 | /* Read the number of root directory entries. */ |
523 | /* Read the number of root directory entries. */ |
500 | bb = block_get(dev_handle, BS_BLOCK, BS_SIZE); |
524 | bb = block_get(dev_handle, BS_BLOCK, BS_SIZE); |
501 | bps = uint16_t_le2host(FAT_BS(bb)->bps); |
525 | bps = uint16_t_le2host(FAT_BS(bb)->bps); |
502 | rde = uint16_t_le2host(FAT_BS(bb)->root_ent_max); |
526 | rde = uint16_t_le2host(FAT_BS(bb)->root_ent_max); |
503 | block_put(bb); |
527 | block_put(bb); |
504 | 528 | ||
505 | if (bps != BS_SIZE) { |
529 | if (bps != BS_SIZE) { |
506 | munmap(dev_buffer, BS_SIZE); |
530 | munmap(dev_buffer, BS_SIZE); |
507 | ipc_answer_0(rid, ENOTSUP); |
531 | ipc_answer_0(rid, ENOTSUP); |
508 | return; |
532 | return; |
509 | } |
533 | } |
510 | 534 | ||
511 | rc = fat_idx_init_by_dev_handle(dev_handle); |
535 | rc = fat_idx_init_by_dev_handle(dev_handle); |
512 | if (rc != EOK) { |
536 | if (rc != EOK) { |
513 | munmap(dev_buffer, BS_SIZE); |
537 | munmap(dev_buffer, BS_SIZE); |
514 | ipc_answer_0(rid, rc); |
538 | ipc_answer_0(rid, rc); |
515 | return; |
539 | return; |
516 | } |
540 | } |
517 | 541 | ||
518 | /* Initialize the root node. */ |
542 | /* Initialize the root node. */ |
519 | fat_node_t *rootp = (fat_node_t *)malloc(sizeof(fat_node_t)); |
543 | fat_node_t *rootp = (fat_node_t *)malloc(sizeof(fat_node_t)); |
520 | if (!rootp) { |
544 | if (!rootp) { |
521 | munmap(dev_buffer, BS_SIZE); |
545 | munmap(dev_buffer, BS_SIZE); |
522 | fat_idx_fini_by_dev_handle(dev_handle); |
546 | fat_idx_fini_by_dev_handle(dev_handle); |
523 | ipc_answer_0(rid, ENOMEM); |
547 | ipc_answer_0(rid, ENOMEM); |
524 | return; |
548 | return; |
525 | } |
549 | } |
526 | fat_node_initialize(rootp); |
550 | fat_node_initialize(rootp); |
527 | 551 | ||
528 | fat_idx_t *ridxp = fat_idx_get_by_pos(dev_handle, FAT_CLST_ROOTPAR, 0); |
552 | fat_idx_t *ridxp = fat_idx_get_by_pos(dev_handle, FAT_CLST_ROOTPAR, 0); |
529 | if (!ridxp) { |
553 | if (!ridxp) { |
530 | munmap(dev_buffer, BS_SIZE); |
554 | munmap(dev_buffer, BS_SIZE); |
531 | free(rootp); |
555 | free(rootp); |
532 | fat_idx_fini_by_dev_handle(dev_handle); |
556 | fat_idx_fini_by_dev_handle(dev_handle); |
533 | ipc_answer_0(rid, ENOMEM); |
557 | ipc_answer_0(rid, ENOMEM); |
534 | return; |
558 | return; |
535 | } |
559 | } |
536 | assert(ridxp->index == 0); |
560 | assert(ridxp->index == 0); |
537 | /* ridxp->lock held */ |
561 | /* ridxp->lock held */ |
538 | 562 | ||
539 | rootp->type = FAT_DIRECTORY; |
563 | rootp->type = FAT_DIRECTORY; |
540 | rootp->firstc = FAT_CLST_ROOT; |
564 | rootp->firstc = FAT_CLST_ROOT; |
541 | rootp->refcnt = 1; |
565 | rootp->refcnt = 1; |
542 | rootp->lnkcnt = 0; /* FS root is not linked */ |
566 | rootp->lnkcnt = 0; /* FS root is not linked */ |
543 | rootp->size = rde * sizeof(fat_dentry_t); |
567 | rootp->size = rde * sizeof(fat_dentry_t); |
544 | rootp->idx = ridxp; |
568 | rootp->idx = ridxp; |
545 | ridxp->nodep = rootp; |
569 | ridxp->nodep = rootp; |
546 | 570 | ||
547 | futex_up(&ridxp->lock); |
571 | futex_up(&ridxp->lock); |
548 | 572 | ||
549 | ipc_answer_3(rid, EOK, ridxp->index, rootp->size, rootp->lnkcnt); |
573 | ipc_answer_3(rid, EOK, ridxp->index, rootp->size, rootp->lnkcnt); |
550 | } |
574 | } |
551 | 575 | ||
552 | void fat_mount(ipc_callid_t rid, ipc_call_t *request) |
576 | void fat_mount(ipc_callid_t rid, ipc_call_t *request) |
553 | { |
577 | { |
554 | ipc_answer_0(rid, ENOTSUP); |
578 | ipc_answer_0(rid, ENOTSUP); |
555 | } |
579 | } |
556 | 580 | ||
557 | void fat_lookup(ipc_callid_t rid, ipc_call_t *request) |
581 | void fat_lookup(ipc_callid_t rid, ipc_call_t *request) |
558 | { |
582 | { |
559 | libfs_lookup(&fat_libfs_ops, fat_reg.fs_handle, rid, request); |
583 | libfs_lookup(&fat_libfs_ops, fat_reg.fs_handle, rid, request); |
560 | } |
584 | } |
561 | 585 | ||
562 | void fat_read(ipc_callid_t rid, ipc_call_t *request) |
586 | void fat_read(ipc_callid_t rid, ipc_call_t *request) |
563 | { |
587 | { |
564 | dev_handle_t dev_handle = (dev_handle_t)IPC_GET_ARG1(*request); |
588 | dev_handle_t dev_handle = (dev_handle_t)IPC_GET_ARG1(*request); |
565 | fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request); |
589 | fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request); |
566 | off_t pos = (off_t)IPC_GET_ARG3(*request); |
590 | off_t pos = (off_t)IPC_GET_ARG3(*request); |
567 | fat_node_t *nodep = (fat_node_t *)fat_node_get(dev_handle, index); |
591 | fat_node_t *nodep = (fat_node_t *)fat_node_get(dev_handle, index); |
568 | uint16_t bps; |
592 | uint16_t bps; |
569 | size_t bytes; |
593 | size_t bytes; |
570 | block_t *bb, *b; |
594 | block_t *bb, *b; |
571 | 595 | ||
572 | if (!nodep) { |
596 | if (!nodep) { |
573 | ipc_answer_0(rid, ENOENT); |
597 | ipc_answer_0(rid, ENOENT); |
574 | return; |
598 | return; |
575 | } |
599 | } |
576 | 600 | ||
577 | ipc_callid_t callid; |
601 | ipc_callid_t callid; |
578 | size_t len; |
602 | size_t len; |
579 | if (!ipc_data_read_receive(&callid, &len)) { |
603 | if (!ipc_data_read_receive(&callid, &len)) { |
580 | fat_node_put(nodep); |
604 | fat_node_put(nodep); |
581 | ipc_answer_0(callid, EINVAL); |
605 | ipc_answer_0(callid, EINVAL); |
582 | ipc_answer_0(rid, EINVAL); |
606 | ipc_answer_0(rid, EINVAL); |
583 | return; |
607 | return; |
584 | } |
608 | } |
585 | 609 | ||
586 | bb = block_get(dev_handle, BS_BLOCK, BS_SIZE); |
610 | bb = block_get(dev_handle, BS_BLOCK, BS_SIZE); |
587 | bps = uint16_t_le2host(FAT_BS(bb)->bps); |
611 | bps = uint16_t_le2host(FAT_BS(bb)->bps); |
588 | 612 | ||
589 | if (nodep->type == FAT_FILE) { |
613 | if (nodep->type == FAT_FILE) { |
590 | /* |
614 | /* |
591 | * Our strategy for regular file reads is to read one block at |
615 | * Our strategy for regular file reads is to read one block at |
592 | * most and make use of the possibility to return less data than |
616 | * most and make use of the possibility to return less data than |
593 | * requested. This keeps the code very simple. |
617 | * requested. This keeps the code very simple. |
594 | */ |
618 | */ |
595 | bytes = min(len, bps - pos % bps); |
619 | bytes = min(len, bps - pos % bps); |
596 | b = fat_block_get(bb->data, nodep, pos / bps); |
620 | b = fat_block_get(bb->data, nodep, pos / bps); |
597 | (void) ipc_data_read_finalize(callid, b->data + pos % bps, |
621 | (void) ipc_data_read_finalize(callid, b->data + pos % bps, |
598 | bytes); |
622 | bytes); |
599 | block_put(b); |
623 | block_put(b); |
600 | } else { |
624 | } else { |
601 | unsigned bnum; |
625 | unsigned bnum; |
602 | off_t spos = pos; |
626 | off_t spos = pos; |
603 | char name[FAT_NAME_LEN + 1 + FAT_EXT_LEN + 1]; |
627 | char name[FAT_NAME_LEN + 1 + FAT_EXT_LEN + 1]; |
604 | fat_dentry_t *d; |
628 | fat_dentry_t *d; |
605 | 629 | ||
606 | assert(nodep->type == FAT_DIRECTORY); |
630 | assert(nodep->type == FAT_DIRECTORY); |
607 | assert(nodep->size % bps == 0); |
631 | assert(nodep->size % bps == 0); |
608 | assert(bps % sizeof(fat_dentry_t) == 0); |
632 | assert(bps % sizeof(fat_dentry_t) == 0); |
609 | 633 | ||
610 | /* |
634 | /* |
611 | * Our strategy for readdir() is to use the position pointer as |
635 | * Our strategy for readdir() is to use the position pointer as |
612 | * an index into the array of all dentries. On entry, it points |
636 | * an index into the array of all dentries. On entry, it points |
613 | * to the first unread dentry. If we skip any dentries, we bump |
637 | * to the first unread dentry. If we skip any dentries, we bump |
614 | * the position pointer accordingly. |
638 | * the position pointer accordingly. |
615 | */ |
639 | */ |
616 | bnum = (pos * sizeof(fat_dentry_t)) / bps; |
640 | bnum = (pos * sizeof(fat_dentry_t)) / bps; |
617 | while (bnum < nodep->size / bps) { |
641 | while (bnum < nodep->size / bps) { |
618 | off_t o; |
642 | off_t o; |
619 | 643 | ||
620 | b = fat_block_get(bb->data, nodep, bnum); |
644 | b = fat_block_get(bb->data, nodep, bnum); |
621 | for (o = pos % (bps / sizeof(fat_dentry_t)); |
645 | for (o = pos % (bps / sizeof(fat_dentry_t)); |
622 | o < bps / sizeof(fat_dentry_t); |
646 | o < bps / sizeof(fat_dentry_t); |
623 | o++, pos++) { |
647 | o++, pos++) { |
624 | d = ((fat_dentry_t *)b->data) + o; |
648 | d = ((fat_dentry_t *)b->data) + o; |
625 | switch (fat_classify_dentry(d)) { |
649 | switch (fat_classify_dentry(d)) { |
626 | case FAT_DENTRY_SKIP: |
650 | case FAT_DENTRY_SKIP: |
627 | continue; |
651 | continue; |
628 | case FAT_DENTRY_LAST: |
652 | case FAT_DENTRY_LAST: |
629 | block_put(b); |
653 | block_put(b); |
630 | goto miss; |
654 | goto miss; |
631 | default: |
655 | default: |
632 | case FAT_DENTRY_VALID: |
656 | case FAT_DENTRY_VALID: |
633 | dentry_name_canonify(d, name); |
657 | dentry_name_canonify(d, name); |
634 | block_put(b); |
658 | block_put(b); |
635 | goto hit; |
659 | goto hit; |
636 | } |
660 | } |
637 | } |
661 | } |
638 | block_put(b); |
662 | block_put(b); |
639 | bnum++; |
663 | bnum++; |
640 | } |
664 | } |
641 | miss: |
665 | miss: |
642 | fat_node_put(nodep); |
666 | fat_node_put(nodep); |
643 | block_put(bb); |
667 | block_put(bb); |
644 | ipc_answer_0(callid, ENOENT); |
668 | ipc_answer_0(callid, ENOENT); |
645 | ipc_answer_1(rid, ENOENT, 0); |
669 | ipc_answer_1(rid, ENOENT, 0); |
646 | return; |
670 | return; |
647 | hit: |
671 | hit: |
648 | (void) ipc_data_read_finalize(callid, name, strlen(name) + 1); |
672 | (void) ipc_data_read_finalize(callid, name, strlen(name) + 1); |
649 | bytes = (pos - spos) + 1; |
673 | bytes = (pos - spos) + 1; |
650 | } |
674 | } |
651 | 675 | ||
652 | fat_node_put(nodep); |
676 | fat_node_put(nodep); |
653 | block_put(bb); |
677 | block_put(bb); |
654 | ipc_answer_1(rid, EOK, (ipcarg_t)bytes); |
678 | ipc_answer_1(rid, EOK, (ipcarg_t)bytes); |
655 | } |
679 | } |
656 | 680 | ||
657 | void fat_write(ipc_callid_t rid, ipc_call_t *request) |
681 | void fat_write(ipc_callid_t rid, ipc_call_t *request) |
658 | { |
682 | { |
659 | dev_handle_t dev_handle = (dev_handle_t)IPC_GET_ARG1(*request); |
683 | dev_handle_t dev_handle = (dev_handle_t)IPC_GET_ARG1(*request); |
660 | fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request); |
684 | fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request); |
661 | off_t pos = (off_t)IPC_GET_ARG3(*request); |
685 | off_t pos = (off_t)IPC_GET_ARG3(*request); |
662 | fat_node_t *nodep = (fat_node_t *)fat_node_get(dev_handle, index); |
686 | fat_node_t *nodep = (fat_node_t *)fat_node_get(dev_handle, index); |
663 | size_t bytes; |
687 | size_t bytes; |
664 | block_t *b, *bb; |
688 | block_t *b, *bb; |
665 | uint16_t bps; |
689 | uint16_t bps; |
666 | unsigned spc; |
690 | unsigned spc; |
667 | off_t boundary; |
691 | off_t boundary; |
668 | 692 | ||
669 | if (!nodep) { |
693 | if (!nodep) { |
670 | ipc_answer_0(rid, ENOENT); |
694 | ipc_answer_0(rid, ENOENT); |
671 | return; |
695 | return; |
672 | } |
696 | } |
673 | 697 | ||
674 | /* XXX remove me when you are ready */ |
698 | /* XXX remove me when you are ready */ |
675 | { |
699 | { |
676 | ipc_answer_0(rid, ENOTSUP); |
700 | ipc_answer_0(rid, ENOTSUP); |
677 | fat_node_put(nodep); |
701 | fat_node_put(nodep); |
678 | return; |
702 | return; |
679 | } |
703 | } |
680 | 704 | ||
681 | ipc_callid_t callid; |
705 | ipc_callid_t callid; |
682 | size_t len; |
706 | size_t len; |
683 | if (!ipc_data_write_receive(&callid, &len)) { |
707 | if (!ipc_data_write_receive(&callid, &len)) { |
684 | fat_node_put(nodep); |
708 | fat_node_put(nodep); |
685 | ipc_answer_0(callid, EINVAL); |
709 | ipc_answer_0(callid, EINVAL); |
686 | ipc_answer_0(rid, EINVAL); |
710 | ipc_answer_0(rid, EINVAL); |
687 | return; |
711 | return; |
688 | } |
712 | } |
689 | 713 | ||
690 | /* |
714 | /* |
691 | * In all scenarios, we will attempt to write out only one block worth |
715 | * In all scenarios, we will attempt to write out only one block worth |
692 | * of data at maximum. There might be some more efficient approaches, |
716 | * of data at maximum. There might be some more efficient approaches, |
693 | * but this one greatly simplifies fat_write(). Note that we can afford |
717 | * but this one greatly simplifies fat_write(). Note that we can afford |
694 | * to do this because the client must be ready to handle the return |
718 | * to do this because the client must be ready to handle the return |
695 | * value signalizing a smaller number of bytes written. |
719 | * value signalizing a smaller number of bytes written. |
696 | */ |
720 | */ |
697 | bytes = min(len, bps - pos % bps); |
721 | bytes = min(len, bps - pos % bps); |
698 | 722 | ||
699 | bb = block_get(dev_handle, BS_BLOCK, BS_SIZE); |
723 | bb = block_get(dev_handle, BS_BLOCK, BS_SIZE); |
700 | bps = uint16_t_le2host(FAT_BS(bb)->bps); |
724 | bps = uint16_t_le2host(FAT_BS(bb)->bps); |
701 | spc = FAT_BS(bb)->spc; |
725 | spc = FAT_BS(bb)->spc; |
702 | 726 | ||
703 | boundary = ROUND_UP(nodep->size, bps * spc); |
727 | boundary = ROUND_UP(nodep->size, bps * spc); |
704 | if (pos < boundary) { |
728 | if (pos < boundary) { |
705 | /* |
729 | /* |
706 | * This is the easier case - we are either overwriting already |
730 | * This is the easier case - we are either overwriting already |
707 | * existing contents or writing behind the EOF, but still within |
731 | * existing contents or writing behind the EOF, but still within |
708 | * the limits of the last cluster. The node size may grow to the |
732 | * the limits of the last cluster. The node size may grow to the |
709 | * next block size boundary. |
733 | * next block size boundary. |
710 | */ |
734 | */ |
711 | fat_fill_gap(bb->data, nodep, FAT_CLST_RES0, pos); |
735 | fat_fill_gap(bb->data, nodep, FAT_CLST_RES0, pos); |
712 | b = fat_block_get(bb->data, nodep, pos / bps); |
736 | b = fat_block_get(bb->data, nodep, pos / bps); |
713 | (void) ipc_data_write_finalize(callid, b->data + pos % bps, |
737 | (void) ipc_data_write_finalize(callid, b->data + pos % bps, |
714 | bytes); |
738 | bytes); |
715 | b->dirty = true; /* need to sync block */ |
739 | b->dirty = true; /* need to sync block */ |
716 | block_put(b); |
740 | block_put(b); |
717 | if (pos + bytes > nodep->size) { |
741 | if (pos + bytes > nodep->size) { |
718 | nodep->size = pos + bytes; |
742 | nodep->size = pos + bytes; |
719 | nodep->dirty = true; /* need to sync node */ |
743 | nodep->dirty = true; /* need to sync node */ |
720 | } |
744 | } |
721 | fat_node_put(nodep); |
745 | fat_node_put(nodep); |
722 | block_put(bb); |
746 | block_put(bb); |
723 | ipc_answer_1(rid, EOK, bytes); |
747 | ipc_answer_1(rid, EOK, bytes); |
724 | return; |
748 | return; |
725 | } else { |
749 | } else { |
726 | /* |
750 | /* |
727 | * This is the more difficult case. We must allocate new |
751 | * This is the more difficult case. We must allocate new |
728 | * clusters for the node and zero them out. |
752 | * clusters for the node and zero them out. |
729 | */ |
753 | */ |
730 | int status; |
754 | int status; |
731 | unsigned nclsts; |
755 | unsigned nclsts; |
732 | fat_cluster_t mcl, lcl; |
756 | fat_cluster_t mcl, lcl; |
733 | 757 | ||
734 | nclsts = (ROUND_UP(pos + bytes, bps * spc) - boundary) / |
758 | nclsts = (ROUND_UP(pos + bytes, bps * spc) - boundary) / |
735 | bps * spc; |
759 | bps * spc; |
736 | /* create an independent chain of nclsts clusters in all FATs */ |
760 | /* create an independent chain of nclsts clusters in all FATs */ |
737 | status = fat_alloc_clusters(bb->data, dev_handle, nclsts, &mcl, |
761 | status = fat_alloc_clusters(bb->data, dev_handle, nclsts, &mcl, |
738 | &lcl); |
762 | &lcl); |
739 | if (status != EOK) { |
763 | if (status != EOK) { |
740 | /* could not allocate a chain of nclsts clusters */ |
764 | /* could not allocate a chain of nclsts clusters */ |
741 | fat_node_put(nodep); |
765 | fat_node_put(nodep); |
742 | block_put(bb); |
766 | block_put(bb); |
743 | ipc_answer_0(callid, status); |
767 | ipc_answer_0(callid, status); |
744 | ipc_answer_0(rid, status); |
768 | ipc_answer_0(rid, status); |
745 | return; |
769 | return; |
746 | } |
770 | } |
747 | /* zero fill any gaps */ |
771 | /* zero fill any gaps */ |
748 | fat_fill_gap(bb->data, nodep, mcl, pos); |
772 | fat_fill_gap(bb->data, nodep, mcl, pos); |
749 | b = _fat_block_get(bb->data, dev_handle, lcl, |
773 | b = _fat_block_get(bb->data, dev_handle, lcl, |
750 | (pos / bps) % spc); |
774 | (pos / bps) % spc); |
751 | (void) ipc_data_write_finalize(callid, b->data + pos % bps, |
775 | (void) ipc_data_write_finalize(callid, b->data + pos % bps, |
752 | bytes); |
776 | bytes); |
753 | b->dirty = true; /* need to sync block */ |
777 | b->dirty = true; /* need to sync block */ |
754 | block_put(b); |
778 | block_put(b); |
755 | /* |
779 | /* |
756 | * Append the cluster chain starting in mcl to the end of the |
780 | * Append the cluster chain starting in mcl to the end of the |
757 | * node's cluster chain. |
781 | * node's cluster chain. |
758 | */ |
782 | */ |
759 | fat_append_clusters(bb->data, nodep, mcl); |
783 | fat_append_clusters(bb->data, nodep, mcl); |
760 | nodep->size = pos + bytes; |
784 | nodep->size = pos + bytes; |
761 | nodep->dirty = true; /* need to sync node */ |
785 | nodep->dirty = true; /* need to sync node */ |
762 | fat_node_put(nodep); |
786 | fat_node_put(nodep); |
763 | block_put(bb); |
787 | block_put(bb); |
764 | ipc_answer_1(rid, EOK, bytes); |
788 | ipc_answer_1(rid, EOK, bytes); |
765 | return; |
789 | return; |
766 | } |
790 | } |
767 | } |
791 | } |
768 | 792 | ||
769 | /** |
793 | /** |
770 | * @} |
794 | * @} |
771 | */ |
795 | */ |
772 | 796 |