/*
- * cluster.c
- * exFAT file system implementation library.
- *
- * Created by Andrew Nayenko on 03.09.09.
- * This software is distributed under the GNU General Public License
- * version 3 or any later.
- */
+ cluster.c (03.09.09)
+ exFAT file system implementation library.
+
+ Copyright (C) 2009, 2010 Andrew Nayenko
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
#include "exfat.h"
#include <errno.h>
}
cluster_t exfat_advance_cluster(const struct exfat* ef,
- const struct exfat_node* node, cluster_t cluster, uint32_t count)
+ struct exfat_node* node, uint32_t count)
{
uint32_t i;
- for (i = 0; i < count; i++)
+ if (node->fptr_index > count)
+ {
+ node->fptr_index = 0;
+ node->fptr_cluster = node->start_cluster;
+ }
+
+ for (i = node->fptr_index; i < count; i++)
{
- cluster = exfat_next_cluster(ef, node, cluster);
- if (CLUSTER_INVALID(cluster))
+ node->fptr_cluster = exfat_next_cluster(ef, node, node->fptr_cluster);
+ if (CLUSTER_INVALID(node->fptr_cluster))
break;
}
- return cluster;
+ node->fptr_index = count;
+ return node->fptr_cluster;
}
static cluster_t find_bit_and_set(uint8_t* bitmap, cluster_t start,
return EXFAT_CLUSTER_END;
}
-static void flush_cmap(struct exfat* ef)
+void exfat_flush_cmap(struct exfat* ef)
{
exfat_write_raw(ef->cmap.chunk, (ef->cmap.chunk_size + 7) / 8,
exfat_c2o(ef, ef->cmap.start_cluster), ef->fd);
+ ef->cmap.dirty = 0;
}
static void set_next_cluster(const struct exfat* ef, int contiguous,
exfat_c2o(ef, cluster) + i * block_size, ef->fd);
}
-static cluster_t allocate_cluster(struct exfat* ef)
+static cluster_t allocate_cluster(struct exfat* ef, cluster_t hint)
{
- cluster_t cluster = find_bit_and_set(ef->cmap.chunk, 0,
- ef->cmap.chunk_size);
+ cluster_t cluster;
+ hint -= EXFAT_FIRST_DATA_CLUSTER;
+ if (hint >= ef->cmap.chunk_size)
+ hint = 0;
+
+ cluster = find_bit_and_set(ef->cmap.chunk, hint, ef->cmap.chunk_size);
+ if (cluster == EXFAT_CLUSTER_END)
+ cluster = find_bit_and_set(ef->cmap.chunk, 0, hint);
if (cluster == EXFAT_CLUSTER_END)
{
exfat_error("no free space left");
}
erase_cluster(ef, cluster);
- /* FIXME no need to flush immediately */
- flush_cmap(ef);
+ ef->cmap.dirty = 1;
/* FIXME update percentage of used space */
return cluster;
}
{
if (CLUSTER_INVALID(cluster))
exfat_bug("attempting to free invalid cluster");
+ if (cluster < EXFAT_FIRST_DATA_CLUSTER ||
+ cluster - EXFAT_FIRST_DATA_CLUSTER >= ef->cmap.size)
+ exfat_bug("bad cluster 0x%x (0x%x)", cluster, ef->cmap.size);
- if (cluster < EXFAT_FIRST_DATA_CLUSTER)
- exfat_bug("bad cluster 0x%x", cluster);
BMAP_CLR(ef->cmap.chunk, cluster - EXFAT_FIRST_DATA_CLUSTER);
- /* FIXME no need to flush immediately */
- flush_cmap(ef);
+ ef->cmap.dirty = 1;
+ /* FIXME update percentage of used space */
}
static void make_noncontiguous(const struct exfat* ef, cluster_t first,
if (node->start_cluster != EXFAT_CLUSTER_FREE)
{
/* get the last cluster of the file */
- previous = exfat_advance_cluster(ef, node, node->start_cluster,
+ previous = exfat_advance_cluster(ef, node,
bytes2clusters(ef, node->size) - 1);
if (CLUSTER_INVALID(previous))
{
}
else
{
+ if (node->fptr_index != 0)
+ exfat_bug("non-zero pointer index (%u)", node->fptr_index);
/* file does not have clusters (i.e. is empty), allocate
the first one for it */
- previous = allocate_cluster(ef);
+ previous = allocate_cluster(ef, 0);
if (CLUSTER_INVALID(previous))
return -ENOSPC;
- node->start_cluster = previous;
+ node->fptr_cluster = node->start_cluster = previous;
difference--;
/* file consists of only one cluster, so it's contiguous */
node->flags |= EXFAT_ATTRIB_CONTIGUOUS;
while (difference--)
{
- next = allocate_cluster(ef);
+ next = allocate_cluster(ef, previous + 1);
if (CLUSTER_INVALID(next))
return -ENOSPC;
if (next != previous - 1 && IS_CONTIGUOUS(*node))
/* crop the file */
if (current > difference)
{
- cluster_t last = exfat_advance_cluster(ef, node, node->start_cluster,
+ cluster_t last = exfat_advance_cluster(ef, node,
current - difference - 1);
if (CLUSTER_INVALID(last))
{
previous = node->start_cluster;
node->start_cluster = EXFAT_CLUSTER_FREE;
}
+ node->fptr_index = 0;
+ node->fptr_cluster = node->start_cluster;
/* free remaining clusters */
while (difference--)
if (node->size != size)
{
+ exfat_update_mtime(node);
node->size = size;
- /* FIXME no need to flush immediately */
- exfat_flush_node(ef, node);
+ node->flags |= EXFAT_ATTRIB_DIRTY;
}
return 0;
}