3 exFAT file system implementation library.
5 Free exFAT implementation.
6 Copyright (C) 2010-2017 Andrew Nayenko
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License along
19 with this program; if not, write to the Free Software Foundation, Inc.,
20 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
29 int exfat_opendir(struct exfat* ef, struct exfat_node* dir,
30 struct exfat_iterator* it)
37 rc = exfat_cache_directory(ef, dir);
39 exfat_put_node(ef, dir);
43 void exfat_closedir(struct exfat* ef, struct exfat_iterator* it)
45 exfat_put_node(ef, it->parent);
50 struct exfat_node* exfat_readdir(struct exfat* ef, struct exfat_iterator* it)
52 if (it->current == NULL)
53 it->current = it->parent->child;
55 it->current = it->current->next;
57 if (it->current != NULL)
58 return exfat_get_node(it->current);
63 static int compare_char(struct exfat* ef, uint16_t a, uint16_t b)
65 return (int) ef->upcase[a] - (int) ef->upcase[b];
68 static int compare_name(struct exfat* ef, const le16_t* a, const le16_t* b)
70 while (le16_to_cpu(*a) && le16_to_cpu(*b))
72 int rc = compare_char(ef, le16_to_cpu(*a), le16_to_cpu(*b));
78 return compare_char(ef, le16_to_cpu(*a), le16_to_cpu(*b));
81 static int lookup_name(struct exfat* ef, struct exfat_node* parent,
82 struct exfat_node** node, const char* name, size_t n)
84 struct exfat_iterator it;
85 le16_t buffer[EXFAT_NAME_MAX + 1];
90 rc = utf8_to_utf16(buffer, name, EXFAT_NAME_MAX + 1, n);
94 rc = exfat_opendir(ef, parent, &it);
97 while ((*node = exfat_readdir(ef, &it)))
99 if (compare_name(ef, buffer, (*node)->name) == 0)
101 exfat_closedir(ef, &it);
104 exfat_put_node(ef, *node);
106 exfat_closedir(ef, &it);
110 static size_t get_comp(const char* path, const char** comp)
114 *comp = path + strspn(path, "/"); /* skip leading slashes */
115 end = strchr(*comp, '/');
117 return strlen(*comp);
122 int exfat_lookup(struct exfat* ef, struct exfat_node** node,
125 struct exfat_node* parent;
130 /* start from the root directory */
131 parent = *node = exfat_get_node(ef->root);
132 for (p = path; (n = get_comp(p, &p)); p += n)
134 if (n == 1 && *p == '.') /* skip "." component */
136 rc = lookup_name(ef, parent, node, p, n);
139 exfat_put_node(ef, parent);
142 exfat_put_node(ef, parent);
148 static bool is_last_comp(const char* comp, size_t length)
150 const char* p = comp + length;
152 return get_comp(p, &p) == 0;
155 static bool is_allowed(const char* comp, size_t length)
159 for (i = 0; i < length; i++)
177 int exfat_split(struct exfat* ef, struct exfat_node** parent,
178 struct exfat_node** node, le16_t* name, const char* path)
184 memset(name, 0, (EXFAT_NAME_MAX + 1) * sizeof(le16_t));
185 *parent = *node = exfat_get_node(ef->root);
186 for (p = path; (n = get_comp(p, &p)); p += n)
188 if (n == 1 && *p == '.')
190 if (is_last_comp(p, n))
192 if (!is_allowed(p, n))
194 /* contains characters that are not allowed */
195 exfat_put_node(ef, *parent);
198 rc = utf8_to_utf16(name, p, EXFAT_NAME_MAX + 1, n);
201 exfat_put_node(ef, *parent);
205 rc = lookup_name(ef, *parent, node, p, n);
206 if (rc != 0 && rc != -ENOENT)
208 exfat_put_node(ef, *parent);
213 rc = lookup_name(ef, *parent, node, p, n);
216 exfat_put_node(ef, *parent);
219 exfat_put_node(ef, *parent);
222 exfat_bug("impossible");