From: Olaf Weber <olaf@xxxxxxx> Change the XFS case-insensitive lookup code to return the first match found, even if it is not an exact match. Whether a filesystem uses case-insensitive lookups is determined by a superblock bit set during filesystem creation. This means that normal use cannot create two files that both match the same filename. Signed-off-by: Olaf Weber <olaf@xxxxxxx> --- libxfs/xfs_dir2_block.c | 17 ++++------- libxfs/xfs_dir2_leaf.c | 38 ++++------------------- libxfs/xfs_dir2_node.c | 80 ++++++++++++++++++------------------------------- libxfs/xfs_dir2_sf.c | 8 ++--- 4 files changed, 44 insertions(+), 99 deletions(-) diff --git a/libxfs/xfs_dir2_block.c b/libxfs/xfs_dir2_block.c index cede01f..2880431 100644 --- a/libxfs/xfs_dir2_block.c +++ b/libxfs/xfs_dir2_block.c @@ -705,28 +705,21 @@ xfs_dir2_block_lookup_int( dep = (xfs_dir2_data_entry_t *) ((char *)hdr + xfs_dir2_dataptr_to_off(mp, addr)); /* - * Compare name and if it's an exact match, return the index - * and buffer. If it's the first case-insensitive match, store - * the index and buffer and continue looking for an exact match. + * Compare name and if it's a match, return the + * index and buffer. */ cmp = mp->m_dirnameops->compname(args, dep->name, dep->namelen); - if (cmp != XFS_CMP_DIFFERENT && cmp != args->cmpresult) { + if (cmp != XFS_CMP_DIFFERENT) { args->cmpresult = cmp; *bpp = bp; *entno = mid; - if (cmp == XFS_CMP_EXACT) - return 0; + return 0; } } while (++mid < be32_to_cpu(btp->count) && be32_to_cpu(blp[mid].hashval) == hash); ASSERT(args->op_flags & XFS_DA_OP_OKNOENT); - /* - * Here, we can only be doing a lookup (not a rename or replace). - * If a case-insensitive match was found earlier, return success. - */ - if (args->cmpresult == XFS_CMP_CASE) - return 0; + ASSERT(args->cmpresult == XFS_CMP_DIFFERENT); /* * No match, release the buffer and return ENOENT. */ diff --git a/libxfs/xfs_dir2_leaf.c b/libxfs/xfs_dir2_leaf.c index 8e0cbc9..b1901d3 100644 --- a/libxfs/xfs_dir2_leaf.c +++ b/libxfs/xfs_dir2_leaf.c @@ -1246,7 +1246,6 @@ xfs_dir2_leaf_lookup_int( xfs_mount_t *mp; /* filesystem mount point */ xfs_dir2_db_t newdb; /* new data block number */ xfs_trans_t *tp; /* transaction pointer */ - xfs_dir2_db_t cidb = -1; /* case match data block no. */ enum xfs_dacmp cmp; /* name compare result */ struct xfs_dir2_leaf_entry *ents; struct xfs_dir3_icleaf_hdr leafhdr; @@ -1307,47 +1306,22 @@ xfs_dir2_leaf_lookup_int( dep = (xfs_dir2_data_entry_t *)((char *)dbp->b_addr + xfs_dir2_dataptr_to_off(mp, be32_to_cpu(lep->address))); /* - * Compare name and if it's an exact match, return the index - * and buffer. If it's the first case-insensitive match, store - * the index and buffer and continue looking for an exact match. + * Compare name and if it's a match, return the index + * and buffer. */ cmp = mp->m_dirnameops->compname(args, dep->name, dep->namelen); - if (cmp != XFS_CMP_DIFFERENT && cmp != args->cmpresult) { + if (cmp != XFS_CMP_DIFFERENT) { args->cmpresult = cmp; *indexp = index; - /* case exact match: return the current buffer. */ - if (cmp == XFS_CMP_EXACT) { - *dbpp = dbp; - return 0; - } - cidb = curdb; + *dbpp = dbp; + return 0; } } ASSERT(args->op_flags & XFS_DA_OP_OKNOENT); - /* - * Here, we can only be doing a lookup (not a rename or remove). - * If a case-insensitive match was found earlier, re-read the - * appropriate data block if required and return it. - */ - if (args->cmpresult == XFS_CMP_CASE) { - ASSERT(cidb != -1); - if (cidb != curdb) { - xfs_trans_brelse(tp, dbp); - error = xfs_dir3_data_read(tp, dp, - xfs_dir2_db_to_da(mp, cidb), - -1, &dbp); - if (error) { - xfs_trans_brelse(tp, lbp); - return error; - } - } - *dbpp = dbp; - return 0; - } + ASSERT(args->cmpresult == XFS_CMP_DIFFERENT); /* * No match found, return ENOENT. */ - ASSERT(cidb == -1); if (dbp) xfs_trans_brelse(tp, dbp); xfs_trans_brelse(tp, lbp); diff --git a/libxfs/xfs_dir2_node.c b/libxfs/xfs_dir2_node.c index 3737e4e..fb27506 100644 --- a/libxfs/xfs_dir2_node.c +++ b/libxfs/xfs_dir2_node.c @@ -702,6 +702,7 @@ xfs_dir2_leafn_lookup_for_entry( xfs_dir2_db_t curdb = -1; /* current data block number */ xfs_dir2_data_entry_t *dep; /* data block entry */ xfs_inode_t *dp; /* incore directory inode */ + int di = -1; /* data entry index */ int error; /* error return value */ int index; /* leaf entry index */ xfs_dir2_leaf_t *leaf; /* leaf structure */ @@ -733,6 +734,7 @@ xfs_dir2_leafn_lookup_for_entry( if (state->extravalid) { curbp = state->extrablk.bp; curdb = state->extrablk.blkno; + di = state->extrablk.index; } /* * Loop over leaf entries with the right hash value. @@ -757,27 +759,20 @@ xfs_dir2_leafn_lookup_for_entry( */ if (newdb != curdb) { /* - * If we had a block before that we aren't saving - * for a CI name, drop it + * If we had a block, drop it */ - if (curbp && (args->cmpresult == XFS_CMP_DIFFERENT || - curdb != state->extrablk.blkno)) + if (curbp) { xfs_trans_brelse(tp, curbp); + di = -1; + } /* - * If needing the block that is saved with a CI match, - * use it otherwise read in the new data block. + * Read in the new data block. */ - if (args->cmpresult != XFS_CMP_DIFFERENT && - newdb == state->extrablk.blkno) { - ASSERT(state->extravalid); - curbp = state->extrablk.bp; - } else { - error = xfs_dir3_data_read(tp, dp, - xfs_dir2_db_to_da(mp, newdb), - -1, &curbp); - if (error) - return error; - } + error = xfs_dir3_data_read(tp, dp, + xfs_dir2_db_to_da(mp, newdb), + -1, &curbp); + if (error) + return error; xfs_dir3_data_check(dp, curbp); curdb = newdb; } @@ -787,53 +782,36 @@ xfs_dir2_leafn_lookup_for_entry( dep = (xfs_dir2_data_entry_t *)((char *)curbp->b_addr + xfs_dir2_dataptr_to_off(mp, be32_to_cpu(lep->address))); /* - * Compare the entry and if it's an exact match, return - * EEXIST immediately. If it's the first case-insensitive - * match, store the block & inode number and continue looking. + * Compare the entry and if it's a match, return + * EEXIST immediately. */ cmp = mp->m_dirnameops->compname(args, dep->name, dep->namelen); - if (cmp != XFS_CMP_DIFFERENT && cmp != args->cmpresult) { - /* If there is a CI match block, drop it */ - if (args->cmpresult != XFS_CMP_DIFFERENT && - curdb != state->extrablk.blkno) - xfs_trans_brelse(tp, state->extrablk.bp); + if (cmp != XFS_CMP_DIFFERENT) { args->cmpresult = cmp; args->inumber = be64_to_cpu(dep->inumber); args->filetype = xfs_dir3_dirent_get_ftype(mp, dep); - *indexp = index; - state->extravalid = 1; - state->extrablk.bp = curbp; - state->extrablk.blkno = curdb; - state->extrablk.index = (int)((char *)dep - - (char *)curbp->b_addr); - state->extrablk.magic = XFS_DIR2_DATA_MAGIC; - curbp->b_ops = &xfs_dir3_data_buf_ops; - xfs_trans_buf_set_type(tp, curbp, XFS_BLFT_DIR_DATA_BUF); - if (cmp == XFS_CMP_EXACT) - return XFS_ERROR(EEXIST); + error = EEXIST; + goto out; } } + /* Didn't find a match */ + error = ENOENT; ASSERT(index == leafhdr.count || (args->op_flags & XFS_DA_OP_OKNOENT)); +out: if (curbp) { - if (args->cmpresult == XFS_CMP_DIFFERENT) { - /* Giving back last used data block. */ - state->extravalid = 1; - state->extrablk.bp = curbp; - state->extrablk.index = -1; - state->extrablk.blkno = curdb; - state->extrablk.magic = XFS_DIR2_DATA_MAGIC; - curbp->b_ops = &xfs_dir3_data_buf_ops; - xfs_trans_buf_set_type(tp, curbp, XFS_BLFT_DIR_DATA_BUF); - } else { - /* If the curbp is not the CI match block, drop it */ - if (state->extrablk.bp != curbp) - xfs_trans_brelse(tp, curbp); - } + /* Giving back last used data block. */ + state->extravalid = 1; + state->extrablk.bp = curbp; + state->extrablk.index = di; + state->extrablk.blkno = curdb; + state->extrablk.magic = XFS_DIR2_DATA_MAGIC; + curbp->b_ops = &xfs_dir3_data_buf_ops; + xfs_trans_buf_set_type(tp, curbp, XFS_BLFT_DIR_DATA_BUF); } else { state->extravalid = 0; } *indexp = index; - return XFS_ERROR(ENOENT); + return XFS_ERROR(error); } /* diff --git a/libxfs/xfs_dir2_sf.c b/libxfs/xfs_dir2_sf.c index 7580333..7b01d43 100644 --- a/libxfs/xfs_dir2_sf.c +++ b/libxfs/xfs_dir2_sf.c @@ -833,13 +833,12 @@ xfs_dir2_sf_lookup( for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->count; i++, sfep = xfs_dir3_sf_nextentry(dp->i_mount, sfp, sfep)) { /* - * Compare name and if it's an exact match, return the inode - * number. If it's the first case-insensitive match, store the - * inode number and continue looking for an exact match. + * Compare name and if it's a match, return the inode + * number. */ cmp = dp->i_mount->m_dirnameops->compname(args, sfep->name, sfep->namelen); - if (cmp != XFS_CMP_DIFFERENT && cmp != args->cmpresult) { + if (cmp != XFS_CMP_DIFFERENT) { args->cmpresult = cmp; args->inumber = xfs_dir3_sfe_get_ino(dp->i_mount, sfp, sfep); @@ -848,6 +847,7 @@ xfs_dir2_sf_lookup( if (cmp == XFS_CMP_EXACT) return XFS_ERROR(EEXIST); ci_sfep = sfep; + break; } } ASSERT(args->op_flags & XFS_DA_OP_OKNOENT); -- 1.7.12.4 -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html