Subversion Repositories HelenOS

Rev

Rev 3547 | Rev 3550 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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