void exfat_put_node(struct exfat* ef, struct exfat_node* node)
{
	if (--node->references < 0)
	{
		char buffer[UTF8_BYTES(EXFAT_NAME_MAX) + 1];
		exfat_get_name(node, buffer, sizeof(buffer) - 1);
		exfat_bug("reference counter of `%s' is below zero", buffer);
	}

	if (node->references == 0)
	{
		/* FIXME handle I/O error */
		if (exfat_flush_node(ef, node) != 0)
			exfat_bug("node flush failed");
		if (node->flags & EXFAT_ATTRIB_UNLINKED)
		{
			/* free all clusters and node structure itself */
			exfat_truncate(ef, node, 0, true);
			free(node);
		}
		/* FIXME handle I/O error */
		if (exfat_flush(ef) != 0)
			exfat_bug("flush failed");
	}
}
static int fuse_exfat_fsync(const char* path, int datasync,
		struct fuse_file_info *fi)
{
	int rc;

	exfat_debug("[%s] %s", __func__, path);
	rc = exfat_flush(&ef);
	if (rc != 0)
		return rc;
	return exfat_fsync(ef.dev);
}
Beispiel #3
0
void exfat_unmount(struct exfat* ef)
{
	exfat_flush_nodes(ef);	/* ignore return code */
	exfat_flush(ef);		/* ignore return code */
	exfat_put_node(ef, ef->root);
	exfat_reset_cache(ef);
	free(ef->root);
	ef->root = NULL;
	finalize_super_block(ef);
	exfat_close(ef->dev);	/* close descriptor immediately after fsync */
	ef->dev = NULL;
	free(ef->zero_cluster);
	ef->zero_cluster = NULL;
	free(ef->cmap.chunk);
	ef->cmap.chunk = NULL;
	free(ef->sb);
	ef->sb = NULL;
	free(ef->upcase);
	ef->upcase = NULL;
	ef->upcase_chars = 0;
}
Beispiel #4
0
int exfat_flush_node(struct exfat* ef, struct exfat_node* node)
{
	cluster_t cluster;
	off_t offset;
	off_t meta1_offset, meta2_offset;
	struct exfat_entry_meta1 meta1;
	struct exfat_entry_meta2 meta2;

	if (!(node->flags & EXFAT_ATTRIB_DIRTY))
		return 0; /* no need to flush */

	if (ef->ro)
		exfat_bug("unable to flush node to read-only FS");

	if (node->parent == NULL)
		return 0; /* do not flush unlinked node */

	cluster = node->entry_cluster;
	offset = node->entry_offset;
	meta1_offset = co2o(ef, cluster, offset);
	if (!next_entry(ef, node->parent, &cluster, &offset))
		return -EIO;
	meta2_offset = co2o(ef, cluster, offset);

	if (exfat_pread(ef->dev, &meta1, sizeof(meta1), meta1_offset) < 0)
	{
		exfat_error("failed to read meta1 entry on flush");
		return -EIO;
	}
	if (meta1.type != EXFAT_ENTRY_FILE)
		exfat_bug("invalid type of meta1: 0x%hhx", meta1.type);
	meta1.attrib = cpu_to_le16(node->flags);
	exfat_unix2exfat(node->mtime, &meta1.mdate, &meta1.mtime, &meta1.mtime_cs);
	exfat_unix2exfat(node->atime, &meta1.adate, &meta1.atime, NULL);

	if (exfat_pread(ef->dev, &meta2, sizeof(meta2), meta2_offset) < 0)
	{
		exfat_error("failed to read meta2 entry on flush");
		return -EIO;
	}
	if (meta2.type != EXFAT_ENTRY_FILE_INFO)
		exfat_bug("invalid type of meta2: 0x%hhx", meta2.type);
	meta2.size = meta2.valid_size = cpu_to_le64(node->size);
	meta2.start_cluster = cpu_to_le32(node->start_cluster);
	meta2.flags = EXFAT_FLAG_ALWAYS1;
	/* empty files must not be marked as contiguous */
	if (node->size != 0 && IS_CONTIGUOUS(*node))
		meta2.flags |= EXFAT_FLAG_CONTIGUOUS;
	/* name hash remains unchanged, no need to recalculate it */

	meta1.checksum = exfat_calc_checksum(&meta1, &meta2, node->name);

	if (exfat_pwrite(ef->dev, &meta1, sizeof(meta1), meta1_offset) < 0)
	{
		exfat_error("failed to write meta1 entry on flush");
		return -EIO;
	}
	if (exfat_pwrite(ef->dev, &meta2, sizeof(meta2), meta2_offset) < 0)
	{
		exfat_error("failed to write meta2 entry on flush");
		return -EIO;
	}

	node->flags &= ~EXFAT_ATTRIB_DIRTY;
	return exfat_flush(ef);
}