X-Git-Url: https://git.sven.stormbind.net/?p=sven%2Fexfatprogs.git;a=blobdiff_plain;f=lib%2Fexfat_dir.c;fp=lib%2Fexfat_dir.c;h=98e820f9404e1011a5f78fe9ff2ac153fcd1e3d4;hp=7c145f4a54978893f03ea6f07e81d001fca14324;hb=fa2bead8d3f2203fb7b22d801443109a52808490;hpb=0a7a8b470671035ad0c2d8dc0d7714d06921273d diff --git a/lib/exfat_dir.c b/lib/exfat_dir.c index 7c145f4..98e820f 100644 --- a/lib/exfat_dir.c +++ b/lib/exfat_dir.c @@ -237,7 +237,7 @@ int exfat_de_iter_init(struct exfat_de_iter *iter, struct exfat *exfat, 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; @@ -356,9 +356,8 @@ int exfat_lookup_dentry_set(struct exfat *exfat, struct exfat_inode *parent, 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) @@ -379,6 +378,12 @@ int exfat_lookup_dentry_set(struct exfat *exfat, struct exfat_inode *parent, 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; @@ -407,18 +412,17 @@ int exfat_lookup_dentry_set(struct exfat *exfat, struct exfat_inode *parent, } 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); @@ -430,7 +434,7 @@ out: 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 { @@ -472,7 +476,7 @@ static int filter_lookup_file(struct exfat_de_iter *de_iter, 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; @@ -485,19 +489,17 @@ static int filter_lookup_file(struct exfat_de_iter *de_iter, 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) @@ -506,6 +508,20 @@ int exfat_lookup_file(struct exfat *exfat, struct exfat_inode *parent, 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) { @@ -514,12 +530,17 @@ void exfat_calc_dentry_checksum(struct exfat_dentry *dentry, 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) @@ -548,8 +569,11 @@ uint16_t exfat_calc_name_hash(struct exfat *exfat, 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; } @@ -678,7 +702,7 @@ int exfat_update_file_dentry_set(struct exfat *exfat, 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) + @@ -805,7 +829,7 @@ static int exfat_alloc_cluster(struct exfat *exfat, struct exfat_inode *inode, 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");