aboutsummaryrefslogtreecommitdiffstats
path: root/libexfat/lookup.c
diff options
context:
space:
mode:
authorrelan <relan@users.noreply.github.com>2009-10-05 17:35:56 +0000
committerrelan <relan@users.noreply.github.com>2015-08-24 08:26:10 +0300
commit7d4f05ff7d833ece42d3e489dd4aa804c4c313c1 (patch)
tree773b12ffdfc82c2542f8b94ddfc15bf81f2c308b /libexfat/lookup.c
parent3e4cfeefa0f27c2c79d125cb65b6b8cda3ccfe88 (diff)
downloadandroid_external_exfat-7d4f05ff7d833ece42d3e489dd4aa804c4c313c1.tar.gz
android_external_exfat-7d4f05ff7d833ece42d3e489dd4aa804c4c313c1.tar.bz2
android_external_exfat-7d4f05ff7d833ece42d3e489dd4aa804c4c313c1.zip
Implement dynamic nodes allocation.
Diffstat (limited to 'libexfat/lookup.c')
-rw-r--r--libexfat/lookup.c92
1 files changed, 62 insertions, 30 deletions
diff --git a/libexfat/lookup.c b/libexfat/lookup.c
index 5f5c3af..1b4613a 100644
--- a/libexfat/lookup.c
+++ b/libexfat/lookup.c
@@ -12,7 +12,12 @@
#include <errno.h>
#include <inttypes.h>
-void exfat_opendir(struct exfat_node* node, struct exfat_iterator* it)
+void exfat_put_node(struct exfat_node* node)
+{
+ free(node);
+}
+
+void exfat_opendir(const struct exfat_node* node, struct exfat_iterator* it)
{
if (!(node->flags & EXFAT_ATTRIB_DIR))
exfat_bug("`%s' is not a directory", node->name);
@@ -35,8 +40,8 @@ void exfat_closedir(struct exfat_iterator* it)
* Reads one entry in directory at position pointed by iterator and fills
* node structure.
*/
-int exfat_readdir(struct exfat* ef, struct exfat_node* node,
- struct exfat_iterator* it)
+int exfat_readdir(struct exfat* ef, const struct exfat_node* parent,
+ struct exfat_node** node, struct exfat_iterator* it)
{
const struct exfat_entry* entry;
const struct exfat_file* file;
@@ -48,6 +53,8 @@ int exfat_readdir(struct exfat* ef, struct exfat_node* node,
uint8_t continuations = 0;
le16_t* namep = NULL;
+ *node = NULL;
+
if (it->chunk == NULL)
{
it->chunk = malloc(CLUSTER_SIZE(*ef->sb));
@@ -76,7 +83,7 @@ int exfat_readdir(struct exfat* ef, struct exfat_node* node,
{
exfat_error("expected %hhu continuations before EOD",
continuations);
- return -EIO;
+ goto error;
}
return -ENOENT; /* that's OK, means end of directory */
@@ -85,14 +92,9 @@ int exfat_readdir(struct exfat* ef, struct exfat_node* node,
{
exfat_error("expected %hhu continuations before new entry",
continuations);
- return -EIO;
+ goto error;
}
- memset(node, 0, sizeof(struct exfat_node));
file = (const struct exfat_file*) entry;
- node->flags = le16_to_cpu(file->attrib);
- node->mtime = exfat_exfat2unix(file->mdate, file->mtime);
- node->atime = exfat_exfat2unix(file->adate, file->atime);
- namep = node->name;
continuations = file->continuations;
/* each file entry must have at least 2 continuations:
info and name */
@@ -101,6 +103,17 @@ int exfat_readdir(struct exfat* ef, struct exfat_node* node,
exfat_error("too few continuations (%hhu)", continuations);
return -EIO;
}
+ *node = malloc(sizeof(struct exfat_node));
+ if (*node == NULL)
+ {
+ exfat_error("failed to allocate node");
+ return -ENOMEM;
+ }
+ memset(*node, 0, sizeof(struct exfat_node));
+ (*node)->flags = le16_to_cpu(file->attrib);
+ (*node)->mtime = exfat_exfat2unix(file->mdate, file->mtime);
+ (*node)->atime = exfat_exfat2unix(file->adate, file->atime);
+ namep = (*node)->name;
break;
case EXFAT_ENTRY_FILE_INFO:
@@ -108,13 +121,13 @@ int exfat_readdir(struct exfat* ef, struct exfat_node* node,
{
exfat_error("unexpected continuation (%hhu)",
continuations);
- return -EIO;
+ goto error;
}
file_info = (const struct exfat_file_info*) entry;
- node->size = le64_to_cpu(file_info->size);
- node->start_cluster = le32_to_cpu(file_info->start_cluster);
+ (*node)->size = le64_to_cpu(file_info->size);
+ (*node)->start_cluster = le32_to_cpu(file_info->start_cluster);
if (file_info->flag == EXFAT_FLAG_CONTIGUOUS)
- node->flags |= EXFAT_ATTRIB_CONTIGUOUS;
+ (*node)->flags |= EXFAT_ATTRIB_CONTIGUOUS;
--continuations;
break;
@@ -122,7 +135,7 @@ int exfat_readdir(struct exfat* ef, struct exfat_node* node,
if (continuations == 0)
{
exfat_error("unexpected continuation");
- return -EIO;
+ goto error;
}
file_name = (const struct exfat_file_name*) entry;
memcpy(namep, file_name->name, EXFAT_ENAME_MAX * sizeof(le16_t));
@@ -191,7 +204,7 @@ int exfat_readdir(struct exfat* ef, struct exfat_node* node,
if (entry->type & EXFAT_ENTRY_VALID)
{
exfat_error("unknown entry type 0x%hhu", entry->type);
- return -EIO;
+ goto error;
}
break;
}
@@ -203,13 +216,21 @@ int exfat_readdir(struct exfat* ef, struct exfat_node* node,
if (CLUSTER_INVALID(it->cluster))
{
exfat_error("invalid cluster while reading directory");
- return -EIO;
+ goto error;
}
exfat_read_raw(it->chunk, CLUSTER_SIZE(*ef->sb),
exfat_c2o(ef, it->cluster), ef->fd);
}
}
/* we never reach here */
+
+error:
+ if (*node != NULL)
+ {
+ free(*node);
+ *node = NULL;
+ }
+ return -EIO;
}
static int compare_char(struct exfat* ef, uint16_t a, uint16_t b)
@@ -233,8 +254,8 @@ static int compare_name(struct exfat* ef, const le16_t* a, const le16_t* b)
return compare_char(ef, le16_to_cpu(*a), le16_to_cpu(*b));
}
-static int lookup_name(struct exfat* ef, struct exfat_node* node,
- const char* name, size_t n)
+static int lookup_name(struct exfat* ef, const struct exfat_node* parent,
+ struct exfat_node** node, const char* name, size_t n)
{
struct exfat_iterator it;
le16_t buffer[EXFAT_NAME_MAX + 1];
@@ -244,14 +265,15 @@ static int lookup_name(struct exfat* ef, struct exfat_node* node,
if (rc != 0)
return rc;
- exfat_opendir(node, &it);
- while (exfat_readdir(ef, node, &it) == 0)
+ exfat_opendir(parent, &it);
+ while (exfat_readdir(ef, parent, node, &it) == 0)
{
- if (compare_name(ef, buffer, node->name) == 0)
+ if (compare_name(ef, buffer, (*node)->name) == 0)
{
exfat_closedir(&it);
return 0;
}
+ exfat_put_node(*node);
}
exfat_closedir(&it);
return -ENOENT;
@@ -269,27 +291,37 @@ size_t get_comp(const char* path, const char** comp)
return end - *comp;
}
-int exfat_lookup(struct exfat* ef, struct exfat_node* node,
+int exfat_lookup(struct exfat* ef, struct exfat_node** node,
const char* path)
{
+ struct exfat_node* parent;
const char* p;
size_t n;
+ parent = *node = malloc(sizeof(struct exfat_node));
+ if (parent == NULL)
+ {
+ exfat_error("failed to allocate root node");
+ return -ENOMEM;
+ }
+
/* start from the root directory */
- node->flags = EXFAT_ATTRIB_DIR;
- node->size = ef->rootdir_size;
- node->start_cluster = le32_to_cpu(ef->sb->rootdir_cluster);
- node->name[0] = cpu_to_le16('\0');
+ parent->flags = EXFAT_ATTRIB_DIR;
+ parent->size = ef->rootdir_size;
+ parent->start_cluster = le32_to_cpu(ef->sb->rootdir_cluster);
+ parent->name[0] = cpu_to_le16('\0');
/* exFAT does not have time attributes for the root directory */
- node->mtime = 0;
- node->atime = 0;
+ parent->mtime = 0;
+ parent->atime = 0;
for (p = path; (n = get_comp(p, &p)); p += n)
{
if (n == 1 && *p == '.') /* skip "." component */
continue;
- if (lookup_name(ef, node, p, n) != 0)
+ if (lookup_name(ef, parent, node, p, n) != 0)
return -ENOENT;
+ exfat_put_node(parent);
+ parent = *node;
}
return 0;
}