Ejemplo n.º 1
0
static bool erase_entry(struct exfat* ef, struct exfat_node* node)
{
	cluster_t cluster = node->entry_cluster;
	off64_t offset = node->entry_offset;
	int name_entries = DIV_ROUND_UP(utf16_length(node->name), EXFAT_ENAME_MAX);
	uint8_t entry_type;

	entry_type = EXFAT_ENTRY_FILE & ~EXFAT_ENTRY_VALID;
	if (exfat_pwrite(ef->dev, &entry_type, 1, co2o(ef, cluster, offset)) < 0)
	{
		exfat_error("failed to erase meta1 entry");
		return false;
	}

	next_entry(ef, node->parent, &cluster, &offset);
	entry_type = EXFAT_ENTRY_FILE_INFO & ~EXFAT_ENTRY_VALID;
	if (exfat_pwrite(ef->dev, &entry_type, 1, co2o(ef, cluster, offset)) < 0)
	{
		exfat_error("failed to erase meta2 entry");
		return false;
	}

	while (name_entries--)
	{
		next_entry(ef, node->parent, &cluster, &offset);
		entry_type = EXFAT_ENTRY_FILE_NAME & ~EXFAT_ENTRY_VALID;
		if (exfat_pwrite(ef->dev, &entry_type, 1,
				co2o(ef, cluster, offset)) < 0)
		{
			exfat_error("failed to erase name entry");
			return false;
		}
	}
	return true;
}
Ejemplo n.º 2
0
static int shrink_directory(struct exfat* ef, struct exfat_node* dir,
                            off64_t deleted_offset)
{
    const struct exfat_node* node;
    const struct exfat_node* last_node;
    uint64_t entries = 1; /* a directory always has at leat 1 entry (EOD) */
    uint64_t new_size;
    struct exfat_entry eod;
    off64_t eod_offset;
    int rc;

    if (!(dir->flags & EXFAT_ATTRIB_DIR))
        exfat_bug("attempted to shrink a file");
    if (!(dir->flags & EXFAT_ATTRIB_CACHED))
        exfat_bug("attempted to shrink uncached directory");

    for (last_node = node = dir->child; node; node = node->next)
    {
        if (deleted_offset < node->entry_offset)
        {
            /* there are other entries after the removed one, no way to shrink
               this directory */
            return 0;
        }
        if (last_node->entry_offset < node->entry_offset)
            last_node = node;
    }

    if (last_node)
    {
        /* offset of the last entry */
        entries += last_node->entry_offset / sizeof(struct exfat_entry);
        /* two subentries with meta info */
        entries += 2;
        /* subentries with file name */
        entries += DIV_ROUND_UP(utf16_length(last_node->name),
                                EXFAT_ENAME_MAX);
    }

    new_size = DIV_ROUND_UP(entries * sizeof(struct exfat_entry),
                            CLUSTER_SIZE(*ef->sb)) * CLUSTER_SIZE(*ef->sb);
    if (new_size == dir->size)
        return 0;
    rc = exfat_truncate(ef, dir, new_size);
    if (rc != 0)
        return rc;

    /* put EOD entry at the end of the last cluster */
    memset(&eod, 0, sizeof(eod));
    eod_offset = new_size - sizeof(struct exfat_entry);
    if (last_node)
        exfat_write_raw(&eod, sizeof(eod),
                        co2o(ef, last_node->entry_cluster, eod_offset), ef->fd);
    else
        exfat_write_raw(&eod, sizeof(eod),
                        co2o(ef, dir->start_cluster, eod_offset), ef->fd);
    return 0;
}
Ejemplo n.º 3
0
static int shrink_directory(struct exfat* ef, struct exfat_node* dir,
		off64_t deleted_offset)
{
	const struct exfat_node* node;
	const struct exfat_node* last_node;
	uint64_t entries = 0;
	uint64_t new_size;
	int rc;

	if (!(dir->flags & EXFAT_ATTRIB_DIR))
		exfat_bug("attempted to shrink a file");
	if (!(dir->flags & EXFAT_ATTRIB_CACHED))
		exfat_bug("attempted to shrink uncached directory");

	for (last_node = node = dir->child; node; node = node->next)
	{
		if (deleted_offset < node->entry_offset)
		{
			/* there are other entries after the removed one, no way to shrink
			   this directory */
			return 0;
		}
		if (last_node->entry_offset < node->entry_offset)
			last_node = node;
	}

	if (last_node)
	{
		/* offset of the last entry */
		entries += last_node->entry_offset / sizeof(struct exfat_entry);
		/* two subentries with meta info */
		entries += 2;
		/* subentries with file name */
		entries += DIV_ROUND_UP(utf16_length(last_node->name),
				EXFAT_ENAME_MAX);
	}

	new_size = DIV_ROUND_UP(entries * sizeof(struct exfat_entry),
				 CLUSTER_SIZE(*ef->sb)) * CLUSTER_SIZE(*ef->sb);
	if (new_size == 0) /* directory always has at least 1 cluster */
		new_size = CLUSTER_SIZE(*ef->sb);
	if (new_size == dir->size)
		return 0;
	rc = exfat_truncate(ef, dir, new_size, true);
	if (rc != 0)
		return rc;
	return 0;
}
Ejemplo n.º 4
0
static void erase_entry(struct exfat* ef, struct exfat_node* node)
{
    cluster_t cluster = node->entry_cluster;
    off64_t offset = node->entry_offset;
    int name_entries = DIV_ROUND_UP(utf16_length(node->name), EXFAT_ENAME_MAX);
    uint8_t entry_type;

    entry_type = EXFAT_ENTRY_FILE & ~EXFAT_ENTRY_VALID;
    exfat_write_raw(&entry_type, 1, co2o(ef, cluster, offset), ef->fd);

    next_entry(ef, node->parent, &cluster, &offset);
    entry_type = EXFAT_ENTRY_FILE_INFO & ~EXFAT_ENTRY_VALID;
    exfat_write_raw(&entry_type, 1, co2o(ef, cluster, offset), ef->fd);

    while (name_entries--)
    {
        next_entry(ef, node->parent, &cluster, &offset);
        entry_type = EXFAT_ENTRY_FILE_NAME & ~EXFAT_ENTRY_VALID;
        exfat_write_raw(&entry_type, 1, co2o(ef, cluster, offset), ef->fd);
    }
}
Ejemplo n.º 5
0
int fat_directory_write(fat_directory_t *di, const char *name, fat_dentry_t *de)
{
	int rc;
	void *data;
	fat_instance_t *instance;

	rc = fs_instance_get(di->nodep->idx->service_id, &data);
	assert(rc == EOK);
	instance = (fat_instance_t *) data;
	
	if (fat_valid_short_name(name)) {
		/*
		 * NAME could be directly stored in dentry without creating
		 * LFN.
		 */
		fat_dentry_name_set(de, name);
		if (fat_directory_is_sfn_exist(di, de))
			return EEXIST;
		rc = fat_directory_lookup_free(di, 1);
		if (rc != EOK)
			return rc;
		rc = fat_directory_write_dentry(di, de);
		return rc;
	} else if (instance->lfn_enabled && fat_valid_name(name)) {
		/* We should create long entries to store name */
		int long_entry_count;
		uint8_t checksum;
		uint16_t wname[FAT_LFN_NAME_SIZE];
		size_t lfn_size, lfn_offset;
		
		rc = str_to_utf16(wname, FAT_LFN_NAME_SIZE, name);
		if (rc != EOK)
			return rc;
		
		lfn_size = utf16_length(wname);
		long_entry_count = lfn_size / FAT_LFN_ENTRY_SIZE;
		if (lfn_size % FAT_LFN_ENTRY_SIZE)
			long_entry_count++;
		rc = fat_directory_lookup_free(di, long_entry_count + 1);
		if (rc != EOK)
			return rc;
		aoff64_t start_pos = di->pos;

		/* Write Short entry */
		rc = fat_directory_create_sfn(di, de, name);
		if (rc != EOK)
			return rc;
		checksum = fat_dentry_chksum(de->name);

		rc = fat_directory_seek(di, start_pos + long_entry_count);
		if (rc != EOK)
			return rc;
		rc = fat_directory_write_dentry(di, de);
		if (rc != EOK)
			return rc;

		/* Write Long entry by parts */
		lfn_offset = 0;
		fat_dentry_t *d;
		size_t idx = 0;
		do {
			rc = fat_directory_prev(di);
			if (rc != EOK)
				return rc;
			rc = fat_directory_get(di, &d);
			if (rc != EOK)
				return rc;
			fat_lfn_set_entry(wname, &lfn_offset, lfn_size + 1, d);
			FAT_LFN_CHKSUM(d) = checksum;
			FAT_LFN_ORDER(d) = ++idx;
			di->b->dirty = true;
		} while (lfn_offset < lfn_size);
		FAT_LFN_ORDER(d) |= FAT_LFN_LAST;

		rc = fat_directory_seek(di, start_pos + long_entry_count);
		return rc;
	}

	return ENOTSUP;
}