struct exfat_node* exfat_readdir(struct exfat* ef, struct exfat_iterator* it);
int exfat_lookup(struct exfat* ef, struct exfat_node** node,
const char* path);
-int exfat_split(struct exfat* ef, struct exfat_node** node, le16_t* name,
- const char* path);
+int exfat_split(struct exfat* ef, struct exfat_node** parent,
+ struct exfat_node** node, le16_t* name, const char* path);
off_t exfat_c2o(const struct exfat* ef, cluster_t cluster);
cluster_t exfat_next_cluster(const struct exfat* ef,
le16_t buffer[EXFAT_NAME_MAX + 1];
int rc;
+ *node = NULL;
+
rc = utf8_to_utf16(buffer, name, EXFAT_NAME_MAX, n);
if (rc != 0)
return rc;
return strcspn(comp, "/\\:*?\"<>|") >= length;
}
-int exfat_split(struct exfat* ef, struct exfat_node** node, le16_t* name,
- const char* path)
+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;
- parent = *node = exfat_get_node(ef->root);
+ *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))
- {
- /* this is not the last component of the path */
- exfat_put_node(ef, parent);
- return -ENOENT;
- }
if (!is_allowed(p, n))
{
/* contains characters that are not allowed */
- exfat_put_node(ef, parent);
+ exfat_put_node(ef, *parent);
return -ENOENT;
}
- *node = parent;
rc = utf8_to_utf16(name, p, EXFAT_NAME_MAX, n);
if (rc != 0)
- exfat_put_node(ef, parent);
- return rc;
+ {
+ 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;
}
- exfat_put_node(ef, parent);
- parent = *node;
+ if (lookup_name(ef, *parent, node, p, n) != 0)
+ {
+ exfat_put_node(ef, *parent);
+ return -ENOENT;
+ }
+ exfat_put_node(ef, *parent);
+ *parent = *node;
}
- exfat_put_node(ef, *node);
- return -EEXIST;
+ exfat_bug("impossible");
}
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;
- rc = exfat_split(ef, &dir, name, path);
+ rc = exfat_split(ef, &dir, &existing, name, path);
if (rc != 0)
return rc;
+ if (existing != NULL)
+ {
+ exfat_put_node(ef, existing);
+ exfat_put_node(ef, dir);
+ return -EEXIST;
+ }
rc = find_slot(ef, dir, &cluster, &offset,
2 + DIV_ROUND_UP(utf16_length(name), EXFAT_ENAME_MAX));
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;
return rc;
memset(name, 0, (EXFAT_NAME_MAX + 1) * sizeof(le16_t));
- rc = exfat_split(ef, &dir, name, new_path);
+ rc = exfat_split(ef, &dir, &existing, name, new_path);
if (rc != 0)
{
exfat_put_node(ef, node);
return rc;
}
+ if (existing != NULL)
+ {
+ if (existing->flags & EXFAT_ATTRIB_DIR)
+ {
+ if (node->flags & EXFAT_ATTRIB_DIR)
+ rc = exfat_rmdir(ef, existing);
+ else
+ rc = -ENOTDIR;
+ }
+ else
+ {
+ if (!(node->flags & EXFAT_ATTRIB_DIR))
+ rc = exfat_unlink(ef, existing);
+ else
+ rc = -EISDIR;
+ }
+ exfat_put_node(ef, existing);
+ if (rc != 0)
+ {
+ exfat_put_node(ef, dir);
+ exfat_put_node(ef, node);
+ return rc;
+ }
+ }
rc = find_slot(ef, dir, &cluster, &offset,
2 + DIV_ROUND_UP(utf16_length(name), EXFAT_ENAME_MAX));