]> git.sven.stormbind.net Git - sven/exfat-utils.git/blobdiff - libexfat/node.c
New upstream version 1.2.7
[sven/exfat-utils.git] / libexfat / node.c
index a3f00af1ba0d700a43d18397731fbd754eb13640..b544bd966d1cd7ff8f3733b89909e3cc588b0e68 100644 (file)
@@ -204,10 +204,13 @@ static bool check_entries(const struct exfat_entry* entry, int n)
        return true;
 }
 
-static bool check_node(const struct exfat_node* node, le16_t actual_checksum,
-               int cluster_size, const struct exfat_entry_meta1* meta1,
+static bool check_node(const struct exfat* ef, struct exfat_node* node,
+               le16_t actual_checksum, const struct exfat_entry_meta1* meta1,
                const struct exfat_entry_meta2* meta2)
 {
+       int cluster_size = CLUSTER_SIZE(*ef->sb);
+       uint64_t clusters_heap_size =
+                       (uint64_t) le32_to_cpu(ef->sb->cluster_count) * cluster_size;
        char buffer[EXFAT_UTF8_NAME_BUFFER_MAX];
        bool ret = true;
 
@@ -251,7 +254,7 @@ static bool check_node(const struct exfat_node* node, le16_t actual_checksum,
                                node->start_cluster);
                ret = false;
        }
-       if (node->size > 0 && CLUSTER_INVALID(node->start_cluster))
+       if (node->size > 0 && CLUSTER_INVALID(*ef->sb, node->start_cluster))
        {
                exfat_get_name(node, buffer);
                exfat_error("'%s' points to invalid cluster %#x", buffer,
@@ -259,6 +262,15 @@ static bool check_node(const struct exfat_node* node, le16_t actual_checksum,
                ret = false;
        }
 
+       /* File or directory cannot be larger than clusters heap. */
+       if (node->size > clusters_heap_size)
+       {
+               exfat_get_name(node, buffer);
+               exfat_error("'%s' is larger than clusters heap: %"PRIu64" > %"PRIu64,
+                               buffer, node->size, clusters_heap_size);
+               ret = false;
+       }
+
        /* Empty file or directory must be marked as non-contiguous. */
        if (node->size == 0 && node->is_contiguous)
        {
@@ -280,8 +292,8 @@ static bool check_node(const struct exfat_node* node, le16_t actual_checksum,
        return ret;
 }
 
-static int parse_file_entries(struct exfat* ef, struct exfat_node* parent,
-               struct exfat_node* node, const struct exfat_entry* entries, int n)
+static int parse_file_entries(struct exfat* ef, struct exfat_node* node,
+               const struct exfat_entry* entries, int n)
 {
        const struct exfat_entry_meta1* meta1;
        const struct exfat_entry_meta2* meta2;
@@ -314,8 +326,7 @@ static int parse_file_entries(struct exfat* ef, struct exfat_node* parent,
        init_node_meta2(node, meta2);
        init_node_name(node, entries + 2, mandatory_entries - 2);
 
-       if (!check_node(node, exfat_calc_checksum(entries, n),
-                       CLUSTER_SIZE(*ef->sb), meta1, meta2))
+       if (!check_node(ef, node, exfat_calc_checksum(entries, n), meta1, meta2))
                return -EIO;
 
        return 0;
@@ -337,7 +348,7 @@ static int parse_file_entry(struct exfat* ef, struct exfat_node* parent,
                return -ENOMEM;
        (*node)->entry_offset = *offset;
 
-       rc = parse_file_entries(ef, parent, *node, entries, n);
+       rc = parse_file_entries(ef, *node, entries, n);
        if (rc != 0)
        {
                free(*node);
@@ -401,7 +412,7 @@ static int readdir(struct exfat* ef, struct exfat_node* parent,
                        if (ef->upcase != NULL)
                                break;
                        upcase = (const struct exfat_entry_upcase*) &entry;
-                       if (CLUSTER_INVALID(le32_to_cpu(upcase->start_cluster)))
+                       if (CLUSTER_INVALID(*ef->sb, le32_to_cpu(upcase->start_cluster)))
                        {
                                exfat_error("invalid cluster 0x%x in upcase table",
                                                le32_to_cpu(upcase->start_cluster));
@@ -452,14 +463,13 @@ static int readdir(struct exfat* ef, struct exfat_node* parent,
                case EXFAT_ENTRY_BITMAP:
                        bitmap = (const struct exfat_entry_bitmap*) &entry;
                        ef->cmap.start_cluster = le32_to_cpu(bitmap->start_cluster);
-                       if (CLUSTER_INVALID(ef->cmap.start_cluster))
+                       if (CLUSTER_INVALID(*ef->sb, ef->cmap.start_cluster))
                        {
                                exfat_error("invalid cluster 0x%x in clusters bitmap",
                                                ef->cmap.start_cluster);
                                return -EIO;
                        }
-                       ef->cmap.size = le32_to_cpu(ef->sb->cluster_count) -
-                               EXFAT_FIRST_DATA_CLUSTER;
+                       ef->cmap.size = le32_to_cpu(ef->sb->cluster_count);
                        if (le64_to_cpu(bitmap->size) < DIV_ROUND_UP(ef->cmap.size, 8))
                        {
                                exfat_error("invalid clusters bitmap size: %"PRIu64
@@ -865,7 +875,7 @@ static int find_slot(struct exfat* ef, struct exfat_node* dir,
 }
 
 static int commit_entry(struct exfat* ef, struct exfat_node* dir,
-               const le16_t* name, cluster_t cluster, off_t offset, uint16_t attrib)
+               const le16_t* name, off_t offset, uint16_t attrib)
 {
        struct exfat_node* node;
        const size_t name_length = utf16_length(name);
@@ -925,7 +935,6 @@ static int create(struct exfat* ef, const char* path, uint16_t attrib)
 {
        struct exfat_node* dir;
        struct exfat_node* existing;
-       cluster_t cluster = EXFAT_CLUSTER_BAD;
        off_t offset = -1;
        le16_t name[EXFAT_NAME_MAX + 1];
        int rc;
@@ -947,7 +956,7 @@ static int create(struct exfat* ef, const char* path, uint16_t attrib)
                exfat_put_node(ef, dir);
                return rc;
        }
-       rc = commit_entry(ef, dir, name, cluster, offset, attrib);
+       rc = commit_entry(ef, dir, name, offset, attrib);
        if (rc != 0)
        {
                exfat_put_node(ef, dir);
@@ -995,8 +1004,7 @@ int exfat_mkdir(struct exfat* ef, const char* path)
 }
 
 static int rename_entry(struct exfat* ef, struct exfat_node* dir,
-               struct exfat_node* node, const le16_t* name, cluster_t new_cluster,
-               off_t new_offset)
+               struct exfat_node* node, const le16_t* name, off_t new_offset)
 {
        const size_t name_length = utf16_length(name);
        const int name_entries = DIV_ROUND_UP(name_length, EXFAT_ENAME_MAX);
@@ -1048,7 +1056,6 @@ int exfat_rename(struct exfat* ef, const char* old_path, const char* new_path)
        struct exfat_node* node;
        struct exfat_node* existing;
        struct exfat_node* dir;
-       cluster_t cluster = EXFAT_CLUSTER_BAD;
        off_t offset = -1;
        le16_t name[EXFAT_NAME_MAX + 1];
        int rc;
@@ -1129,7 +1136,7 @@ int exfat_rename(struct exfat* ef, const char* old_path, const char* new_path)
                exfat_put_node(ef, node);
                return rc;
        }
-       rc = rename_entry(ef, dir, node, name, cluster, offset);
+       rc = rename_entry(ef, dir, node, name, offset);
        if (rc != 0)
        {
                exfat_put_node(ef, dir);