Commit 5163f95a authored by Barry Naujok's avatar Barry Naujok Committed by Niv Sardi

[XFS] Name operation vector for hash and compare

Adds two pieces of functionality for the basis of case-insensitive support
in XFS:

1. A comparison result enumerated type: xfs_dacmp. It represents an

exact match, case-insensitive match or no match at all. This patch

only implements different and exact results.

2. xfs_nameops vector for specifying how to perform the hash generation

of filenames and comparision methods. In this patch the hash vector

points to the existing xfs_da_hashname function and the comparison

method does a length compare, and if the same, does a memcmp and

return the xfs_dacmp result.

All filename functions that use the hash (create, lookup remove, rename,
etc) now use the xfs_nameops.hashname function and all directory lookup
functions also use the xfs_nameops.compname function.

The lookup functions also handle case-insensitive results even though the
default comparison function cannot return that. And important aspect of
the lookup functions is that an exact match always has precedence over a
case-insensitive. So while a case-insensitive match is found, we have to
keep looking just in case there is an exact match. In the meantime, the
info for the first case-insensitive match is retained if no exact match is
found.

SGI-PV: 981519
SGI-Modid: xfs-linux-melb:xfs-kern:31205a
Signed-off-by: default avatarBarry Naujok <bnaujok@sgi.com>
Signed-off-by: default avatarChristoph Hellwig <hch@infradead.org>
parent 68f34d51
...@@ -1530,6 +1530,28 @@ xfs_da_hashname(const uchar_t *name, int namelen) ...@@ -1530,6 +1530,28 @@ xfs_da_hashname(const uchar_t *name, int namelen)
} }
} }
enum xfs_dacmp
xfs_da_compname(
struct xfs_da_args *args,
const char *name,
int len)
{
return (args->namelen == len && memcmp(args->name, name, len) == 0) ?
XFS_CMP_EXACT : XFS_CMP_DIFFERENT;
}
static xfs_dahash_t
xfs_default_hashname(
struct xfs_name *name)
{
return xfs_da_hashname(name->name, name->len);
}
const struct xfs_nameops xfs_default_nameops = {
.hashname = xfs_default_hashname,
.compname = xfs_da_compname
};
/* /*
* Add a block to the btree ahead of the file. * Add a block to the btree ahead of the file.
* Return the new block number to the caller. * Return the new block number to the caller.
......
...@@ -98,6 +98,15 @@ typedef struct xfs_da_node_entry xfs_da_node_entry_t; ...@@ -98,6 +98,15 @@ typedef struct xfs_da_node_entry xfs_da_node_entry_t;
* Btree searching and modification structure definitions. * Btree searching and modification structure definitions.
*========================================================================*/ *========================================================================*/
/*
* Search comparison results
*/
enum xfs_dacmp {
XFS_CMP_DIFFERENT, /* names are completely different */
XFS_CMP_EXACT, /* names are exactly the same */
XFS_CMP_CASE /* names are same but differ in case */
};
/* /*
* Structure to ease passing around component names. * Structure to ease passing around component names.
*/ */
...@@ -127,6 +136,7 @@ typedef struct xfs_da_args { ...@@ -127,6 +136,7 @@ typedef struct xfs_da_args {
unsigned char rename; /* T/F: this is an atomic rename op */ unsigned char rename; /* T/F: this is an atomic rename op */
unsigned char addname; /* T/F: this is an add operation */ unsigned char addname; /* T/F: this is an add operation */
unsigned char oknoent; /* T/F: ok to return ENOENT, else die */ unsigned char oknoent; /* T/F: ok to return ENOENT, else die */
enum xfs_dacmp cmpresult; /* name compare result for lookups */
} xfs_da_args_t; } xfs_da_args_t;
/* /*
...@@ -201,6 +211,14 @@ typedef struct xfs_da_state { ...@@ -201,6 +211,14 @@ typedef struct xfs_da_state {
(uint)(XFS_DA_LOGOFF(BASE, ADDR)), \ (uint)(XFS_DA_LOGOFF(BASE, ADDR)), \
(uint)(XFS_DA_LOGOFF(BASE, ADDR)+(SIZE)-1) (uint)(XFS_DA_LOGOFF(BASE, ADDR)+(SIZE)-1)
/*
* Name ops for directory and/or attr name operations
*/
struct xfs_nameops {
xfs_dahash_t (*hashname)(struct xfs_name *);
enum xfs_dacmp (*compname)(struct xfs_da_args *, const char *, int);
};
#ifdef __KERNEL__ #ifdef __KERNEL__
/*======================================================================== /*========================================================================
...@@ -249,6 +267,10 @@ int xfs_da_shrink_inode(xfs_da_args_t *args, xfs_dablk_t dead_blkno, ...@@ -249,6 +267,10 @@ int xfs_da_shrink_inode(xfs_da_args_t *args, xfs_dablk_t dead_blkno,
xfs_dabuf_t *dead_buf); xfs_dabuf_t *dead_buf);
uint xfs_da_hashname(const uchar_t *name_string, int name_length); uint xfs_da_hashname(const uchar_t *name_string, int name_length);
enum xfs_dacmp xfs_da_compname(struct xfs_da_args *args,
const char *name, int len);
xfs_da_state_t *xfs_da_state_alloc(void); xfs_da_state_t *xfs_da_state_alloc(void);
void xfs_da_state_free(xfs_da_state_t *state); void xfs_da_state_free(xfs_da_state_t *state);
......
...@@ -65,6 +65,7 @@ xfs_dir_mount( ...@@ -65,6 +65,7 @@ xfs_dir_mount(
(mp->m_dirblksize - (uint)sizeof(xfs_da_node_hdr_t)) / (mp->m_dirblksize - (uint)sizeof(xfs_da_node_hdr_t)) /
(uint)sizeof(xfs_da_node_entry_t); (uint)sizeof(xfs_da_node_entry_t);
mp->m_dir_magicpct = (mp->m_dirblksize * 37) / 100; mp->m_dir_magicpct = (mp->m_dirblksize * 37) / 100;
mp->m_dirnameops = &xfs_default_nameops;
} }
/* /*
...@@ -164,7 +165,7 @@ xfs_dir_createname( ...@@ -164,7 +165,7 @@ xfs_dir_createname(
args.name = name->name; args.name = name->name;
args.namelen = name->len; args.namelen = name->len;
args.hashval = xfs_da_hashname(name->name, name->len); args.hashval = dp->i_mount->m_dirnameops->hashname(name);
args.inumber = inum; args.inumber = inum;
args.dp = dp; args.dp = dp;
args.firstblock = first; args.firstblock = first;
...@@ -210,11 +211,12 @@ xfs_dir_lookup( ...@@ -210,11 +211,12 @@ xfs_dir_lookup(
args.name = name->name; args.name = name->name;
args.namelen = name->len; args.namelen = name->len;
args.hashval = xfs_da_hashname(name->name, name->len); args.hashval = dp->i_mount->m_dirnameops->hashname(name);
args.dp = dp; args.dp = dp;
args.whichfork = XFS_DATA_FORK; args.whichfork = XFS_DATA_FORK;
args.trans = tp; args.trans = tp;
args.oknoent = 1; args.oknoent = 1;
args.cmpresult = XFS_CMP_DIFFERENT;
if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
rval = xfs_dir2_sf_lookup(&args); rval = xfs_dir2_sf_lookup(&args);
...@@ -257,7 +259,7 @@ xfs_dir_removename( ...@@ -257,7 +259,7 @@ xfs_dir_removename(
args.name = name->name; args.name = name->name;
args.namelen = name->len; args.namelen = name->len;
args.hashval = xfs_da_hashname(name->name, name->len); args.hashval = dp->i_mount->m_dirnameops->hashname(name);
args.inumber = ino; args.inumber = ino;
args.dp = dp; args.dp = dp;
args.firstblock = first; args.firstblock = first;
...@@ -340,7 +342,7 @@ xfs_dir_replace( ...@@ -340,7 +342,7 @@ xfs_dir_replace(
args.name = name->name; args.name = name->name;
args.namelen = name->len; args.namelen = name->len;
args.hashval = xfs_da_hashname(name->name, name->len); args.hashval = dp->i_mount->m_dirnameops->hashname(name);
args.inumber = inum; args.inumber = inum;
args.dp = dp; args.dp = dp;
args.firstblock = first; args.firstblock = first;
...@@ -388,7 +390,7 @@ xfs_dir_canenter( ...@@ -388,7 +390,7 @@ xfs_dir_canenter(
args.name = name->name; args.name = name->name;
args.namelen = name->len; args.namelen = name->len;
args.hashval = xfs_da_hashname(name->name, name->len); args.hashval = dp->i_mount->m_dirnameops->hashname(name);
args.dp = dp; args.dp = dp;
args.whichfork = XFS_DATA_FORK; args.whichfork = XFS_DATA_FORK;
args.trans = tp; args.trans = tp;
......
...@@ -643,6 +643,7 @@ xfs_dir2_block_lookup_int( ...@@ -643,6 +643,7 @@ xfs_dir2_block_lookup_int(
int mid; /* binary search current idx */ int mid; /* binary search current idx */
xfs_mount_t *mp; /* filesystem mount point */ xfs_mount_t *mp; /* filesystem mount point */
xfs_trans_t *tp; /* transaction pointer */ xfs_trans_t *tp; /* transaction pointer */
enum xfs_dacmp cmp; /* comparison result */
dp = args->dp; dp = args->dp;
tp = args->trans; tp = args->trans;
...@@ -697,20 +698,31 @@ xfs_dir2_block_lookup_int( ...@@ -697,20 +698,31 @@ xfs_dir2_block_lookup_int(
dep = (xfs_dir2_data_entry_t *) dep = (xfs_dir2_data_entry_t *)
((char *)block + xfs_dir2_dataptr_to_off(mp, addr)); ((char *)block + xfs_dir2_dataptr_to_off(mp, addr));
/* /*
* Compare, if it's right give back buffer & entry number. * 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.
*/ */
if (dep->namelen == args->namelen && cmp = mp->m_dirnameops->compname(args, dep->name, dep->namelen);
dep->name[0] == args->name[0] && if (cmp != XFS_CMP_DIFFERENT && cmp != args->cmpresult) {
memcmp(dep->name, args->name, args->namelen) == 0) { args->cmpresult = cmp;
*bpp = bp; *bpp = bp;
*entno = mid; *entno = mid;
return 0; if (cmp == XFS_CMP_EXACT)
return 0;
} }
} while (++mid < be32_to_cpu(btp->count) && be32_to_cpu(blp[mid].hashval) == hash); } while (++mid < be32_to_cpu(btp->count) &&
be32_to_cpu(blp[mid].hashval) == hash);
ASSERT(args->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;
/* /*
* No match, release the buffer and return ENOENT. * No match, release the buffer and return ENOENT.
*/ */
ASSERT(args->oknoent);
xfs_da_brelse(tp, bp); xfs_da_brelse(tp, bp);
return XFS_ERROR(ENOENT); return XFS_ERROR(ENOENT);
} }
...@@ -1033,6 +1045,7 @@ xfs_dir2_sf_to_block( ...@@ -1033,6 +1045,7 @@ xfs_dir2_sf_to_block(
xfs_dir2_sf_t *sfp; /* shortform structure */ xfs_dir2_sf_t *sfp; /* shortform structure */
__be16 *tagp; /* end of data entry */ __be16 *tagp; /* end of data entry */
xfs_trans_t *tp; /* transaction pointer */ xfs_trans_t *tp; /* transaction pointer */
struct xfs_name name;
xfs_dir2_trace_args("sf_to_block", args); xfs_dir2_trace_args("sf_to_block", args);
dp = args->dp; dp = args->dp;
...@@ -1187,8 +1200,10 @@ xfs_dir2_sf_to_block( ...@@ -1187,8 +1200,10 @@ xfs_dir2_sf_to_block(
tagp = xfs_dir2_data_entry_tag_p(dep); tagp = xfs_dir2_data_entry_tag_p(dep);
*tagp = cpu_to_be16((char *)dep - (char *)block); *tagp = cpu_to_be16((char *)dep - (char *)block);
xfs_dir2_data_log_entry(tp, bp, dep); xfs_dir2_data_log_entry(tp, bp, dep);
blp[2 + i].hashval = cpu_to_be32(xfs_da_hashname( name.name = sfep->name;
(char *)sfep->name, sfep->namelen)); name.len = sfep->namelen;
blp[2 + i].hashval = cpu_to_be32(mp->m_dirnameops->
hashname(&name));
blp[2 + i].address = cpu_to_be32(xfs_dir2_byte_to_dataptr(mp, blp[2 + i].address = cpu_to_be32(xfs_dir2_byte_to_dataptr(mp,
(char *)dep - (char *)block)); (char *)dep - (char *)block));
offset = (int)((char *)(tagp + 1) - (char *)block); offset = (int)((char *)(tagp + 1) - (char *)block);
......
...@@ -65,6 +65,7 @@ xfs_dir2_data_check( ...@@ -65,6 +65,7 @@ xfs_dir2_data_check(
xfs_mount_t *mp; /* filesystem mount point */ xfs_mount_t *mp; /* filesystem mount point */
char *p; /* current data position */ char *p; /* current data position */
int stale; /* count of stale leaves */ int stale; /* count of stale leaves */
struct xfs_name name;
mp = dp->i_mount; mp = dp->i_mount;
d = bp->data; d = bp->data;
...@@ -140,7 +141,9 @@ xfs_dir2_data_check( ...@@ -140,7 +141,9 @@ xfs_dir2_data_check(
addr = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk, addr = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
(xfs_dir2_data_aoff_t) (xfs_dir2_data_aoff_t)
((char *)dep - (char *)d)); ((char *)dep - (char *)d));
hash = xfs_da_hashname((char *)dep->name, dep->namelen); name.name = dep->name;
name.len = dep->namelen;
hash = mp->m_dirnameops->hashname(&name);
for (i = 0; i < be32_to_cpu(btp->count); i++) { for (i = 0; i < be32_to_cpu(btp->count); i++) {
if (be32_to_cpu(lep[i].address) == addr && if (be32_to_cpu(lep[i].address) == addr &&
be32_to_cpu(lep[i].hashval) == hash) be32_to_cpu(lep[i].hashval) == hash)
......
...@@ -1331,6 +1331,8 @@ xfs_dir2_leaf_lookup_int( ...@@ -1331,6 +1331,8 @@ xfs_dir2_leaf_lookup_int(
xfs_mount_t *mp; /* filesystem mount point */ xfs_mount_t *mp; /* filesystem mount point */
xfs_dir2_db_t newdb; /* new data block number */ xfs_dir2_db_t newdb; /* new data block number */
xfs_trans_t *tp; /* transaction pointer */ xfs_trans_t *tp; /* transaction pointer */
xfs_dabuf_t *cbp; /* case match data buffer */
enum xfs_dacmp cmp; /* name compare result */
dp = args->dp; dp = args->dp;
tp = args->trans; tp = args->trans;
...@@ -1354,9 +1356,11 @@ xfs_dir2_leaf_lookup_int( ...@@ -1354,9 +1356,11 @@ xfs_dir2_leaf_lookup_int(
* Loop over all the entries with the right hash value * Loop over all the entries with the right hash value
* looking to match the name. * looking to match the name.
*/ */
cbp = NULL;
for (lep = &leaf->ents[index], dbp = NULL, curdb = -1; for (lep = &leaf->ents[index], dbp = NULL, curdb = -1;
index < be16_to_cpu(leaf->hdr.count) && be32_to_cpu(lep->hashval) == args->hashval; index < be16_to_cpu(leaf->hdr.count) &&
lep++, index++) { be32_to_cpu(lep->hashval) == args->hashval;
lep++, index++) {
/* /*
* Skip over stale leaf entries. * Skip over stale leaf entries.
*/ */
...@@ -1371,12 +1375,12 @@ xfs_dir2_leaf_lookup_int( ...@@ -1371,12 +1375,12 @@ xfs_dir2_leaf_lookup_int(
* need to pitch the old one and read the new one. * need to pitch the old one and read the new one.
*/ */
if (newdb != curdb) { if (newdb != curdb) {
if (dbp) if (dbp != cbp)
xfs_da_brelse(tp, dbp); xfs_da_brelse(tp, dbp);
if ((error = error = xfs_da_read_buf(tp, dp,
xfs_da_read_buf(tp, dp, xfs_dir2_db_to_da(mp, newdb),
xfs_dir2_db_to_da(mp, newdb), -1, &dbp, -1, &dbp, XFS_DATA_FORK);
XFS_DATA_FORK))) { if (error) {
xfs_da_brelse(tp, lbp); xfs_da_brelse(tp, lbp);
return error; return error;
} }
...@@ -1386,24 +1390,46 @@ xfs_dir2_leaf_lookup_int( ...@@ -1386,24 +1390,46 @@ xfs_dir2_leaf_lookup_int(
/* /*
* Point to the data entry. * Point to the data entry.
*/ */
dep = (xfs_dir2_data_entry_t *) dep = (xfs_dir2_data_entry_t *)((char *)dbp->data +
((char *)dbp->data + xfs_dir2_dataptr_to_off(mp, be32_to_cpu(lep->address)));
xfs_dir2_dataptr_to_off(mp, be32_to_cpu(lep->address)));
/* /*
* If it matches then return it. * 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.
*/ */
if (dep->namelen == args->namelen && cmp = mp->m_dirnameops->compname(args, dep->name, dep->namelen);
dep->name[0] == args->name[0] && if (cmp != XFS_CMP_DIFFERENT && cmp != args->cmpresult) {
memcmp(dep->name, args->name, args->namelen) == 0) { args->cmpresult = cmp;
*dbpp = dbp;
*indexp = index; *indexp = index;
return 0; /*
* case exact match: release the stored CI buffer if it
* exists and return the current buffer.
*/
if (cmp == XFS_CMP_EXACT) {
if (cbp && cbp != dbp)
xfs_da_brelse(tp, cbp);
*dbpp = dbp;
return 0;
}
cbp = dbp;
} }
} }
ASSERT(args->oknoent);
/*
* Here, we can only be doing a lookup (not a rename or replace).
* If a case-insensitive match was found earlier, release the current
* buffer and return the stored CI matching buffer.
*/
if (args->cmpresult == XFS_CMP_CASE) {
if (cbp != dbp)
xfs_da_brelse(tp, dbp);
*dbpp = cbp;
return 0;
}
/* /*
* No match found, return ENOENT. * No match found, return ENOENT.
*/ */
ASSERT(args->oknoent); ASSERT(cbp == NULL);
if (dbp) if (dbp)
xfs_da_brelse(tp, dbp); xfs_da_brelse(tp, dbp);
xfs_da_brelse(tp, lbp); xfs_da_brelse(tp, lbp);
......
...@@ -556,6 +556,7 @@ xfs_dir2_leafn_lookup_for_entry( ...@@ -556,6 +556,7 @@ xfs_dir2_leafn_lookup_for_entry(
xfs_mount_t *mp; /* filesystem mount point */ xfs_mount_t *mp; /* filesystem mount point */
xfs_dir2_db_t newdb; /* new data block number */ xfs_dir2_db_t newdb; /* new data block number */
xfs_trans_t *tp; /* transaction pointer */ xfs_trans_t *tp; /* transaction pointer */
enum xfs_dacmp cmp; /* comparison result */
dp = args->dp; dp = args->dp;
tp = args->trans; tp = args->trans;
...@@ -620,17 +621,21 @@ xfs_dir2_leafn_lookup_for_entry( ...@@ -620,17 +621,21 @@ xfs_dir2_leafn_lookup_for_entry(
dep = (xfs_dir2_data_entry_t *)((char *)curbp->data + dep = (xfs_dir2_data_entry_t *)((char *)curbp->data +
xfs_dir2_dataptr_to_off(mp, be32_to_cpu(lep->address))); xfs_dir2_dataptr_to_off(mp, be32_to_cpu(lep->address)));
/* /*
* Compare the entry, return it if it matches. * Compare the entry and if it's an exact match, return
* EEXIST immediately. If it's the first case-insensitive
* match, store the inode number and continue looking.
*/ */
if (dep->namelen == args->namelen && memcmp(dep->name, cmp = mp->m_dirnameops->compname(args, dep->name, dep->namelen);
args->name, args->namelen) == 0) { if (cmp != XFS_CMP_DIFFERENT && cmp != args->cmpresult) {
args->cmpresult = cmp;
args->inumber = be64_to_cpu(dep->inumber); args->inumber = be64_to_cpu(dep->inumber);
di = (int)((char *)dep - (char *)curbp->data); di = (int)((char *)dep - (char *)curbp->data);
error = EEXIST; error = EEXIST;
goto out; if (cmp == XFS_CMP_EXACT)
goto out;
} }
} }
/* Didn't find a match. */ /* Didn't find an exact match. */
error = ENOENT; error = ENOENT;
di = -1; di = -1;
ASSERT(index == be16_to_cpu(leaf->hdr.count) || args->oknoent); ASSERT(index == be16_to_cpu(leaf->hdr.count) || args->oknoent);
...@@ -1813,6 +1818,8 @@ xfs_dir2_node_lookup( ...@@ -1813,6 +1818,8 @@ xfs_dir2_node_lookup(
error = xfs_da_node_lookup_int(state, &rval); error = xfs_da_node_lookup_int(state, &rval);
if (error) if (error)
rval = error; rval = error;
else if (rval == ENOENT && args->cmpresult == XFS_CMP_CASE)
rval = EEXIST; /* a case-insensitive match was found */
/* /*
* Release the btree blocks and leaf block. * Release the btree blocks and leaf block.
*/ */
...@@ -1856,9 +1863,8 @@ xfs_dir2_node_removename( ...@@ -1856,9 +1863,8 @@ xfs_dir2_node_removename(
* Look up the entry we're deleting, set up the cursor. * Look up the entry we're deleting, set up the cursor.
*/ */
error = xfs_da_node_lookup_int(state, &rval); error = xfs_da_node_lookup_int(state, &rval);
if (error) { if (error)
rval = error; rval = error;
}
/* /*
* Didn't find it, upper layer screwed up. * Didn't find it, upper layer screwed up.
*/ */
...@@ -1875,9 +1881,8 @@ xfs_dir2_node_removename( ...@@ -1875,9 +1881,8 @@ xfs_dir2_node_removename(
*/ */
error = xfs_dir2_leafn_remove(args, blk->bp, blk->index, error = xfs_dir2_leafn_remove(args, blk->bp, blk->index,
&state->extrablk, &rval); &state->extrablk, &rval);
if (error) { if (error)
return error; return error;
}
/* /*
* Fix the hash values up the btree. * Fix the hash values up the btree.
*/ */
......
...@@ -814,6 +814,7 @@ xfs_dir2_sf_lookup( ...@@ -814,6 +814,7 @@ xfs_dir2_sf_lookup(
int i; /* entry index */ int i; /* entry index */
xfs_dir2_sf_entry_t *sfep; /* shortform directory entry */ xfs_dir2_sf_entry_t *sfep; /* shortform directory entry */
xfs_dir2_sf_t *sfp; /* shortform structure */ xfs_dir2_sf_t *sfp; /* shortform structure */
enum xfs_dacmp cmp; /* comparison result */
xfs_dir2_trace_args("sf_lookup", args); xfs_dir2_trace_args("sf_lookup", args);
xfs_dir2_sf_check(args); xfs_dir2_sf_check(args);
...@@ -836,6 +837,7 @@ xfs_dir2_sf_lookup( ...@@ -836,6 +837,7 @@ xfs_dir2_sf_lookup(
*/ */
if (args->namelen == 1 && args->name[0] == '.') { if (args->namelen == 1 && args->name[0] == '.') {
args->inumber = dp->i_ino; args->inumber = dp->i_ino;
args->cmpresult = XFS_CMP_EXACT;
return XFS_ERROR(EEXIST); return XFS_ERROR(EEXIST);
} }
/* /*
...@@ -844,27 +846,39 @@ xfs_dir2_sf_lookup( ...@@ -844,27 +846,39 @@ xfs_dir2_sf_lookup(
if (args->namelen == 2 && if (args->namelen == 2 &&
args->name[0] == '.' && args->name[1] == '.') { args->name[0] == '.' && args->name[1] == '.') {
args->inumber = xfs_dir2_sf_get_inumber(sfp, &sfp->hdr.parent); args->inumber = xfs_dir2_sf_get_inumber(sfp, &sfp->hdr.parent);
args->cmpresult = XFS_CMP_EXACT;
return XFS_ERROR(EEXIST); return XFS_ERROR(EEXIST);
} }
/* /*
* Loop over all the entries trying to match ours. * Loop over all the entries trying to match ours.
*/ */
for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->hdr.count;
i < sfp->hdr.count; i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep)) {
i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep)) { /*
if (sfep->namelen == args->namelen && * Compare name and if it's an exact match, return the inode
sfep->name[0] == args->name[0] && * number. If it's the first case-insensitive match, store the
memcmp(args->name, sfep->name, args->namelen) == 0) { * inode number and continue looking for an exact match.
args->inumber = */
xfs_dir2_sf_get_inumber(sfp, cmp = dp->i_mount->m_dirnameops->compname(args, sfep->name,
xfs_dir2_sf_inumberp(sfep)); sfep->namelen);
return XFS_ERROR(EEXIST); if (cmp != XFS_CMP_DIFFERENT && cmp != args->cmpresult) {
args->cmpresult = cmp;
args->inumber = xfs_dir2_sf_get_inumber(sfp,
xfs_dir2_sf_inumberp(sfep));
if (cmp == XFS_CMP_EXACT)
return XFS_ERROR(EEXIST);
} }
} }
ASSERT(args->oknoent);
/*
* Here, we can only be doing a lookup (not a rename or replace).
* If a case-insensitive match was found earlier, return "found".
*/
if (args->cmpresult == XFS_CMP_CASE)
return XFS_ERROR(EEXIST);
/* /*
* Didn't find it. * Didn't find it.
*/ */
ASSERT(args->oknoent);
return XFS_ERROR(ENOENT); return XFS_ERROR(ENOENT);
} }
...@@ -904,24 +918,21 @@ xfs_dir2_sf_removename( ...@@ -904,24 +918,21 @@ xfs_dir2_sf_removename(
* Loop over the old directory entries. * Loop over the old directory entries.
* Find the one we're deleting. * Find the one we're deleting.
*/ */
for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->hdr.count;
i < sfp->hdr.count; i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep)) {
i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep)) { if (xfs_da_compname(args, sfep->name, sfep->namelen) ==
if (sfep->namelen == args->namelen && XFS_CMP_EXACT) {
sfep->name[0] == args->name[0] &&
memcmp(sfep->name, args->name, args->namelen) == 0) {
ASSERT(xfs_dir2_sf_get_inumber(sfp, ASSERT(xfs_dir2_sf_get_inumber(sfp,
xfs_dir2_sf_inumberp(sfep)) == xfs_dir2_sf_inumberp(sfep)) ==
args->inumber); args->inumber);
break; break;
} }
} }
/* /*
* Didn't find it. * Didn't find it.
*/ */
if (i == sfp->hdr.count) { if (i == sfp->hdr.count)
return XFS_ERROR(ENOENT); return XFS_ERROR(ENOENT);
}
/* /*
* Calculate sizes. * Calculate sizes.
*/ */
...@@ -1042,11 +1053,10 @@ xfs_dir2_sf_replace( ...@@ -1042,11 +1053,10 @@ xfs_dir2_sf_replace(
*/ */
else { else {
for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp);
i < sfp->hdr.count; i < sfp->hdr.count;
i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep)) { i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep)) {
if (sfep->namelen == args->namelen && if (xfs_da_compname(args, sfep->name, sfep->namelen) ==
sfep->name[0] == args->name[0] && XFS_CMP_EXACT) {
memcmp(args->name, sfep->name, args->namelen) == 0) {
#if XFS_BIG_INUMS || defined(DEBUG) #if XFS_BIG_INUMS || defined(DEBUG)
ino = xfs_dir2_sf_get_inumber(sfp, ino = xfs_dir2_sf_get_inumber(sfp,
xfs_dir2_sf_inumberp(sfep)); xfs_dir2_sf_inumberp(sfep));
......
...@@ -61,6 +61,7 @@ struct xfs_bmap_free; ...@@ -61,6 +61,7 @@ struct xfs_bmap_free;
struct xfs_extdelta; struct xfs_extdelta;
struct xfs_swapext; struct xfs_swapext;
struct xfs_mru_cache; struct xfs_mru_cache;
struct xfs_nameops;
/* /*
* Prototypes and functions for the Data Migration subsystem. * Prototypes and functions for the Data Migration subsystem.
...@@ -315,6 +316,7 @@ typedef struct xfs_mount { ...@@ -315,6 +316,7 @@ typedef struct xfs_mount {
__uint8_t m_inode_quiesce;/* call quiesce on new inodes. __uint8_t m_inode_quiesce;/* call quiesce on new inodes.
field governed by m_ilock */ field governed by m_ilock */
__uint8_t m_sectbb_log; /* sectlog - BBSHIFT */ __uint8_t m_sectbb_log; /* sectlog - BBSHIFT */
const struct xfs_nameops *m_dirnameops; /* vector of dir name ops */
int m_dirblksize; /* directory block sz--bytes */ int m_dirblksize; /* directory block sz--bytes */
int m_dirblkfsbs; /* directory block sz--fsbs */ int m_dirblkfsbs; /* directory block sz--fsbs */
xfs_dablk_t m_dirdatablk; /* blockno of dir data v2 */ xfs_dablk_t m_dirdatablk; /* blockno of dir data v2 */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment