iter->de_file_offset = 0;
iter->next_read_offset = iter->read_size;
iter->max_skip_dentries = 0;
- iter->dot_name_num = 0;
+ iter->invalid_name_num = 0;
if (iter->parent->size == 0)
return EOF;
struct exfat_dentry *dentry = NULL;
off_t free_file_offset = 0, free_dev_offset = 0;
struct exfat_de_iter de_iter;
- int dentry_count;
+ int dentry_count, empty_dentry_count = 0;
int retval;
- bool last_is_free = false;
bd = exfat_alloc_buffer(2, exfat->clus_size, exfat->sect_size);
if (!bd)
goto out;
}
+ if (!IS_EXFAT_DELETED(dentry->type)) {
+ if (filter->in.dentry_count == 0 ||
+ empty_dentry_count < filter->in.dentry_count)
+ empty_dentry_count = 0;
+ }
+
dentry_count = 1;
if (dentry->type == filter->in.type) {
retval = 0;
} else if (retval < 0) {
goto out;
}
- last_is_free = false;
- } else if ((dentry->type == EXFAT_LAST ||
- IS_EXFAT_DELETED(dentry->type))) {
- if (!last_is_free) {
+ } else if (IS_EXFAT_DELETED(dentry->type)) {
+ if (empty_dentry_count == 0) {
free_file_offset =
exfat_de_iter_file_offset(&de_iter);
free_dev_offset =
exfat_de_iter_device_offset(&de_iter);
- last_is_free = true;
}
- } else {
- last_is_free = false;
+
+ if (filter->in.dentry_count == 0 ||
+ empty_dentry_count < filter->in.dentry_count)
+ empty_dentry_count++;
}
exfat_de_iter_advance(&de_iter, dentry_count);
exfat_de_iter_file_offset(&de_iter);
filter->out.dev_offset =
exfat_de_iter_device_offset(&de_iter);
- } else if (retval == EOF && last_is_free) {
+ } else if (retval == EOF && empty_dentry_count) {
filter->out.file_offset = free_file_offset;
filter->out.dev_offset = free_dev_offset;
} else {
if (retval || name_de->type != EXFAT_NAME)
return 1;
- len = MIN(name_len, ENTRY_NAME_MAX);
+ len = MIN(name_len + 1, ENTRY_NAME_MAX);
if (memcmp(name_de->dentry.name.unicode_0_14,
name, len * 2) != 0)
return 1;
return 0;
}
-int exfat_lookup_file(struct exfat *exfat, struct exfat_inode *parent,
- const char *name, struct exfat_lookup_filter *filter_out)
+int exfat_lookup_file_by_utf16name(struct exfat *exfat,
+ struct exfat_inode *parent,
+ __le16 *utf16_name,
+ struct exfat_lookup_filter *filter_out)
{
int retval;
- __le16 utf16_name[PATH_MAX + 2] = {0, };
-
- retval = (int)exfat_utf16_enc(name, utf16_name, sizeof(utf16_name));
- if (retval < 0)
- return retval;
filter_out->in.type = EXFAT_FILE;
filter_out->in.filter = filter_lookup_file;
filter_out->in.param = utf16_name;
+ filter_out->in.dentry_count = 0;
retval = exfat_lookup_dentry_set(exfat, parent, filter_out);
if (retval < 0)
return 0;
}
+int exfat_lookup_file(struct exfat *exfat, struct exfat_inode *parent,
+ const char *name, struct exfat_lookup_filter *filter_out)
+{
+ int retval;
+ __le16 utf16_name[PATH_MAX + 2] = {0, };
+
+ retval = (int)exfat_utf16_enc(name, utf16_name, sizeof(utf16_name));
+ if (retval < 0)
+ return retval;
+
+ return exfat_lookup_file_by_utf16name(exfat, parent, utf16_name,
+ filter_out);
+}
+
void exfat_calc_dentry_checksum(struct exfat_dentry *dentry,
uint16_t *checksum, bool primary)
{
bytes = (uint8_t *)dentry;
- *checksum = ((*checksum << 15) | (*checksum >> 1)) + bytes[0];
- *checksum = ((*checksum << 15) | (*checksum >> 1)) + bytes[1];
+ /* use += to avoid promotion to int; UBSan complaints about signed overflow */
+ *checksum = (*checksum << 15) | (*checksum >> 1);
+ *checksum += bytes[0];
+ *checksum = (*checksum << 15) | (*checksum >> 1);
+ *checksum += bytes[1];
i = primary ? 4 : 2;
- for (; i < sizeof(*dentry); i++)
- *checksum = ((*checksum << 15) | (*checksum >> 1)) + bytes[i];
+ for (; i < sizeof(*dentry); i++) {
+ *checksum = (*checksum << 15) | (*checksum >> 1);
+ *checksum += bytes[i];
+ }
}
static uint16_t calc_dentry_set_checksum(struct exfat_dentry *dset, int dcount)
ch = exfat->upcase_table[le16_to_cpu(name[i])];
ch = cpu_to_le16(ch);
- chksum = ((chksum << 15) | (chksum >> 1)) + (ch & 0xFF);
- chksum = ((chksum << 15) | (chksum >> 1)) + (ch >> 8);
+ /* use += to avoid promotion to int; UBSan complaints about signed overflow */
+ chksum = (chksum << 15) | (chksum >> 1);
+ chksum += ch & 0xFF;
+ chksum = (chksum << 15) | (chksum >> 1);
+ chksum += ch >> 8;
}
return chksum;
}
return 0;
}
-int exfat_find_free_cluster(struct exfat *exfat,
+static int find_free_cluster(struct exfat *exfat,
clus_t start, clus_t *new_clu)
{
clus_t end = le32_to_cpu(exfat->bs->bsx.clu_count) +
if ((need_dset && !inode->dentry_set) || inode->is_contiguous)
return -EINVAL;
- err = exfat_find_free_cluster(exfat, exfat->start_clu, new_clu);
+ err = find_free_cluster(exfat, exfat->start_clu, new_clu);
if (err) {
exfat->start_clu = EXFAT_FIRST_CLUSTER;
exfat_err("failed to find an free cluster\n");