Ejemplo n.º 1
0
static int fat_node_sync(fat_node_t *node)
{
	block_t *b;
	fat_bs_t *bs;
	fat_dentry_t *d;
	int rc;

	assert(node->dirty);

	bs = block_bb_get(node->idx->service_id);

	/* Read the block that contains the dentry of interest. */
	rc = _fat_block_get(&b, bs, node->idx->service_id, node->idx->pfc,
	    NULL, (node->idx->pdi * sizeof(fat_dentry_t)) / BPS(bs),
	    BLOCK_FLAGS_NONE);
	if (rc != EOK)
		return rc;

	d = ((fat_dentry_t *)b->data) + (node->idx->pdi % DPS(bs));

	d->firstc = host2uint16_t_le(node->firstc);
	if (node->type == FAT_FILE) {
		d->size = host2uint32_t_le(node->size);
	} else if (node->type == FAT_DIRECTORY) {
		d->attr = FAT_ATTR_SUBDIR;
	}

	/* TODO: update other fields? (e.g time fields) */

	b->dirty = true;		/* need to sync block */
	rc = block_put(b);
	return rc;
}
Ejemplo n.º 2
0
/** Read block from file located on a FAT file system.
 *
 * @param block		Pointer to a block pointer for storing result.
 * @param bs		Buffer holding the boot sector of the file system.
 * @param nodep		FAT node.
 * @param bn		Block number.
 * @param flags		Flags passed to libblock.
 *
 * @return		EOK on success or a negative error code.
 */
int
fat_block_get(block_t **block, struct fat_bs *bs, fat_node_t *nodep,
    aoff64_t bn, int flags)
{
	fat_cluster_t firstc = nodep->firstc;
	fat_cluster_t currc;
	aoff64_t relbn = bn;
	int rc;

	if (!nodep->size)
		return ELIMIT;

	if (!FAT_IS_FAT32(bs) && nodep->firstc == FAT_CLST_ROOT)
		goto fall_through;

	if (((((nodep->size - 1) / BPS(bs)) / SPC(bs)) == bn / SPC(bs)) &&
	    nodep->lastc_cached_valid) {
	    	/*
		 * This is a request to read a block within the last cluster
		 * when fortunately we have the last cluster number cached.
		 */
		return block_get(block, nodep->idx->service_id,
		    CLBN2PBN(bs, nodep->lastc_cached_value, bn), flags);
	}

	if (nodep->currc_cached_valid && bn >= nodep->currc_cached_bn) {
		/*
		 * We can start with the cluster cached by the previous call to
		 * fat_block_get().
		 */
		firstc = nodep->currc_cached_value;
		relbn -= (nodep->currc_cached_bn / SPC(bs)) * SPC(bs);
	}

fall_through:
	rc = _fat_block_get(block, bs, nodep->idx->service_id, firstc,
	    &currc, relbn, flags);
	if (rc != EOK)
		return rc;

	/*
	 * Update the "current" cluster cache.
	 */
	nodep->currc_cached_valid = true;
	nodep->currc_cached_bn = bn;
	nodep->currc_cached_value = currc;

	return rc;
}
Ejemplo n.º 3
0
/** Fill the gap between EOF and a new file position.
 *
 * @param bs		Buffer holding the boot sector for nodep.
 * @param nodep		FAT node with the gap.
 * @param mcl		First cluster in an independent cluster chain that will
 *			be later appended to the end of the node's own cluster
 *			chain. If pos is still in the last allocated cluster,
 *			this argument is ignored.
 * @param pos		Position in the last node block.
 *
 * @return		EOK on success or a negative error code.
 */
int
fat_fill_gap(fat_bs_t *bs, fat_node_t *nodep, fat_cluster_t mcl, aoff64_t pos)
{
	block_t *b;
	aoff64_t o, boundary;
	int rc;

	boundary = ROUND_UP(nodep->size, BPS(bs) * SPC(bs));

	/* zero out already allocated space */
	for (o = nodep->size; o < pos && o < boundary;
	    o = ALIGN_DOWN(o + BPS(bs), BPS(bs))) {
	    	int flags = (o % BPS(bs) == 0) ?
		    BLOCK_FLAGS_NOREAD : BLOCK_FLAGS_NONE;
		rc = fat_block_get(&b, bs, nodep, o / BPS(bs), flags);
		if (rc != EOK)
			return rc;
		memset(b->data + o % BPS(bs), 0, BPS(bs) - o % BPS(bs));
		b->dirty = true;		/* need to sync node */
		rc = block_put(b);
		if (rc != EOK)
			return rc;
	}

	if (o >= pos)
		return EOK;

	/* zero out the initial part of the new cluster chain */
	for (o = boundary; o < pos; o += BPS(bs)) {
		rc = _fat_block_get(&b, bs, nodep->idx->service_id, mcl,
		    NULL, (o - boundary) / BPS(bs), BLOCK_FLAGS_NOREAD);
		if (rc != EOK)
			return rc;
		memset(b->data, 0, min(BPS(bs), pos - o));
		b->dirty = true;		/* need to sync node */
		rc = block_put(b);
		if (rc != EOK)
			return rc;
	}

	return EOK;
}