summaryrefslogtreecommitdiffstats
path: root/exfat/libexfat
diff options
context:
space:
mode:
Diffstat (limited to 'exfat/libexfat')
-rw-r--r--exfat/libexfat/cluster.c65
-rw-r--r--exfat/libexfat/exfat.h3
-rw-r--r--exfat/libexfat/io.c13
-rw-r--r--exfat/libexfat/node.c73
4 files changed, 71 insertions, 83 deletions
diff --git a/exfat/libexfat/cluster.c b/exfat/libexfat/cluster.c
index 83c983da4..d10a5dfe7 100644
--- a/exfat/libexfat/cluster.c
+++ b/exfat/libexfat/cluster.c
@@ -106,41 +106,24 @@ cluster_t exfat_advance_cluster(const struct exfat* ef,
return node->fptr_cluster;
}
-static cluster_t find_bit_and_set(uint8_t* bitmap, cluster_t start,
- cluster_t end)
+static cluster_t find_bit_and_set(uint8_t* bitmap, size_t start, size_t end)
{
- const cluster_t mid_start = (start + 7) / 8 * 8;
- const cluster_t mid_end = end / 8 * 8;
- cluster_t c;
- cluster_t byte;
-
- for (c = start; c < mid_start; c++)
- if (BMAP_GET(bitmap, c) == 0)
- {
- BMAP_SET(bitmap, c);
- return c + EXFAT_FIRST_DATA_CLUSTER;
- }
-
- for (byte = mid_start / 8; byte < mid_end / 8; byte++)
- if (bitmap[byte] != 0xff)
- {
- cluster_t bit;
-
- for (bit = 0; bit < 8; bit++)
- if (!(bitmap[byte] & (1u << bit)))
- {
- bitmap[byte] |= (1u << bit);
- return byte * 8 + bit + EXFAT_FIRST_DATA_CLUSTER;
- }
- }
-
- for (c = mid_end; c < end; c++)
- if (BMAP_GET(bitmap, c) == 0)
- {
- BMAP_SET(bitmap, c);
- return c + EXFAT_FIRST_DATA_CLUSTER;
- }
+ const size_t start_index = start / 8;
+ const size_t end_index = DIV_ROUND_UP(end, 8);
+ size_t i;
+ size_t c;
+ for (i = start_index; i < end_index; i++)
+ {
+ if (bitmap[i] == 0xff)
+ continue;
+ for (c = MAX(i * 8, start); c < MIN((i + 1) * 8, end); c++)
+ if (BMAP_GET(bitmap, c) == 0)
+ {
+ BMAP_SET(bitmap, c);
+ return c + EXFAT_FIRST_DATA_CLUSTER;
+ }
+ }
return EXFAT_CLUSTER_END;
}
@@ -151,7 +134,7 @@ void exfat_flush_cmap(struct exfat* ef)
ef->cmap.dirty = false;
}
-static void set_next_cluster(const struct exfat* ef, int contiguous,
+static void set_next_cluster(const struct exfat* ef, bool contiguous,
cluster_t current, cluster_t next)
{
off64_t fat_offset;
@@ -204,7 +187,7 @@ static void make_noncontiguous(const struct exfat* ef, cluster_t first,
cluster_t c;
for (c = first; c < last; c++)
- set_next_cluster(ef, 0, c, c + 1);
+ set_next_cluster(ef, false, c, c + 1);
}
static int shrink_file(struct exfat* ef, struct exfat_node* node,
@@ -361,7 +344,8 @@ static int erase_range(struct exfat* ef, struct exfat_node* node,
return 0;
}
-int exfat_truncate(struct exfat* ef, struct exfat_node* node, uint64_t size)
+int exfat_truncate(struct exfat* ef, struct exfat_node* node, uint64_t size,
+ bool erase)
{
uint32_t c1 = bytes2clusters(ef, node->size);
uint32_t c2 = bytes2clusters(ef, size);
@@ -381,9 +365,12 @@ int exfat_truncate(struct exfat* ef, struct exfat_node* node, uint64_t size)
if (rc != 0)
return rc;
- rc = erase_range(ef, node, node->size, size);
- if (rc != 0)
- return rc;
+ if (erase)
+ {
+ rc = erase_range(ef, node, node->size, size);
+ if (rc != 0)
+ return rc;
+ }
exfat_update_mtime(node);
node->size = size;
diff --git a/exfat/libexfat/exfat.h b/exfat/libexfat/exfat.h
index 11be06f7b..3e4223e5d 100644
--- a/exfat/libexfat/exfat.h
+++ b/exfat/libexfat/exfat.h
@@ -164,7 +164,8 @@ cluster_t exfat_next_cluster(const struct exfat* ef,
cluster_t exfat_advance_cluster(const struct exfat* ef,
struct exfat_node* node, uint32_t count);
void exfat_flush_cmap(struct exfat* ef);
-int exfat_truncate(struct exfat* ef, struct exfat_node* node, uint64_t size);
+int exfat_truncate(struct exfat* ef, struct exfat_node* node, uint64_t size,
+ bool erase);
uint32_t exfat_count_free_clusters(const struct exfat* ef);
int exfat_find_used_sectors(const struct exfat* ef, off64_t* a, off64_t* b);
diff --git a/exfat/libexfat/io.c b/exfat/libexfat/io.c
index 1be028cf3..7f79d97c0 100644
--- a/exfat/libexfat/io.c
+++ b/exfat/libexfat/io.c
@@ -2,7 +2,7 @@
io.c (02.09.09)
exFAT file system implementation library.
- Copyright (C) 2010-2012 Andrew Nayenko
+ Copyright (C) 2010-2013 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
@@ -350,10 +350,13 @@ ssize_t exfat_generic_pwrite(struct exfat* ef, struct exfat_node* node,
cluster_t cluster;
const char* bufp = buffer;
off64_t lsize, loffset, remainder;
- printf("node: %s\n", node);
- if (offset + size > node->size)
- if (exfat_truncate(ef, node, offset + size) != 0)
- return -1;
+
+ if (offset > node->size)
+ if (exfat_truncate(ef, node, offset, true) != 0)
+ return -1;
+ if (offset + size > node->size)
+ if (exfat_truncate(ef, node, offset + size, false) != 0)
+ return -1;
if (size == 0)
return 0;
diff --git a/exfat/libexfat/node.c b/exfat/libexfat/node.c
index ff2cea9ab..c2ee0da38 100644
--- a/exfat/libexfat/node.c
+++ b/exfat/libexfat/node.c
@@ -56,7 +56,7 @@ void exfat_put_node(struct exfat* ef, struct exfat_node* node)
if (node->flags & EXFAT_ATTRIB_UNLINKED)
{
/* free all clusters and node structure itself */
- exfat_truncate(ef, node, 0);
+ exfat_truncate(ef, node, 0, true);
free(node);
}
if (ef->cmap.dirty)
@@ -457,17 +457,40 @@ int exfat_cache_directory(struct exfat* ef, struct exfat_node* dir)
return 0;
}
-static void reset_cache(struct exfat* ef, struct exfat_node* node)
+static void tree_attach(struct exfat_node* dir, struct exfat_node* node)
+{
+ node->parent = dir;
+ if (dir->child)
+ {
+ dir->child->prev = node;
+ node->next = dir->child;
+ }
+ dir->child = node;
+}
+
+static void tree_detach(struct exfat_node* node)
{
- struct exfat_node* child;
- struct exfat_node* next;
+ if (node->prev)
+ node->prev->next = node->next;
+ else /* this is the first node in the list */
+ node->parent->child = node->next;
+ if (node->next)
+ node->next->prev = node->prev;
+ node->parent = NULL;
+ node->prev = NULL;
+ node->next = NULL;
+}
- for (child = node->child; child; child = next)
+static void reset_cache(struct exfat* ef, struct exfat_node* node)
+{
+ while (node->child)
{
- reset_cache(ef, child);
- next = child->next;
- free(child);
+ struct exfat_node* p = node->child;
+ reset_cache(ef, p);
+ tree_detach(p);
+ free(p);
}
+ node->flags &= ~EXFAT_ATTRIB_CACHED;
if (node->references != 0)
{
char buffer[EXFAT_NAME_MAX + 1];
@@ -475,10 +498,8 @@ static void reset_cache(struct exfat* ef, struct exfat_node* node)
exfat_warn("non-zero reference counter (%d) for `%s'",
node->references, buffer);
}
- while (node->references--)
+ while (node->references)
exfat_put_node(ef, node);
- node->child = NULL;
- node->flags &= ~EXFAT_ATTRIB_CACHED;
}
void exfat_reset_cache(struct exfat* ef)
@@ -563,30 +584,6 @@ static void erase_entry(struct exfat* ef, struct exfat_node* node)
}
}
-static void tree_detach(struct exfat_node* node)
-{
- if (node->prev)
- node->prev->next = node->next;
- else /* this is the first node in the list */
- node->parent->child = node->next;
- if (node->next)
- node->next->prev = node->prev;
- node->parent = NULL;
- node->prev = NULL;
- node->next = NULL;
-}
-
-static void tree_attach(struct exfat_node* dir, struct exfat_node* node)
-{
- node->parent = dir;
- if (dir->child)
- {
- dir->child->prev = node;
- node->next = dir->child;
- }
- dir->child = node;
-}
-
static int shrink_directory(struct exfat* ef, struct exfat_node* dir,
off64_t deleted_offset)
{
@@ -630,7 +627,7 @@ static int shrink_directory(struct exfat* ef, struct exfat_node* dir,
new_size = CLUSTER_SIZE(*ef->sb);
if (new_size == dir->size)
return 0;
- rc = exfat_truncate(ef, dir, new_size);
+ rc = exfat_truncate(ef, dir, new_size, true);
if (rc != 0)
return rc;
return 0;
@@ -676,7 +673,7 @@ static int grow_directory(struct exfat* ef, struct exfat_node* dir,
{
return exfat_truncate(ef, dir,
DIV_ROUND_UP(asize + difference, CLUSTER_SIZE(*ef->sb))
- * CLUSTER_SIZE(*ef->sb));
+ * CLUSTER_SIZE(*ef->sb), true);
}
static int find_slot(struct exfat* ef, struct exfat_node* dir,
@@ -829,7 +826,7 @@ int exfat_mkdir(struct exfat* ef, const char* path)
if (rc != 0)
return 0;
/* directories always have at least one cluster */
- rc = exfat_truncate(ef, node, CLUSTER_SIZE(*ef->sb));
+ rc = exfat_truncate(ef, node, CLUSTER_SIZE(*ef->sb), true);
if (rc != 0)
{
delete(ef, node);