X-Git-Url: http://git.sven.stormbind.net/?a=blobdiff_plain;f=lib%2Fexfat_dir.c;h=98e820f9404e1011a5f78fe9ff2ac153fcd1e3d4;hb=760c7a0f47754a291cc741cdeb8144f0d4266c15;hp=499b672f34fb977553c464f0dc64f32855df1b55;hpb=03290761e3849db9b13d2d3b176b36ab31c395bb;p=sven%2Fexfatprogs.git diff --git a/lib/exfat_dir.c b/lib/exfat_dir.c index 499b672..98e820f 100644 --- a/lib/exfat_dir.c +++ b/lib/exfat_dir.c @@ -35,10 +35,11 @@ static ssize_t write_block(struct exfat_de_iter *iter, unsigned int block) unsigned int i; desc = &iter->buffer_desc[block & 0x01]; - device_offset = exfat_c2o(exfat, desc->p_clus) + desc->offset; for (i = 0; i < iter->read_size / iter->write_size; i++) { if (desc->dirty[i]) { + device_offset = exfat_c2o(exfat, desc->p_clus) + + desc->offset; if (exfat_write(exfat->blk_dev->dev_fd, desc->buffer + i * iter->write_size, iter->write_size, @@ -236,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; @@ -355,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) @@ -378,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; @@ -406,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); @@ -429,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 { @@ -471,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; @@ -484,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) @@ -505,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) { @@ -513,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) @@ -547,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; }