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