OSDN Git Service

Relicensed the code from GPLv3+ to GPLv2+.
[android-x86/external-exfat.git] / libexfat / node.c
index 2eada9a..0c6800d 100644 (file)
@@ -2,11 +2,12 @@
        node.c (09.10.09)
        exFAT file system implementation library.
 
        node.c (09.10.09)
        exFAT file system implementation library.
 
-       Copyright (C) 2010-2012  Andrew Nayenko
+       Free exFAT implementation.
+       Copyright (C) 2010-2013  Andrew Nayenko
 
 
-       This program is free software: you can redistribute it and/or modify
+       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
        it under the terms of the GNU General Public License as published by
-       the Free Software Foundation, either version 3 of the License, or
+       the Free Software Foundation, either version 2 of the License, or
        (at your option) any later version.
 
        This program is distributed in the hope that it will be useful,
        (at your option) any later version.
 
        This program is distributed in the hope that it will be useful,
@@ -14,8 +15,9 @@
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        GNU General Public License for more details.
 
        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/>.
+       You should have received a copy of the GNU General Public License along
+       with this program; if not, write to the Free Software Foundation, Inc.,
+       51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
 
 #include "exfat.h"
 */
 
 #include "exfat.h"
@@ -44,8 +46,8 @@ void exfat_put_node(struct exfat* ef, struct exfat_node* node)
 {
        if (--node->references < 0)
        {
 {
        if (--node->references < 0)
        {
-               char buffer[EXFAT_NAME_MAX + 1];
-               exfat_get_name(node, buffer, EXFAT_NAME_MAX);
+               char buffer[UTF8_BYTES(EXFAT_NAME_MAX) + 1];
+               exfat_get_name(node, buffer, sizeof(buffer) - 1);
                exfat_bug("reference counter of `%s' is below zero", buffer);
        }
 
                exfat_bug("reference counter of `%s' is below zero", buffer);
        }
 
@@ -56,7 +58,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 */
                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)
                        free(node);
                }
                if (ef->cmap.dirty)
@@ -293,9 +295,9 @@ static int readdir(struct exfat* ef, const struct exfat_node* parent,
                                */
                                if (real_size != (*node)->size)
                                {
                                */
                                if (real_size != (*node)->size)
                                {
-                                       char buffer[EXFAT_NAME_MAX + 1];
+                                       char buffer[UTF8_BYTES(EXFAT_NAME_MAX) + 1];
 
 
-                                       exfat_get_name(*node, buffer, EXFAT_NAME_MAX);
+                                       exfat_get_name(*node, buffer, sizeof(buffer) - 1);
                                        exfat_error("`%s' real size does not equal to size "
                                                        "(%"PRIu64" != %"PRIu64")", buffer,
                                                        real_size, (*node)->size);
                                        exfat_error("`%s' real size does not equal to size "
                                                        "(%"PRIu64" != %"PRIu64")", buffer,
                                                        real_size, (*node)->size);
@@ -303,9 +305,9 @@ static int readdir(struct exfat* ef, const struct exfat_node* parent,
                                }
                                if (actual_checksum != reference_checksum)
                                {
                                }
                                if (actual_checksum != reference_checksum)
                                {
-                                       char buffer[EXFAT_NAME_MAX + 1];
+                                       char buffer[UTF8_BYTES(EXFAT_NAME_MAX) + 1];
 
 
-                                       exfat_get_name(*node, buffer, EXFAT_NAME_MAX);
+                                       exfat_get_name(*node, buffer, sizeof(buffer) - 1);
                                        exfat_error("`%s' has invalid checksum (0x%hx != 0x%hx)",
                                                        buffer, actual_checksum, reference_checksum);
                                        goto error;
                                        exfat_error("`%s' has invalid checksum (0x%hx != 0x%hx)",
                                                        buffer, actual_checksum, reference_checksum);
                                        goto error;
@@ -389,7 +391,7 @@ static int readdir(struct exfat* ef, const struct exfat_node* parent,
                                goto error;
                        }
                        if (utf16_to_utf8(ef->label, label->name,
                                goto error;
                        }
                        if (utf16_to_utf8(ef->label, label->name,
-                                               sizeof(ef->label), EXFAT_ENAME_MAX) != 0)
+                                               sizeof(ef->label) - 1, EXFAT_ENAME_MAX) != 0)
                                goto error;
                        break;
 
                                goto error;
                        break;
 
@@ -493,8 +495,8 @@ static void reset_cache(struct exfat* ef, struct exfat_node* node)
        node->flags &= ~EXFAT_ATTRIB_CACHED;
        if (node->references != 0)
        {
        node->flags &= ~EXFAT_ATTRIB_CACHED;
        if (node->references != 0)
        {
-               char buffer[EXFAT_NAME_MAX + 1];
-               exfat_get_name(node, buffer, EXFAT_NAME_MAX);
+               char buffer[UTF8_BYTES(EXFAT_NAME_MAX) + 1];
+               exfat_get_name(node, buffer, sizeof(buffer) - 1);
                exfat_warn("non-zero reference counter (%d) for `%s'",
                                node->references, buffer);
        }
                exfat_warn("non-zero reference counter (%d) for `%s'",
                                node->references, buffer);
        }
@@ -507,7 +509,7 @@ void exfat_reset_cache(struct exfat* ef)
        reset_cache(ef, ef->root);
 }
 
        reset_cache(ef, ef->root);
 }
 
-void next_entry(struct exfat* ef, const struct exfat_node* parent,
+static void next_entry(struct exfat* ef, const struct exfat_node* parent,
                cluster_t* cluster, off_t* offset)
 {
        *offset += sizeof(struct exfat_entry);
                cluster_t* cluster, off_t* offset)
 {
        *offset += sizeof(struct exfat_entry);
@@ -627,7 +629,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;
                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;
        if (rc != 0)
                return rc;
        return 0;
@@ -673,7 +675,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))
 {
        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,
 }
 
 static int find_slot(struct exfat* ef, struct exfat_node* dir,
@@ -826,7 +828,7 @@ int exfat_mkdir(struct exfat* ef, const char* path)
        if (rc != 0)
                return 0;
        /* directories always have at least one cluster */
        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);
        if (rc != 0)
        {
                delete(ef, node);
@@ -905,6 +907,23 @@ int exfat_rename(struct exfat* ef, const char* old_path, const char* new_path)
                exfat_put_node(ef, node);
                return rc;
        }
                exfat_put_node(ef, node);
                return rc;
        }
+
+       /* check that target is not a subdirectory of the source */
+       if (node->flags & EXFAT_ATTRIB_DIR)
+       {
+               struct exfat_node* p;
+
+               for (p = dir; p; p = p->parent)
+                       if (node == p)
+                       {
+                               if (existing != NULL)
+                                       exfat_put_node(ef, existing);
+                               exfat_put_node(ef, dir);
+                               exfat_put_node(ef, node);
+                               return -EINVAL;
+                       }
+       }
+
        if (existing != NULL)
        {
                /* remove target if it's not the same node as source */
        if (existing != NULL)
        {
                /* remove target if it's not the same node as source */
@@ -1034,5 +1053,6 @@ int exfat_set_label(struct exfat* ef, const char* label)
 
        exfat_pwrite(ef->dev, &entry, sizeof(struct exfat_entry_label),
                        co2o(ef, cluster, offset));
 
        exfat_pwrite(ef->dev, &entry, sizeof(struct exfat_entry_label),
                        co2o(ef, cluster, offset));
+       strcpy(ef->label, label);
        return 0;
 }
        return 0;
 }