OSDN Git Service

Generic I/O for directories: switch find_slot().
[android-x86/external-exfat.git] / libexfat / lookup.c
index 8cb5811..feb5a22 100644 (file)
@@ -1,11 +1,24 @@
 /*
- *  lookup.c
- *  exFAT file system implementation library.
- *
- *  Created by Andrew Nayenko on 02.09.09.
- *  This software is distributed under the GNU General Public License 
- *  version 3 or any later.
- */
+       lookup.c (02.09.09)
+       exFAT file system implementation library.
+
+       Free exFAT implementation.
+       Copyright (C) 2010-2016  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 2 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, write to the Free Software Foundation, Inc.,
+       51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
 
 #include "exfat.h"
 #include <string.h>
@@ -48,10 +61,7 @@ struct exfat_node* exfat_readdir(struct exfat* ef, struct exfat_iterator* it)
 
 static int compare_char(struct exfat* ef, uint16_t a, uint16_t b)
 {
-       if (a >= ef->upcase_chars || b >= ef->upcase_chars)
-               return (int) a - (int) b;
-
-       return (int) le16_to_cpu(ef->upcase[a]) - (int) le16_to_cpu(ef->upcase[b]);
+       return (int) ef->upcase[a] - (int) ef->upcase[b];
 }
 
 static int compare_name(struct exfat* ef, const le16_t* a, const le16_t* b)
@@ -74,7 +84,9 @@ static int lookup_name(struct exfat* ef, struct exfat_node* parent,
        le16_t buffer[EXFAT_NAME_MAX + 1];
        int rc;
 
-       rc = utf8_to_utf16(buffer, name, EXFAT_NAME_MAX, n);
+       *node = NULL;
+
+       rc = utf8_to_utf16(buffer, name, EXFAT_NAME_MAX + 1, n);
        if (rc != 0)
                return rc;
 
@@ -112,6 +124,7 @@ int exfat_lookup(struct exfat* ef, struct exfat_node** node,
        struct exfat_node* parent;
        const char* p;
        size_t n;
+       int rc;
 
        /* start from the root directory */
        parent = *node = exfat_get_node(ef->root);
@@ -119,10 +132,11 @@ int exfat_lookup(struct exfat* ef, struct exfat_node** node,
        {
                if (n == 1 && *p == '.')                                /* skip "." component */
                        continue;
-               if (lookup_name(ef, parent, node, p, n) != 0)
+               rc = lookup_name(ef, parent, node, p, n);
+               if (rc != 0)
                {
                        exfat_put_node(ef, parent);
-                       return -ENOENT;
+                       return rc;
                }
                exfat_put_node(ef, parent);
                parent = *node;
@@ -130,44 +144,79 @@ int exfat_lookup(struct exfat* ef, struct exfat_node** node,
        return 0;
 }
 
-static int is_last_comp(const char* comp, size_t length)
+static bool is_last_comp(const char* comp, size_t length)
 {
        const char* p = comp + length;
 
        return get_comp(p, &p) == 0;
 }
 
-int exfat_split(struct exfat* ef, struct exfat_node** node, le16_t* name,
-               const char* path)
+static bool is_allowed(const char* comp, size_t length)
+{
+       size_t i;
+
+       for (i = 0; i < length; i++)
+               switch (comp[i])
+               {
+               case 0x01 ... 0x1f:
+               case '/':
+               case '\\':
+               case ':':
+               case '*':
+               case '?':
+               case '"':
+               case '<':
+               case '>':
+               case '|':
+                       return false;
+               }
+       return true;
+}
+
+int exfat_split(struct exfat* ef, struct exfat_node** parent,
+               struct exfat_node** node, le16_t* name, const char* path)
 {
-       struct exfat_node* parent;
        const char* p;
        size_t n;
+       int rc;
 
-       parent = *node = exfat_get_node(ef->root);
+       memset(name, 0, (EXFAT_NAME_MAX + 1) * sizeof(le16_t));
+       *parent = *node = exfat_get_node(ef->root);
        for (p = path; (n = get_comp(p, &p)); p += n)
        {
                if (n == 1 && *p == '.')
                        continue;
-               if (lookup_name(ef, parent, node, p, n) != 0)
+               if (is_last_comp(p, n))
                {
-                       int rc;
-
-                       if (!is_last_comp(p, n))
+                       if (!is_allowed(p, n))
                        {
-                               /* this is not the last component of the path */
-                               exfat_put_node(ef, parent);
+                               /* contains characters that are not allowed */
+                               exfat_put_node(ef, *parent);
                                return -ENOENT;
                        }
-                       *node = parent;
-                       rc = utf8_to_utf16(name, p, EXFAT_NAME_MAX, n);
+                       rc = utf8_to_utf16(name, p, EXFAT_NAME_MAX + 1, n);
                        if (rc != 0)
-                               exfat_put_node(ef, parent);
+                       {
+                               exfat_put_node(ef, *parent);
+                               return rc;
+                       }
+
+                       rc = lookup_name(ef, *parent, node, p, n);
+                       if (rc != 0 && rc != -ENOENT)
+                       {
+                               exfat_put_node(ef, *parent);
+                               return rc;
+                       }
+                       return 0;
+               }
+               rc = lookup_name(ef, *parent, node, p, n);
+               if (rc != 0)
+               {
+                       exfat_put_node(ef, *parent);
                        return rc;
                }
-               exfat_put_node(ef, parent);
-               parent = *node;
+               exfat_put_node(ef, *parent);
+               *parent = *node;
        }
-       exfat_put_node(ef, *node);
-       return -EEXIST;
+       exfat_bug("impossible");
 }